diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 973f3e074681..5835c94a0a8b 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -1,6 +1,358 @@ JUCE breaking changes ===================== +Version 7.0.7 +============= + +Change +------ +The minimum supported CMake version is now 3.22. + +Possible Issues +--------------- +It will no longer be possible to configure JUCE projects with CMake versions +between 3.15 and 3.21 inclusive. + +Workaround +---------- +No workaround is available. Newer versions of CMake can be obtained from the +official download page, or through system package managers. + +Rationale +--------- +Moving to CMake 3.22 improves consistency with the Projucer's Android exporter, +which already requires CMake 3.22. It also allows us to make use of the +XCODE_EMBED_APP_EXTENSIONS property (introduced in CMake 3.21), fixing an +issue when archiving AUv3 plugins. + + +Version 7.0.6 +============= + +Change +------ +Thread::wait and WaitableEvent::wait now take a double rather than an int to +indicate the number of milliseconds to wait. + +Possible Issues +--------------- +Calls to either wait function may trigger warnings. + +Workaround +---------- +Explicitly cast the value to double. + +Rationale +--------- +Changing to double allows sub-millisecond waits which was important for +supporting changes to the HighResolutionTimer. + + +Change +------ +RealtimeOptions member workDurationMs was replaced by three optional member +variables in RealtimeOptions, and all RealtimeOptions member variables were +marked private. + +Possible Issues +--------------- +Trying to construct a RealtimeOptions object with one or two values, or access +any of its member variables, will no longer compile. + +Workaround +---------- +Use the withMember functions to construct the object, and the getter functions +to access the member variable values. + +Rationale +--------- +The new approach improves the flexibility for users to specify realtime thread +options on macOS/iOS and improves the flexibility for the API to evolve without +introducing further breaking changes. + + +Change +------ +JUCE module compilation files with a platform suffix are now checked case +insensitively for CMake builds. + +Possible Issues +--------------- +If a JUCE module compilation file ends in a specific platform suffix but does +not match the case for the string previously checked by the CMake +implementation, it may have compiled for all platforms. Now, it will only +compile for the platform specified by the suffix. + +Workaround +---------- +In most cases this was probably a bug, in other cases rename the file to remove +the platform suffix. + +Rationale +--------- +This change improves consistency between the Projucer and CMake integrations. + + +Change +------ +An undocumented feature that allowed JUCE module compilation files to compile +for a specific platform or subset of platforms by declaring the platform name +followed by an underscore, was removed. + +Possible Issues +--------------- +If a JUCE module compilation file contains a matching platform suffix followed +by an underscore and is loaded by the Projucer it will no longer compile for +just that platform. + +Workaround +---------- +Use the suffix of the name only. If the undocumented feature was used to select +multiple platforms, make multiple separate files for each of the required +platforms. + +Rationale +--------- +This change improves consistency between the Projucer and CMake integrations. +Given the functionality was undocumented, the ease of a workaround, and the +added complexity required for CMake support, the functionality was removed. + + +Change +------ +Unique device IDs on iOS now use the OS provided 'identifierForVendor'. +OnlineUnlockStatus has been updated to handle the iOS edge-case where a device +ID query might return an empty String. + +Possible Issues +--------------- +The License checks using InAppPurchases, getLocalMachineIDs(), and +getUniqueDeviceID() may return an empty String if iOS 'is not ready'. This can +occur for example if the device has restarted but has not yet been unlocked. + +Workaround +---------- +InAppPurchase has been updated to handle this and propagate the error +accordingly. The relevant methods have been updated to return a Result object +that can be queried for additional information on failure. + +Rationale +--------- +Apple have introduced restrictions on device identification rendering our +previous methods unsuitable. + + +Change +------ +AudioProcessor::getAAXPluginIDForMainBusConfig() has been deprecated. + +Possible Issues +--------------- +Any AudioProcessor overriding this method will fail to compile. + +Workaround +---------- +- Create an object which inherits from AAXClientExtensions. +- In the object override and implement getPluginIDForMainBusConfig(). +- In the AudioProcessor override getAAXClientExtensions() and return a pointer + to the object. + +Rationale +--------- +Additional AAX specific functionality was required in the audio processor. +Rather than continuing to grow and expand the AudioProcessor class with format +specific functionality, separating this concern into a new class allows for +greater expansion for those that need it without burdening those that don't. +Moving this function into this class improves consistency both with the new +functionality and with similar functionality for the VST2 and VST3 formats. + + +Change +------ +Unique device IDs on Windows have been updated to use a more reliable SMBIOS +parser. The SystemStats::getUniqueDeviceID function now returns new IDs using +this improved parser. Additionally, a new function, +SystemStats::getMachineIdentifiers, has been introduced to aggregate all ID +sources. It is recommended to use this new function to verify any IDs. + +Possible Issues +---------------- +The SystemStats::getUniqueDeviceID function will return a different ID for the +same machine due to the updated parser. + +Workaround +---------- +For code that previously relied on SystemStats::getUniqueDeviceID, it is advised +to switch to using SystemStats::getMachineIdentifiers() instead. + +Rationale +--------- +This update ensures the generation of more stable and reliable unique device +IDs, while also maintaining backward compatibility with the previous ID +generation methods. + + +Change +------ +The Grid layout algorithm has been slightly altered to provide more consistent +behaviour. The new approach guarantees that dimensions specified using the +absolute Px quantity will always be correctly rounded when applied to the +integer dimensions of Components. + +Possible Issues +--------------- +Components laid out using Grid can observe a size or position change of +/- 1px +along each dimension compared with the result of the previous algorithm. + +Workaround +---------- +If the Grid based graphical layout is sensitive to changes of +/- 1px, then the +UI layout code may have to be adjusted to the new algorithm. + +Rationale +--------- +The old Grid layout algorithm could exhibit surprising and difficult to control +single pixel artifacts, where an item with a specified absolute size of +e.g. 100px could end up with a layout size of 101px. The new approach +guarantees that such items will have a layout size exactly as specified, and +this new behaviour is also in line with CSS behaviour in browsers. The new +approach makes necessary corrections easier as adding 1px to the size of an +item with absolute dimensions is guaranteed to translate into an observable 1px +increase in the layout size. + + +Change +------ +The k91_4 and k90_4 VST3 layouts are now mapped to the canonical JUCE 9.1.4 and +9.0.4 AudioChannelSets. This has a different ChannelType layout than the +AudioChannelSet previously used with such VST3 SpeakerArrangements. + +Possible Issues +--------------- +VST3 plugins that were prepared to work with the k91_4 and k90_4 +SpeakerArrangements may now have incorrect channel mapping. The channels +previously accessible through ChannelType::left and right are now accessible +through ChannelType::wideLeft and wideRight, and channels previously accessible +through ChannelType::leftCentre and rightCentre are now accessible through +ChannelType::left and right. + +Workaround +---------- +Code that accesses the channels that correspond to the VST3 Speakers kSpeakerL, +kSpeakerR, kSpeakerLc and kSpeakerRc needs to be updated. These channels are now +accessible respectively through ChannelTypes wideLeft, wideRight, left and +right. Previously they were accessible respectively through left, right, +leftCentre and rightCentre. + +Rationale +--------- +This change allows developers to handle the 9.1.4 and 9.0.4 surround layouts +with one codepath across all plugin formats. Previously the +AudioChannelSet::create9point1point4() and create9point0point4() layouts would +only be used in CoreAudio and AAX, but a different AudioChannelSet would be used +in VST3 even though they were functionally equivalent. + + +Change +------ +The signatures of the ContentSharer member functions have been updated. The +ContentSharer class itself is no longer a singleton. + +Possible Issues +--------------- +Projects that use the old signatures will not build until they are updated. + +Workaround +---------- +Instead of calling content sharer functions through a singleton instance, e.g. + ContentSharer::getInstance()->shareText (...); +call the static member functions directly: + ScopedMessageBox messageBox = ContentSharer::shareTextScoped (...); +The new functions return a ScopedMessageBox instance. On iOS, the content +sharer will only remain open for as long as the ScopedMessageBox remains alive. +On Android, this functionality will be added as/when the native APIs allow. + +Rationale +--------- +The new signatures are safer and easier to use. The ScopedMessageBox also +allows content sharers to be dismissed programmatically, which wasn't +previously possible. + + +Change +------ +The minimum supported AAX library version has been bumped to 2.4.0 and the +library is now built automatically while building an AAX plugin. The +JucePlugin_AAXLibs_path preprocessor definition is no longer defined in AAX +plugin builds. + +Possible Issues +--------------- +Projects that use the JucePlugin_AAXLibs_path definition may no longer build +correctly. Projects that reference an AAX library version earlier than 2.4.0 +will fail to build. + +Workaround +---------- +You must download an AAX library distribution with a version of at least 2.4.0. +Use the definition JucePlugin_Build_AAX to check whether the AAX format is +enabled at build time. + +Rationale +--------- +The JUCE framework now requires features only present in version 2.4.0 of the +AAX library. The build change removes steps from the build process, and ensures +that the same compiler flags are used across the entire project. + + +Change +------ +The implementation of ColourGradient::createLookupTable has been updated to use +non-premultiplied colours. + +Possible Issues +--------------- +Programs that draw transparent gradients using the OpenGL or software +renderers, or that use lookup tables generated from transparent gradients for +other purposes, may now produce different results. + +Workaround +---------- +For gradients to render the same as they did previously, transparent colour +stops should be un-premultiplied. For colours with an alpha component of 0, it +may be necessary to specify appropriate RGB components. + +Rationale +--------- +Previously, transparent gradients rendered using CoreGraphics looked different +to the same gradients drawn using OpenGL or the software renderer. This change +updates the OpenGL and software renderers, so that they produce the same +results as CoreGraphics. + + +Change +------ +Projucer-generated MSVC projects now build VST3s as bundles, rather than as +single DLL files. + +Possible Issues +--------------- +Build workflows that expect the VST3 to be a single DLL may break. + +Workaround +---------- +Any post-build scripts that expect to copy or move the built VST3 should be +updated so that the entire bundle directory is copied/moved. The DLL itself +can still be located and extracted from within the generated bundle if +necessary. + +Rationale +--------- +Distributing VST3s as single files was deprecated in VST3 v3.6.10. JUCE's CMake +scripts already produce VST3s as bundles, so this change increases consistency +between the two build systems. + + Version 7.0.3 ============= @@ -733,7 +1085,7 @@ querying the capabilities of the current context at runtime. Change ------ -The minimum support CMake version is now 3.15. +The minimum supported CMake version is now 3.15. Possible Issues --------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 4289d0672194..b8ff58e73a5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,9 +21,9 @@ # # ============================================================================== -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.22) -project(JUCE VERSION 7.0.5 LANGUAGES C CXX) +project(JUCE VERSION 7.0.7 LANGUAGES C CXX) include(CMakeDependentOption) @@ -160,14 +160,21 @@ install(FILES "${JUCE_BINARY_DIR}/JUCEConfigVersion.cmake" "${JUCE_CMAKE_UTILS_DIR}/checkBundleSigning.cmake" "${JUCE_CMAKE_UTILS_DIR}/copyDir.cmake" "${JUCE_CMAKE_UTILS_DIR}/juce_runtime_arch_detection.cpp" + "${JUCE_CMAKE_UTILS_DIR}/juce_LinuxSubprocessHelper.cpp" DESTINATION "${JUCE_INSTALL_DESTINATION}") -if("${CMAKE_SOURCE_DIR}" STREQUAL "${JUCE_SOURCE_DIR}") +if(("${CMAKE_SOURCE_DIR}" STREQUAL "${JUCE_SOURCE_DIR}") AND (NOT JUCE_BUILD_HELPER_TOOLS)) _juce_add_lv2_manifest_helper_target() if(TARGET juce_lv2_helper) install(TARGETS juce_lv2_helper EXPORT LV2_HELPER DESTINATION "bin/JUCE-${JUCE_VERSION}") install(EXPORT LV2_HELPER NAMESPACE juce:: DESTINATION "${JUCE_INSTALL_DESTINATION}") endif() -endif() + _juce_add_vst3_manifest_helper_target() + + if(TARGET juce_vst3_helper) + install(TARGETS juce_vst3_helper EXPORT VST3_HELPER DESTINATION "bin/JUCE-${JUCE_VERSION}") + install(EXPORT VST3_HELPER NAMESPACE juce:: DESTINATION "${JUCE_INSTALL_DESTINATION}") + endif() +endif() diff --git a/ChangeList.txt b/ChangeList.txt index 324eebbc8283..220633988a2b 100644 --- a/ChangeList.txt +++ b/ChangeList.txt @@ -3,6 +3,24 @@ This file just lists the more notable headline features. For more detailed info about changes and bugfixes please see the git log and BREAKING-CHANGES.txt. +Version 7.0.7 + - Fixed some macOS 14.0 deprecations + - Fixed some issues with VST3 manifest generation + - Fixed a Metal layer rendering issue + - Fixed an issue setting realtime thread priorities + - Fixed a crash in VirtualDesktopWatcher + - Fixed an AUv3 bundling problem + +Version 7.0.6 + - Added support for VST3 bundles and moduleinfo.json + - Improved message box dismissal + - Improved WebView support + - Updated to the latest VST3 and AAX SDKs + - Fixed some Metal layer rendering issues + - Improved ambisonic support + - Improved machine ID support + - Improved the HighResolutionTimer implementation + Version 7.0.5 - Fixed Windows 7 compatibility - Fixed dark mode notifications on macOS diff --git a/README.md b/README.md index 2f675c4411e2..7f4e4c23e751 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ JUCE is an open-source cross-platform C++ application framework for creating high quality desktop and mobile applications, including VST, VST3, AU, AUv3, AAX and LV2 audio plug-ins and plug-in hosts. JUCE can be easily integrated with existing projects via CMake, or can -be used as a project generation tool via the [Projucer](https://juce.com/discover/projucer), -which supports exporting projects for Xcode (macOS and iOS), Visual Studio, Android Studio, -Code::Blocks and Linux Makefiles as well as containing a source code editor. +be used as a project generation tool via the [Projucer](#the-projucer), which supports +exporting projects for Xcode (macOS and iOS), Visual Studio, Android Studio, Code::Blocks +and Linux Makefiles as well as containing a source code editor. ## Getting Started @@ -56,6 +56,7 @@ of the target you wish to build. #### Building JUCE Projects +- __C++ Standard__: 17+ - __macOS/iOS__: Xcode 10.1 (macOS 10.13.6) - __Windows__: Windows 8.1 and Visual Studio 2017 - __Linux__: g++ 7.0 or Clang 6.0 (for a full list of dependencies, see diff --git a/docs/CMake API.md b/docs/CMake API.md index 059c73ab7db7..2bd1d8f854d1 100644 --- a/docs/CMake API.md +++ b/docs/CMake API.md @@ -224,6 +224,15 @@ plugin folders may be protected, so the build may require elevated permissions i installation to work correctly, or you may need to adjust the permissions of the destination folders. +#### `JUCE_MODULES_ONLY` + +Only brings in targets for the built-in JUCE modules, and the `juce_add_module*` CMake functions. +This is meant for highly custom use-cases where the `juce_add_gui_app` and `juce_add_plugin` +functions are not required. Most importantly, the 'juceaide' helper tool is not built when this +option is enabled, which may improve build times for established products that use other methods to +handle plugin bundle structures, icons, plists, and so on. If this option is enabled, then +`JUCE_ENABLE_MODULE_SOURCE_GROUPS` will have no effect. + ### Functions #### `juce_add_` @@ -266,7 +275,7 @@ attributes directly to these creation functions, rather than adding them later. `BUNDLE_ID` - An identifier string in the form "com.yourcompany.productname" which should uniquely identify this target. Mainly used for macOS builds. If not specified, a default will be generated using - the target's `COMPANY_NAME` and `PRODUCT_NAME`. + the target's `COMPANY_NAME` and the name of the CMake target. `MICROPHONE_PERMISSION_ENABLED` - May be either TRUE or FALSE. Adds the appropriate entries to an app's Info.plist. @@ -635,6 +644,17 @@ attributes directly to these creation functions, rather than adding them later. `kARAPlaybackTransformationContentBasedFadeAtTail`, `kARAPlaybackTransformationContentBasedFadeAtHead` +`VST3_AUTO_MANIFEST` +- May be either TRUE or FALSE (defaults to TRUE). When TRUE, a POST_BUILD step will be added to the + VST3 target which will generate a moduleinfo.json file into the Resources subdirectory of the + plugin bundle. This is normally desirable, but does require that the plugin can be successfully + loaded immediately after building the VST3 target. If the plugin needs further processing before + it can be loaded (e.g. custom signing), then set this option to FALSE to disable the automatic + manifest generation. To generate the manifest at a later point in the build, use the + `juce_enable_vst3_manifest_step` function. It is strongly recommended to generate a manifest for + your plugin, as this allows compatible hosts to scan the plugin much more quickly, leading to + an improved experience for users. + #### `juce_add_binary_data` juce_add_binary_data( @@ -695,6 +715,19 @@ If your custom build steps need to use the location of the plugin artefact, you by querying the property `JUCE_PLUGIN_ARTEFACT_FILE` on a plugin target (*not* the shared code target!). +#### `juce_enable_vst3_manifest_step` + + juce_enable_vst3_manifest_step() + +You may call this function to manually enable VST3 manifest generation on a plugin. The argument to +this function should be a target previously created with `juce_add_plugin`. + +VST3_AUTO_MANIFEST TRUE will cause the VST3 manifest to be generated immediately after building. +This is not always appropriate, if extra build steps (such as signing or modifying the plugin +bundle) must be executed before the plugin can be loaded. In such cases, you should set +VST3_AUTO_MANIFEST FALSE, use `add_custom_command(TARGET POST_BUILD)` to add your own post-build +steps, and then finally call `juce_enable_vst3_manifest_step`. + #### `juce_set__sdk_path` juce_set_aax_sdk_path() @@ -755,6 +788,21 @@ This function sets the `CMAKE__FLAGS_` to empty in the current direc allowing alternative optimisation/debug flags to be supplied without conflicting with the CMake-supplied defaults. +#### `juce_link_with_embedded_linux_subprocess` + + juce_link_with_embedded_linux_subprocess() + +This function links the provided target with an interface library that generates a barebones +standalone executable file and embeds it as a binary resource. This binary resource is only used +by the `juce_gui_extra` module and only when its `JUCE_WEB_BROWSER` capability is enabled. This +executable will then be deployed into a temporary file only when the code is running in a +non-standalone format, and will be used to host a WebKit view. This technique is used by audio +plugins on Linux. + +This function is automatically called if necessary for all targets created by one of the JUCE target +creation functions i.e. `juce_add_gui_app`, `juce_add_console_app` and `juce_add_gui_app`. You don't +need to call this function manually in these cases. + ### Targets #### `juce::juce_recommended_warning_flags` diff --git a/docs/JUCE Module Format.md b/docs/JUCE Module Format.md index c114b302aa8e..af59a76f22ea 100644 --- a/docs/JUCE Module Format.md +++ b/docs/JUCE Module Format.md @@ -65,28 +65,28 @@ adding these files to their projects. The names of these source files must begin with the name of the module, but they can have a number or other suffix if there is more than one. -In order to specify that a source file should only be compiled on a specific platform, -then the filename can be suffixed with one of the following strings: +In order to specify that a source file should only be compiled for a specific platform, +then the filename can be suffixed with one of the following (case insensitive) strings: - _OSX - _Windows - _Linux - _Android - _iOS + _mac or _osx <- compiled for macOS and OSX platforms only + _windows <- compiled for Windows platforms only + _linux <- compiled for Linux and FreeBSD platforms only + _andoid <- compiled for Android platforms only + _ios <- compiled for iOS platforms only e.g. - juce_mymodule/juce_mymodule_1.cpp <- compiled on all platforms - juce_mymodule/juce_mymodule_2.cpp <- compiled on all platforms - juce_mymodule/juce_mymodule_OSX.cpp <- compiled only on OSX - juce_mymodule/juce_mymodule_Windows.cpp <- compiled only on Windows + juce_mymodule/juce_mymodule_1.cpp <- compiled for all platforms + juce_mymodule/juce_mymodule_2.cpp <- compiled for all platforms + juce_mymodule/juce_mymodule_mac.cpp <- compiled for macOS and OSX platforms only + juce_mymodule/juce_mymodule_windows.cpp <- compiled for Windows platforms only Often this isn't necessary, as in most cases you can easily add checks inside the files to do different things depending on the platform, but this may be handy just to avoid clutter in user projects where files aren't needed. To simplify the use of obj-C++ there's also a special-case rule: If the folder contains -both a .mm and a .cpp file whose names are otherwise identical, then on OSX/iOS the .mm +both a .mm and a .cpp file whose names are otherwise identical, then on macOS/iOS the .mm will be used and the cpp ignored. (And vice-versa for other platforms, of course). diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 9ce59be69d0e..13de46435ddf 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.6 +# Doxyfile 1.9.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -374,6 +374,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 0 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -498,6 +509,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -604,7 +623,7 @@ HIDE_IN_BODY_DOCS = YES # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. -INTERNAL_DOCS = YES +INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the @@ -883,7 +902,14 @@ WARN_IF_UNDOC_ENUM_VAL = NO # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -1026,11 +1052,8 @@ EXCLUDE_PATTERNS = juce_GIFLoader* \ # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = detail # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -1371,15 +1394,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1399,6 +1413,14 @@ HTML_DYNAMIC_MENUS = NO HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING and SOURCE_BROWSER tags are set to YES then classes +# and functions can be dynamically folded and expanded in the generated HTML +# source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1529,6 +1551,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -2017,9 +2049,16 @@ PDF_HYPERLINKS = NO USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag ignals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2040,14 +2079,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2213,7 +2244,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -2275,7 +2306,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2330,7 +2361,16 @@ PREDEFINED = WIN32=1 \ JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES=1 \ JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL=1 \ JUCE_COMPILER_SUPPORTS_LAMBDAS=1 \ - JUCE_MODAL_LOOPS_PERMITTED=1 + JUCE_MODAL_LOOPS_PERMITTED=1 \ + JUCE_HAS_CONSTEXPR=1 \ + JUCE_CONSTEXPR=constexpr \ + JUCE_IGNORE_MSVC(warnings)= \ + JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC(level, warnings)= \ + JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings)= \ + JUCE_END_IGNORE_WARNINGS_MSVC= \ + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...)= \ + JUCE_END_IGNORE_WARNINGS_GCC_LIKE= \ + JUCE_ENABLE_ALLOCATION_HOOKS=0 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2398,16 +2438,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2416,7 +2449,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2469,13 +2502,15 @@ DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a -# graph for each documented class showing the direct and indirect inheritance -# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, -# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set -# to TEXT the direct and indirect inheritance relations will be shown as texts / -# links. -# Possible values are: NO, YES, TEXT and GRAPH. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. CLASS_GRAPH = YES @@ -2616,7 +2651,7 @@ DIR_GRAPH_MAX_DEPTH = 1 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2653,11 +2688,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2734,3 +2770,19 @@ GENERATE_LEGEND = NO # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/examples/Assets/DSPDemos_Common.h b/examples/Assets/DSPDemos_Common.h index 9fa1d5c3a087..26d0e3b966d2 100644 --- a/examples/Assets/DSPDemos_Common.h +++ b/examples/Assets/DSPDemos_Common.h @@ -596,13 +596,17 @@ class AudioFileReaderComponent : public Component, const auto u = fc.getURLResult(); if (! audioFileReader.loadURL (u)) - NativeMessageBox::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::WarningIcon) - .withTitle ("Error loading file") - .withMessage ("Unable to load audio file"), - nullptr); + { + auto options = MessageBoxOptions().withIconType (MessageBoxIconType::WarningIcon) + .withTitle ("Error loading file") + .withMessage ("Unable to load audio file") + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); + } else + { thumbnailComp.setCurrentURL (u); + } } fileChooser = nullptr; @@ -629,6 +633,7 @@ class AudioFileReaderComponent : public Component, AudioFileReaderComponent& audioFileReader; std::unique_ptr fileChooser; + ScopedMessageBox messageBox; }; //============================================================================== diff --git a/examples/Assets/DemoUtilities.h b/examples/Assets/DemoUtilities.h index ffdfc3631c93..b2d38fffb610 100644 --- a/examples/Assets/DemoUtilities.h +++ b/examples/Assets/DemoUtilities.h @@ -244,10 +244,8 @@ struct SlowerBouncingNumber : public BouncingNumber inline std::unique_ptr makeInputSource (const URL& url) { - #if JUCE_ANDROID - if (auto doc = AndroidDocument::fromDocument (url)) + if (const auto doc = AndroidDocument::fromDocument (url)) return std::make_unique (doc); - #endif #if ! JUCE_IOS if (url.isLocalFile()) @@ -257,4 +255,17 @@ inline std::unique_ptr makeInputSource (const URL& url) return std::make_unique (url); } +inline std::unique_ptr makeOutputStream (const URL& url) +{ + if (const auto doc = AndroidDocument::fromDocument (url)) + return doc.createOutputStream(); + + #if ! JUCE_IOS + if (url.isLocalFile()) + return url.getLocalFile().createOutputStream(); + #endif + + return url.createOutputStream(); +} + #endif // PIP_DEMO_UTILITIES_INCLUDED diff --git a/examples/Audio/AudioPlaybackDemo.h b/examples/Audio/AudioPlaybackDemo.h index 6d317f446604..211fadd1e1da 100644 --- a/examples/Audio/AudioPlaybackDemo.h +++ b/examples/Audio/AudioPlaybackDemo.h @@ -188,7 +188,7 @@ class DemoThumbnailComp : public Component, if (canMoveTransport()) setRange ({ newStart, newStart + visibleRange.getLength() }); - if (wheel.deltaY != 0.0f) + if (! approximatelyEqual (wheel.deltaY, 0.0f)) zoomSlider.setValue (zoomSlider.getValue() - wheel.deltaY); repaint(); @@ -312,12 +312,7 @@ class AudioPlaybackDemo : public Component, thread.startThread (Thread::Priority::normal); #ifndef JUCE_DEMO_RUNNER - RuntimePermissions::request (RuntimePermissions::recordAudio, - [this] (bool granted) - { - int numInputChannels = granted ? 2 : 0; - audioDeviceManager.initialise (numInputChannels, 2, nullptr, true, {}, nullptr); - }); + audioDeviceManager.initialise (0, 2, nullptr, true, {}, nullptr); #endif audioDeviceManager.addAudioCallback (&audioSourcePlayer); @@ -415,9 +410,14 @@ class AudioPlaybackDemo : public Component, //============================================================================== void showAudioResource (URL resource) { - if (loadURLIntoTransport (resource)) - currentAudioFile = std::move (resource); + if (! loadURLIntoTransport (resource)) + { + // Failed to load the audio file! + jassertfalse; + return; + } + currentAudioFile = std::move (resource); zoomSlider.setValue (0, dontSendNotification); thumbnail->setURL (currentAudioFile); } @@ -492,7 +492,7 @@ class AudioPlaybackDemo : public Component, if (FileChooser::isPlatformDialogAvailable()) { - fileChooser = std::make_unique ("Select an audio file...", File(), "*.wav;*.mp3;*.aif"); + fileChooser = std::make_unique ("Select an audio file...", File(), "*.wav;*.flac;*.aif"); fileChooser->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles, [this] (const FileChooser& fc) mutable diff --git a/examples/Audio/AudioRecordingDemo.h b/examples/Audio/AudioRecordingDemo.h index 38bf15b7d7b8..8084383caa9e 100644 --- a/examples/Audio/AudioRecordingDemo.h +++ b/examples/Audio/AudioRecordingDemo.h @@ -305,17 +305,14 @@ class AudioRecordingDemo : public Component LiveScrollingAudioDisplay liveAudioScroller; RecordingThumbnail recordingThumbnail; - AudioRecorder recorder { recordingThumbnail.getAudioThumbnail() }; - - Label explanationLabel { {}, "This page demonstrates how to record a wave file from the live audio input..\n\n" - #if (JUCE_ANDROID || JUCE_IOS) - "After you are done with your recording you can share with other apps." - #else - "Pressing record will start recording a file in your \"Documents\" folder." - #endif - }; + AudioRecorder recorder { recordingThumbnail.getAudioThumbnail() }; + + Label explanationLabel { {}, + "This page demonstrates how to record a wave file from the live audio input.\n\n" + "After you are done with your recording you can choose where to save it." }; TextButton recordButton { "Record" }; File lastRecording; + FileChooser chooser { "Output file...", File::getCurrentWorkingDirectory().getChildFile ("recording.wav"), "*.wav" }; void startRecording() { @@ -350,28 +347,18 @@ class AudioRecordingDemo : public Component { recorder.stop(); - #if JUCE_CONTENT_SHARING - SafePointer safeThis (this); - File fileToShare = lastRecording; - - ContentSharer::getInstance()->shareFiles (Array ({URL (fileToShare)}), - [safeThis, fileToShare] (bool success, const String& error) - { - if (fileToShare.existsAsFile()) - fileToShare.deleteFile(); - - if (! success && error.isNotEmpty()) - NativeMessageBox::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::WarningIcon) - .withTitle ("Sharing Error") - .withMessage (error), - nullptr); - }); - #endif - - lastRecording = File(); - recordButton.setButtonText ("Record"); - recordingThumbnail.setDisplayFullThumbnail (true); + chooser.launchAsync ( FileBrowserComponent::saveMode + | FileBrowserComponent::canSelectFiles + | FileBrowserComponent::warnAboutOverwriting, + [this] (const FileChooser& c) + { + if (FileInputStream inputStream (lastRecording); inputStream.openedOk()) + if (const auto outputStream = makeOutputStream (c.getURLResult())) + outputStream->writeFromInputStream (inputStream, -1); + + recordButton.setButtonText ("Record"); + recordingThumbnail.setDisplayFullThumbnail (true); + }); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioRecordingDemo) diff --git a/examples/Audio/AudioSynthesiserDemo.h b/examples/Audio/AudioSynthesiserDemo.h index 11891911b621..a70b3d7e84be 100644 --- a/examples/Audio/AudioSynthesiserDemo.h +++ b/examples/Audio/AudioSynthesiserDemo.h @@ -55,8 +55,6 @@ /** Our demo synth sound is just a basic sine wave.. */ struct SineWaveSound : public SynthesiserSound { - SineWaveSound() {} - bool appliesToNote (int /*midiNoteNumber*/) override { return true; } bool appliesToChannel (int /*midiChannel*/) override { return true; } }; @@ -65,8 +63,6 @@ struct SineWaveSound : public SynthesiserSound /** Our demo synth voice just plays a sine wave.. */ struct SineWaveVoice : public SynthesiserVoice { - SineWaveVoice() {} - bool canPlaySound (SynthesiserSound* sound) override { return dynamic_cast (sound) != nullptr; @@ -92,8 +88,8 @@ struct SineWaveVoice : public SynthesiserVoice // start a tail-off by setting this flag. The render callback will pick up on // this and do a fade out, calling clearCurrentNote() when it's finished. - if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the - tailOff = 1.0; // stopNote method could be called more than once. + if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the + tailOff = 1.0; // stopNote method could be called more than once. } else { @@ -108,7 +104,7 @@ struct SineWaveVoice : public SynthesiserVoice void renderNextBlock (AudioBuffer& outputBuffer, int startSample, int numSamples) override { - if (angleDelta != 0.0) + if (! approximatelyEqual (angleDelta, 0.0)) { if (tailOff > 0.0) { @@ -241,6 +237,51 @@ struct SynthAudioSource : public AudioSource Synthesiser synth; }; +//============================================================================== +class Callback : public AudioIODeviceCallback +{ +public: + Callback (AudioSourcePlayer& playerIn, LiveScrollingAudioDisplay& displayIn) + : player (playerIn), display (displayIn) {} + + void audioDeviceIOCallbackWithContext (const float* const* inputChannelData, + int numInputChannels, + float* const* outputChannelData, + int numOutputChannels, + int numSamples, + const AudioIODeviceCallbackContext& context) override + { + player.audioDeviceIOCallbackWithContext (inputChannelData, + numInputChannels, + outputChannelData, + numOutputChannels, + numSamples, + context); + display.audioDeviceIOCallbackWithContext (outputChannelData, + numOutputChannels, + nullptr, + 0, + numSamples, + context); + } + + void audioDeviceAboutToStart (AudioIODevice* device) override + { + player.audioDeviceAboutToStart (device); + display.audioDeviceAboutToStart (device); + } + + void audioDeviceStopped() override + { + player.audioDeviceStopped(); + display.audioDeviceStopped(); + } + +private: + AudioSourcePlayer& player; + LiveScrollingAudioDisplay& display; +}; + //============================================================================== class AudioSynthesiserDemo : public Component { @@ -259,19 +300,13 @@ class AudioSynthesiserDemo : public Component sampledButton.onClick = [this] { synthAudioSource.setUsingSampledSound(); }; addAndMakeVisible (liveAudioDisplayComp); - audioDeviceManager.addAudioCallback (&liveAudioDisplayComp); audioSourcePlayer.setSource (&synthAudioSource); #ifndef JUCE_DEMO_RUNNER - RuntimePermissions::request (RuntimePermissions::recordAudio, - [this] (bool granted) - { - int numInputChannels = granted ? 2 : 0; - audioDeviceManager.initialise (numInputChannels, 2, nullptr, true, {}, nullptr); - }); + audioDeviceManager.initialise (0, 2, nullptr, true, {}, nullptr); #endif - audioDeviceManager.addAudioCallback (&audioSourcePlayer); + audioDeviceManager.addAudioCallback (&callback); audioDeviceManager.addMidiInputDeviceCallback ({}, &(synthAudioSource.midiCollector)); setOpaque (true); @@ -282,8 +317,7 @@ class AudioSynthesiserDemo : public Component { audioSourcePlayer.setSource (nullptr); audioDeviceManager.removeMidiInputDeviceCallback ({}, &(synthAudioSource.midiCollector)); - audioDeviceManager.removeAudioCallback (&audioSourcePlayer); - audioDeviceManager.removeAudioCallback (&liveAudioDisplayComp); + audioDeviceManager.removeAudioCallback (&callback); } //============================================================================== @@ -318,5 +352,7 @@ class AudioSynthesiserDemo : public Component LiveScrollingAudioDisplay liveAudioDisplayComp; + Callback callback { audioSourcePlayer, liveAudioDisplayComp }; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSynthesiserDemo) }; diff --git a/examples/Audio/MPEDemo.h b/examples/Audio/MPEDemo.h index 10615ee7336d..dfb2a4c08cde 100644 --- a/examples/Audio/MPEDemo.h +++ b/examples/Audio/MPEDemo.h @@ -279,13 +279,14 @@ class MPESetupComponent : public Component return legacyStartChannel.getText().getIntValue() <= legacyEndChannel.getText().getIntValue(); } - void handleInvalidLegacyModeParameters() const + void handleInvalidLegacyModeParameters() { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Invalid legacy mode channel layout", - "Cannot set legacy mode start/end channel:\n" - "The end channel must not be less than the start channel!", - "Got it"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Invalid legacy mode channel layout", + "Cannot set legacy mode start/end channel:\n" + "The end channel must not be less than the start channel!", + "Got it"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } Range getLegacyModeChannelRange() const @@ -338,6 +339,8 @@ class MPESetupComponent : public Component ComboBox numberOfVoices; Label numberOfVoicesLabel { {}, "Number of synth voices"}; + ScopedMessageBox messageBox; + static constexpr int defaultMemberChannels = 15, defaultMasterPitchbendRange = 2, defaultNotePitchbendRange = 48; @@ -496,8 +499,8 @@ class MPEDemoSynthVoice : public MPESynthesiserVoice // start a tail-off by setting this flag. The render callback will pick up on // this and do a fade out, calling clearCurrentNote() when it's finished. - if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the - // stopNote method could be called more than once. + if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the + // stopNote method could be called more than once. tailOff = 1.0; } else @@ -527,7 +530,7 @@ class MPEDemoSynthVoice : public MPESynthesiserVoice void setCurrentSampleRate (double newRate) override { - if (currentSampleRate != newRate) + if (! approximatelyEqual (currentSampleRate, newRate)) { noteStopped (false); currentSampleRate = newRate; @@ -543,7 +546,7 @@ class MPEDemoSynthVoice : public MPESynthesiserVoice int startSample, int numSamples) override { - if (phaseDelta != 0.0) + if (! approximatelyEqual (phaseDelta, 0.0)) { if (tailOff > 0.0) { diff --git a/examples/Audio/MidiDemo.h b/examples/Audio/MidiDemo.h index 35e9db0e1548..6287818ada5f 100644 --- a/examples/Audio/MidiDemo.h +++ b/examples/Audio/MidiDemo.h @@ -52,19 +52,27 @@ //============================================================================== struct MidiDeviceListEntry : ReferenceCountedObject { - MidiDeviceListEntry (MidiDeviceInfo info) : deviceInfo (info) {} + explicit MidiDeviceListEntry (MidiDeviceInfo info) : deviceInfo (info) {} MidiDeviceInfo deviceInfo; std::unique_ptr inDevice; std::unique_ptr outDevice; using Ptr = ReferenceCountedObjectPtr; + + void stopAndReset() + { + if (inDevice != nullptr) + inDevice->stop(); + + inDevice .reset(); + outDevice.reset(); + } }; //============================================================================== class MidiDemo : public Component, - private Timer, private MidiKeyboardState::Listener, private MidiInputCallback, private AsyncUpdater @@ -113,12 +121,11 @@ class MidiDemo : public Component, setSize (732, 520); - startTimer (500); + updateDeviceLists(); } ~MidiDemo() override { - stopTimer(); midiInputs .clear(); midiOutputs.clear(); keyboardState.removeListener (this); @@ -128,12 +135,6 @@ class MidiDemo : public Component, } //============================================================================== - void timerCallback() override - { - updateDeviceList (true); - updateDeviceList (false); - } - void handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override { MidiMessage m (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity)); @@ -211,17 +212,8 @@ class MidiDemo : public Component, void closeDevice (bool isInput, int index) { - if (isInput) - { - jassert (midiInputs[index]->inDevice.get() != nullptr); - midiInputs[index]->inDevice->stop(); - midiInputs[index]->inDevice.reset(); - } - else - { - jassert (midiOutputs[index]->outDevice.get() != nullptr); - midiOutputs[index]->outDevice.reset(); - } + auto& list = isInput ? midiInputs : midiOutputs; + list[index]->stopAndReset(); } int getNumMidiInputs() const noexcept @@ -423,7 +415,6 @@ class MidiDemo : public Component, if (hasDeviceListChanged (availableDevices, isInputDeviceList)) { - ReferenceCountedArray& midiDevices = isInputDeviceList ? midiInputs : midiOutputs; @@ -463,6 +454,12 @@ class MidiDemo : public Component, addAndMakeVisible (label); } + void updateDeviceLists() + { + for (const auto isInput : { true, false }) + updateDeviceList (isInput); + } + //============================================================================== Label midiInputLabel { "Midi Input Label", "MIDI Input:" }; Label midiOutputLabel { "Midi Output Label", "MIDI Output:" }; @@ -473,12 +470,17 @@ class MidiDemo : public Component, TextEditor midiMonitor { "MIDI Monitor" }; TextButton pairButton { "MIDI Bluetooth devices..." }; - std::unique_ptr midiInputSelector, midiOutputSelector; ReferenceCountedArray midiInputs, midiOutputs; + std::unique_ptr midiInputSelector, midiOutputSelector; CriticalSection midiMonitorLock; Array incomingMessages; + MidiDeviceListConnection connection = MidiDeviceListConnection::make ([this] + { + updateDeviceLists(); + }); + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiDemo) }; diff --git a/examples/DSP/FIRFilterDemo.h b/examples/DSP/FIRFilterDemo.h index a0fa4148d0e8..ffbf3866766e 100644 --- a/examples/DSP/FIRFilterDemo.h +++ b/examples/DSP/FIRFilterDemo.h @@ -77,7 +77,7 @@ struct FIRFilterDemoDSP void updateParameters() { - if (sampleRate != 0.0) + if (! approximatelyEqual (sampleRate, 0.0)) { auto cutoff = static_cast (cutoffParam.getCurrentValue()); auto windowingMethod = static_cast::WindowingMethod> (typeParam.getCurrentSelectedID() - 1); diff --git a/examples/DSP/IIRFilterDemo.h b/examples/DSP/IIRFilterDemo.h index b12f0e70a9fb..92c8e0730f5a 100644 --- a/examples/DSP/IIRFilterDemo.h +++ b/examples/DSP/IIRFilterDemo.h @@ -76,7 +76,7 @@ struct IIRFilterDemoDSP void updateParameters() { - if (sampleRate != 0.0) + if (! approximatelyEqual (sampleRate, 0.0)) { auto cutoff = static_cast (cutoffParam.getCurrentValue()); auto qVal = static_cast (qParam.getCurrentValue()); diff --git a/examples/DSP/OverdriveDemo.h b/examples/DSP/OverdriveDemo.h index c00f700ec0f6..84f0242ecb42 100644 --- a/examples/DSP/OverdriveDemo.h +++ b/examples/DSP/OverdriveDemo.h @@ -90,7 +90,7 @@ struct OverdriveDemoDSP void updateParameters() { - if (sampleRate != 0.0) + if (! approximatelyEqual (sampleRate, 0.0)) { overdrive.get<0>().setGainDecibels (static_cast (inGainParam.getCurrentValue())); overdrive.get<4>().setGainDecibels (static_cast (outGainParam.getCurrentValue())); diff --git a/examples/DSP/SIMDRegisterDemo.h b/examples/DSP/SIMDRegisterDemo.h index f1ba7cde2b4c..a4ccd4cd7831 100644 --- a/examples/DSP/SIMDRegisterDemo.h +++ b/examples/DSP/SIMDRegisterDemo.h @@ -124,7 +124,7 @@ struct SIMDRegisterDemoDSP void updateParameters() { - if (sampleRate != 0.0) + if (! approximatelyEqual (sampleRate, 0.0)) { auto cutoff = static_cast (cutoffParam.getCurrentValue()); auto qVal = static_cast (qParam.getCurrentValue()); diff --git a/examples/DSP/StateVariableFilterDemo.h b/examples/DSP/StateVariableFilterDemo.h index e9b97b542472..d92479cdca12 100644 --- a/examples/DSP/StateVariableFilterDemo.h +++ b/examples/DSP/StateVariableFilterDemo.h @@ -74,7 +74,7 @@ struct StateVariableFilterDemoDSP void updateParameters() { - if (sampleRate != 0.0) + if (! approximatelyEqual (sampleRate, 0.0)) { filter.setCutoffFrequency (static_cast (cutoffParam.getCurrentValue())); filter.setResonance (static_cast (qParam.getCurrentValue())); diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt index 5b9e96454320..b0472976cf41 100644 --- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt +++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt @@ -1,7 +1,7 @@ # Automatically generated CMakeLists, created by the Projucer # Don't edit this file! Your changes will be overwritten when you re-save the Projucer project! -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.22) project(juce_jni_project) @@ -14,7 +14,7 @@ add_subdirectory (${OBOE_DIR} ./oboe) add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression") -add_definitions([[-DJUCE_ANDROID=1]] [[-DJUCE_ANDROID_API_VERSION=23]] [[-DJUCE_PUSH_NOTIFICATIONS=1]] [[-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY="com/rmsl/juce/JuceActivity"]] [[-DJUCE_CONTENT_SHARING=1]] [[-DJUCE_ANDROID_GL_ES_VERSION_3_0=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.5]] [[-DJUCE_APP_VERSION_HEX=0x70005]]) +add_definitions([[-DJUCE_ANDROID=1]] [[-DJUCE_ANDROID_API_VERSION=23]] [[-DJUCE_PUSH_NOTIFICATIONS=1]] [[-DJUCE_PUSH_NOTIFICATIONS_ACTIVITY="com/rmsl/juce/JuceActivity"]] [[-DJUCE_CONTENT_SHARING=1]] [[-DJUCE_ANDROID_GL_ES_VERSION_3_0=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.7]] [[-DJUCE_APP_VERSION_HEX=0x70007]]) include_directories( AFTER "../../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src" @@ -34,9 +34,9 @@ include_directories( AFTER enable_language(ASM) if(JUCE_BUILD_CONFIGURATION MATCHES "DEBUG") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_analytics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_box2d=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1]] [[-DJUCE_MODULE_AVAILABLE_juce_video=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_USE_MP3AUDIOFORMAT=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0]] [[-DJUCE_STRICT_REFCOUNTEDPOINTER=1]] [[-DJUCE_USE_CAMERA=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.5]] [[-DJUCE_APP_VERSION_HEX=0x70005]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_analytics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_box2d=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1]] [[-DJUCE_MODULE_AVAILABLE_juce_video=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_USE_MP3AUDIOFORMAT=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0]] [[-DJUCE_STRICT_REFCOUNTEDPOINTER=1]] [[-DJUCE_USE_CAMERA=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.7]] [[-DJUCE_APP_VERSION_HEX=0x70007]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) elseif(JUCE_BUILD_CONFIGURATION MATCHES "RELEASE") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_analytics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_box2d=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1]] [[-DJUCE_MODULE_AVAILABLE_juce_video=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_USE_MP3AUDIOFORMAT=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0]] [[-DJUCE_STRICT_REFCOUNTEDPOINTER=1]] [[-DJUCE_USE_CAMERA=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.5]] [[-DJUCE_APP_VERSION_HEX=0x70005]] [[-DNDEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_analytics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_box2d=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1]] [[-DJUCE_MODULE_AVAILABLE_juce_video=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_USE_MP3AUDIOFORMAT=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0]] [[-DJUCE_STRICT_REFCOUNTEDPOINTER=1]] [[-DJUCE_USE_CAMERA=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEMO_RUNNER=1]] [[-DJUCE_UNIT_TESTS=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=7.0.7]] [[-DJUCE_APP_VERSION_HEX=0x70007]] [[-DNDEBUG=1]]) else() message( FATAL_ERROR "No matching build-configuration found." ) endif() @@ -129,8 +129,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -306,23 +306,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -609,6 +609,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -639,6 +640,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -676,14 +678,34 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -763,6 +785,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -785,9 +809,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -814,16 +838,16 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -954,6 +978,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -993,6 +1018,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -1018,6 +1044,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -1027,41 +1055,44 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -1255,13 +1286,13 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_dsp/maths/juce_Polynomial.h" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.cpp" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.h" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.h" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.cpp" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.h" "../../../../../modules/juce_dsp/processors/juce_DelayLine.cpp" @@ -1318,6 +1349,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -1339,19 +1372,20 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -1503,24 +1537,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -1580,6 +1614,27 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -1634,6 +1689,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -1720,63 +1777,77 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -1844,18 +1915,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -1902,24 +1978,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -1929,9 +2005,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" @@ -1988,21 +2064,21 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_product_unlocking/marketplace/juce_OnlineUnlockStatus.h" "../../../../../modules/juce_product_unlocking/marketplace/juce_TracktionMarketplaceStatus.cpp" "../../../../../modules/juce_product_unlocking/marketplace/juce_TracktionMarketplaceStatus.h" - "../../../../../modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp" - "../../../../../modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp" + "../../../../../modules/juce_product_unlocking/native/juce_InAppPurchases_android.cpp" + "../../../../../modules/juce_product_unlocking/native/juce_InAppPurchases_ios.cpp" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.cpp" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.mm" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.h" "../../../../../modules/juce_video/capture/juce_CameraDevice.cpp" "../../../../../modules/juce_video/capture/juce_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_android_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_android_Video.h" - "../../../../../modules/juce_video/native/juce_ios_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_mac_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_mac_Video.h" - "../../../../../modules/juce_video/native/juce_win32_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_win32_ComTypes.h" - "../../../../../modules/juce_video/native/juce_win32_Video.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_android.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_ios.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_mac.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_windows.h" + "../../../../../modules/juce_video/native/juce_ComTypes_windows.h" + "../../../../../modules/juce_video/native/juce_Video_android.h" + "../../../../../modules/juce_video/native/juce_Video_mac.h" + "../../../../../modules/juce_video/native/juce_Video_windows.h" "../../../../../modules/juce_video/playback/juce_VideoComponent.cpp" "../../../../../modules/juce_video/playback/juce_VideoComponent.h" "../../../../../modules/juce_video/juce_video.cpp" @@ -2111,8 +2187,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -2288,23 +2364,23 @@ set_source_files_properties( "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -2591,6 +2667,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -2621,6 +2698,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -2658,14 +2736,34 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -2745,6 +2843,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -2767,9 +2867,9 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -2796,16 +2896,16 @@ set_source_files_properties( "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -2936,6 +3036,7 @@ set_source_files_properties( "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -2975,6 +3076,7 @@ set_source_files_properties( "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -3000,6 +3102,8 @@ set_source_files_properties( "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -3009,41 +3113,44 @@ set_source_files_properties( "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -3237,13 +3344,13 @@ set_source_files_properties( "../../../../../modules/juce_dsp/maths/juce_Polynomial.h" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.cpp" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.h" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.h" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.cpp" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.h" "../../../../../modules/juce_dsp/processors/juce_DelayLine.cpp" @@ -3300,6 +3407,8 @@ set_source_files_properties( "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -3321,19 +3430,20 @@ set_source_files_properties( "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -3485,24 +3595,24 @@ set_source_files_properties( "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -3562,6 +3672,27 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -3616,6 +3747,8 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -3702,63 +3835,77 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -3826,18 +3973,23 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -3884,24 +4036,24 @@ set_source_files_properties( "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -3911,9 +4063,9 @@ set_source_files_properties( "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" @@ -3970,21 +4122,21 @@ set_source_files_properties( "../../../../../modules/juce_product_unlocking/marketplace/juce_OnlineUnlockStatus.h" "../../../../../modules/juce_product_unlocking/marketplace/juce_TracktionMarketplaceStatus.cpp" "../../../../../modules/juce_product_unlocking/marketplace/juce_TracktionMarketplaceStatus.h" - "../../../../../modules/juce_product_unlocking/native/juce_android_InAppPurchases.cpp" - "../../../../../modules/juce_product_unlocking/native/juce_ios_InAppPurchases.cpp" + "../../../../../modules/juce_product_unlocking/native/juce_InAppPurchases_android.cpp" + "../../../../../modules/juce_product_unlocking/native/juce_InAppPurchases_ios.cpp" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.cpp" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.mm" "../../../../../modules/juce_product_unlocking/juce_product_unlocking.h" "../../../../../modules/juce_video/capture/juce_CameraDevice.cpp" "../../../../../modules/juce_video/capture/juce_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_android_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_android_Video.h" - "../../../../../modules/juce_video/native/juce_ios_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_mac_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_mac_Video.h" - "../../../../../modules/juce_video/native/juce_win32_CameraDevice.h" - "../../../../../modules/juce_video/native/juce_win32_ComTypes.h" - "../../../../../modules/juce_video/native/juce_win32_Video.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_android.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_ios.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_mac.h" + "../../../../../modules/juce_video/native/juce_CameraDevice_windows.h" + "../../../../../modules/juce_video/native/juce_ComTypes_windows.h" + "../../../../../modules/juce_video/native/juce_Video_android.h" + "../../../../../modules/juce_video/native/juce_Video_mac.h" + "../../../../../modules/juce_video/native/juce_Video_windows.h" "../../../../../modules/juce_video/playback/juce_VideoComponent.cpp" "../../../../../modules/juce_video/playback/juce_VideoComponent.h" "../../../../../modules/juce_video/juce_video.cpp" @@ -3994,11 +4146,11 @@ set_source_files_properties( PROPERTIES HEADER_FILE_ONLY TRUE) if( JUCE_BUILD_CONFIGURATION MATCHES "DEBUG" ) - target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) + target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) endif() if( JUCE_BUILD_CONFIGURATION MATCHES "RELEASE" ) - target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) + target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) endif() find_library(log "log") diff --git a/examples/DemoRunner/Builds/Android/app/build.gradle b/examples/DemoRunner/Builds/Android/app/build.gradle index a120c191f34d..493b015fb673 100644 --- a/examples/DemoRunner/Builds/Android/app/build.gradle +++ b/examples/DemoRunner/Builds/Android/app/build.gradle @@ -2,10 +2,12 @@ apply plugin: 'com.android.application' android { compileSdkVersion 33 + ndkVersion "25.2.9519653" namespace "com.rmsl.jucedemorunner" externalNativeBuild { cmake { path "CMakeLists.txt" + version "3.22.1" } } signingConfigs { diff --git a/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml b/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml index 7500ac43f5d3..cbaac94a202b 100644 --- a/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml +++ b/examples/DemoRunner/Builds/Android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ - + @@ -8,19 +8,20 @@ - - + + - + + diff --git a/examples/DemoRunner/Builds/Android/app/src/main/assets/DSPDemos_Common.h b/examples/DemoRunner/Builds/Android/app/src/main/assets/DSPDemos_Common.h index 9fa1d5c3a087..26d0e3b966d2 100644 --- a/examples/DemoRunner/Builds/Android/app/src/main/assets/DSPDemos_Common.h +++ b/examples/DemoRunner/Builds/Android/app/src/main/assets/DSPDemos_Common.h @@ -596,13 +596,17 @@ class AudioFileReaderComponent : public Component, const auto u = fc.getURLResult(); if (! audioFileReader.loadURL (u)) - NativeMessageBox::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::WarningIcon) - .withTitle ("Error loading file") - .withMessage ("Unable to load audio file"), - nullptr); + { + auto options = MessageBoxOptions().withIconType (MessageBoxIconType::WarningIcon) + .withTitle ("Error loading file") + .withMessage ("Unable to load audio file") + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); + } else + { thumbnailComp.setCurrentURL (u); + } } fileChooser = nullptr; @@ -629,6 +633,7 @@ class AudioFileReaderComponent : public Component, AudioFileReaderComponent& audioFileReader; std::unique_ptr fileChooser; + ScopedMessageBox messageBox; }; //============================================================================== diff --git a/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h b/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h index ffdfc3631c93..b2d38fffb610 100644 --- a/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h +++ b/examples/DemoRunner/Builds/Android/app/src/main/assets/DemoUtilities.h @@ -244,10 +244,8 @@ struct SlowerBouncingNumber : public BouncingNumber inline std::unique_ptr makeInputSource (const URL& url) { - #if JUCE_ANDROID - if (auto doc = AndroidDocument::fromDocument (url)) + if (const auto doc = AndroidDocument::fromDocument (url)) return std::make_unique (doc); - #endif #if ! JUCE_IOS if (url.isLocalFile()) @@ -257,4 +255,17 @@ inline std::unique_ptr makeInputSource (const URL& url) return std::make_unique (url); } +inline std::unique_ptr makeOutputStream (const URL& url) +{ + if (const auto doc = AndroidDocument::fromDocument (url)) + return doc.createOutputStream(); + + #if ! JUCE_IOS + if (url.isLocalFile()) + return url.getLocalFile().createOutputStream(); + #endif + + return url.createOutputStream(); +} + #endif // PIP_DEMO_UTILITIES_INCLUDED diff --git a/examples/DemoRunner/Builds/LinuxMakefile/Makefile b/examples/DemoRunner/Builds/LinuxMakefile/Makefile index faa2c752954f..e802663c295a 100644 --- a/examples/DemoRunner/Builds/LinuxMakefile/Makefile +++ b/examples/DemoRunner/Builds/LinuxMakefile/Makefile @@ -39,13 +39,13 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_box2d=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_USE_MP3AUDIOFORMAT=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_USE_CAMERA=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.5" "-DJUCE_APP_VERSION_HEX=0x70005" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_box2d=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_USE_MP3AUDIOFORMAT=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_USE_CAMERA=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.7" "-DJUCE_APP_VERSION_HEX=0x70007" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := DemoRunner JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -60,13 +60,13 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_box2d=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_USE_MP3AUDIOFORMAT=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_USE_CAMERA=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.5" "-DJUCE_APP_VERSION_HEX=0x70005" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_box2d=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_USE_MP3AUDIOFORMAT=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_USE_CAMERA=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_DEMO_RUNNER=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.7" "-DJUCE_APP_VERSION_HEX=0x70007" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := DemoRunner JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -104,150 +104,155 @@ OBJECTS_APP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } - @$(PKG_CONFIG) --print-errors alsa freetype2 libcurl + @$(PKG_CONFIG) --print-errors alsa freetype2 gl libcurl @echo Linking "DemoRunner - App" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/DemoPIPs1_5b52b434.o: ../../Source/Demos/DemoPIPs1.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling DemoPIPs1.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/DemoPIPs2_5b60cbb5.o: ../../Source/Demos/DemoPIPs2.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling DemoPIPs2.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/JUCEDemos_5a07ba05.o: ../../Source/Demos/JUCEDemos.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling JUCEDemos.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/DemoContentComponent_c5bb9cc3.o: ../../Source/UI/DemoContentComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling DemoContentComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/MainComponent_a54318d2.o: ../../Source/UI/MainComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling MainComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o: ../../JuceLibraryCode/include_juce_analytics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_analytics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_devices_63111d02.o: ../../JuceLibraryCode/include_juce_audio_devices.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_devices.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_formats.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_10c03666.o: ../../JuceLibraryCode/include_juce_audio_processors.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_ara_2a4c6ef7.o: ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_ara.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_12bdca08.o: ../../JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_lv2_libs.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_utils_9f9fb2d6.o: ../../JuceLibraryCode/include_juce_audio_utils.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_utils.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_box2d_b0305d8b.o: ../../JuceLibraryCode/include_juce_box2d.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_box2d.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o: ../../JuceLibraryCode/include_juce_cryptography.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_cryptography.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_dsp_aeb2060f.o: ../../JuceLibraryCode/include_juce_dsp.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_dsp.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_opengl_a8a032b.o: ../../JuceLibraryCode/include_juce_opengl.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_opengl.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_osc_f3df604d.o: ../../JuceLibraryCode/include_juce_osc.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_osc.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_product_unlocking_8278fcdc.o: ../../JuceLibraryCode/include_juce_product_unlocking.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_product_unlocking.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_video_be78589.o: ../../JuceLibraryCode/include_juce_video.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_video.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning DemoRunner $(V_AT)$(CLEANCMD) diff --git a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj index f69455f9aca0..47c9b596d532 100644 --- a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj +++ b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 0140787C0118A95E37DE90B4 /* include_juce_video.mm */ = {isa = PBXBuildFile; fileRef = 9144821E003E15E4042B57DB; }; 028383D0577D0236899D8CA5 /* OpenGL.framework */ = {isa = PBXBuildFile; fileRef = 40BD06D4AB0D2C73E936A2F1; }; + 05E2CC77AE99E8A2E3A18777 /* Security.framework */ = {isa = PBXBuildFile; fileRef = 87D5F938A115568F9CF3BE5A; }; 1351A13E78F38741C6075600 /* CoreAudio.framework */ = {isa = PBXBuildFile; fileRef = 4F0A137A4115946A346180E6; }; 163B0CF2DD0990A63DF1D5A6 /* AudioToolbox.framework */ = {isa = PBXBuildFile; fileRef = 470C3E4553B513FFEF752779; }; 1BA301E39E29966719B710A1 /* GUI */ = {isa = PBXBuildFile; fileRef = 9EBAEBBD9093CB005D1692F2; }; @@ -104,6 +105,7 @@ 71A91516AFD980FEE694C0E1 /* IOKit.framework */ /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 7A5AAE9EE573FC6105CC4AAC /* SettingsContent.h */ /* SettingsContent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SettingsContent.h; path = ../../Source/UI/SettingsContent.h; sourceTree = SOURCE_ROOT; }; 7B3243C92248D379A0489AA4 /* Utilities */ /* Utilities */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Utilities; path = ../../../Utilities; sourceTree = ""; }; + 87D5F938A115568F9CF3BE5A /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 8CE533D611CD0984AD028D73 /* juce_graphics */ /* juce_graphics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_graphics; path = ../../../../modules/juce_graphics; sourceTree = SOURCE_ROOT; }; 8D44097417573B38729A0179 /* include_juce_audio_processors_ara.cpp */ /* include_juce_audio_processors_ara.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_processors_ara.cpp; path = ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp; sourceTree = SOURCE_ROOT; }; 903CD4126C779884797EF915 /* juce_core */ /* juce_core */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_core; path = ../../../../modules/juce_core; sourceTree = SOURCE_ROOT; }; @@ -158,6 +160,7 @@ 8584640341100008744861A5, 028383D0577D0236899D8CA5, B1981F62F6A91FD2F579A198, + 05E2CC77AE99E8A2E3A18777, 89AD16514B1F4133FFEA1DF9, ); runOnlyForDeploymentPostprocessing = 0; @@ -182,6 +185,7 @@ 71A91516AFD980FEE694C0E1, 40BD06D4AB0D2C73E936A2F1, 23CD1A3F9067C3A0ECE7BB67, + 87D5F938A115568F9CF3BE5A, 96D99A08027CA35D6A4E5CFD, ); name = Frameworks; @@ -509,7 +513,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -540,8 +544,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -572,8 +576,8 @@ LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.rmsl.jucedemorunner; PRODUCT_NAME = "DemoRunner"; @@ -600,7 +604,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -631,8 +635,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -662,8 +666,8 @@ INSTALL_PATH = "$(HOME)/Applications"; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.rmsl.jucedemorunner; PRODUCT_NAME = "DemoRunner"; diff --git a/examples/DemoRunner/Builds/MacOSX/Info-App.plist b/examples/DemoRunner/Builds/MacOSX/Info-App.plist index f2a852d1900a..6df4fd9d88e4 100644 --- a/examples/DemoRunner/Builds/MacOSX/Info-App.plist +++ b/examples/DemoRunner/Builds/MacOSX/Info-App.plist @@ -24,9 +24,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 7.0.5 + 7.0.7 CFBundleVersion - 7.0.5 + 7.0.7 NSHumanReadableCopyright Copyright (c) 2020 - Raw Material Software Limited NSHighResolutionCapable diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj index 187c40f26619..5e065573e50c 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -473,46 +473,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -857,18 +857,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -968,6 +992,9 @@ true + + true + true @@ -998,7 +1025,7 @@ true - + true @@ -1037,22 +1064,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1289,6 +1316,9 @@ true + + true + true @@ -1301,6 +1331,9 @@ true + + true + true @@ -1310,67 +1343,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1622,13 +1661,13 @@ true - + true - + true - + true @@ -1697,6 +1736,9 @@ true + + true + true @@ -1721,19 +1763,19 @@ true - + true - + true - + true - + true - + true @@ -2012,40 +2054,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2117,6 +2159,9 @@ true + + true + true @@ -2189,6 +2234,9 @@ true + + true + true @@ -2312,52 +2360,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2459,9 +2534,18 @@ true + + true + + + true + true + + true + true @@ -2471,7 +2555,7 @@ true - + true @@ -2528,43 +2612,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2645,10 +2729,10 @@ true - + true - + true @@ -2737,8 +2821,8 @@ - - + + @@ -2833,8 +2917,8 @@ - - + + @@ -3011,6 +3095,7 @@ + @@ -3030,6 +3115,7 @@ + @@ -3066,8 +3152,18 @@ + + + + + + + + + + @@ -3108,6 +3204,7 @@ + @@ -3120,8 +3217,8 @@ + - @@ -3203,6 +3300,7 @@ + @@ -3245,20 +3343,22 @@ + - - - - - - - - + + + + + + + + + @@ -3366,10 +3466,10 @@ - - - - + + + + @@ -3403,6 +3503,7 @@ + @@ -3416,12 +3517,13 @@ - - - + + + + + - - + @@ -3478,10 +3580,10 @@ - - + + + - @@ -3517,6 +3619,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3547,6 +3669,7 @@ + @@ -3592,36 +3715,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3659,10 +3783,12 @@ + - + + @@ -3690,7 +3816,7 @@ - + @@ -3698,9 +3824,9 @@ - - - + + + @@ -3733,14 +3859,14 @@ - - - - - - - - + + + + + + + + @@ -3757,6 +3883,7 @@ + diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters index 57a30d71d186..3e516cf81796 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters @@ -308,12 +308,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -572,6 +590,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -599,9 +620,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -1036,49 +1054,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1429,18 +1447,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1543,6 +1588,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1573,7 +1621,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1615,34 +1663,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1882,6 +1930,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1894,6 +1945,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1903,82 +1957,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2239,13 +2299,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2317,6 +2377,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2341,25 +2404,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2641,46 +2704,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2755,6 +2818,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2827,6 +2893,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2950,85 +3019,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -3130,9 +3238,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3142,7 +3259,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3202,55 +3319,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3337,10 +3454,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3567,10 +3684,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3855,10 +3972,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4389,6 +4506,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4446,6 +4566,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4554,12 +4677,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4680,6 +4833,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4716,10 +4872,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4965,6 +5121,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -5091,6 +5250,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -5106,31 +5268,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5454,16 +5619,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5565,6 +5730,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5604,22 +5772,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5790,16 +5961,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5907,6 +6078,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5997,6 +6228,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -6132,9 +6366,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -6144,82 +6375,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -6333,6 +6570,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -6342,7 +6582,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6426,7 +6669,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6450,13 +6693,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6555,28 +6798,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6623,6 +6866,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/examples/DemoRunner/Builds/VisualStudio2017/resources.rc b/examples/DemoRunner/Builds/VisualStudio2017/resources.rc index d1e516af447a..30dc1b9b7783 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2017/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Copyright (c) 2020 - Raw Material Software Limited\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj index 08a4d4c8a07f..0aee62df7af0 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -473,46 +473,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -857,18 +857,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -968,6 +992,9 @@ true + + true + true @@ -998,7 +1025,7 @@ true - + true @@ -1037,22 +1064,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1289,6 +1316,9 @@ true + + true + true @@ -1301,6 +1331,9 @@ true + + true + true @@ -1310,67 +1343,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1622,13 +1661,13 @@ true - + true - + true - + true @@ -1697,6 +1736,9 @@ true + + true + true @@ -1721,19 +1763,19 @@ true - + true - + true - + true - + true - + true @@ -2012,40 +2054,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2117,6 +2159,9 @@ true + + true + true @@ -2189,6 +2234,9 @@ true + + true + true @@ -2312,52 +2360,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2459,9 +2534,18 @@ true + + true + + + true + true + + true + true @@ -2471,7 +2555,7 @@ true - + true @@ -2528,43 +2612,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2645,10 +2729,10 @@ true - + true - + true @@ -2737,8 +2821,8 @@ - - + + @@ -2833,8 +2917,8 @@ - - + + @@ -3011,6 +3095,7 @@ + @@ -3030,6 +3115,7 @@ + @@ -3066,8 +3152,18 @@ + + + + + + + + + + @@ -3108,6 +3204,7 @@ + @@ -3120,8 +3217,8 @@ + - @@ -3203,6 +3300,7 @@ + @@ -3245,20 +3343,22 @@ + - - - - - - - - + + + + + + + + + @@ -3366,10 +3466,10 @@ - - - - + + + + @@ -3403,6 +3503,7 @@ + @@ -3416,12 +3517,13 @@ - - - + + + + + - - + @@ -3478,10 +3580,10 @@ - - + + + - @@ -3517,6 +3619,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3547,6 +3669,7 @@ + @@ -3592,36 +3715,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3659,10 +3783,12 @@ + - + + @@ -3690,7 +3816,7 @@ - + @@ -3698,9 +3824,9 @@ - - - + + + @@ -3733,14 +3859,14 @@ - - - - - - - - + + + + + + + + @@ -3757,6 +3883,7 @@ + diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters index c91a76b8c83a..57d886986f8b 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters @@ -308,12 +308,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -572,6 +590,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -599,9 +620,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -1036,49 +1054,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1429,18 +1447,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1543,6 +1588,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1573,7 +1621,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1615,34 +1663,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1882,6 +1930,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1894,6 +1945,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1903,82 +1957,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2239,13 +2299,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2317,6 +2377,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2341,25 +2404,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2641,46 +2704,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2755,6 +2818,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2827,6 +2893,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2950,85 +3019,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -3130,9 +3238,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3142,7 +3259,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3202,55 +3319,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3337,10 +3454,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3567,10 +3684,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3855,10 +3972,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4389,6 +4506,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4446,6 +4566,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4554,12 +4677,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4680,6 +4833,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4716,10 +4872,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4965,6 +5121,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -5091,6 +5250,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -5106,31 +5268,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5454,16 +5619,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5565,6 +5730,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5604,22 +5772,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5790,16 +5961,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5907,6 +6078,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5997,6 +6228,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -6132,9 +6366,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -6144,82 +6375,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -6333,6 +6570,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -6342,7 +6582,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6426,7 +6669,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6450,13 +6693,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6555,28 +6798,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6623,6 +6866,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/examples/DemoRunner/Builds/VisualStudio2019/resources.rc b/examples/DemoRunner/Builds/VisualStudio2019/resources.rc index d1e516af447a..30dc1b9b7783 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2019/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Copyright (c) 2020 - Raw Material Software Limited\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj index 678c53488c60..cdad9ae45e2c 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_box2d=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_USE_MP3AUDIOFORMAT=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_CAMERA=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DEMO_RUNNER=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\DemoRunner.exe @@ -473,46 +473,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -857,18 +857,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -968,6 +992,9 @@ true + + true + true @@ -998,7 +1025,7 @@ true - + true @@ -1037,22 +1064,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1289,6 +1316,9 @@ true + + true + true @@ -1301,6 +1331,9 @@ true + + true + true @@ -1310,67 +1343,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1622,13 +1661,13 @@ true - + true - + true - + true @@ -1697,6 +1736,9 @@ true + + true + true @@ -1721,19 +1763,19 @@ true - + true - + true - + true - + true - + true @@ -2012,40 +2054,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2117,6 +2159,9 @@ true + + true + true @@ -2189,6 +2234,9 @@ true + + true + true @@ -2312,52 +2360,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2459,9 +2534,18 @@ true + + true + + + true + true + + true + true @@ -2471,7 +2555,7 @@ true - + true @@ -2528,43 +2612,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2645,10 +2729,10 @@ true - + true - + true @@ -2737,8 +2821,8 @@ - - + + @@ -2833,8 +2917,8 @@ - - + + @@ -3011,6 +3095,7 @@ + @@ -3030,6 +3115,7 @@ + @@ -3066,8 +3152,18 @@ + + + + + + + + + + @@ -3108,6 +3204,7 @@ + @@ -3120,8 +3217,8 @@ + - @@ -3203,6 +3300,7 @@ + @@ -3245,20 +3343,22 @@ + - - - - - - - - + + + + + + + + + @@ -3366,10 +3466,10 @@ - - - - + + + + @@ -3403,6 +3503,7 @@ + @@ -3416,12 +3517,13 @@ - - - + + + + + - - + @@ -3478,10 +3580,10 @@ - - + + + - @@ -3517,6 +3619,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3547,6 +3669,7 @@ + @@ -3592,36 +3715,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3659,10 +3783,12 @@ + - + + @@ -3690,7 +3816,7 @@ - + @@ -3698,9 +3824,9 @@ - - - + + + @@ -3733,14 +3859,14 @@ - - - - - - - - + + + + + + + + @@ -3757,6 +3883,7 @@ + diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters index c430519c950a..e93c1f373a25 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters @@ -308,12 +308,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -572,6 +590,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -599,9 +620,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -1036,49 +1054,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1429,18 +1447,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1543,6 +1588,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1573,7 +1621,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1615,34 +1663,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1882,6 +1930,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1894,6 +1945,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1903,82 +1957,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2239,13 +2299,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2317,6 +2377,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2341,25 +2404,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2641,46 +2704,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2755,6 +2818,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2827,6 +2893,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2950,85 +3019,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -3130,9 +3238,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3142,7 +3259,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3202,55 +3319,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3337,10 +3454,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3567,10 +3684,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3855,10 +3972,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4389,6 +4506,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4446,6 +4566,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4554,12 +4677,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4680,6 +4833,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4716,10 +4872,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4965,6 +5121,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -5091,6 +5250,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -5106,31 +5268,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5454,16 +5619,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5565,6 +5730,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5604,22 +5772,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5790,16 +5961,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5907,6 +6078,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5997,6 +6228,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -6132,9 +6366,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -6144,82 +6375,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -6333,6 +6570,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -6342,7 +6582,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6426,7 +6669,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6450,13 +6693,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6555,28 +6798,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6623,6 +6866,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/examples/DemoRunner/Builds/VisualStudio2022/resources.rc b/examples/DemoRunner/Builds/VisualStudio2022/resources.rc index d1e516af447a..30dc1b9b7783 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/resources.rc +++ b/examples/DemoRunner/Builds/VisualStudio2022/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Copyright (c) 2020 - Raw Material Software Limited\0" VALUE "FileDescription", "DemoRunner\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "DemoRunner\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj index 1e9d52e0a4cc..ed915ecbe464 100644 --- a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj +++ b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj @@ -517,7 +517,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -548,8 +548,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_IPHONE_5BC26AE3=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -579,8 +579,8 @@ INSTALL_PATH = "$(HOME)/Applications"; LLVM_LTO = YES; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications"; PRODUCT_BUNDLE_IDENTIFIER = com.rmsl.jucedemorunner; PRODUCT_NAME = "DemoRunner"; @@ -608,7 +608,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -639,8 +639,8 @@ "JUCE_DEMO_RUNNER=1", "JUCE_UNIT_TESTS=1", "JUCER_XCODE_IPHONE_5BC26AE3=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -669,8 +669,8 @@ INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(HOME)/Applications"; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications"; PRODUCT_BUNDLE_IDENTIFIER = com.rmsl.jucedemorunner; PRODUCT_NAME = "DemoRunner"; diff --git a/examples/DemoRunner/Builds/iOS/Info-App.plist b/examples/DemoRunner/Builds/iOS/Info-App.plist index 287e00744135..9f5698881e40 100644 --- a/examples/DemoRunner/Builds/iOS/Info-App.plist +++ b/examples/DemoRunner/Builds/iOS/Info-App.plist @@ -30,9 +30,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 7.0.5 + 7.0.7 CFBundleVersion - 7.0.5 + 7.0.7 NSHumanReadableCopyright Copyright (c) 2020 - Raw Material Software Limited NSHighResolutionCapable diff --git a/examples/DemoRunner/CMakeLists.txt b/examples/DemoRunner/CMakeLists.txt index 140d829e44a9..01cf615f7554 100644 --- a/examples/DemoRunner/CMakeLists.txt +++ b/examples/DemoRunner/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources(DemoRunner PRIVATE target_compile_definitions(DemoRunner PRIVATE PIP_JUCE_EXAMPLES_DIRECTORY_STRING="${JUCE_SOURCE_DIR}/examples" JUCE_ALLOW_STATIC_NULL_VARIABLES=0 + JUCE_CONTENT_SHARING=1 JUCE_DEMO_RUNNER=1 JUCE_PLUGINHOST_LV2=1 JUCE_PLUGINHOST_VST3=1 diff --git a/examples/DemoRunner/DemoRunner.jucer b/examples/DemoRunner/DemoRunner.jucer index 7e9e10ddbb2f..257bc37f11df 100644 --- a/examples/DemoRunner/DemoRunner.jucer +++ b/examples/DemoRunner/DemoRunner.jucer @@ -1,7 +1,7 @@ createAccessibilityHandler() override { return createIgnoredAccessibilityHandler (*this); } + private: GraphicsSettingsGroup graphicsSettings; AudioSettingsGroup audioSettings; }; diff --git a/examples/GUI/AccessibilityDemo.h b/examples/GUI/AccessibilityDemo.h index aff7e54fec6c..c3641a132c92 100644 --- a/examples/GUI/AccessibilityDemo.h +++ b/examples/GUI/AccessibilityDemo.h @@ -195,7 +195,13 @@ class JUCEWidgetsComponent : public Component addAndMakeVisible (textButton); shapeButton.setShape (getJUCELogoPath(), false, true, false); - shapeButton.onClick = [] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Alert", "This is an AlertWindow"); }; + shapeButton.onClick = [this] + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "Alert", + "This is an AlertWindow"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + }; shapeButton.setHasFocusOutline (true); addAndMakeVisible (shapeButton); } @@ -250,6 +256,7 @@ class JUCEWidgetsComponent : public Component Colours::darkorange, Colours::darkorange.brighter (0.5f), Colours::darkorange.brighter (0.75f) }; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonsComponent) diff --git a/examples/GUI/CameraDemo.h b/examples/GUI/CameraDemo.h index 0765e6692e1f..f49eed85a78c 100644 --- a/examples/GUI/CameraDemo.h +++ b/examples/GUI/CameraDemo.h @@ -252,8 +252,10 @@ class CameraDemo : public Component } else { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Camera open failed", - "Camera open failed, reason: " + error); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Camera open failed", + "Camera open failed, reason: " + error); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } snapshotButton .setEnabled (cameraDevice.get() != nullptr && ! contentSharingPending); @@ -312,12 +314,11 @@ class CameraDemo : public Component SafePointer safeThis (this); - juce::ContentSharer::getInstance()->shareFiles ({url}, - [safeThis] (bool success, const String&) mutable - { - if (safeThis) - safeThis->sharingFinished (success, false); - }); + messageBox = ContentSharer::shareFilesScoped ({ url }, [safeThis] (bool success, const String&) + { + if (safeThis) + safeThis->sharingFinished (success, false); + }); #endif } } @@ -353,21 +354,21 @@ class CameraDemo : public Component SafePointer safeThis (this); - juce::ContentSharer::getInstance()->shareFiles ({url}, - [safeThis] (bool success, const String&) mutable - { - if (safeThis) - safeThis->sharingFinished (success, true); - }); + messageBox = ContentSharer::shareFilesScoped ({ url }, [safeThis] (bool success, const String&) + { + if (safeThis) + safeThis->sharingFinished (success, true); + }); } #endif } void errorOccurred (const String& error) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - "Camera Device Error", - "An error has occurred: " + error + " Camera will be closed."); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "Camera Device Error", + "An error has occurred: " + error + " Camera will be closed."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); cameraDevice.reset(); @@ -378,14 +379,17 @@ class CameraDemo : public Component void sharingFinished (bool success, bool isCapture) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - isCapture ? "Image sharing result" : "Video sharing result", - success ? "Success!" : "Failed!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + isCapture ? "Image sharing result" : "Video sharing result", + success ? "Success!" : "Failed!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); contentSharingPending = false; snapshotButton .setEnabled (true); recordMovieButton.setEnabled (true); } + ScopedMessageBox messageBox; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CameraDemo) }; diff --git a/examples/GUI/DialogsDemo.h b/examples/GUI/DialogsDemo.h index 23a2c862432c..ea090af31f1f 100644 --- a/examples/GUI/DialogsDemo.h +++ b/examples/GUI/DialogsDemo.h @@ -48,12 +48,19 @@ #include "../Assets/DemoUtilities.h" +//============================================================================== +struct MessageBoxOwnerComponent : public Component +{ + ScopedMessageBox messageBox; +}; + //============================================================================== class DemoBackgroundThread : public ThreadWithProgressWindow { public: - DemoBackgroundThread() - : ThreadWithProgressWindow ("busy doing some important things...", true, true) + explicit DemoBackgroundThread (MessageBoxOwnerComponent& comp) + : ThreadWithProgressWindow ("busy doing some important things...", true, true), + owner (&comp) { setStatusMessage ("Getting ready..."); } @@ -91,21 +98,26 @@ class DemoBackgroundThread : public ThreadWithProgressWindow { const String messageString (userPressedCancel ? "You pressed cancel!" : "Thread finished ok!"); - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Progress window") - .withMessage (messageString) - .withButton ("OK"), - nullptr); + if (owner != nullptr) + { + owner->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Progress window") + .withMessage (messageString) + .withButton ("OK"), + nullptr); + } // ..and clean up by deleting our thread object.. delete this; } + + Component::SafePointer owner; }; //============================================================================== -class DialogsDemo : public Component +class DialogsDemo : public MessageBoxOwnerComponent { public: enum DialogType @@ -114,7 +126,7 @@ class DialogsDemo : public Component warningAlertWindow, infoAlertWindow, questionAlertWindow, - okCancelAlertWindow, + yesNoCancelAlertWindow, extraComponentsAlertWindow, calloutBoxWindow, progressWindow, @@ -140,7 +152,7 @@ class DialogsDemo : public Component "Alert Window With Warning Icon", "Alert Window With Info Icon", "Alert Window With Question Icon", - "OK Cancel Alert Window", + "Yes No Cancel Alert Window", "Alert Window With Extra Components", "CalloutBox", "Thread With Progress Window", @@ -168,18 +180,19 @@ class DialogsDemo : public Component setSize (500, 500); - RuntimePermissions::request (RuntimePermissions::readExternalStorage, - [] (bool granted) - { - if (! granted) - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::WarningIcon) - .withTitle ("Permissions warning") - .withMessage ("External storage access permission not granted, some files" - " may be inaccessible.") - .withButton ("OK"), - nullptr); - }); + RuntimePermissions::request (RuntimePermissions::readExternalStorage, [ptr = Component::SafePointer (this)] (bool granted) + { + if (granted || ptr == nullptr) + return; + + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::WarningIcon) + .withTitle ("Permissions warning") + .withMessage ("External storage access permission not granted, some files" + " may be inaccessible.") + .withButton ("OK"), + nullptr); + }); } //============================================================================== @@ -214,49 +227,51 @@ class DialogsDemo : public Component OwnedArray windowButtons; ToggleButton nativeButton; - struct AlertBoxResultChosen + auto getAlertBoxResultChosen() { - void operator() (int result) const noexcept + return [ptr = Component::SafePointer (this)] (int result) { - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Alert Box") - .withMessage ("Result code: " + String (result)) - .withButton ("OK"), - nullptr); - } - }; + if (ptr != nullptr) + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Alert Box") + .withMessage ("Result code: " + String (result)) + .withButton ("OK"), + nullptr); + }; + } - struct AsyncAlertBoxResultChosen + auto getAsyncAlertBoxResultChosen() { - void operator() (int result) const noexcept + return [ptr = Component::SafePointer (this)] (int result) { - auto& aw = *demo.asyncAlertWindow; + if (ptr == nullptr) + return; + + auto& aw = *ptr->asyncAlertWindow; aw.exitModalState (result); aw.setVisible (false); if (result == 0) { - AlertBoxResultChosen{} (result); + ptr->getAlertBoxResultChosen() (result); return; } auto optionIndexChosen = aw.getComboBoxComponent ("option")->getSelectedItemIndex(); auto text = aw.getTextEditorContents ("text"); - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Alert Box") - .withMessage ("Result code: " + String (result) + newLine - + "Option index chosen: " + String (optionIndexChosen) + newLine - + "Text: " + text) - .withButton ("OK"), - nullptr); - } - - DialogsDemo& demo; - }; + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Alert Box") + .withMessage ("Result code: " + String (result) + newLine + + "Option index chosen: " + String (optionIndexChosen) + newLine + + "Text: " + text) + .withButton ("OK"), + nullptr); + }; + } void showWindow (Component& button, DialogType type) { @@ -268,16 +283,19 @@ class DialogsDemo : public Component if (type == infoAlertWindow) icon = MessageBoxIconType::InfoIcon; if (type == questionAlertWindow) icon = MessageBoxIconType::QuestionIcon; - AlertWindow::showMessageBoxAsync (icon, "This is an AlertWindow", - "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (icon, + "This is an AlertWindow", + "And this is the AlertWindow's message. " + "Blah blah blah blah blah blah blah blah blah blah blah blah blah."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } - else if (type == okCancelAlertWindow) + else if (type == yesNoCancelAlertWindow) { - AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon, "This is an ok/cancel AlertWindow", - "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.", - {}, {}, {}, - ModalCallbackFunction::create (AlertBoxResultChosen{})); + auto options = MessageBoxOptions::makeOptionsYesNoCancel (MessageBoxIconType::QuestionIcon, + "This is a yes/no/cancel AlertWindow", + "And this is the AlertWindow's message. " + "Blah blah blah blah blah blah blah blah blah blah blah blah blah."); + messageBox = AlertWindow::showScopedAsync (options, getAlertBoxResultChosen()); } else if (type == calloutBoxWindow) { @@ -301,13 +319,13 @@ class DialogsDemo : public Component asyncAlertWindow->addButton ("OK", 1, KeyPress (KeyPress::returnKey, 0, 0)); asyncAlertWindow->addButton ("Cancel", 0, KeyPress (KeyPress::escapeKey, 0, 0)); - asyncAlertWindow->enterModalState (true, ModalCallbackFunction::create (AsyncAlertBoxResultChosen { *this })); + asyncAlertWindow->enterModalState (true, ModalCallbackFunction::create (getAsyncAlertBoxResultChosen())); } else if (type == progressWindow) { // This will launch our ThreadWithProgressWindow in a modal state. (Our subclass // will take care of deleting the object when the task has finished) - (new DemoBackgroundThread())->launchThread(); + (new DemoBackgroundThread (*this))->launchThread(); } else if (type >= loadChooser && type <= saveChooser) { @@ -318,9 +336,10 @@ class DialogsDemo : public Component fc.reset (new FileChooser ("Choose a file to open...", File::getCurrentWorkingDirectory(), "*", useNativeVersion)); - fc->launchAsync (FileBrowserComponent::canSelectMultipleItems | FileBrowserComponent::openMode - | FileBrowserComponent::canSelectFiles, - [] (const FileChooser& chooser) + fc->launchAsync (FileBrowserComponent::canSelectMultipleItems + | FileBrowserComponent::openMode + | FileBrowserComponent::canSelectFiles, + [this] (const FileChooser& chooser) { String chosen; auto results = chooser.getURLResults(); @@ -329,12 +348,12 @@ class DialogsDemo : public Component chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() : result.toString (false)) << "\n"; - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("File Chooser...") - .withMessage ("You picked: " + chosen) - .withButton ("OK"), - nullptr); + messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("File Chooser...") + .withMessage ("You picked: " + chosen) + .withButton ("OK"), + nullptr); }); } else if (type == loadWithPreviewChooser) @@ -344,9 +363,10 @@ class DialogsDemo : public Component fc.reset (new FileChooser ("Choose an image to open...", File::getCurrentWorkingDirectory(), "*.jpg;*.jpeg;*.png;*.gif", useNativeVersion)); - fc->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles - | FileBrowserComponent::canSelectMultipleItems, - [] (const FileChooser& chooser) + fc->launchAsync (FileBrowserComponent::openMode + | FileBrowserComponent::canSelectFiles + | FileBrowserComponent::canSelectMultipleItems, + [this] (const FileChooser& chooser) { String chosen; auto results = chooser.getURLResults(); @@ -355,12 +375,12 @@ class DialogsDemo : public Component chosen << (result.isLocalFile() ? result.getLocalFile().getFullPathName() : result.toString (false)) << "\n"; - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("File Chooser...") - .withMessage ("You picked: " + chosen) - .withButton ("OK"), - nullptr); + messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("File Chooser...") + .withMessage ("You picked: " + chosen) + .withButton ("OK"), + nullptr); }, &imagePreview); } @@ -385,7 +405,7 @@ class DialogsDemo : public Component "*", useNativeVersion)); fc->launchAsync (FileBrowserComponent::saveMode | FileBrowserComponent::canSelectFiles, - [fileToSave] (const FileChooser& chooser) + [this, fileToSave] (const FileChooser& chooser) { auto result = chooser.getURLResult(); auto name = result.isEmpty() ? String() @@ -409,12 +429,12 @@ class DialogsDemo : public Component } #endif - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("File Chooser...") - .withMessage ("You picked: " + name) - .withButton ("OK"), - nullptr); + messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("File Chooser...") + .withMessage ("You picked: " + name) + .withButton ("OK"), + nullptr); }); } else if (type == directoryChooser) @@ -425,35 +445,37 @@ class DialogsDemo : public Component useNativeVersion)); fc->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories, - [] (const FileChooser& chooser) + [this] (const FileChooser& chooser) { auto result = chooser.getURLResult(); auto name = result.isLocalFile() ? result.getLocalFile().getFullPathName() : result.toString (true); - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("File Chooser...") - .withMessage ("You picked: " + name) - .withButton ("OK"), - nullptr); + messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("File Chooser...") + .withMessage ("You picked: " + name) + .withButton ("OK"), + nullptr); }); } } else if (type == shareText) { - ContentSharer::getInstance()->shareText ("I love JUCE!", - [] (bool success, const String& error) - { - auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); - - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Sharing Text Result") - .withMessage ("Sharing text finished\nwith " + resultString) - .withButton ("OK"), - nullptr); - }); + messageBox = ContentSharer::shareTextScoped ("I love JUCE!", [ptr = Component::SafePointer (this)] (bool success, const String& error) + { + if (ptr == nullptr) + return; + + auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); + + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Sharing Text Result") + .withMessage ("Sharing text finished\nwith " + resultString) + .withButton ("OK"), + nullptr); + }); } else if (type == shareFile) { @@ -467,18 +489,20 @@ class DialogsDemo : public Component Array urls; urls.add (URL (fileToSave)); - ContentSharer::getInstance()->shareFiles (urls, - [] (bool success, const String& error) - { - auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); + messageBox = ContentSharer::shareFilesScoped (urls, [ptr = Component::SafePointer (this)] (bool success, const String& error) + { + if (ptr == nullptr) + return; - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Sharing Files Result") - .withMessage ("Sharing files finished\nwith " + resultString) - .withButton ("OK"), - nullptr); - }); + auto resultString = success ? String ("success") : ("failure\n (error: " + error + ")"); + + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Sharing Files Result") + .withMessage ("Sharing files finished\nwith " + resultString) + .withButton ("OK"), + nullptr); + }); } } @@ -495,19 +519,21 @@ class DialogsDemo : public Component Array images { myImage, myImage2 }; - ContentSharer::getInstance()->shareImages (images, - [] (bool success, const String& error) - { - String resultString = success ? String ("success") - : ("failure\n (error: " + error + ")"); - - AlertWindow::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::InfoIcon) - .withTitle ("Sharing Images Result") - .withMessage ("Sharing images finished\nwith " + resultString) - .withButton ("OK"), - nullptr); - }); + messageBox = ContentSharer::shareImagesScoped (images, nullptr, [ptr = Component::SafePointer (this)] (bool success, const String& error) + { + if (ptr == nullptr) + return; + + String resultString = success ? String ("success") + : ("failure\n (error: " + error + ")"); + + ptr->messageBox = AlertWindow::showScopedAsync (MessageBoxOptions() + .withIconType (MessageBoxIconType::InfoIcon) + .withTitle ("Sharing Images Result") + .withMessage ("Sharing images finished\nwith " + resultString) + .withButton ("OK"), + nullptr); + }); } } diff --git a/examples/GUI/OpenGLDemo.h b/examples/GUI/OpenGLDemo.h index 8718acdf3cfb..564e9b3b9183 100644 --- a/examples/GUI/OpenGLDemo.h +++ b/examples/GUI/OpenGLDemo.h @@ -763,6 +763,7 @@ class OpenGLDemo : public Component, controlsOverlay.reset (new DemoControlsOverlay (*this)); addAndMakeVisible (controlsOverlay.get()); + openGLContext.setOpenGLVersionRequired (OpenGLContext::openGL3_2); openGLContext.setRenderer (this); openGLContext.attachTo (*this); openGLContext.setContinuousRepainting (true); @@ -841,7 +842,9 @@ class OpenGLDemo : public Component, glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture (GL_TEXTURE0); - glEnable (GL_TEXTURE_2D); + + if (! openGLContext.isCoreProfile()) + glEnable (GL_TEXTURE_2D); glViewport (0, 0, roundToInt (desktopScale * (float) bounds.getWidth()), diff --git a/examples/GUI/PropertiesDemo.h b/examples/GUI/PropertiesDemo.h index a242d68371e7..346b1a79bf22 100644 --- a/examples/GUI/PropertiesDemo.h +++ b/examples/GUI/PropertiesDemo.h @@ -61,8 +61,10 @@ class DemoButtonPropertyComponent : public ButtonPropertyComponent void buttonClicked() override { ++counter; - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, "Action Button Pressed", - "Pressing this type of property component can trigger an action such as showing an alert window!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "Action Button Pressed", + "Pressing this type of property component can trigger an action such as showing an alert window!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); refresh(); } @@ -73,6 +75,7 @@ class DemoButtonPropertyComponent : public ButtonPropertyComponent private: int counter = 0; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoButtonPropertyComponent) }; diff --git a/examples/GUI/VideoDemo.h b/examples/GUI/VideoDemo.h index 086f5aa0a11d..569ea6f92cf7 100644 --- a/examples/GUI/VideoDemo.h +++ b/examples/GUI/VideoDemo.h @@ -134,12 +134,15 @@ class MovieComponentWithFileBrowser : public Component, } else { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Couldn't load the file!", - result.getErrorMessage()); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Couldn't load the file!", + result.getErrorMessage()); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } } + ScopedMessageBox messageBox; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MovieComponentWithFileBrowser) }; @@ -627,7 +630,7 @@ class VideoDemo : public Component, currentPositionLabel.setText (getPositionString (position, duration), sendNotification); if (! positionSliderDragging) - positionSlider.setValue (duration != 0 ? (position / duration) : 0.0, dontSendNotification); + positionSlider.setValue (approximatelyEqual (duration, 0.0) ? 0.0 : (position / duration), dontSendNotification); } void seekVideoToStart() diff --git a/examples/GUI/WidgetsDemo.h b/examples/GUI/WidgetsDemo.h index 4d524c035904..b1751a08b744 100644 --- a/examples/GUI/WidgetsDemo.h +++ b/examples/GUI/WidgetsDemo.h @@ -461,7 +461,8 @@ struct ButtonsPage : public Component //============================================================================== -struct MiscPage : public Component +struct MiscPage : public Component, + private Timer { MiscPage() { @@ -482,6 +483,21 @@ struct MiscPage : public Component comboBox.addItem ("combo box item " + String (i), i); comboBox.setSelectedId (1); + + addAndMakeVisible (linearProgressBar); + linearProgressBar.setStyle (ProgressBar::Style::linear); + linearProgressBar.setBounds (10, 115, 200, 24); + + addAndMakeVisible (circularProgressBar); + circularProgressBar.setStyle (ProgressBar::Style::circular); + circularProgressBar.setBounds (10, 145, 200, 100); + + startTimerHz (10); + } + + ~MiscPage() override + { + stopTimer(); } void lookAndFeelChanged() override @@ -490,10 +506,37 @@ struct MiscPage : public Component textEditor2.applyFontToAllText (textEditor2.getFont()); } + void timerCallback() override + { + constexpr auto minValue = -0.2; + constexpr auto maxValue = 1.2; + constexpr auto maxIncrement = 0.05; + + if (progress >= maxValue) + progress = minValue; + else + progress += Random::getSystemRandom().nextDouble() * maxIncrement; + + if (isPositiveAndNotGreaterThan (progress, 1.0)) + { + linearProgressBar.setPercentageDisplay (true); + circularProgressBar.setPercentageDisplay (true); + } + else + { + linearProgressBar.setTextToDisplay ("Linear progress bar"); + circularProgressBar.setTextToDisplay ("Circular progress bar"); + } + } + TextEditor textEditor1, textEditor2 { "Password", (juce_wchar) 0x2022 }; ComboBox comboBox { "Combo" }; + + double progress { 0.0 }; + ProgressBar linearProgressBar { progress }; + ProgressBar circularProgressBar { progress }; }; //============================================================================== diff --git a/examples/GUI/WindowsDemo.h b/examples/GUI/WindowsDemo.h index 1c703f92b459..4aff0d49be25 100644 --- a/examples/GUI/WindowsDemo.h +++ b/examples/GUI/WindowsDemo.h @@ -228,6 +228,9 @@ class WindowsDemo : public Component addAndMakeVisible (closeWindowsButton); closeWindowsButton.onClick = [this] { closeAllWindows(); }; + addAndMakeVisible (alertWindowResult); + alertWindowResult.setJustificationType (Justification::centred); + setSize (250, 250); } @@ -253,14 +256,27 @@ class WindowsDemo : public Component void resized() override { - Rectangle buttonSize (0, 0, 108, 28); + FlexBox flexBox; + flexBox.flexDirection = FlexBox::Direction::column; + flexBox.justifyContent = FlexBox::JustifyContent::center; + + constexpr auto buttonWidth = 108.0f; + constexpr auto componentHeight = 24.0f; + constexpr auto gap = 4.0f; + + flexBox.items.add (FlexItem { showWindowsButton }.withHeight (componentHeight) + .withMinWidth (buttonWidth) + .withAlignSelf (FlexItem::AlignSelf::center)); - Rectangle area ((getWidth() / 2) - (buttonSize.getWidth() / 2), - (getHeight() / 2) - buttonSize.getHeight(), - buttonSize.getWidth(), buttonSize.getHeight()); + flexBox.items.add (FlexItem{}.withHeight (gap)); + flexBox.items.add (FlexItem { closeWindowsButton }.withHeight (componentHeight) + .withMinWidth (buttonWidth) + .withAlignSelf (FlexItem::AlignSelf::center)); - showWindowsButton .setBounds (area.reduced (2)); - closeWindowsButton.setBounds (area.translated (0, buttonSize.getHeight()).reduced (2)); + flexBox.items.add (FlexItem{}.withHeight (gap)); + flexBox.items.add (FlexItem { alertWindowResult }.withHeight (componentHeight)); + + flexBox.performLayout (getLocalBounds()); } private: @@ -272,6 +288,7 @@ class WindowsDemo : public Component TextButton showWindowsButton { "Show Windows" }, closeWindowsButton { "Close Windows" }; + Label alertWindowResult { "Alert Window result" }; void showAllWindows() { @@ -280,6 +297,7 @@ class WindowsDemo : public Component showDocumentWindow (false); showDocumentWindow (true); showTransparentWindow(); + showAlertWindow(); showDialogWindow(); } @@ -289,6 +307,12 @@ class WindowsDemo : public Component window.deleteAndZero(); windows.clear(); + alertWindowResult.setText ("", dontSendNotification); + } + + static auto getDisplayArea() + { + return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea.reduced (20); } void showDialogWindow() @@ -333,8 +357,7 @@ class WindowsDemo : public Component | RectanglePlacement::yTop | RectanglePlacement::doNotResize); - auto result = placement.appliedTo (area, Desktop::getInstance().getDisplays() - .getPrimaryDisplay()->userArea.reduced (20)); + auto result = placement.appliedTo (area, getDisplayArea()); dw->setBounds (result); dw->setResizable (true, ! native); @@ -354,12 +377,113 @@ class WindowsDemo : public Component | RectanglePlacement::yBottom | RectanglePlacement::doNotResize); - auto result = placement.appliedTo (area, Desktop::getInstance().getDisplays() - .getPrimaryDisplay()->userArea.reduced (20)); + auto result = placement.appliedTo (area, getDisplayArea()); balls->setBounds (result); balls->setVisible (true); } + void showAlertWindow() + { + auto* alertWindow = new AlertWindow ("Alert Window", + "For more complex dialogs, you can easily add components to an AlertWindow, such as...", + MessageBoxIconType::InfoIcon); + windows.add (alertWindow); + + alertWindow->addTextBlock ("Text block"); + alertWindow->addComboBox ("Combo box", {"Combo box", "Item 2", "Item 3"}); + alertWindow->addTextEditor ("Text editor", "Text editor"); + alertWindow->addTextEditor ("Password", "password", "including for passwords", true); + alertWindowCustomComponent.emplace(); + alertWindow->addCustomComponent (&(*alertWindowCustomComponent)); + alertWindow->addTextBlock ("Progress bar"); + alertWindow->addProgressBarComponent (alertWindowCustomComponent->value, ProgressBar::Style::linear); + alertWindow->addProgressBarComponent (alertWindowCustomComponent->value, ProgressBar::Style::circular); + alertWindow->addTextBlock ("Press any button, or the escape key, to close the window"); + + enum AlertWindowResult + { + noButtonPressed, + button1Pressed, + button2Pressed + }; + + alertWindow->addButton ("Button 1", AlertWindowResult::button1Pressed); + alertWindow->addButton ("Button 2", AlertWindowResult::button2Pressed); + + RectanglePlacement placement { RectanglePlacement::yMid + | RectanglePlacement::xLeft + | RectanglePlacement::doNotResize }; + + alertWindow->setBounds (placement.appliedTo (alertWindow->getBounds(), getDisplayArea())); + + alertWindowResult.setText ("", dontSendNotification); + alertWindow->enterModalState (false, ModalCallbackFunction::create ([ref = SafePointer { this }] (int result) + { + if (ref == nullptr) + return; + + const auto text = [&] + { + switch (result) + { + case noButtonPressed: + return "Dismissed the Alert Window without pressing a button"; + case button1Pressed: + return "Dismissed the Alert Window using Button 1"; + case button2Pressed: + return "Dismissed the Alert Window using Button 2"; + } + + return "Unhandled event when dismissing the Alert Window"; + }(); + + ref->alertWindowResult.setText (text, dontSendNotification); + }), true); + } + + class AlertWindowCustomComponent : public Component, + private Slider::Listener + { + public: + AlertWindowCustomComponent() + { + slider.setRange (0.0, 1.0); + slider.setValue (0.5, NotificationType::dontSendNotification); + slider.addListener (this); + + addAndMakeVisible (label); + addAndMakeVisible (slider); + + setSize (200, 50); + } + + ~AlertWindowCustomComponent() override + { + slider.removeListener (this); + } + + void resized() override + { + auto bounds = getLocalBounds(); + label.setBounds (bounds.removeFromTop (getHeight() / 2)); + slider.setBounds (bounds); + } + + void sliderValueChanged (Slider*) override + { + value = slider.getValue(); + } + + double value { -1.0 }; + + private: + Label label { "Label", "Custom component" }; + Slider slider { Slider::SliderStyle::LinearHorizontal, + Slider::TextEntryBoxPosition::NoTextBox }; + }; + + std::optional alertWindowCustomComponent; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDemo) }; diff --git a/examples/Plugins/ARAPluginDemo.h b/examples/Plugins/ARAPluginDemo.h index 17befd7bed2c..7fc740899c01 100644 --- a/examples/Plugins/ARAPluginDemo.h +++ b/examples/Plugins/ARAPluginDemo.h @@ -296,11 +296,18 @@ class PossiblyBufferedReader std::unique_ptr reader; }; +struct ProcessingLockInterface +{ + virtual ~ProcessingLockInterface() = default; + virtual ScopedTryReadLock getProcessingLock() = 0; +}; + //============================================================================== class PlaybackRenderer : public ARAPlaybackRenderer { public: - using ARAPlaybackRenderer::ARAPlaybackRenderer; + PlaybackRenderer (ARA::PlugIn::DocumentController* dc, ProcessingLockInterface& lockInterfaceIn) + : ARAPlaybackRenderer (dc), lockInterface (lockInterfaceIn) {} void prepareToPlay (double sampleRateIn, int maximumSamplesPerBlockIn, @@ -351,6 +358,11 @@ class PlaybackRenderer : public ARAPlaybackRenderer AudioProcessor::Realtime realtime, const AudioPlayHead::PositionInfo& positionInfo) noexcept override { + const auto lock = lockInterface.getProcessingLock(); + + if (! lock.isLocked()) + return true; + const auto numSamples = buffer.getNumSamples(); jassert (numSamples <= maximumSamplesPerBlock); jassert (numChannels == buffer.getNumChannels()); @@ -458,8 +470,7 @@ class PlaybackRenderer : public ARAPlaybackRenderer private: //============================================================================== - // We're subclassing here only to provide a proper default c'tor for our shared resource - + ProcessingLockInterface& lockInterface; SharedResourcePointer sharedTimesliceThread; std::map audioSourceReaders; bool useBufferedAudioSourceReader = true; @@ -473,8 +484,12 @@ class EditorRenderer : public ARAEditorRenderer, private ARARegionSequence::Listener { public: - EditorRenderer (ARA::PlugIn::DocumentController* documentController, const PreviewState* previewStateIn) - : ARAEditorRenderer (documentController), previewState (previewStateIn), previewBuffer() + EditorRenderer (ARA::PlugIn::DocumentController* documentController, + const PreviewState* previewStateIn, + ProcessingLockInterface& lockInterfaceIn) + : ARAEditorRenderer (documentController), + lockInterface (lockInterfaceIn), + previewState (previewStateIn) { jassert (previewState != nullptr); } @@ -549,6 +564,11 @@ class EditorRenderer : public ARAEditorRenderer, { ignoreUnused (realtime); + const auto lock = lockInterface.getProcessingLock(); + + if (! lock.isLocked()) + return true; + return asyncConfigCallback.withLock ([&] (bool locked) { if (! locked) @@ -596,9 +616,9 @@ class EditorRenderer : public ARAEditorRenderer, const auto previewDimmed = previewedRegion->getAudioModification() ->isDimmed(); - if (lastPreviewTime != previewTime - || lastPlaybackRegion != previewedRegion - || lastPreviewDimmed != previewDimmed) + if (! exactlyEqual (lastPreviewTime, previewTime) + || ! exactlyEqual (lastPlaybackRegion, previewedRegion) + || ! exactlyEqual (lastPreviewDimmed, previewDimmed)) { Range previewRangeInPlaybackTime { previewTime - 0.25, previewTime + 0.25 }; previewBuffer->clear(); @@ -661,6 +681,7 @@ class EditorRenderer : public ARAEditorRenderer, }); } + ProcessingLockInterface& lockInterface; const PreviewState* previewState = nullptr; AsyncConfigurationCallback asyncConfigCallback { [this] { configure(); } }; double lastPreviewTime = 0.0; @@ -678,7 +699,8 @@ class EditorRenderer : public ARAEditorRenderer, }; //============================================================================== -class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControllerSpecialisation +class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControllerSpecialisation, + private ProcessingLockInterface { public: using ARADocumentControllerSpecialisation::ARADocumentControllerSpecialisation; @@ -686,6 +708,16 @@ class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControl PreviewState previewState; protected: + void willBeginEditing (ARADocument*) override + { + processBlockLock.enterWrite(); + } + + void didEndEditing (ARADocument*) override + { + processBlockLock.exitWrite(); + } + ARAAudioModification* doCreateAudioModification (ARAAudioSource* audioSource, ARA::ARAAudioModificationHostRef hostRef, const ARAAudioModification* optionalModificationToClone) noexcept override @@ -697,12 +729,12 @@ class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControl ARAPlaybackRenderer* doCreatePlaybackRenderer() noexcept override { - return new PlaybackRenderer (getDocumentController()); + return new PlaybackRenderer (getDocumentController(), *this); } EditorRenderer* doCreateEditorRenderer() noexcept override { - return new EditorRenderer (getDocumentController(), &previewState); + return new EditorRenderer (getDocumentController(), &previewState, *this); } bool doRestoreObjectsFromStream (ARAInputStream& input, @@ -779,6 +811,14 @@ class ARADemoPluginDocumentControllerSpecialisation : public ARADocumentControl return true; } + +private: + ScopedTryReadLock getProcessingLock() override + { + return ScopedTryReadLock { processBlockLock }; + } + + ReadWriteLock processBlockLock; }; struct PlayHeadState @@ -1062,7 +1102,7 @@ class RulersView : public Component, const auto quarterPos = barSignaturesConverter.getQuarterForBeat (beat); const int x = timeToViewScaling.getXForTime (tempoConverter.getTimeForQuarter (quarterPos)); const auto barSignature = barSignaturesConverter.getBarSignatureForQuarter (quarterPos); - const int lineWidth = (quarterPos == barSignature.position) ? heavyLineWidth : lightLineWidth; + const int lineWidth = (approximatelyEqual (quarterPos, barSignature.position)) ? heavyLineWidth : lightLineWidth; const int beatsSinceBarStart = roundToInt( barSignaturesConverter.getBeatDistanceFromBarStartForQuarter (quarterPos)); const int lineHeight = (beatsSinceBarStart == 0) ? rulerHeight : rulerHeight / 2; rects.addWithoutMerging (Rectangle (x - lineWidth / 2, 2 * rulerHeight - lineHeight, lineWidth, lineHeight)); diff --git a/examples/Plugins/AudioPluginDemo.h b/examples/Plugins/AudioPluginDemo.h index da12a3da595d..189f090154a3 100644 --- a/examples/Plugins/AudioPluginDemo.h +++ b/examples/Plugins/AudioPluginDemo.h @@ -97,8 +97,8 @@ class SineWaveVoice : public SynthesiserVoice // start a tail-off by setting this flag. The render callback will pick up on // this and do a fade out, calling clearCurrentNote() when it's finished. - if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the - // stopNote method could be called more than once. + if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the + // stopNote method could be called more than once. tailOff = 1.0; } else @@ -122,7 +122,7 @@ class SineWaveVoice : public SynthesiserVoice void renderNextBlock (AudioBuffer& outputBuffer, int startSample, int numSamples) override { - if (angleDelta != 0.0) + if (! approximatelyEqual (angleDelta, 0.0)) { if (tailOff > 0.0) { diff --git a/examples/Plugins/DSPModulePluginDemo.h b/examples/Plugins/DSPModulePluginDemo.h index 6e5c9c36917a..004753132e80 100644 --- a/examples/Plugins/DSPModulePluginDemo.h +++ b/examples/Plugins/DSPModulePluginDemo.h @@ -969,7 +969,7 @@ class DspModulePluginDemo : public AudioProcessor, //============================================================================== static String getPanningTextForValue (float value) { - if (value == 0.5f) + if (approximatelyEqual (value, 0.5f)) return "center"; if (value < 0.5f) diff --git a/examples/Plugins/HostPluginDemo.h b/examples/Plugins/HostPluginDemo.h index 589e9a0f3170..804f96898b1b 100644 --- a/examples/Plugins/HostPluginDemo.h +++ b/examples/Plugins/HostPluginDemo.h @@ -213,11 +213,10 @@ class HostAudioProcessorImpl : public AudioProcessor, { if (error.isNotEmpty()) { - NativeMessageBox::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Plugin Load Failed", - error, - nullptr, - nullptr); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Plugin Load Failed", + error); + messageBox = AlertWindow::showScopedAsync (options, nullptr); return; } @@ -281,6 +280,7 @@ class HostAudioProcessorImpl : public AudioProcessor, std::unique_ptr inner; EditorStyle editorStyle = EditorStyle{}; bool active = false; + ScopedMessageBox messageBox; static constexpr const char* innerStateTag = "inner_state"; static constexpr const char* editorStyleTag = "editor_style"; @@ -298,7 +298,6 @@ class HostAudioProcessorImpl : public AudioProcessor, } }; - constexpr const char* HostAudioProcessorImpl::innerStateTag; constexpr const char* HostAudioProcessorImpl::editorStyleTag; diff --git a/examples/Plugins/MidiLoggerPluginDemo.h b/examples/Plugins/MidiLoggerPluginDemo.h index 7602d14549d8..104ef89f4187 100644 --- a/examples/Plugins/MidiLoggerPluginDemo.h +++ b/examples/Plugins/MidiLoggerPluginDemo.h @@ -337,9 +337,11 @@ class MidiLoggerPluginDemoProcessor : public AudioProcessor, static BusesProperties getBusesLayout() { - // Live doesn't like to load midi-only plugins, so we add an audio output there. - return PluginHostType().isAbletonLive() ? BusesProperties().withOutput ("out", AudioChannelSet::stereo()) - : BusesProperties(); + // Live and Cakewalk don't like to load midi-only plugins, so we add an audio output there. + const PluginHostType host; + return host.isAbletonLive() || host.isSonar() + ? BusesProperties().withOutput ("out", AudioChannelSet::stereo()) + : BusesProperties(); } ValueTree state { "state" }; diff --git a/examples/Plugins/ReaperEmbeddedViewPluginDemo.h b/examples/Plugins/ReaperEmbeddedViewPluginDemo.h index dbc5f718776f..3fbccb80ac28 100644 --- a/examples/Plugins/ReaperEmbeddedViewPluginDemo.h +++ b/examples/Plugins/ReaperEmbeddedViewPluginDemo.h @@ -47,7 +47,7 @@ *******************************************************************************/ -/* This demo shows how to use the VSTCallbackHandler and VST3ClientExtensions +/* This demo shows how to use the VST2ClientExtensions and VST3ClientExtensions classes to provide extended functionality in compatible VST/VST3 hosts. If this project is built as a VST or VST3 plugin and loaded in REAPER @@ -104,6 +104,8 @@ struct EmbeddedViewListener virtual Steinberg::TPtrInt handledEmbeddedUIMessage (int msg, Steinberg::TPtrInt parm2, Steinberg::TPtrInt parm3) = 0; + + virtual void setGlobalBypassFunction (void (*) (int)) = 0; }; JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnon-virtual-dtor") @@ -144,6 +146,85 @@ class EmbeddedUI : public reaper::IReaperUIEmbedInterface JUCE_END_IGNORE_WARNINGS_GCC_LIKE +class VST2Extensions : public VST2ClientExtensions +{ +public: + explicit VST2Extensions (EmbeddedViewListener& l) + : listener (l) {} + + pointer_sized_int handleVstPluginCanDo (int32, pointer_sized_int, void* ptr, float) override + { + if (auto* str = static_cast (ptr)) + { + if (strcmp (str, "hasCockosEmbeddedUI") == 0) + return 0xbeef0000; + + if (strcmp (str, "hasCockosExtensions") == 0) + return 0xbeef0000; + } + + return 0; + } + + pointer_sized_int handleVstManufacturerSpecific (int32 index, + pointer_sized_int value, + void* ptr, + float opt) override + { + // The docstring at the top of reaper_plugin_fx_embed.h specifies + // that the index will always be effEditDraw, which is now deprecated. + if (index != __effEditDrawDeprecated) + return 0; + + return (pointer_sized_int) listener.handledEmbeddedUIMessage ((int) opt, + (Steinberg::TPtrInt) value, + (Steinberg::TPtrInt) ptr); + } + + void handleVstHostCallbackAvailable (std::function&& hostcb) override + { + char functionName[] = "BypassFxAllTracks"; + listener.setGlobalBypassFunction (reinterpret_cast (hostcb ((int32_t) 0xdeadbeef, (int32_t) 0xdeadf00d, 0, functionName, 0.0))); + } + +private: + EmbeddedViewListener& listener; +}; + +class VST3Extensions : public VST3ClientExtensions +{ +public: + explicit VST3Extensions (EmbeddedViewListener& l) + : listener (l) {} + + int32_t queryIEditController (const Steinberg::TUID tuid, void** obj) override + { + if (embeddedUi.queryInterface (tuid, obj) == Steinberg::kResultOk) + return Steinberg::kResultOk; + + *obj = nullptr; + return Steinberg::kNoInterface; + } + + void setIHostApplication (Steinberg::FUnknown* ptr) override + { + if (ptr == nullptr) + return; + + void* objPtr = nullptr; + + if (ptr->queryInterface (reaper::IReaperHostApplication::iid, &objPtr) == Steinberg::kResultOk) + { + if (void* fnPtr = static_cast (objPtr)->getReaperApi ("BypassFxAllTracks")) + listener.setGlobalBypassFunction (reinterpret_cast (fnPtr)); + } + } + +private: + EmbeddedViewListener& listener; + EmbeddedUI embeddedUi { listener }; +}; + //============================================================================== class Editor : public AudioProcessorEditor { @@ -182,8 +263,6 @@ class Editor : public AudioProcessorEditor //============================================================================== class ReaperEmbeddedViewDemo : public AudioProcessor, - public VSTCallbackHandler, - public VST3ClientExtensions, private EmbeddedViewListener, private Timer { @@ -236,63 +315,8 @@ class ReaperEmbeddedViewDemo : public AudioProcessor, false).readFloat()); } - int32_t queryIEditController (const Steinberg::TUID tuid, void** obj) override - { - if (embeddedUi.queryInterface (tuid, obj) == Steinberg::kResultOk) - return Steinberg::kResultOk; - - *obj = nullptr; - return Steinberg::kNoInterface; - } - - void setIHostApplication (Steinberg::FUnknown* ptr) override - { - if (ptr == nullptr) - return; - - void* objPtr = nullptr; - - if (ptr->queryInterface (reaper::IReaperHostApplication::iid, &objPtr) == Steinberg::kResultOk) - { - if (void* fnPtr = static_cast (objPtr)->getReaperApi ("BypassFxAllTracks")) - globalBypassFn = reinterpret_cast (fnPtr); - } - } - - pointer_sized_int handleVstPluginCanDo (int32, pointer_sized_int, void* ptr, float) override - { - if (auto* str = static_cast (ptr)) - { - if (strcmp (str, "hasCockosEmbeddedUI") == 0) - return 0xbeef0000; - - if (strcmp (str, "hasCockosExtensions") == 0) - return 0xbeef0000; - } - - return 0; - } - - pointer_sized_int handleVstManufacturerSpecific (int32 index, - pointer_sized_int value, - void* ptr, - float opt) override - { - // The docstring at the top of reaper_plugin_fx_embed.h specifies - // that the index will always be effEditDraw, which is now deprecated. - if (index != __effEditDrawDeprecated) - return 0; - - return (pointer_sized_int) handledEmbeddedUIMessage ((int) opt, - (Steinberg::TPtrInt) value, - (Steinberg::TPtrInt) ptr); - } - - void handleVstHostCallbackAvailable (std::function&& hostcb) override - { - char functionName[] = "BypassFxAllTracks"; - globalBypassFn = reinterpret_cast (hostcb ((int32_t) 0xdeadbeef, (int32_t) 0xdeadf00d, 0, functionName, 0.0)); - } + VST2ClientExtensions* getVST2ClientExtensions() override { return &vst2Extensions; } + VST3ClientExtensions* getVST3ClientExtensions() override { return &vst3Extensions; } private: template @@ -414,10 +438,14 @@ class ReaperEmbeddedViewDemo : public AudioProcessor, return 0; } + void setGlobalBypassFunction (void (*fn) (int)) override { globalBypassFn = fn; } + AudioParameterFloat* gain = nullptr; void (*globalBypassFn) (int) = nullptr; - EmbeddedUI embeddedUi { *this }; std::atomic storedLevel { 0.0f }; float levelToDraw = 0.0f; + + VST2Extensions vst2Extensions { *this }; + VST3Extensions vst3Extensions { *this }; }; diff --git a/examples/Plugins/SamplerPluginDemo.h b/examples/Plugins/SamplerPluginDemo.h index 289e9ff3528c..6e6d15c02d6e 100644 --- a/examples/Plugins/SamplerPluginDemo.h +++ b/examples/Plugins/SamplerPluginDemo.h @@ -208,7 +208,7 @@ class MPESamplerSound final public: void setSample (std::unique_ptr value) { - sample = move (value); + sample = std::move (value); setLoopPointsInSeconds (loopPoints); } @@ -291,7 +291,7 @@ class MPESamplerVoice : public MPESynthesiserVoice { jassert (currentlyPlayingNote.keyState == MPENote::off); - if (allowTailOff && tailOff == 0.0) + if (allowTailOff && approximatelyEqual (tailOff, 0.0)) tailOff = 1.0; else stopNote(); @@ -422,7 +422,7 @@ class MPESamplerVoice : public MPESynthesiserVoice bool isTailingOff() const { - return tailOff != 0.0; + return ! approximatelyEqual (tailOff, 0.0); } void stopNote() @@ -995,7 +995,7 @@ class DataModel : private ValueTree::Listener void setSampleReader (std::unique_ptr readerFactory, UndoManager* undoManager) { - sampleReader.setValue (move (readerFactory), undoManager); + sampleReader.setValue (std::move (readerFactory), undoManager); setLoopPointsSeconds (Range (0, getSampleLengthSeconds()).constrainRange (loopPointsSeconds), undoManager); } @@ -1192,7 +1192,7 @@ class MPELegacySettingsComponent final : public Component, } } - bool isLegacyModeValid() const + bool isLegacyModeValid() { if (! areLegacyModeParametersValid()) { @@ -1233,13 +1233,14 @@ class MPELegacySettingsComponent final : public Component, return getFirstChannel() <= getLastChannel(); } - void handleInvalidLegacyModeParameters() const + void handleInvalidLegacyModeParameters() { - AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, - "Invalid legacy mode channel layout", - "Cannot set legacy mode start/end channel:\n" - "The end channel must not be less than the start channel!", - "Got it"); + auto options = MessageBoxOptions::makeOptionsOk (AlertWindow::WarningIcon, + "Invalid legacy mode channel layout", + "Cannot set legacy mode start/end channel:\n" + "The end channel must not be less than the start channel!", + "Got it"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } MPESettingsDataModel dataModel; @@ -1251,6 +1252,7 @@ class MPELegacySettingsComponent final : public Component, legacyPitchbendRangeLabel { {}, "Pitchbend range (semitones)" }; UndoManager* undoManager; + ScopedMessageBox messageBox; }; //============================================================================== @@ -1860,7 +1862,7 @@ class WaveformEditor : public Component, UndoManager& undoManager) : dataModel (model), waveformView (model, visibleRange), - playbackOverlay (visibleRange, move (provider)), + playbackOverlay (visibleRange, std::move (provider)), loopPoints (dataModel, visibleRange, undoManager), ruler (visibleRange) { @@ -1916,7 +1918,7 @@ class MainSamplerView : public Component, PlaybackPositionOverlay::Provider provider, UndoManager& um) : dataModel (model), - waveformEditor (dataModel, move (provider), um), + waveformEditor (dataModel, std::move (provider), um), undoManager (um) { dataModel.addListener (*this); @@ -2123,7 +2125,7 @@ class SamplerAudioProcessor : public AudioProcessor auto sample = std::unique_ptr (new Sample (*reader, 10.0)); auto lengthInSeconds = sample->getLength() / sample->getSampleRate(); sound->setLoopPointsInSeconds ({lengthInSeconds * 0.1, lengthInSeconds * 0.9 }); - sound->setSample (move (sample)); + sound->setSample (std::move (sample)); // Start with the max number of voices for (auto i = 0; i != maxVoices; ++i) @@ -2216,7 +2218,7 @@ class SamplerAudioProcessor : public AudioProcessor void operator() (SamplerAudioProcessor& proc) { - proc.readerFactory = move (readerFactory); + proc.readerFactory = std::move (readerFactory); auto sound = proc.samplerSound; sound->setSample (std::move (sample)); auto numberOfVoices = proc.synthesiser.getNumVoices(); @@ -2245,15 +2247,15 @@ class SamplerAudioProcessor : public AudioProcessor if (fact == nullptr) { - commands.push (SetSampleCommand (move (fact), + commands.push (SetSampleCommand (std::move (fact), nullptr, - move (newSamplerVoices))); + std::move (newSamplerVoices))); } else if (auto reader = fact->make (formatManager)) { - commands.push (SetSampleCommand (move (fact), + commands.push (SetSampleCommand (std::move (fact), std::unique_ptr (new Sample (*reader, 10.0)), - move (newSamplerVoices))); + std::move (newSamplerVoices))); } } @@ -2350,7 +2352,7 @@ class SamplerAudioProcessor : public AudioProcessor for (auto i = 0; i != numberOfVoices; ++i) newSamplerVoices.emplace_back (new MPESamplerVoice (loadedSamplerSound)); - commands.push (SetNumVoicesCommand (move (newSamplerVoices))); + commands.push (SetNumVoicesCommand (std::move (newSamplerVoices))); } // These accessors are just for an 'overview' and won't give the exact @@ -2409,7 +2411,8 @@ class SamplerAudioProcessor : public AudioProcessor mpeSettings.setVoiceStealingEnabled (state.voiceStealingEnabled, nullptr); mpeSettings.setMPEZoneLayout (state.mpeZoneLayout, nullptr); - dataModel.setSampleReader (move (state.readerFactory), nullptr); + dataModel.setSampleReader (std::move (state.readerFactory), nullptr); + dataModel.setLoopPointsSeconds (state.loopPointsSeconds, nullptr); dataModel.setCentreFrequencyHz (state.centreFrequencyHz, nullptr); dataModel.setLoopMode (state.loopMode, nullptr); diff --git a/examples/Utilities/InAppPurchasesDemo.h b/examples/Utilities/InAppPurchasesDemo.h index ffc050827262..d0503f36e405 100644 --- a/examples/Utilities/InAppPurchasesDemo.h +++ b/examples/Utilities/InAppPurchasesDemo.h @@ -156,12 +156,13 @@ class VoicePurchases : private InAppPurchases::Listener voiceProduct.purchasePrice = "In-App purchases unavailable"; } - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "In-app purchase is unavailable!", - "In-App purchases are not available. This either means you are trying " - "to use IAP on a platform that does not support IAP or you haven't setup " - "your app correctly to work with IAP.", - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "In-app purchase is unavailable!", + "In-App purchases are not available. This either means you are trying " + "to use IAP on a platform that does not support IAP or you haven't setup " + "your app correctly to work with IAP.", + "OK"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } else { @@ -178,17 +179,18 @@ class VoicePurchases : private InAppPurchases::Listener } } - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Your credit card will be charged!", - "You are running the sample code for JUCE In-App purchases. " - "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!", - "Understood!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Your credit card will be charged!", + "You are running the sample code for JUCE In-App purchases. " + "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!", + "Understood!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } guiUpdater.triggerAsyncUpdate(); } - void productPurchaseFinished (const PurchaseInfo& info, bool success, const String&) override + void productPurchaseFinished (const PurchaseInfo& info, bool success, const String& error) override { purchaseInProgress = false; @@ -211,6 +213,12 @@ class VoicePurchases : private InAppPurchases::Listener } } + if (! success) + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, "Purchase failed", error); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } + guiUpdater.triggerAsyncUpdate(); } @@ -264,6 +272,7 @@ class VoicePurchases : private InAppPurchases::Listener AsyncUpdater& guiUpdater; bool havePurchasesBeenRestored = false, havePricesBeenFetched = false, purchaseInProgress = false; Array voiceProducts; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VoicePurchases) }; diff --git a/examples/Utilities/MultithreadingDemo.h b/examples/Utilities/MultithreadingDemo.h index 9b329253ff9b..d674e3902891 100644 --- a/examples/Utilities/MultithreadingDemo.h +++ b/examples/Utilities/MultithreadingDemo.h @@ -317,7 +317,8 @@ class MultithreadingDemo : public Component, } //============================================================================== - ThreadPool pool { 3 }; + ThreadPool pool { ThreadPoolOptions{}.withThreadName ("Demo thread pool") + .withNumberOfThreads (3) }; TextButton controlButton { "Thread type" }; bool isUsingPool = false; diff --git a/examples/Utilities/OSCDemo.h b/examples/Utilities/OSCDemo.h index 063713599267..1ec2e05ac8d3 100644 --- a/examples/Utilities/OSCDemo.h +++ b/examples/Utilities/OSCDemo.h @@ -222,16 +222,17 @@ class OSCSenderDemo : public Component //============================================================================== void showConnectionErrorMessage (const String& messageText) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Connection error", - messageText, - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Connection error", + messageText); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } //============================================================================== Slider rotaryKnob; OSCSender sender1, sender2; Label senderLabel { {}, "Sender" }; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSCSenderDemo) }; @@ -273,15 +274,16 @@ class OSCReceiverDemo : public Component, void showConnectionErrorMessage (const String& messageText) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Connection error", - messageText, - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Connection error", + messageText); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } //============================================================================== Slider rotaryKnob; Label receiverLabel { {}, "Receiver" }; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSCReceiverDemo) }; @@ -403,28 +405,28 @@ class OSCMonitorDemo : public Component, //============================================================================== void handleConnectError (int failedPort) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "OSC Connection error", - "Error: could not connect to port " + String (failedPort), - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "OSC Connection error", + "Error: could not connect to port " + String (failedPort)); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } //============================================================================== void handleDisconnectError() { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Unknown error", - "An unknown error occurred while trying to disconnect from UDP port.", - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Unknown error", + "An unknown error occurred while trying to disconnect from UDP port."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } //============================================================================== void handleInvalidPortNumberEntered() { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Invalid port number", - "Error: you have entered an invalid UDP port number.", - "OK"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Invalid port number", + "Error: you have entered an invalid UDP port number."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } //============================================================================== @@ -457,6 +459,8 @@ class OSCMonitorDemo : public Component, connectionStatusLabel.setJustificationType (Justification::centredRight); } + ScopedMessageBox messageBox; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSCMonitorDemo) }; diff --git a/examples/Utilities/PushNotificationsDemo.h b/examples/Utilities/PushNotificationsDemo.h index 9788dd6691dd..0637e705e348 100644 --- a/examples/Utilities/PushNotificationsDemo.h +++ b/examples/Utilities/PushNotificationsDemo.h @@ -185,21 +185,25 @@ class PushNotificationsDemo : public Component, { PushNotifications::getInstance()->removeAllPendingLocalNotifications(); }; #endif - remoteView.getDeviceTokenButton.onClick = [] + remoteView.getDeviceTokenButton.onClick = [this] { String token = PushNotifications::getInstance()->getDeviceToken(); DBG ("token = " + token); if (token.isEmpty()) + { showRemoteInstructions(); + } else - NativeMessageBox::showAsync (MessageBoxOptions() + { + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Device token") .withMessage (token) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); + } }; #if JUCE_ANDROID @@ -313,12 +317,12 @@ class PushNotificationsDemo : public Component, String requiredFields = "all required fields"; #endif - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Incorrect notifications setup") .withMessage ("Please make sure that " + requiredFields + " are set.") - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); return; } @@ -565,14 +569,14 @@ class PushNotificationsDemo : public Component, { ignoreUnused (isLocalNotification); - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Received notification") .withMessage ("ID: " + n.identifier + ", title: " + n.title + ", body: " + n.body) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void handleNotificationAction (bool isLocalNotification, @@ -582,7 +586,7 @@ class PushNotificationsDemo : public Component, { ignoreUnused (isLocalNotification); - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Received notification action") .withMessage ("ID: " + n.identifier @@ -590,22 +594,22 @@ class PushNotificationsDemo : public Component, + ", body: " + n.body + ", action: " + actionIdentifier + ", optionalResponse: " + optionalResponse) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); PushNotifications::getInstance()->removeDeliveredNotification (n.identifier); } void localNotificationDismissedByUser (const PushNotifications::Notification& n) override { - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Notification dismissed by a user") .withMessage ("ID: " + n.identifier + ", title: " + n.title + ", body: " + n.body) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void deliveredNotificationsListReceived (const Array& notifs) override @@ -615,12 +619,12 @@ class PushNotificationsDemo : public Component, for (auto& n : notifs) text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Received notification list") .withMessage (text) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void pendingLocalNotificationsListReceived (const Array& notifs) override @@ -630,54 +634,54 @@ class PushNotificationsDemo : public Component, for (auto& n : notifs) text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), "; - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Pending notification list") .withMessage (text) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void deviceTokenRefreshed (const String& token) override { - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Device token refreshed") .withMessage (token) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } #if JUCE_ANDROID void remoteNotificationsDeleted() override { - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Remote notifications deleted") .withMessage ("Some of the pending messages were removed!") - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void upstreamMessageSent (const String& messageId) override { - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Upstream message sent") .withMessage ("Message id: " + messageId) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } void upstreamMessageSendingError (const String& messageId, const String& error) override { - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Upstream message sending error") .withMessage ("Message id: " + messageId + "\nerror: " + error) - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); } static Array getAndroidChannels() @@ -1207,8 +1211,8 @@ class PushNotificationsDemo : public Component, struct DemoTabbedComponent : public TabbedComponent { - explicit DemoTabbedComponent (TabbedButtonBar::Orientation orientation) - : TabbedComponent (orientation) + DemoTabbedComponent (PushNotificationsDemo& demoIn, TabbedButtonBar::Orientation orientation) + : TabbedComponent (orientation), demo (demoIn) { } @@ -1216,27 +1220,28 @@ class PushNotificationsDemo : public Component, { if (! showedRemoteInstructions && newCurrentTabName == "Remote") { - PushNotificationsDemo::showRemoteInstructions(); + demo.showRemoteInstructions(); showedRemoteInstructions = true; } } private: bool showedRemoteInstructions = false; + PushNotificationsDemo& demo; }; - static void showRemoteInstructions() + void showRemoteInstructions() { #if JUCE_IOS || JUCE_MAC - NativeMessageBox::showAsync (MessageBoxOptions() + auto options = MessageBoxOptions() .withIconType (MessageBoxIconType::InfoIcon) .withTitle ("Remote Notifications instructions") .withMessage ("In order to be able to test remote notifications " "ensure that the app is signed and that you register " "the bundle ID for remote notifications in " "Apple Developer Center.") - .withButton ("OK"), - nullptr); + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); #endif } @@ -1246,10 +1251,11 @@ class PushNotificationsDemo : public Component, AuxActionsView auxActionsView; TabbedComponent localNotificationsTabs { TabbedButtonBar::TabsAtTop }; RemoteView remoteView; - DemoTabbedComponent mainTabs { TabbedButtonBar::TabsAtTop }; + DemoTabbedComponent mainTabs { *this, TabbedButtonBar::TabsAtTop }; TextButton sendButton { "Send!" }; Label notAvailableYetLabel { "notAvailableYetLabel", "Push Notifications feature is not available on this platform yet!" }; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PushNotificationsDemo) diff --git a/examples/Utilities/SystemInfoDemo.h b/examples/Utilities/SystemInfoDemo.h index f4bcddbe8feb..ab70171656a2 100644 --- a/examples/Utilities/SystemInfoDemo.h +++ b/examples/Utilities/SystemInfoDemo.h @@ -120,6 +120,11 @@ static String getDisplayInfo() return displayDesc; } +static String boolString (bool b) +{ + return b ? "yes" : "no"; +} + static String getAllSystemInfo() { String systemInfo; @@ -150,30 +155,36 @@ static String getAllSystemInfo() << "CPU vendor: " << SystemStats::getCpuVendor() << newLine << "CPU model: " << SystemStats::getCpuModel() << newLine << "CPU speed: " << SystemStats::getCpuSpeedInMegahertz() << " MHz" << newLine - << "CPU has MMX: " << (SystemStats::hasMMX() ? "yes" : "no") << newLine - << "CPU has FMA3: " << (SystemStats::hasFMA3() ? "yes" : "no") << newLine - << "CPU has FMA4: " << (SystemStats::hasFMA4() ? "yes" : "no") << newLine - << "CPU has SSE: " << (SystemStats::hasSSE() ? "yes" : "no") << newLine - << "CPU has SSE2: " << (SystemStats::hasSSE2() ? "yes" : "no") << newLine - << "CPU has SSE3: " << (SystemStats::hasSSE3() ? "yes" : "no") << newLine - << "CPU has SSSE3: " << (SystemStats::hasSSSE3() ? "yes" : "no") << newLine - << "CPU has SSE4.1: " << (SystemStats::hasSSE41() ? "yes" : "no") << newLine - << "CPU has SSE4.2: " << (SystemStats::hasSSE42() ? "yes" : "no") << newLine - << "CPU has 3DNOW: " << (SystemStats::has3DNow() ? "yes" : "no") << newLine - << "CPU has AVX: " << (SystemStats::hasAVX() ? "yes" : "no") << newLine - << "CPU has AVX2: " << (SystemStats::hasAVX2() ? "yes" : "no") << newLine - << "CPU has AVX512F: " << (SystemStats::hasAVX512F() ? "yes" : "no") << newLine - << "CPU has AVX512BW: " << (SystemStats::hasAVX512BW() ? "yes" : "no") << newLine - << "CPU has AVX512CD: " << (SystemStats::hasAVX512CD() ? "yes" : "no") << newLine - << "CPU has AVX512DQ: " << (SystemStats::hasAVX512DQ() ? "yes" : "no") << newLine - << "CPU has AVX512ER: " << (SystemStats::hasAVX512ER() ? "yes" : "no") << newLine - << "CPU has AVX512IFMA: " << (SystemStats::hasAVX512IFMA() ? "yes" : "no") << newLine - << "CPU has AVX512PF: " << (SystemStats::hasAVX512PF() ? "yes" : "no") << newLine - << "CPU has AVX512VBMI: " << (SystemStats::hasAVX512VBMI() ? "yes" : "no") << newLine - << "CPU has AVX512VL: " << (SystemStats::hasAVX512VL() ? "yes" : "no") << newLine - << "CPU has AVX512VPOPCNTDQ: " << (SystemStats::hasAVX512VPOPCNTDQ() ? "yes" : "no") << newLine - << "CPU has Neon: " << (SystemStats::hasNeon() ? "yes" : "no") << newLine + << "CPU has MMX: " << boolString (SystemStats::hasMMX() ) << newLine + << "CPU has FMA3: " << boolString (SystemStats::hasFMA3() ) << newLine + << "CPU has FMA4: " << boolString (SystemStats::hasFMA4() ) << newLine + << "CPU has SSE: " << boolString (SystemStats::hasSSE() ) << newLine + << "CPU has SSE2: " << boolString (SystemStats::hasSSE2() ) << newLine + << "CPU has SSE3: " << boolString (SystemStats::hasSSE3() ) << newLine + << "CPU has SSSE3: " << boolString (SystemStats::hasSSSE3() ) << newLine + << "CPU has SSE4.1: " << boolString (SystemStats::hasSSE41() ) << newLine + << "CPU has SSE4.2: " << boolString (SystemStats::hasSSE42() ) << newLine + << "CPU has 3DNOW: " << boolString (SystemStats::has3DNow() ) << newLine + << "CPU has AVX: " << boolString (SystemStats::hasAVX() ) << newLine + << "CPU has AVX2: " << boolString (SystemStats::hasAVX2() ) << newLine + << "CPU has AVX512F: " << boolString (SystemStats::hasAVX512F() ) << newLine + << "CPU has AVX512BW: " << boolString (SystemStats::hasAVX512BW() ) << newLine + << "CPU has AVX512CD: " << boolString (SystemStats::hasAVX512CD() ) << newLine + << "CPU has AVX512DQ: " << boolString (SystemStats::hasAVX512DQ() ) << newLine + << "CPU has AVX512ER: " << boolString (SystemStats::hasAVX512ER() ) << newLine + << "CPU has AVX512IFMA: " << boolString (SystemStats::hasAVX512IFMA() ) << newLine + << "CPU has AVX512PF: " << boolString (SystemStats::hasAVX512PF() ) << newLine + << "CPU has AVX512VBMI: " << boolString (SystemStats::hasAVX512VBMI() ) << newLine + << "CPU has AVX512VL: " << boolString (SystemStats::hasAVX512VL() ) << newLine + << "CPU has AVX512VPOPCNTDQ: " << boolString (SystemStats::hasAVX512VPOPCNTDQ() ) << newLine + << "CPU has Neon: " << boolString (SystemStats::hasNeon() ) << newLine + << newLine; + + #if JUCE_MAC + systemInfo + << "Application sandbox enabled: " << boolString (SystemStats::isAppSandboxEnabled()) << newLine << newLine; + #endif systemInfo << "Current working directory: " << File::getCurrentWorkingDirectory().getFullPathName() << newLine diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt index be3f6cd76d09..18ff72d94a40 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt @@ -1,7 +1,7 @@ # Automatically generated CMakeLists, created by the Projucer # Don't edit this file! Your changes will be overwritten when you re-save the Projucer project! -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.22) project(juce_jni_project) @@ -25,9 +25,9 @@ include_directories( AFTER enable_language(ASM) if(JUCE_BUILD_CONFIGURATION MATCHES "DEBUG") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) elseif(JUCE_BUILD_CONFIGURATION MATCHES "RELEASE") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) else() message( FATAL_ERROR "No matching build-configuration found." ) endif() @@ -101,8 +101,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -278,23 +278,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -581,6 +581,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -611,6 +612,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -648,14 +650,34 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -735,6 +757,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -757,9 +781,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -786,16 +810,16 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -830,6 +854,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -869,6 +894,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -894,6 +920,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -903,41 +931,44 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -1095,6 +1126,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -1116,19 +1149,20 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -1280,24 +1314,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -1357,6 +1391,27 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -1411,6 +1466,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -1497,63 +1554,77 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -1621,18 +1692,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -1679,24 +1755,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -1781,8 +1857,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -1958,23 +2034,23 @@ set_source_files_properties( "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -2261,6 +2337,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -2291,6 +2368,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -2328,14 +2406,34 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -2415,6 +2513,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -2437,9 +2537,9 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -2466,16 +2566,16 @@ set_source_files_properties( "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -2510,6 +2610,7 @@ set_source_files_properties( "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -2549,6 +2650,7 @@ set_source_files_properties( "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -2574,6 +2676,8 @@ set_source_files_properties( "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -2583,41 +2687,44 @@ set_source_files_properties( "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -2775,6 +2882,8 @@ set_source_files_properties( "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -2796,19 +2905,20 @@ set_source_files_properties( "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -2960,24 +3070,24 @@ set_source_files_properties( "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -3037,6 +3147,27 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -3091,6 +3222,8 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -3177,63 +3310,77 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -3301,18 +3448,23 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -3359,24 +3511,24 @@ set_source_files_properties( "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" diff --git a/extras/AudioPerformanceTest/Builds/Android/app/build.gradle b/extras/AudioPerformanceTest/Builds/Android/app/build.gradle index d3ce65207934..7274fd3640e4 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/build.gradle +++ b/extras/AudioPerformanceTest/Builds/Android/app/build.gradle @@ -2,10 +2,12 @@ apply plugin: 'com.android.application' android { compileSdkVersion 33 + ndkVersion "25.2.9519653" namespace "com.juce.audioperformancetest" externalNativeBuild { cmake { path "CMakeLists.txt" + version "3.22.1" } } signingConfigs { diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml b/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml index 7ab456a92186..5b9c0d726613 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/AudioPerformanceTest/Builds/Android/app/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ + diff --git a/extras/AudioPerformanceTest/Builds/LinuxMakefile/Makefile b/extras/AudioPerformanceTest/Builds/LinuxMakefile/Makefile index d4c14bfe4a18..ffd771342996 100644 --- a/extras/AudioPerformanceTest/Builds/LinuxMakefile/Makefile +++ b/extras/AudioPerformanceTest/Builds/LinuxMakefile/Makefile @@ -39,7 +39,7 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl 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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := AudioPerformanceTest @@ -60,7 +60,7 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl 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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := AudioPerformanceTest @@ -91,85 +91,90 @@ OBJECTS_APP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } @$(PKG_CONFIG) --print-errors alsa freetype2 libcurl @echo Linking "AudioPerformanceTest - App" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_devices_63111d02.o: ../../JuceLibraryCode/include_juce_audio_devices.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_devices.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_formats.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_10c03666.o: ../../JuceLibraryCode/include_juce_audio_processors.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_ara_2a4c6ef7.o: ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_ara.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_12bdca08.o: ../../JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_lv2_libs.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_utils_9f9fb2d6.o: ../../JuceLibraryCode/include_juce_audio_utils.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_utils.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning AudioPerformanceTest $(V_AT)$(CLEANCMD) diff --git a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj b/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj index 133817549367..c6e80d9d1b0e 100644 --- a/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj +++ b/extras/AudioPerformanceTest/Builds/MacOSX/AudioPerformanceTest.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ D2CECF93178A1738DA02CA4A /* include_juce_data_structures.mm */ = {isa = PBXBuildFile; fileRef = EDD11E2CC0B18196ADA0C87B; }; DA21A6E7A18555DCFC63B07C /* RecentFilesMenuTemplate.nib */ = {isa = PBXBuildFile; fileRef = FAAB4EAE4A57B642D3B9EC23; }; E1282ABB96DD2E7FA7F63559 /* App */ = {isa = PBXBuildFile; fileRef = 614F2084407B35D62101F69F; }; + ED96AB7BB45155C78DABD3B9 /* Security.framework */ = {isa = PBXBuildFile; fileRef = 5307BB2EB4B0D26BB39EA248; }; F8099BB77DC0D01DCCC6AFB9 /* QuartzCore.framework */ = {isa = PBXBuildFile; fileRef = 0A58FDDF6FB9253F51939A52; }; FFAF94080FF4A9995B33151E /* include_juce_core.mm */ = {isa = PBXBuildFile; fileRef = 24425FFB0BCC7E54CADAA013; }; /* End PBXBuildFile section */ @@ -54,6 +55,7 @@ 43775DC3D9F7917846EA5327 /* IOKit.framework */ /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 453777CEB7099A5D61901D13 /* Cocoa.framework */ /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 50FEDCEF881CC99174035167 /* juce_gui_basics */ /* juce_gui_basics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_basics; path = ../../../../modules/juce_gui_basics; sourceTree = SOURCE_ROOT; }; + 5307BB2EB4B0D26BB39EA248 /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 614F2084407B35D62101F69F /* App */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AudioPerformanceTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77AA9722BAADD4108205501A /* juce_data_structures */ /* juce_data_structures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_data_structures; path = ../../../../modules/juce_data_structures; sourceTree = SOURCE_ROOT; }; 7E951216B6138C76653B1460 /* include_juce_graphics.mm */ /* include_juce_graphics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_graphics.mm; path = ../../JuceLibraryCode/include_juce_graphics.mm; sourceTree = SOURCE_ROOT; }; @@ -95,6 +97,7 @@ CC782AABFA20787BABBCED90, 9031C69145EE085B60904363, F8099BB77DC0D01DCCC6AFB9, + ED96AB7BB45155C78DABD3B9, 537E779F6008999191B2920A, ); runOnlyForDeploymentPostprocessing = 0; @@ -115,6 +118,7 @@ E1BB9D521BF6C055F5B88628, 43775DC3D9F7917846EA5327, 0A58FDDF6FB9253F51939A52, + 5307BB2EB4B0D26BB39EA248, 3058871156B921B9E5946C4F, ); name = Frameworks; @@ -328,7 +332,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -390,7 +394,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj index 5ef37cc67b0a..1862fc6f0193 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -78,7 +78,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPerformanceTest.exe @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -120,7 +120,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPerformanceTest.exe @@ -454,46 +454,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -838,18 +838,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -949,6 +973,9 @@ true + + true + true @@ -979,7 +1006,7 @@ true - + true @@ -1018,22 +1045,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1129,6 +1156,9 @@ true + + true + true @@ -1141,6 +1171,9 @@ true + + true + true @@ -1150,67 +1183,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1408,6 +1447,9 @@ true + + true + true @@ -1432,19 +1474,19 @@ true - + true - + true - + true - + true - + true @@ -1723,40 +1765,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1828,6 +1870,9 @@ true + + true + true @@ -1900,6 +1945,9 @@ true + + true + true @@ -2023,52 +2071,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2170,9 +2245,18 @@ true + + true + + + true + true + + true + true @@ -2182,7 +2266,7 @@ true - + true @@ -2239,43 +2323,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2338,8 +2422,8 @@ - - + + @@ -2434,8 +2518,8 @@ - - + + @@ -2612,6 +2696,7 @@ + @@ -2631,6 +2716,7 @@ + @@ -2667,8 +2753,18 @@ + + + + + + + + + + @@ -2709,6 +2805,7 @@ + @@ -2721,8 +2818,8 @@ + - @@ -2756,6 +2853,7 @@ + @@ -2798,20 +2896,22 @@ + - - - - - - - - + + + + + + + + + @@ -2902,6 +3002,7 @@ + @@ -2915,12 +3016,13 @@ - - - + + + + + - - + @@ -2977,10 +3079,10 @@ - - + + + - @@ -3016,6 +3118,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3046,6 +3168,7 @@ + @@ -3091,36 +3214,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3158,10 +3282,12 @@ + - + + @@ -3189,7 +3315,7 @@ - + @@ -3204,6 +3330,7 @@ + diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters index 81bc0c6d38b2..3e89495e2b6e 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters @@ -293,12 +293,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -494,6 +512,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -521,9 +542,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -886,49 +904,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1279,18 +1297,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1393,6 +1438,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1423,7 +1471,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1465,34 +1513,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1591,6 +1639,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1603,6 +1654,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1612,82 +1666,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -1891,6 +1951,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -1915,25 +1978,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2215,46 +2278,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2329,6 +2392,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2401,6 +2467,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2524,85 +2593,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2704,9 +2812,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2716,7 +2833,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2776,55 +2893,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -2988,10 +3105,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3276,10 +3393,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -3810,6 +3927,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -3867,6 +3987,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -3975,12 +4098,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4101,6 +4254,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4137,10 +4293,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4242,6 +4398,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4368,6 +4527,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4383,31 +4545,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -4680,6 +4845,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -4719,22 +4887,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -4905,16 +5076,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5022,6 +5193,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5112,6 +5343,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5247,9 +5481,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5259,82 +5490,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5448,6 +5685,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5457,7 +5697,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5541,7 +5784,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -5582,6 +5825,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj index 841dc5264122..7ce3b0a28d74 100644 --- a/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj +++ b/extras/AudioPerformanceTest/Builds/iOS/AudioPerformanceTest.xcodeproj/project.pbxproj @@ -345,7 +345,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -406,7 +406,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", diff --git a/extras/AudioPluginHost/AudioPluginHost.jucer b/extras/AudioPluginHost/AudioPluginHost.jucer index 5e56f67f018b..dd7f2efe54f9 100644 --- a/extras/AudioPluginHost/AudioPluginHost.jucer +++ b/extras/AudioPluginHost/AudioPluginHost.jucer @@ -1,7 +1,7 @@ diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt index 4e41480c5eae..9d3f672fdf24 100644 --- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt @@ -1,7 +1,7 @@ # Automatically generated CMakeLists, created by the Projucer # Don't edit this file! Your changes will be overwritten when you re-save the Projucer project! -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.22) project(juce_jni_project) @@ -34,9 +34,9 @@ include_directories( AFTER enable_language(ASM) if(JUCE_BUILD_CONFIGURATION MATCHES "DEBUG") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_WASAPI=1]] [[-DJUCE_DIRECTSOUND=1]] [[-DJUCE_ALSA=1]] [[-DJUCE_USE_FLAC=0]] [[-DJUCE_USE_OGGVORBIS=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_AU=1]] [[-DJUCE_PLUGINHOST_LADSPA=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_USE_CDREADER=0]] [[-DJUCE_USE_CDBURNER=0]] [[-DJUCE_WEB_BROWSER=0]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_WASAPI=1]] [[-DJUCE_DIRECTSOUND=1]] [[-DJUCE_ALSA=1]] [[-DJUCE_USE_FLAC=0]] [[-DJUCE_USE_OGGVORBIS=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_AU=1]] [[-DJUCE_PLUGINHOST_LADSPA=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_USE_CDREADER=0]] [[-DJUCE_USE_CDBURNER=0]] [[-DJUCE_WEB_BROWSER=0]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) elseif(JUCE_BUILD_CONFIGURATION MATCHES "RELEASE") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_WASAPI=1]] [[-DJUCE_DIRECTSOUND=1]] [[-DJUCE_ALSA=1]] [[-DJUCE_USE_FLAC=0]] [[-DJUCE_USE_OGGVORBIS=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_AU=1]] [[-DJUCE_PLUGINHOST_LADSPA=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_USE_CDREADER=0]] [[-DJUCE_USE_CDBURNER=0]] [[-DJUCE_WEB_BROWSER=0]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_dsp=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_WASAPI=1]] [[-DJUCE_DIRECTSOUND=1]] [[-DJUCE_ALSA=1]] [[-DJUCE_USE_FLAC=0]] [[-DJUCE_USE_OGGVORBIS=1]] [[-DJUCE_PLUGINHOST_VST3=1]] [[-DJUCE_PLUGINHOST_AU=1]] [[-DJUCE_PLUGINHOST_LADSPA=1]] [[-DJUCE_PLUGINHOST_LV2=1]] [[-DJUCE_USE_CDREADER=0]] [[-DJUCE_USE_CDBURNER=0]] [[-DJUCE_WEB_BROWSER=0]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) if(NOT (ANDROID_ABI STREQUAL "mips" OR ANDROID_ABI STREQUAL "mips64")) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -flto") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") @@ -134,8 +134,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -311,23 +311,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -614,6 +614,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -644,6 +645,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -681,14 +683,34 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -768,6 +790,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -790,9 +814,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -819,16 +843,16 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -863,6 +887,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -902,6 +927,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -927,6 +953,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -936,41 +964,44 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -1164,13 +1195,13 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_dsp/maths/juce_Polynomial.h" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.cpp" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.h" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.h" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.cpp" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.h" "../../../../../modules/juce_dsp/processors/juce_DelayLine.cpp" @@ -1227,6 +1258,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -1248,19 +1281,20 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -1412,24 +1446,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -1489,6 +1523,27 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -1543,6 +1598,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -1629,63 +1686,77 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -1753,18 +1824,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -1811,24 +1887,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -1838,9 +1914,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" @@ -1969,8 +2045,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -2146,23 +2222,23 @@ set_source_files_properties( "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -2449,6 +2525,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -2479,6 +2556,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -2516,14 +2594,34 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -2603,6 +2701,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -2625,9 +2725,9 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -2654,16 +2754,16 @@ set_source_files_properties( "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -2698,6 +2798,7 @@ set_source_files_properties( "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -2737,6 +2838,7 @@ set_source_files_properties( "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -2762,6 +2864,8 @@ set_source_files_properties( "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -2771,41 +2875,44 @@ set_source_files_properties( "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -2999,13 +3106,13 @@ set_source_files_properties( "../../../../../modules/juce_dsp/maths/juce_Polynomial.h" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.cpp" "../../../../../modules/juce_dsp/maths/juce_SpecialFunctions.h" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_avx_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_neon_SIMDNativeOps.h" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp" - "../../../../../modules/juce_dsp/native/juce_sse_SIMDNativeOps.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_avx.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_neon.h" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp" + "../../../../../modules/juce_dsp/native/juce_SIMDNativeOps_sse.h" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.cpp" "../../../../../modules/juce_dsp/processors/juce_BallisticsFilter.h" "../../../../../modules/juce_dsp/processors/juce_DelayLine.cpp" @@ -3062,6 +3169,8 @@ set_source_files_properties( "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -3083,19 +3192,20 @@ set_source_files_properties( "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -3247,24 +3357,24 @@ set_source_files_properties( "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -3324,6 +3434,27 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -3378,6 +3509,8 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -3464,63 +3597,77 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -3588,18 +3735,23 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -3646,24 +3798,24 @@ set_source_files_properties( "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -3673,9 +3825,9 @@ set_source_files_properties( "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" @@ -3710,11 +3862,11 @@ set_source_files_properties( PROPERTIES HEADER_FILE_ONLY TRUE) if( JUCE_BUILD_CONFIGURATION MATCHES "DEBUG" ) - target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) + target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) endif() if( JUCE_BUILD_CONFIGURATION MATCHES "RELEASE" ) - target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) + target_compile_options( ${BINARY_NAME} PRIVATE -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override "-fsigned-char" ) endif() find_library(log "log") diff --git a/extras/AudioPluginHost/Builds/Android/app/build.gradle b/extras/AudioPluginHost/Builds/Android/app/build.gradle index 314b1168e81c..a422c1cf156a 100644 --- a/extras/AudioPluginHost/Builds/Android/app/build.gradle +++ b/extras/AudioPluginHost/Builds/Android/app/build.gradle @@ -2,10 +2,12 @@ apply plugin: 'com.android.application' android { compileSdkVersion 33 - namespace "com.juce.pluginhost" + ndkVersion "25.2.9519653" + namespace "com.juce.audiopluginhost" externalNativeBuild { cmake { path "CMakeLists.txt" + version "3.22.1" } } signingConfigs { @@ -19,7 +21,7 @@ android { } defaultConfig { - applicationId "com.juce.pluginhost" + applicationId "com.juce.audiopluginhost" minSdkVersion 23 targetSdkVersion 33 externalNativeBuild { diff --git a/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml b/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml index ed0fcf1b0cd0..f99a0ecc2c28 100644 --- a/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/AudioPluginHost/Builds/Android/app/src/main/AndroidManifest.xml @@ -8,18 +8,19 @@ - - + + - + + diff --git a/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DSPDemos_Common.h b/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DSPDemos_Common.h index 9fa1d5c3a087..26d0e3b966d2 100644 --- a/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DSPDemos_Common.h +++ b/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DSPDemos_Common.h @@ -596,13 +596,17 @@ class AudioFileReaderComponent : public Component, const auto u = fc.getURLResult(); if (! audioFileReader.loadURL (u)) - NativeMessageBox::showAsync (MessageBoxOptions() - .withIconType (MessageBoxIconType::WarningIcon) - .withTitle ("Error loading file") - .withMessage ("Unable to load audio file"), - nullptr); + { + auto options = MessageBoxOptions().withIconType (MessageBoxIconType::WarningIcon) + .withTitle ("Error loading file") + .withMessage ("Unable to load audio file") + .withButton ("OK"); + messageBox = NativeMessageBox::showScopedAsync (options, nullptr); + } else + { thumbnailComp.setCurrentURL (u); + } } fileChooser = nullptr; @@ -629,6 +633,7 @@ class AudioFileReaderComponent : public Component, AudioFileReaderComponent& audioFileReader; std::unique_ptr fileChooser; + ScopedMessageBox messageBox; }; //============================================================================== diff --git a/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DemoUtilities.h b/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DemoUtilities.h index ffdfc3631c93..b2d38fffb610 100644 --- a/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DemoUtilities.h +++ b/extras/AudioPluginHost/Builds/Android/app/src/main/assets/DemoUtilities.h @@ -244,10 +244,8 @@ struct SlowerBouncingNumber : public BouncingNumber inline std::unique_ptr makeInputSource (const URL& url) { - #if JUCE_ANDROID - if (auto doc = AndroidDocument::fromDocument (url)) + if (const auto doc = AndroidDocument::fromDocument (url)) return std::make_unique (doc); - #endif #if ! JUCE_IOS if (url.isLocalFile()) @@ -257,4 +255,17 @@ inline std::unique_ptr makeInputSource (const URL& url) return std::make_unique (url); } +inline std::unique_ptr makeOutputStream (const URL& url) +{ + if (const auto doc = AndroidDocument::fromDocument (url)) + return doc.createOutputStream(); + + #if ! JUCE_IOS + if (url.isLocalFile()) + return url.getLocalFile().createOutputStream(); + #endif + + return url.createOutputStream(); +} + #endif // PIP_DEMO_UTILITIES_INCLUDED diff --git a/extras/AudioPluginHost/Builds/LinuxMakefile/Makefile b/extras/AudioPluginHost/Builds/LinuxMakefile/Makefile index 6439db8f7210..bff8aa65673d 100644 --- a/extras/AudioPluginHost/Builds/LinuxMakefile/Makefile +++ b/extras/AudioPluginHost/Builds/LinuxMakefile/Makefile @@ -39,13 +39,13 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_WASAPI=1" "-DJUCE_DIRECTSOUND=1" "-DJUCE_ALSA=1" "-DJUCE_USE_FLAC=0" "-DJUCE_USE_OGGVORBIS=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_AU=1" "-DJUCE_PLUGINHOST_LADSPA=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_USE_CDREADER=0" "-DJUCE_USE_CDBURNER=0" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_WASAPI=1" "-DJUCE_DIRECTSOUND=1" "-DJUCE_ALSA=1" "-DJUCE_USE_FLAC=0" "-DJUCE_USE_OGGVORBIS=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_AU=1" "-DJUCE_PLUGINHOST_LADSPA=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_USE_CDREADER=0" "-DJUCE_USE_CDBURNER=0" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := AudioPluginHost JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -60,13 +60,13 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_WASAPI=1" "-DJUCE_DIRECTSOUND=1" "-DJUCE_ALSA=1" "-DJUCE_USE_FLAC=0" "-DJUCE_USE_OGGVORBIS=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_AU=1" "-DJUCE_PLUGINHOST_LADSPA=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_USE_CDREADER=0" "-DJUCE_USE_CDBURNER=0" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_WASAPI=1" "-DJUCE_DIRECTSOUND=1" "-DJUCE_ALSA=1" "-DJUCE_USE_FLAC=0" "-DJUCE_USE_OGGVORBIS=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_AU=1" "-DJUCE_PLUGINHOST_LADSPA=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_USE_CDREADER=0" "-DJUCE_USE_CDBURNER=0" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := AudioPluginHost JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -Os $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -101,135 +101,140 @@ OBJECTS_APP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } - @$(PKG_CONFIG) --print-errors alsa freetype2 libcurl + @$(PKG_CONFIG) --print-errors alsa freetype2 gl libcurl @echo Linking "AudioPluginHost - App" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/ARAPlugin_e9864935.o: ../../Source/Plugins/ARAPlugin.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling ARAPlugin.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/InternalPlugins_8278e3f5.o: ../../Source/Plugins/InternalPlugins.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling InternalPlugins.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/IOConfigurationWindow_d71a5732.o: ../../Source/Plugins/IOConfigurationWindow.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling IOConfigurationWindow.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/PluginGraph_6bd15e2d.o: ../../Source/Plugins/PluginGraph.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling PluginGraph.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/GraphEditorPanel_2223d925.o: ../../Source/UI/GraphEditorPanel.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling GraphEditorPanel.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/MainHostWindow_b3494acd.o: ../../Source/UI/MainHostWindow.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling MainHostWindow.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/HostStartup_5ce96f96.o: ../../Source/HostStartup.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling HostStartup.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/BinaryData_ce4232d4.o: ../../JuceLibraryCode/BinaryData.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling BinaryData.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_devices_63111d02.o: ../../JuceLibraryCode/include_juce_audio_devices.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_devices.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_formats.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_10c03666.o: ../../JuceLibraryCode/include_juce_audio_processors.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_ara_2a4c6ef7.o: ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_ara.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_12bdca08.o: ../../JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_lv2_libs.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_utils_9f9fb2d6.o: ../../JuceLibraryCode/include_juce_audio_utils.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_utils.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o: ../../JuceLibraryCode/include_juce_cryptography.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_cryptography.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_dsp_aeb2060f.o: ../../JuceLibraryCode/include_juce_dsp.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_dsp.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_opengl_a8a032b.o: ../../JuceLibraryCode/include_juce_opengl.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_opengl.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning AudioPluginHost $(V_AT)$(CLEANCMD) diff --git a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj index 0fb33e31d613..ce9796dd2fe0 100644 --- a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj +++ b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ B288A89F96704F142ED8E939 /* AudioUnit.framework */ = {isa = PBXBuildFile; fileRef = 5ACC21AA45BBF48C3C64D56D; }; BBA1733CF8B064A5FD0B4CF4 /* OpenGL.framework */ = {isa = PBXBuildFile; fileRef = D313CF37B25D7FD313C4F336; }; C38D14DC58F1941DD5E4BF60 /* include_juce_gui_extra.mm */ = {isa = PBXBuildFile; fileRef = 2BE6C2DFD6EBB9A89109AEB5; }; + C4AD86AA4B49877C7E02A4C0 /* Security.framework */ = {isa = PBXBuildFile; fileRef = C1981AC950A91C9050CE8358; }; CAC10E4345428CAEE6F0DA1B /* include_juce_audio_processors_ara.cpp */ = {isa = PBXBuildFile; fileRef = A43CE79CB190C2D69E17E1E3; }; CAF0DE157C8F7D9F168AA3B6 /* include_juce_audio_processors.mm */ = {isa = PBXBuildFile; fileRef = 5FBD6C402617272052BB4D81; }; D92C7BF86C9CCF6B4D14F809 /* RecentFilesMenuTemplate.nib */ = {isa = PBXBuildFile; fileRef = 7DA35787B5F6F7440D667CC8; }; @@ -113,6 +114,7 @@ B8774D8AD307D798831C0DF7 /* DiscRecording.framework */ /* DiscRecording.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiscRecording.framework; path = System/Library/Frameworks/DiscRecording.framework; sourceTree = SDKROOT; }; B8E24A5CEE6B7055537725CF /* include_juce_cryptography.mm */ /* include_juce_cryptography.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_cryptography.mm; path = ../../JuceLibraryCode/include_juce_cryptography.mm; sourceTree = SOURCE_ROOT; }; B95B9D6774059DBB19F2B4E2 /* InternalPlugins.h */ /* InternalPlugins.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InternalPlugins.h; path = ../../Source/Plugins/InternalPlugins.h; sourceTree = SOURCE_ROOT; }; + C1981AC950A91C9050CE8358 /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; C37B2E77AAB6C9E13729BF99 /* IOConfigurationWindow.cpp */ /* IOConfigurationWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IOConfigurationWindow.cpp; path = ../../Source/Plugins/IOConfigurationWindow.cpp; sourceTree = SOURCE_ROOT; }; CA726B9AA0EC87B58D005C8D /* ARAPlugin.h */ /* ARAPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ARAPlugin.h; path = ../../Source/Plugins/ARAPlugin.h; sourceTree = SOURCE_ROOT; }; D313CF37B25D7FD313C4F336 /* OpenGL.framework */ /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; @@ -142,6 +144,7 @@ 68FBFDA1FE637B3EDA09A592, BBA1733CF8B064A5FD0B4CF4, A02C9F4C4B840C27B6CAFEBD, + C4AD86AA4B49877C7E02A4C0, 4DB15177DDC357F4503F88CF, ); runOnlyForDeploymentPostprocessing = 0; @@ -283,6 +286,7 @@ 4DF6E6E41E10965AD169143B, D313CF37B25D7FD313C4F336, 89309C0C5F3269BD06BE7F27, + C1981AC950A91C9050CE8358, B457EE687507BF1DEEA7581F, ); name = Frameworks; @@ -442,7 +446,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -504,10 +508,10 @@ LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; - PRODUCT_BUNDLE_IDENTIFIER = com.juce.pluginhost; + PRODUCT_BUNDLE_IDENTIFIER = com.juce.audiopluginhost; PRODUCT_NAME = "AudioPluginHost"; USE_HEADERMAP = NO; VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; @@ -580,7 +584,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -641,10 +645,10 @@ INSTALL_PATH = "$(HOME)/Applications"; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; - PRODUCT_BUNDLE_IDENTIFIER = com.juce.pluginhost; + PRODUCT_BUNDLE_IDENTIFIER = com.juce.audiopluginhost; PRODUCT_NAME = "AudioPluginHost"; USE_HEADERMAP = NO; VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGL; diff --git a/extras/AudioPluginHost/Builds/MacOSX/Info-App.plist b/extras/AudioPluginHost/Builds/MacOSX/Info-App.plist index 95f25f210f42..db47747e6696 100644 --- a/extras/AudioPluginHost/Builds/MacOSX/Info-App.plist +++ b/extras/AudioPluginHost/Builds/MacOSX/Info-App.plist @@ -12,7 +12,7 @@ CFBundleIconFile Icon.icns CFBundleIdentifier - com.juce.pluginhost + com.juce.audiopluginhost CFBundleName AudioPluginHost CFBundleDisplayName diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj index dd2de8a96733..1afbe9a04690 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -462,46 +462,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -846,18 +846,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -957,6 +981,9 @@ true + + true + true @@ -987,7 +1014,7 @@ true - + true @@ -1026,22 +1053,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1137,6 +1164,9 @@ true + + true + true @@ -1149,6 +1179,9 @@ true + + true + true @@ -1158,67 +1191,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1470,13 +1509,13 @@ true - + true - + true - + true @@ -1545,6 +1584,9 @@ true + + true + true @@ -1569,19 +1611,19 @@ true - + true - + true - + true - + true - + true @@ -1860,40 +1902,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1965,6 +2007,9 @@ true + + true + true @@ -2037,6 +2082,9 @@ true + + true + true @@ -2160,52 +2208,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2307,9 +2382,18 @@ true + + true + + + true + true + + true + true @@ -2319,7 +2403,7 @@ true - + true @@ -2376,43 +2460,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2521,8 +2605,8 @@ - - + + @@ -2617,8 +2701,8 @@ - - + + @@ -2795,6 +2879,7 @@ + @@ -2814,6 +2899,7 @@ + @@ -2850,8 +2936,18 @@ + + + + + + + + + + @@ -2892,6 +2988,7 @@ + @@ -2904,8 +3001,8 @@ + - @@ -2939,6 +3036,7 @@ + @@ -2981,20 +3079,22 @@ + - - - - - - - - + + + + + + + + + @@ -3102,10 +3202,10 @@ - - - - + + + + @@ -3139,6 +3239,7 @@ + @@ -3152,12 +3253,13 @@ - - - + + + + + - - + @@ -3214,10 +3316,10 @@ - - + + + - @@ -3253,6 +3355,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3283,6 +3405,7 @@ + @@ -3328,36 +3451,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3395,10 +3519,12 @@ + - + + @@ -3426,7 +3552,7 @@ - + @@ -3434,9 +3560,9 @@ - - - + + + @@ -3474,6 +3600,7 @@ + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters index 644f19ed72ed..21606bf9ae1c 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -961,49 +979,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1354,18 +1372,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1468,6 +1513,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1498,7 +1546,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1540,34 +1588,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1666,6 +1714,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1678,6 +1729,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1687,82 +1741,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2023,13 +2083,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2101,6 +2161,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2125,25 +2188,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2425,46 +2488,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2539,6 +2602,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2611,6 +2677,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2734,85 +2803,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2914,9 +3022,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2926,7 +3043,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2986,55 +3103,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3267,10 +3384,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3555,10 +3672,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4089,6 +4206,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4146,6 +4266,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4254,12 +4377,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4380,6 +4533,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4416,10 +4572,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4521,6 +4677,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4647,6 +4806,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4662,31 +4824,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5010,16 +5175,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5121,6 +5286,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5160,22 +5328,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5346,16 +5517,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5463,6 +5634,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5553,6 +5784,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5688,9 +5922,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5700,82 +5931,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5889,6 +6126,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5898,7 +6138,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5982,7 +6225,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6006,13 +6249,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6122,6 +6365,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj index 6e7a859c5778..94bba88acb02 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -462,46 +462,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -846,18 +846,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -957,6 +981,9 @@ true + + true + true @@ -987,7 +1014,7 @@ true - + true @@ -1026,22 +1053,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1137,6 +1164,9 @@ true + + true + true @@ -1149,6 +1179,9 @@ true + + true + true @@ -1158,67 +1191,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1470,13 +1509,13 @@ true - + true - + true - + true @@ -1545,6 +1584,9 @@ true + + true + true @@ -1569,19 +1611,19 @@ true - + true - + true - + true - + true - + true @@ -1860,40 +1902,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1965,6 +2007,9 @@ true + + true + true @@ -2037,6 +2082,9 @@ true + + true + true @@ -2160,52 +2208,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2307,9 +2382,18 @@ true + + true + + + true + true + + true + true @@ -2319,7 +2403,7 @@ true - + true @@ -2376,43 +2460,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2521,8 +2605,8 @@ - - + + @@ -2617,8 +2701,8 @@ - - + + @@ -2795,6 +2879,7 @@ + @@ -2814,6 +2899,7 @@ + @@ -2850,8 +2936,18 @@ + + + + + + + + + + @@ -2892,6 +2988,7 @@ + @@ -2904,8 +3001,8 @@ + - @@ -2939,6 +3036,7 @@ + @@ -2981,20 +3079,22 @@ + - - - - - - - - + + + + + + + + + @@ -3102,10 +3202,10 @@ - - - - + + + + @@ -3139,6 +3239,7 @@ + @@ -3152,12 +3253,13 @@ - - - + + + + + - - + @@ -3214,10 +3316,10 @@ - - + + + - @@ -3253,6 +3355,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3283,6 +3405,7 @@ + @@ -3328,36 +3451,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3395,10 +3519,12 @@ + - + + @@ -3426,7 +3552,7 @@ - + @@ -3434,9 +3560,9 @@ - - - + + + @@ -3474,6 +3600,7 @@ + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters index 4cc5b50e3a77..b377ad122bc4 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -961,49 +979,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1354,18 +1372,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1468,6 +1513,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1498,7 +1546,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1540,34 +1588,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1666,6 +1714,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1678,6 +1729,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1687,82 +1741,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2023,13 +2083,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2101,6 +2161,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2125,25 +2188,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2425,46 +2488,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2539,6 +2602,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2611,6 +2677,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2734,85 +2803,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2914,9 +3022,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2926,7 +3043,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2986,55 +3103,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3267,10 +3384,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3555,10 +3672,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4089,6 +4206,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4146,6 +4266,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4254,12 +4377,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4380,6 +4533,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4416,10 +4572,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4521,6 +4677,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4647,6 +4806,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4662,31 +4824,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5010,16 +5175,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5121,6 +5286,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5160,22 +5328,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5346,16 +5517,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5463,6 +5634,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5553,6 +5784,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5688,9 +5922,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5700,82 +5931,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5889,6 +6126,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5898,7 +6138,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5982,7 +6225,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6006,13 +6249,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6122,6 +6365,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj index 75283ced3375..fc98f6eb036b 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -79,7 +79,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -107,7 +107,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -122,7 +122,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_WASAPI=1;JUCE_DIRECTSOUND=1;JUCE_ALSA=1;JUCE_USE_FLAC=0;JUCE_USE_OGGVORBIS=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_AU=1;JUCE_PLUGINHOST_LADSPA=1;JUCE_PLUGINHOST_LV2=1;JUCE_USE_CDREADER=0;JUCE_USE_CDBURNER=0;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\AudioPluginHost.exe @@ -462,46 +462,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -846,18 +846,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -957,6 +981,9 @@ true + + true + true @@ -987,7 +1014,7 @@ true - + true @@ -1026,22 +1053,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1137,6 +1164,9 @@ true + + true + true @@ -1149,6 +1179,9 @@ true + + true + true @@ -1158,67 +1191,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1470,13 +1509,13 @@ true - + true - + true - + true @@ -1545,6 +1584,9 @@ true + + true + true @@ -1569,19 +1611,19 @@ true - + true - + true - + true - + true - + true @@ -1860,40 +1902,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1965,6 +2007,9 @@ true + + true + true @@ -2037,6 +2082,9 @@ true + + true + true @@ -2160,52 +2208,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2307,9 +2382,18 @@ true + + true + + + true + true + + true + true @@ -2319,7 +2403,7 @@ true - + true @@ -2376,43 +2460,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2521,8 +2605,8 @@ - - + + @@ -2617,8 +2701,8 @@ - - + + @@ -2795,6 +2879,7 @@ + @@ -2814,6 +2899,7 @@ + @@ -2850,8 +2936,18 @@ + + + + + + + + + + @@ -2892,6 +2988,7 @@ + @@ -2904,8 +3001,8 @@ + - @@ -2939,6 +3036,7 @@ + @@ -2981,20 +3079,22 @@ + - - - - - - - - + + + + + + + + + @@ -3102,10 +3202,10 @@ - - - - + + + + @@ -3139,6 +3239,7 @@ + @@ -3152,12 +3253,13 @@ - - - + + + + + - - + @@ -3214,10 +3316,10 @@ - - + + + - @@ -3253,6 +3355,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3283,6 +3405,7 @@ + @@ -3328,36 +3451,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3395,10 +3519,12 @@ + - + + @@ -3426,7 +3552,7 @@ - + @@ -3434,9 +3560,9 @@ - - - + + + @@ -3474,6 +3600,7 @@ + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters index 1e37071622a4..1291e712dc94 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -961,49 +979,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1354,18 +1372,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1468,6 +1513,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1498,7 +1546,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1540,34 +1588,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1666,6 +1714,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1678,6 +1729,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1687,82 +1741,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2023,13 +2083,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2101,6 +2161,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2125,25 +2188,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2425,46 +2488,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2539,6 +2602,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2611,6 +2677,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2734,85 +2803,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2914,9 +3022,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2926,7 +3043,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2986,55 +3103,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3267,10 +3384,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3555,10 +3672,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4089,6 +4206,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4146,6 +4266,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4254,12 +4377,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4380,6 +4533,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4416,10 +4572,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4521,6 +4677,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4647,6 +4806,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4662,31 +4824,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5010,16 +5175,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5121,6 +5286,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5160,22 +5328,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5346,16 +5517,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5463,6 +5634,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5553,6 +5784,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5688,9 +5922,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5700,82 +5931,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5889,6 +6126,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5898,7 +6138,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5982,7 +6225,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6006,13 +6249,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6122,6 +6365,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/AudioPluginHost/Builds/iOS/App.entitlements b/extras/AudioPluginHost/Builds/iOS/App.entitlements new file mode 100644 index 000000000000..ee8c4fb8d846 --- /dev/null +++ b/extras/AudioPluginHost/Builds/iOS/App.entitlements @@ -0,0 +1,8 @@ + + + + + inter-app-audio + + + diff --git a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj index 4825c292641c..785f95ad82ec 100644 --- a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj +++ b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj @@ -103,6 +103,7 @@ 94CB96C8E4B51F52776C2638 /* juce_graphics */ /* juce_graphics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_graphics; path = ../../../../modules/juce_graphics; sourceTree = SOURCE_ROOT; }; 97918AB43AD460AFA8FA2FFE /* PluginWindow.h */ /* PluginWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginWindow.h; path = ../../Source/UI/PluginWindow.h; sourceTree = SOURCE_ROOT; }; 97E63C295843A1E665E70473 /* cello.wav */ /* cello.wav */ = {isa = PBXFileReference; lastKnownFileType = file.wav; name = cello.wav; path = ../../../../examples/Assets/cello.wav; sourceTree = SOURCE_ROOT; }; + 9A92E8C5ECBBF926B5CF57BC /* App.entitlements */ /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = App.entitlements; path = App.entitlements; sourceTree = SOURCE_ROOT; }; 9F9B445E6755CAA19E4344ED /* CoreAudio.framework */ /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; A43CE79CB190C2D69E17E1E3 /* include_juce_audio_processors_ara.cpp */ /* include_juce_audio_processors_ara.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = include_juce_audio_processors_ara.cpp; path = ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp; sourceTree = SOURCE_ROOT; }; A5DFC13E4F09134B0D226A3E /* MainHostWindow.h */ /* MainHostWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MainHostWindow.h; path = ../../Source/UI/MainHostWindow.h; sourceTree = SOURCE_ROOT; }; @@ -360,7 +361,7 @@ enabled = 0; }; com.apple.InterAppAudio = { - enabled = 0; + enabled = 1; }; com.apple.Push = { enabled = 0; @@ -444,6 +445,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_ENTITLEMENTS = "App.entitlements"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; DEAD_CODE_STRIPPING = YES; @@ -455,7 +457,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -516,10 +518,10 @@ INSTALL_PATH = "$(HOME)/Applications"; LLVM_LTO = YES; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications"; - PRODUCT_BUNDLE_IDENTIFIER = com.juce.pluginhost; + PRODUCT_BUNDLE_IDENTIFIER = com.juce.audiopluginhost; PRODUCT_NAME = "Plugin Host"; USE_HEADERMAP = NO; VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGLES; @@ -583,6 +585,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_LINK_OBJC_RUNTIME = NO; + CODE_SIGN_ENTITLEMENTS = "App.entitlements"; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; COPY_PHASE_STRIP = NO; @@ -594,7 +597,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -654,10 +657,10 @@ INFOPLIST_PREPROCESS = NO; INSTALL_PATH = "$(HOME)/Applications"; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications"; - PRODUCT_BUNDLE_IDENTIFIER = com.juce.pluginhost; + PRODUCT_BUNDLE_IDENTIFIER = com.juce.audiopluginhost; PRODUCT_NAME = "Plugin Host"; USE_HEADERMAP = NO; VALIDATE_WORKSPACE_SKIPPED_SDK_FRAMEWORKS = OpenGLES; diff --git a/extras/AudioPluginHost/Builds/iOS/Info-App.plist b/extras/AudioPluginHost/Builds/iOS/Info-App.plist index bfff983749a3..9be3f854359c 100644 --- a/extras/AudioPluginHost/Builds/iOS/Info-App.plist +++ b/extras/AudioPluginHost/Builds/iOS/Info-App.plist @@ -14,7 +14,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.juce.pluginhost + com.juce.audiopluginhost CFBundleName AudioPluginHost CFBundleDisplayName diff --git a/extras/AudioPluginHost/CMakeLists.txt b/extras/AudioPluginHost/CMakeLists.txt index cd7f495e8e74..b38dfd9dbf6e 100644 --- a/extras/AudioPluginHost/CMakeLists.txt +++ b/extras/AudioPluginHost/CMakeLists.txt @@ -48,6 +48,7 @@ juce_add_binary_data(AudioPluginHostData SOURCES target_compile_definitions(AudioPluginHost PRIVATE JUCE_ALSA=1 + JUCE_CONTENT_SHARING=1 JUCE_DIRECTSOUND=1 JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING=1 JUCE_PLUGINHOST_LADSPA=1 diff --git a/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp b/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp index f7b99e25601c..e5b85fa57b47 100644 --- a/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp +++ b/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp @@ -267,7 +267,7 @@ class IOConfigurationWindow::InputOutputConfig : public Component, auto itemId = 1; auto selectedId = -1; - for (auto i = 1; i < AudioChannelSet::maxChannelsOfNamedLayout; ++i) + for (auto i = 1; i <= AudioChannelSet::maxChannelsOfNamedLayout; ++i) { for (const auto& set : AudioChannelSet::channelSetsWithNumberOfChannels (i)) { diff --git a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp index 6edfc6510ac6..61f065f33c27 100644 --- a/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp +++ b/extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp @@ -262,8 +262,8 @@ class SineWaveSynth : public AudioProcessor // start a tail-off by setting this flag. The render callback will pick up on // this and do a fade out, calling clearCurrentNote() when it's finished. - if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the - // stopNote method could be called more than once. + if (approximatelyEqual (tailOff, 0.0)) // we only need to begin a tail-off if it's not already doing so - the + // stopNote method could be called more than once. tailOff = 1.0; } else @@ -287,7 +287,7 @@ class SineWaveSynth : public AudioProcessor void renderNextBlock (AudioBuffer& outputBuffer, int startSample, int numSamples) override { - if (angleDelta != 0.0) + if (! approximatelyEqual (angleDelta, 0.0)) { if (tailOff > 0) { diff --git a/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp b/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp index 0701dd82c1d7..95f441ef9da2 100644 --- a/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp +++ b/extras/AudioPluginHost/Source/Plugins/PluginGraph.cpp @@ -100,9 +100,10 @@ void PluginGraph::addPluginCallback (std::unique_ptr instan { if (instance == nullptr) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Couldn't create plugin"), - error); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Couldn't create plugin"), + error); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } else { diff --git a/extras/AudioPluginHost/Source/Plugins/PluginGraph.h b/extras/AudioPluginHost/Source/Plugins/PluginGraph.h index 7bc12f23aec7..86ca82f5b1c8 100644 --- a/extras/AudioPluginHost/Source/Plugins/PluginGraph.h +++ b/extras/AudioPluginHost/Source/Plugins/PluginGraph.h @@ -110,6 +110,7 @@ class PluginGraph : public FileBasedDocument, AudioPluginFormatManager& formatManager; KnownPluginList& knownPlugins; OwnedArray activePluginWindows; + ScopedMessageBox messageBox; NodeID lastUID; NodeID getNextUID() noexcept; diff --git a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp index 195f47ae6c65..483b4f5ddc2c 100644 --- a/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp +++ b/extras/AudioPluginHost/Source/UI/GraphEditorPanel.cpp @@ -33,8 +33,8 @@ class AUScanner { public: - AUScanner (KnownPluginList& list) - : knownPluginList (list), pool (5) + explicit AUScanner (KnownPluginList& list) + : knownPluginList (list) { knownPluginList.clearBlacklistedFiles(); paths = formatToScan.getDefaultLocationsToSearch(); @@ -49,7 +49,8 @@ std::unique_ptr scanner; FileSearchPath paths; - ThreadPool pool; + static constexpr auto numJobs = 5; + ThreadPool pool { ThreadPoolOptions{}.withNumberOfThreads (numJobs) }; void startScan() { @@ -59,17 +60,14 @@ scanner.reset (new PluginDirectoryScanner (knownPluginList, formatToScan, paths, true, deadMansPedalFile, true)); - for (int i = 5; --i >= 0;) + for (int i = numJobs; --i >= 0;) pool.addJob (new ScanJob (*this), true); } bool doNextScan() { String pluginBeingScanned; - if (scanner->scanNextFile (true, pluginBeingScanned)) - return true; - - return false; + return scanner->scanNextFile (true, pluginBeingScanned); } struct ScanJob : public ThreadPoolJob @@ -896,9 +894,9 @@ void GraphEditorPanel::showPopupMenu (Point mousePos) menu->showMenuAsync ({}, ModalCallbackFunction::create ([this, mousePos] (int r) { - if (r > 0) - if (auto* mainWin = findParentComponentOfClass()) - createNewPlugin (mainWin->getChosenType (r), mousePos); + if (auto* mainWin = findParentComponentOfClass()) + if (const auto chosen = mainWin->getChosenType (r)) + createNewPlugin (*chosen, mousePos); })); } } diff --git a/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp b/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp index b911a6e8bd4f..b0eebf562ba0 100644 --- a/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp +++ b/extras/AudioPluginHost/Source/UI/MainHostWindow.cpp @@ -602,9 +602,9 @@ void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/ } else { - if (getIndexChosenByMenu (menuItemID) >= 0) - createPlugin (getChosenType (menuItemID), { proportionOfWidth (0.3f + Random::getSystemRandom().nextFloat() * 0.6f), - proportionOfHeight (0.3f + Random::getSystemRandom().nextFloat() * 0.6f) }); + if (const auto chosen = getChosenType (menuItemID)) + createPlugin (*chosen, { proportionOfWidth (0.3f + Random::getSystemRandom().nextFloat() * 0.6f), + proportionOfHeight (0.3f + Random::getSystemRandom().nextFloat() * 0.6f) }); } } @@ -697,18 +697,19 @@ void MainHostWindow::addPluginsToMenu (PopupMenu& m) addToMenu (*tree, m, pluginDescriptions, pluginDescriptionsAndPreference); } -int MainHostWindow::getIndexChosenByMenu (int menuID) const +std::optional MainHostWindow::getChosenType (const int menuID) const { - const auto i = menuID - menuIDBase; - return isPositiveAndBelow (i, pluginDescriptionsAndPreference.size()) ? i : -1; -} + const auto internalIndex = menuID - 1; -PluginDescriptionAndPreference MainHostWindow::getChosenType (const int menuID) const -{ - if (menuID >= 1 && menuID < (int) (1 + internalTypes.size())) - return PluginDescriptionAndPreference { internalTypes[(size_t) (menuID - 1)] }; + if (isPositiveAndBelow (internalIndex, internalTypes.size())) + return PluginDescriptionAndPreference { internalTypes[(size_t) internalIndex] }; + + const auto externalIndex = menuID - menuIDBase; + + if (isPositiveAndBelow (externalIndex, pluginDescriptionsAndPreference.size())) + return pluginDescriptionsAndPreference[externalIndex]; - return pluginDescriptionsAndPreference[getIndexChosenByMenu (menuID)]; + return {}; } //============================================================================== diff --git a/extras/AudioPluginHost/Source/UI/MainHostWindow.h b/extras/AudioPluginHost/Source/UI/MainHostWindow.h index 16e159879725..0a7319408417 100644 --- a/extras/AudioPluginHost/Source/UI/MainHostWindow.h +++ b/extras/AudioPluginHost/Source/UI/MainHostWindow.h @@ -110,7 +110,7 @@ class MainHostWindow : public DocumentWindow, void createPlugin (const PluginDescriptionAndPreference&, Point pos); void addPluginsToMenu (PopupMenu&); - PluginDescriptionAndPreference getChosenType (int menuID) const; + std::optional getChosenType (int menuID) const; std::unique_ptr graphHolder; @@ -124,8 +124,6 @@ class MainHostWindow : public DocumentWindow, void showAudioSettings(); - int getIndexChosenByMenu (int menuID) const; - //============================================================================== AudioDeviceManager deviceManager; AudioPluginFormatManager formatManager; diff --git a/extras/AudioPluginHost/Source/UI/PluginWindow.h b/extras/AudioPluginHost/Source/UI/PluginWindow.h index 40160cd4c07b..212d28ba89c5 100644 --- a/extras/AudioPluginHost/Source/UI/PluginWindow.h +++ b/extras/AudioPluginHost/Source/UI/PluginWindow.h @@ -175,6 +175,8 @@ class PluginWindow : public DocumentWindow setResizable (ui->isResizable(), false); } + setConstrainer (&constrainer); + #if JUCE_IOS || JUCE_ANDROID const auto screenBounds = Desktop::getInstance().getDisplays().getTotalBounds (true).toFloat(); const auto scaleFactor = jmin ((screenBounds.getWidth() - 50.0f) / (float) getWidth(), @@ -233,6 +235,38 @@ class PluginWindow : public DocumentWindow } private: + class DecoratorConstrainer : public BorderedComponentBoundsConstrainer + { + public: + explicit DecoratorConstrainer (DocumentWindow& windowIn) + : window (windowIn) {} + + ComponentBoundsConstrainer* getWrappedConstrainer() const override + { + auto* editor = dynamic_cast (window.getContentComponent()); + return editor != nullptr ? editor->getConstrainer() : nullptr; + } + + BorderSize getAdditionalBorder() const override + { + const auto nativeFrame = [&]() -> BorderSize + { + if (auto* peer = window.getPeer()) + if (const auto frameSize = peer->getFrameSizeIfPresent()) + return *frameSize; + + return {}; + }(); + + return nativeFrame.addedTo (window.getContentComponentBorder()); + } + + private: + DocumentWindow& window; + }; + + DecoratorConstrainer constrainer { *this }; + float getDesktopScaleFactor() const override { return 1.0f; } static AudioProcessorEditor* createProcessorEditor (AudioProcessor& processor, @@ -257,10 +291,21 @@ class PluginWindow : public DocumentWindow return {}; } - if (type == PluginWindow::Type::generic) return new GenericAudioProcessorEditor (processor); - if (type == PluginWindow::Type::programs) return new ProgramAudioProcessorEditor (processor); - if (type == PluginWindow::Type::audioIO) return new IOConfigurationWindow (processor); - if (type == PluginWindow::Type::debug) return new PluginDebugWindow (processor); + if (type == PluginWindow::Type::generic) + { + auto* result = new GenericAudioProcessorEditor (processor); + result->setResizeLimits (200, 300, 1'000, 10'000); + return result; + } + + if (type == PluginWindow::Type::programs) + return new ProgramAudioProcessorEditor (processor); + + if (type == PluginWindow::Type::audioIO) + return new IOConfigurationWindow (processor); + + if (type == PluginWindow::Type::debug) + return new PluginDebugWindow (processor); jassertfalse; return {}; diff --git a/extras/BinaryBuilder/Builds/LinuxMakefile/Makefile b/extras/BinaryBuilder/Builds/LinuxMakefile/Makefile index cdb676f3b1e2..64426375f87c 100644 --- a/extras/BinaryBuilder/Builds/LinuxMakefile/Makefile +++ b/extras/BinaryBuilder/Builds/LinuxMakefile/Makefile @@ -39,7 +39,7 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_CONSOLEAPP := BinaryBuilder @@ -60,7 +60,7 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_CONSOLEAPP := BinaryBuilder @@ -79,25 +79,30 @@ OBJECTS_CONSOLEAPP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) : $(OBJECTS_CONSOLEAPP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) : $(OBJECTS_CONSOLEAPP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } @$(PKG_CONFIG) --print-errors libcurl @echo Linking "BinaryBuilder - ConsoleApp" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) $(OBJECTS_CONSOLEAPP) $(JUCE_LDFLAGS) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) $(OBJECTS_CONSOLEAPP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning BinaryBuilder $(V_AT)$(CLEANCMD) diff --git a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj b/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj index 032956a7a890..5caf40f4a6ff 100644 --- a/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj +++ b/extras/BinaryBuilder/Builds/MacOSX/BinaryBuilder.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 3C6FF7689E2FD827A48E2303 /* Main.cpp */ = {isa = PBXBuildFile; fileRef = 50B7C64414A3E778021F5EC4; }; 4B72EFB0E9D74CA7227F6CAB /* Cocoa.framework */ = {isa = PBXBuildFile; fileRef = 57DDB771ED96A256F190ADF8; }; 542006E949BB022F198DF0F2 /* RecentFilesMenuTemplate.nib */ = {isa = PBXBuildFile; fileRef = 1A71A586C0F50B6B328D877B; }; + 76329EF5627C14DD1C621F6E /* Security.framework */ = {isa = PBXBuildFile; fileRef = F9E4EBBA2682611A3978340C; }; 9E4D85A3D54739A0FA80A446 /* include_juce_core.mm */ = {isa = PBXBuildFile; fileRef = D186E2D509765FAE0758F17D; }; C17566E1AACD033B3DD74E9F /* Foundation.framework */ = {isa = PBXBuildFile; fileRef = 6AA23C81496E022290EB2A0C; }; /* End PBXBuildFile section */ @@ -26,6 +27,7 @@ D186E2D509765FAE0758F17D /* include_juce_core.mm */ /* include_juce_core.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_core.mm; path = ../../JuceLibraryCode/include_juce_core.mm; sourceTree = SOURCE_ROOT; }; D6C3594C8BEC94040AF108FE /* JuceHeader.h */ /* JuceHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = SOURCE_ROOT; }; F769CD634476C91F4C9D0596 /* IOKit.framework */ /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + F9E4EBBA2682611A3978340C /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,6 +38,7 @@ 4B72EFB0E9D74CA7227F6CAB, C17566E1AACD033B3DD74E9F, 0D53D8B0AEE37C02C147344B, + 76329EF5627C14DD1C621F6E, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,6 +113,7 @@ 57DDB771ED96A256F190ADF8, 6AA23C81496E022290EB2A0C, F769CD634476C91F4C9D0596, + F9E4EBBA2682611A3978340C, ); name = Frameworks; sourceTree = ""; @@ -200,7 +204,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_core=1", "JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1", "JUCE_STANDALONE_APPLICATION=1", @@ -296,7 +300,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_core=1", "JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1", "JUCE_STANDALONE_APPLICATION=1", diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj index c8eed5032329..a4de621e3718 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj +++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -78,7 +78,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\BinaryBuilder.exe @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -120,7 +120,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\BinaryBuilder.exe @@ -226,6 +226,9 @@ true + + true + true @@ -238,6 +241,9 @@ true + + true + true @@ -247,67 +253,73 @@ true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -486,6 +498,7 @@ + @@ -528,20 +541,22 @@ + - - - - - - - - + + + + + + + + + diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters index b821c96bfee0..6967555eab71 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters +++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters @@ -163,6 +163,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -175,6 +178,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -184,82 +190,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -477,6 +489,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -603,6 +618,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -618,31 +636,34 @@ JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native diff --git a/extras/Build/CMake/JUCEHelperTargets.cmake b/extras/Build/CMake/JUCEHelperTargets.cmake index a377864039d3..6aec8eddaef9 100644 --- a/extras/Build/CMake/JUCEHelperTargets.cmake +++ b/extras/Build/CMake/JUCEHelperTargets.cmake @@ -24,32 +24,82 @@ add_library(juce_recommended_warning_flags INTERFACE) add_library(juce::juce_recommended_warning_flags ALIAS juce_recommended_warning_flags) +function(_juce_get_debug_config_genex result) + get_property(debug_configs GLOBAL PROPERTY DEBUG_CONFIGURATIONS) + if(NOT debug_configs) + set(debug_configs Debug) + endif() + list(TRANSFORM debug_configs REPLACE [[^.+$]] [[$]]) + list(JOIN debug_configs "," debug_configs) + # $ doesn't accept multiple configurations until CMake 3.19 + set(${result} "$" PARENT_SCOPE) +endfunction() + +# ================================================================================================== + if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) target_compile_options(juce_recommended_warning_flags INTERFACE "/W4") elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")) target_compile_options(juce_recommended_warning_flags INTERFACE - -Wall -Wshadow-all -Wshorten-64-to-32 -Wstrict-aliasing - -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare - -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion - -Wsign-conversion -Wbool-conversion -Wextra-semi -Wunreachable-code - -Wcast-align -Wshift-sign-overflow -Wmissing-prototypes - -Wnullable-to-nonnull-conversion -Wno-ignored-qualifiers -Wswitch-enum - -Wpedantic -Wdeprecated + -Wall + -Wshadow-all + -Wshorten-64-to-32 + -Wstrict-aliasing + -Wuninitialized + -Wunused-parameter + -Wconversion + -Wsign-compare + -Wint-conversion + -Wconditional-uninitialized + -Wconstant-conversion + -Wsign-conversion + -Wbool-conversion + -Wextra-semi + -Wunreachable-code + -Wcast-align + -Wshift-sign-overflow + -Wmissing-prototypes + -Wnullable-to-nonnull-conversion + -Wno-ignored-qualifiers + -Wswitch-enum + -Wpedantic + -Wdeprecated + -Wfloat-equal + -Wmissing-field-initializers $<$,$>: - -Wzero-as-null-pointer-constant -Wunused-private-field - -Woverloaded-virtual -Wreorder + -Wzero-as-null-pointer-constant + -Wunused-private-field + -Woverloaded-virtual + -Wreorder -Winconsistent-missing-destructor-override> $<$,$>: - -Wunguarded-availability -Wunguarded-availability-new>) + -Wunguarded-availability + -Wunguarded-availability-new>) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(juce_recommended_warning_flags INTERFACE - -Wall -Wextra -Wpedantic -Wstrict-aliasing -Wuninitialized - -Wunused-parameter -Wsign-compare -Wsign-conversion -Wunreachable-code - -Wcast-align -Wno-implicit-fallthrough -Wno-maybe-uninitialized - -Wno-ignored-qualifiers -Wswitch-enum - -Wredundant-decls -Wno-strict-overflow -Wshadow + -Wall + -Wextra + -Wpedantic + -Wstrict-aliasing + -Wuninitialized + -Wunused-parameter + -Wsign-compare + -Wsign-conversion + -Wunreachable-code + -Wcast-align + -Wno-implicit-fallthrough + -Wno-maybe-uninitialized + -Wno-ignored-qualifiers + -Wswitch-enum + -Wredundant-decls + -Wno-strict-overflow + -Wshadow + -Wfloat-equal + -Wmissing-field-initializers $<$: - -Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant>) + -Woverloaded-virtual + -Wreorder + -Wzero-as-null-pointer-constant>) endif() # ================================================================================================== @@ -58,13 +108,15 @@ add_library(juce_recommended_config_flags INTERFACE) add_library(juce::juce_recommended_config_flags ALIAS juce_recommended_config_flags) if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) + _juce_get_debug_config_genex(debug_config) target_compile_options(juce_recommended_config_flags INTERFACE - $,/Od /Zi,/Ox> $<$:/MP> /EHsc) + $ $<$:/MP> /EHsc) elseif((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) + _juce_get_debug_config_genex(debug_config) target_compile_options(juce_recommended_config_flags INTERFACE - $<$:-g -O0> + $<${debug_config}:-g -O0> $<$:-O3>) endif() diff --git a/extras/Build/CMake/JUCEModuleSupport.cmake b/extras/Build/CMake/JUCEModuleSupport.cmake index 25d53400d52d..f353be4e326b 100644 --- a/extras/Build/CMake/JUCEModuleSupport.cmake +++ b/extras/Build/CMake/JUCEModuleSupport.cmake @@ -33,7 +33,7 @@ # ================================================================================================== include_guard(GLOBAL) -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.22) # ================================================================================================== @@ -73,9 +73,10 @@ endfunction() # ================================================================================================== function(_juce_add_standard_defs juce_target) + _juce_get_debug_config_genex(debug_config) target_compile_definitions(${juce_target} INTERFACE JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 - $,DEBUG=1 _DEBUG=1,NDEBUG=1 _NDEBUG=1> + $ $<$:JUCE_ANDROID=1>) endfunction() @@ -155,24 +156,25 @@ function(_juce_get_metadata target key out_var) endfunction() # ================================================================================================== - function(_juce_should_build_module_source filename output_var) - get_filename_component(trimmed_name "${filename}" NAME_WE) + get_filename_component(trimmed_filename "${filename}" NAME_WE) + string(TOLOWER "${trimmed_filename}" trimmed_filename_lowercase) - set(result TRUE) + set(system_name_regex_for_suffix + "android\;Android" + "ios\;iOS" + "linux\;Linux|.*BSD" + "mac\;Darwin" + "osx\;Darwin" + "windows\;Windows") - set(pairs - "OSX\;Darwin" - "Windows\;Windows" - "Linux\;Linux" - "Android\;Android" - "iOS\;iOS") + set(result TRUE) - foreach(pair IN LISTS pairs) + foreach(pair IN LISTS system_name_regex_for_suffix) list(GET pair 0 suffix) - list(GET pair 1 system_name) + list(GET pair 1 regex) - if((trimmed_name MATCHES "_${suffix}$") AND NOT (CMAKE_SYSTEM_NAME STREQUAL "${system_name}")) + if((trimmed_filename_lowercase MATCHES "_${suffix}$") AND NOT (CMAKE_SYSTEM_NAME MATCHES "${regex}")) set(result FALSE) endif() endforeach() @@ -251,10 +253,13 @@ function(_juce_get_platform_plugin_kinds out) endif() if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android") - list(APPEND result Unity VST VST3 LV2) + list(APPEND result VST LV2) + if(NOT (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) + list(APPEND result Unity VST3) + endif() endif() - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "Windows") + if((CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "Windows") AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) list(APPEND result AAX) endif() @@ -310,7 +315,6 @@ endfunction() function(_juce_add_plugin_wrapper_target format path out_path) _juce_module_sources("${path}" "${out_path}" out_var headers) - list(FILTER out_var EXCLUDE REGEX "/juce_audio_plugin_client_utils.cpp$") set(target_name juce_audio_plugin_client_${format}) _juce_add_interface_library("${target_name}" ${out_var}) @@ -441,7 +445,10 @@ function(juce_add_module module_path) _juce_module_sources("${module_path}" "${base_path}" globbed_sources headers) if(${module_name} STREQUAL "juce_audio_plugin_client") - list(REMOVE_ITEM headers "${module_path}/LV2/juce_LV2TurtleDumpProgram.cpp") + list(REMOVE_ITEM headers + "${module_path}/LV2/juce_LV2ManifestHelper.cpp" + "${module_path}/VST3/juce_VST3ManifestHelper.mm" + "${module_path}/VST3/juce_VST3ManifestHelper.cpp") _juce_get_platform_plugin_kinds(plugin_kinds) @@ -449,16 +456,6 @@ function(juce_add_module module_path) _juce_add_plugin_wrapper_target(${kind} "${module_path}" "${base_path}") endforeach() - set(utils_source - "${base_path}/${module_name}/juce_audio_plugin_client_utils.cpp") - add_library(juce_audio_plugin_client_utils INTERFACE) - target_sources(juce_audio_plugin_client_utils INTERFACE "${utils_source}") - - if(JUCE_ARG_ALIAS_NAMESPACE) - add_library(${JUCE_ARG_ALIAS_NAMESPACE}::juce_audio_plugin_client_utils - ALIAS juce_audio_plugin_client_utils) - endif() - file(GLOB_RECURSE all_module_files CONFIGURE_DEPENDS LIST_DIRECTORIES FALSE RELATIVE "${module_parent_path}" diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index 90f59fbf9077..9eaacd22b6fe 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -33,7 +33,7 @@ # ================================================================================================== include_guard(GLOBAL) -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.22) define_property(TARGET PROPERTY JUCE_COMPANY_NAME INHERITED BRIEF_DOCS "The company name for a particular target" @@ -147,6 +147,86 @@ endfunction() # ================================================================================================== +function(_juce_create_linux_subprocess_helper_target) + if(TARGET juce_linux_subprocess_helper) + return() + endif() + + set(source "${JUCE_CMAKE_UTILS_DIR}/juce_LinuxSubprocessHelper.cpp") + + add_executable(juce_linux_subprocess_helper ${source}) + add_executable(juce::juce_linux_subprocess_helper ALIAS juce_linux_subprocess_helper) + target_compile_features(juce_linux_subprocess_helper PRIVATE cxx_std_17) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(juce_linux_subprocess_helper PRIVATE Threads::Threads ${CMAKE_DL_LIBS}) +endfunction() + +function(_juce_create_embedded_linux_subprocess_target output_target_name target) + # This library needs to be created in every directory where a target wants to link against it. + # Pre CMake 3.20 the GENERATED property is only visible in the directory of the current target, + # and even post 3.20, CMake will not know how to generate the sources outside this directory. + set(target_directory_key JUCE_EMBEDDED_LINUX_SUBPROCESS_TARGET) + get_directory_property(embedded_linux_subprocess_target ${target_directory_key}) + + if(embedded_linux_subprocess_target) + set(${output_target_name} juce::${embedded_linux_subprocess_target} PARENT_SCOPE) + return() + endif() + + set(prefix "_juce_directory_prefix") + set(embedded_linux_subprocess_target ${prefix}_embedded_linux_subprocess) + + while(TARGET ${embedded_linux_subprocess_target}) + set(embedded_linux_subprocess_target ${prefix}_${embedded_linux_subprocess_target}) + endwhile() + + _juce_create_linux_subprocess_helper_target() + + get_target_property(generated_sources_directory ${target} JUCE_GENERATED_SOURCES_DIRECTORY) + + if(generated_sources_directory) + set(juce_linux_subprocess_helper_binary_dir "${generated_sources_directory}") + else() + set(juce_linux_subprocess_helper_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/juce_LinuxSubprocessHelper") + endif() + + set(binary_header_file "${juce_linux_subprocess_helper_binary_dir}/juce_LinuxSubprocessHelperBinaryData.h") + set(binary_source_file "${juce_linux_subprocess_helper_binary_dir}/juce_LinuxSubprocessHelperBinaryData.cpp") + set(juceaide_input_file "${juce_linux_subprocess_helper_binary_dir}/input_file_list") + + file(GENERATE OUTPUT ${juceaide_input_file} CONTENT "$") + file(MAKE_DIRECTORY ${juce_linux_subprocess_helper_binary_dir}) + + add_custom_command( + OUTPUT + ${binary_header_file} + ${binary_source_file} + COMMAND juce::juceaide binarydata "LinuxSubprocessHelperBinaryData" "${binary_header_file}" + ${juce_linux_subprocess_helper_binary_dir} "${juceaide_input_file}" + COMMAND + ${CMAKE_COMMAND} -E rename "${juce_linux_subprocess_helper_binary_dir}/BinaryData1.cpp" "${binary_source_file}" + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + DEPENDS juce_linux_subprocess_helper + VERBATIM) + + add_library(${embedded_linux_subprocess_target} INTERFACE) + target_sources(${embedded_linux_subprocess_target} INTERFACE ${binary_source_file}) + target_include_directories(${embedded_linux_subprocess_target} INTERFACE ${juce_linux_subprocess_helper_binary_dir}) + target_compile_definitions(${embedded_linux_subprocess_target} INTERFACE JUCE_USE_EXTERNAL_TEMPORARY_SUBPROCESS=1) + add_library(juce::${embedded_linux_subprocess_target} ALIAS ${embedded_linux_subprocess_target}) + + set_directory_properties(PROPERTIES ${target_directory_key} ${embedded_linux_subprocess_target}) + set(${output_target_name} juce::${embedded_linux_subprocess_target} PARENT_SCOPE) +endfunction() + +function(juce_link_with_embedded_linux_subprocess target) + _juce_create_embedded_linux_subprocess_target(embedded_linux_subprocess_target ${target}) + target_link_libraries(${target} PRIVATE ${embedded_linux_subprocess_target}) +endfunction() + +# ================================================================================================== + # Ideally, we'd check the preprocessor defs on the target to see whether # JUCE_USE_CURL, JUCE_WEB_BROWSER, or JUCE_IN_APP_PURCHASES have been explicitly turned off, # and then link libraries as appropriate. @@ -167,6 +247,12 @@ function(_juce_link_optional_libraries target) if(needs_browser) target_link_libraries(${target} PRIVATE juce::pkgconfig_JUCE_BROWSER_LINUX_DEPS) + + get_target_property(is_plugin ${target} JUCE_IS_PLUGIN) + + if(is_plugin) + juce_link_with_embedded_linux_subprocess(${target}) + endif() endif() elseif(APPLE) get_target_property(needs_storekit ${target} JUCE_NEEDS_STORE_KIT) @@ -270,6 +356,7 @@ function(_juce_write_configure_time_info target) _juce_append_target_property(file_content APP_GROUP_IDS ${target} JUCE_APP_GROUP_IDS) _juce_append_target_property(file_content IS_PLUGIN ${target} JUCE_IS_PLUGIN) _juce_append_target_property(file_content ICLOUD_PERMISSIONS_ENABLED ${target} JUCE_ICLOUD_PERMISSIONS_ENABLED) + _juce_append_target_property(file_content IS_AU_PLUGIN_HOST ${target} JUCE_PLUGINHOST_AU) if(CMAKE_SYSTEM_NAME STREQUAL "iOS") _juce_append_record(file_content IS_IOS 1) @@ -351,7 +438,7 @@ function(juce_add_binary_data target) COMMAND juce::juceaide binarydata "${JUCE_ARG_NAMESPACE}" "${JUCE_ARG_HEADER_NAME}" ${juce_binary_data_folder} "${input_file_list}" WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - DEPENDS "${input_file_list}" + DEPENDS "${input_file_list}" ${JUCE_ARG_SOURCES} VERBATIM) target_sources(${target} PRIVATE "${binary_file_names}") @@ -456,7 +543,7 @@ function(_juce_execute_juceaide) ERROR_VARIABLE output) if(result_variable) - message(FATAL_ERROR "Running juceaide failed:\n${output}") + message(FATAL_ERROR "Running juceaide failed:\ncommand: ${juceaide_location} ${ARGN}\noutput: ${output}") endif() endfunction() @@ -648,22 +735,17 @@ function(_juce_configure_bundle source_target dest_target) if(CMAKE_GENERATOR STREQUAL "Xcode") get_target_property(product_name ${source_target} JUCE_PRODUCT_NAME) - + set(skip_install NO) set(install_path "$(LOCAL_APPS_DIR)") if(juce_kind_string STREQUAL "AUv3 AppExtension") - set(install_path "${install_path}/${product_name}.app") - - if(CMAKE_SYSTEM_NAME STREQUAL "iOS") - set(install_path "${install_path}/PlugIns") - else() - set(install_path "${install_path}/Contents/PlugIns") - endif() + set(skip_install YES) + set(install_path "") endif() set_target_properties(${dest_target} PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "${install_path}" - XCODE_ATTRIBUTE_SKIP_INSTALL "NO") + XCODE_ATTRIBUTE_SKIP_INSTALL "${skip_install}") endif() endfunction() @@ -673,7 +755,7 @@ function(_juce_add_resources_rc source_target dest_target) endif() get_target_property(juce_library_code ${source_target} JUCE_GENERATED_SOURCES_DIRECTORY) - set(input_info_file "$") + get_target_property(input_info_file ${source_target} JUCE_INFO_FILE) get_target_property(generated_icon ${source_target} JUCE_ICON_FILE) set(dependency) @@ -682,7 +764,7 @@ function(_juce_add_resources_rc source_target dest_target) set(dependency DEPENDS "${generated_icon}") endif() - set(resource_rc_file "${juce_library_code}/resources.rc") + set(resource_rc_file "${juce_library_code}/${dest_target}_resources.rc") add_custom_command(OUTPUT "${resource_rc_file}" COMMAND juce::juceaide rcfile "${input_info_file}" "${resource_rc_file}" @@ -698,8 +780,6 @@ function(_juce_configure_app_bundle source_target dest_target) MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE) - _juce_add_resources_rc(${source_target} ${dest_target}) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(nib_path "${JUCE_CMAKE_UTILS_DIR}/RecentFilesMenuTemplate.nib") target_sources("${dest_target}" PRIVATE "${nib_path}") @@ -801,6 +881,15 @@ function(_juce_set_copy_properties shared_code target from to_property) endfunction() function(juce_enable_copy_plugin_step shared_code_target) + get_target_property(step_added ${shared_code_target} _JUCE_PLUGIN_COPY_STEP_ADDED) + + if(step_added) + message(WARNING "Plugin copy step requested multiple times for ${shared_code_target}") + return() + endif() + + set_target_properties(${shared_code_target} PROPERTIES _JUCE_PLUGIN_COPY_STEP_ADDED TRUE) + get_target_property(active_targets "${shared_code_target}" JUCE_ACTIVE_PLUGIN_TARGETS) foreach(target IN LISTS active_targets) @@ -840,15 +929,109 @@ function(_juce_add_lv2_manifest_helper_target) endif() get_target_property(module_path juce::juce_audio_plugin_client INTERFACE_JUCE_MODULE_PATH) - set(source "${module_path}/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp") + set(source "${module_path}/juce_audio_plugin_client/LV2/juce_LV2ManifestHelper.cpp") add_executable(juce_lv2_helper "${source}") add_executable(juce::juce_lv2_helper ALIAS juce_lv2_helper) target_compile_features(juce_lv2_helper PRIVATE cxx_std_17) set_target_properties(juce_lv2_helper PROPERTIES BUILD_WITH_INSTALL_RPATH ON) - target_link_libraries(juce_lv2_helper PRIVATE ${CMAKE_DL_LIBS}) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) - target_link_libraries(juce_lv2_helper PRIVATE Threads::Threads) + target_link_libraries(juce_lv2_helper PRIVATE Threads::Threads ${CMAKE_DL_LIBS}) +endfunction() + +# ================================================================================================== + +function(_juce_add_vst3_manifest_helper_target) + if(TARGET juce_vst3_helper + OR (CMAKE_SYSTEM_NAME STREQUAL "iOS") + OR (CMAKE_SYSTEM_NAME STREQUAL "Android") + OR (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) + return() + endif() + + get_target_property(module_path juce::juce_audio_processors INTERFACE_JUCE_MODULE_PATH) + set(vst3_dir "${module_path}/juce_audio_processors/format_types/VST3_SDK") + + set(extension "cpp") + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(extension "mm") + endif() + + set(source "${module_path}/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.${extension}") + + add_executable(juce_vst3_helper "${source}") + add_executable(juce::juce_vst3_helper ALIAS juce_vst3_helper) + + target_include_directories(juce_vst3_helper PRIVATE "${vst3_dir}" "${module_path}") + + add_library(juce_interface_definitions INTERFACE) + _juce_add_standard_defs(juce_interface_definitions) + target_link_libraries(juce_vst3_helper PRIVATE juce_interface_definitions) + target_compile_features(juce_vst3_helper PRIVATE cxx_std_17) + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + _juce_link_frameworks(juce_vst3_helper PRIVATE Cocoa) + target_compile_options(juce_vst3_helper PRIVATE -fobjc-arc) + endif() + + if(MSYS OR MINGW) + target_link_options(juce_vst3_helper PRIVATE -municode) + endif() + + set_target_properties(juce_vst3_helper PROPERTIES BUILD_WITH_INSTALL_RPATH ON) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(juce_vst3_helper PRIVATE Threads::Threads ${CMAKE_DL_LIBS} juce_recommended_config_flags) +endfunction() + +function(juce_enable_vst3_manifest_step shared_code_target) + get_target_property(manifest_step_added ${shared_code_target} _JUCE_VST3_MANIFEST_STEP_ADDED) + + if(manifest_step_added) + message(WARNING "VST3 manifest generation has already been enabled for target ${shared_code_target}. " + "You may need to set VST3_AUTO_MANIFEST FALSE in juce_add_plugin, and/or check that you're " + "not calling juce_enable_vst3_manifest_step multiple times.") + return() + endif() + + get_target_property(copy_step_added ${shared_code_target} _JUCE_PLUGIN_COPY_STEP_ADDED) + + if(copy_step_added) + message(FATAL "VST3 manifest generation would run after plugin copy step, so it has been disabled. " + "If you're manually calling juce_enable_vst3_manifest_step, then you probably need to call " + "juce_enable_copy_plugin_step too.") + endif() + + if((MSYS OR MINGW) AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) + message(WARNING "VST3 manifest generation is disabled for ${shared_code_target} because the compiler is not supported.") + return() + endif() + + set(target_name ${shared_code_target}_VST3) + get_target_property(product ${target_name} JUCE_PLUGIN_ARTEFACT_FILE) + + if(NOT product) + message(FATAL "Property JUCE_PLUGIN_ARTEFACT_FILE not set for ${target_name}") + endif() + + # Add a target for the helper tool + _juce_add_vst3_manifest_helper_target() + + get_target_property(target_version_string ${shared_code_target} JUCE_VERSION) + + # Use the helper tool to write out the moduleinfo.json + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove -f "${product}/Contents/moduleinfo.json" + COMMAND ${CMAKE_COMMAND} -E make_directory "${product}/Contents/Resources" + COMMAND juce_vst3_helper + -create + -version "${target_version_string}" + -path "${product}" + -output "${product}/Contents/Resources/moduleinfo.json" + VERBATIM) + + set_target_properties(${shared_code_target} PROPERTIES _JUCE_VST3_MANIFEST_STEP_ADDED TRUE) endfunction() # ================================================================================================== @@ -893,6 +1076,12 @@ function(_juce_set_plugin_target_properties shared_code_target kind) endif() _juce_set_copy_properties(${shared_code_target} ${target_name} "${output_path}" JUCE_VST3_COPY_DIR) + + get_target_property(vst3_auto_manifest ${shared_code_target} JUCE_VST3_AUTO_MANIFEST) + + if(vst3_auto_manifest) + juce_enable_vst3_manifest_step(${shared_code_target}) + endif() elseif(kind STREQUAL "VST") set_target_properties(${target_name} PROPERTIES BUNDLE_EXTENSION vst @@ -1086,9 +1275,12 @@ function(_juce_link_plugin_wrapper shared_code_target kind) if(NOT kind STREQUAL "LV2") _juce_configure_bundle(${shared_code_target} ${target_name}) + else() + _juce_write_configure_time_info(${shared_code_target}) endif() _juce_set_plugin_target_properties(${shared_code_target} ${kind}) + _juce_add_resources_rc(${shared_code_target} ${target_name}) endfunction() # ================================================================================================== @@ -1125,7 +1317,7 @@ endfunction() function(_juce_configure_plugin_targets target) _juce_set_output_name(${target} $_SharedCode) - target_link_libraries(${target} PRIVATE juce::juce_audio_plugin_client_utils) + target_link_libraries(${target} PRIVATE juce::juce_audio_plugin_client) get_target_property(enabled_formats ${target} JUCE_FORMATS) @@ -1245,10 +1437,8 @@ function(_juce_configure_plugin_targets target) if((TARGET ${target}_AUv3) AND (TARGET ${target}_Standalone)) add_dependencies(${target}_Standalone ${target}_AUv3) - # Copy the AUv3 into the Standalone app bundle - _juce_copy_dir(${target}_Standalone - "$" - "$/PlugIns") + set_target_properties(${target}_Standalone PROPERTIES + XCODE_EMBED_APP_EXTENSIONS ${target}_AUv3) endif() get_target_property(wants_copy "${target}" JUCE_COPY_PLUGIN_AFTER_BUILD) @@ -1297,6 +1487,12 @@ function(_juce_set_fallback_properties target) get_target_property(real_company_name ${target} JUCE_COMPANY_NAME) _juce_set_property_if_not_set(${target} BUNDLE_ID "com.${real_company_name}.${target}") + get_target_property(applied_bundle_id ${target} JUCE_BUNDLE_ID) + + if("${applied_bundle_id}" MATCHES ".* .*") + message(WARNING "Target ${target} has JUCE_BUNDLE_ID '${applied_bundle_id}', which contains spaces. Use the BUNDLE_ID option to specify a valid ID.") + endif() + _juce_set_property_if_not_set(${target} VERSION ${PROJECT_VERSION}) get_target_property(final_version ${target} JUCE_VERSION) @@ -1355,9 +1551,11 @@ function(_juce_set_fallback_properties target) _juce_set_property_if_not_set(${target} SUPPRESS_AU_PLIST_RESOURCE_USAGE FALSE) - _juce_set_property_if_not_set(${target} HARDENED_RUNTIME_ENABLED NO) - _juce_set_property_if_not_set(${target} APP_SANDBOX_ENABLED NO) - _juce_set_property_if_not_set(${target} APP_SANDBOX_INHERIT NO) + _juce_set_property_if_not_set(${target} HARDENED_RUNTIME_ENABLED FALSE) + _juce_set_property_if_not_set(${target} APP_SANDBOX_ENABLED FALSE) + _juce_set_property_if_not_set(${target} APP_SANDBOX_INHERIT FALSE) + + _juce_set_property_if_not_set(${target} VST3_AUTO_MANIFEST TRUE) get_target_property(is_synth ${target} JUCE_IS_SYNTH) @@ -1612,6 +1810,7 @@ function(_juce_initialise_target target) HARDENED_RUNTIME_ENABLED APP_SANDBOX_ENABLED APP_SANDBOX_INHERIT + VST3_AUTO_MANIFEST PLUGIN_NAME PLUGIN_MANUFACTURER_CODE @@ -1738,6 +1937,10 @@ endfunction() # ================================================================================================== function(juce_add_console_app target) + # The _NO_RESOURCERC option is private, and is only intended for use when building juceaide. + # We can't add a resources.rc to juceaide because we need juceaide to generate the resources.rc! + cmake_parse_arguments(JUCE_ARG "_NO_RESOURCERC" "" "" ${ARGN}) + add_executable(${target}) target_compile_definitions(${target} PRIVATE JUCE_STANDALONE_APPLICATION=1) @@ -1746,6 +1949,11 @@ function(juce_add_console_app target) endif() _juce_initialise_target(${target} ${ARGN}) + + if(NOT JUCE_ARG__NO_RESOURCERC) + _juce_write_configure_time_info(${target}) + _juce_add_resources_rc(${target} ${target}) + endif() endfunction() function(juce_add_gui_app target) @@ -1761,6 +1969,7 @@ function(juce_add_gui_app target) set_target_properties(${target} PROPERTIES JUCE_TARGET_KIND_STRING "App") _juce_configure_bundle(${target} ${target}) _juce_configure_app_bundle(${target} ${target}) + _juce_add_resources_rc(${target} ${target}) endfunction() function(juce_add_plugin target) @@ -1892,11 +2101,15 @@ function(juce_add_pip header) list(APPEND extra_formats VST) endif() + if(NOT (CMAKE_SYSTEM_NAME MATCHES ".*BSD")) + list(APPEND extra_formats VST3) + endif() + # Standalone plugins might want to access the mic list(APPEND extra_target_args MICROPHONE_PERMISSION_ENABLED TRUE) juce_add_plugin(${JUCE_PIP_NAME} - FORMATS AU AUv3 LV2 Standalone Unity VST3 ${extra_formats} + FORMATS AU AUv3 LV2 Standalone Unity ${extra_formats} ${extra_target_args}) endif() elseif(pip_kind STREQUAL "Component") @@ -1996,12 +2209,7 @@ function(juce_set_aax_sdk_path path) message(FATAL_ERROR "Could not find AAX SDK at the specified path: ${path}") endif() - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - add_library(juce_aax_sdk STATIC IMPORTED GLOBAL) - set_target_properties(juce_aax_sdk PROPERTIES - IMPORTED_LOCATION_DEBUG "${path}/Libs/Debug/libAAXLibrary_libcpp.a" - IMPORTED_LOCATION "${path}/Libs/Release/libAAXLibrary_libcpp.a") - elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if((CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR (CMAKE_SYSTEM_NAME STREQUAL "Windows")) add_library(juce_aax_sdk INTERFACE IMPORTED GLOBAL) else() return() @@ -2011,7 +2219,6 @@ function(juce_set_aax_sdk_path path) "${path}" "${path}/Interfaces" "${path}/Interfaces/ACF") - target_compile_definitions(juce_aax_sdk INTERFACE JucePlugin_AAXLibs_path="${path}/Libs") set_target_properties(juce_aax_sdk PROPERTIES INTERFACE_JUCE_AAX_DEFAULT_ICON "${path}/Utilities/PlugIn.ico") endfunction() diff --git a/extras/Build/CMake/copyDir.cmake b/extras/Build/CMake/copyDir.cmake index fca14a865b2d..1f95ac910dab 100644 --- a/extras/Build/CMake/copyDir.cmake +++ b/extras/Build/CMake/copyDir.cmake @@ -21,4 +21,16 @@ # # ============================================================================== +if(NOT EXISTS "${src}") + message(STATUS "Unable to copy ${src} as it does not exist") + return() +endif() + +get_filename_component(name "${src}" NAME) + +if(EXISTS "${dest}/${name}") + message(STATUS "Destination ${dest}/${name} exists, overwriting") + file(REMOVE_RECURSE "${dest}/${name}") +endif() + file(INSTALL ${src} DESTINATION ${dest} USE_SOURCE_PERMISSIONS) diff --git a/extras/Build/CMake/juce_LinuxSubprocessHelper.cpp b/extras/Build/CMake/juce_LinuxSubprocessHelper.cpp new file mode 100644 index 000000000000..c690442f06f1 --- /dev/null +++ b/extras/Build/CMake/juce_LinuxSubprocessHelper.cpp @@ -0,0 +1,36 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 + +int main (int argc, const char* const* argv) +{ + if (argc >= 3) + if (auto* handle = dlopen (argv[1], RTLD_LAZY)) + if (auto* function = reinterpret_cast (dlsym (handle, argv[2]))) + return function (argc - 3, argv + 3); + + return 1; +} diff --git a/extras/Build/juce_build_tools/juce_build_tools.h b/extras/Build/juce_build_tools/juce_build_tools.h index ef702c13bf3b..5d4499379ef8 100644 --- a/extras/Build/juce_build_tools/juce_build_tools.h +++ b/extras/Build/juce_build_tools/juce_build_tools.h @@ -34,7 +34,7 @@ ID: juce_build_tools vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE Build Tools description: Classes for generating intermediate files for JUCE projects. website: http://www.juce.com/juce diff --git a/extras/Build/juce_build_tools/utils/juce_BuildHelperFunctions.cpp b/extras/Build/juce_build_tools/utils/juce_BuildHelperFunctions.cpp index f44839db3e9c..0131d8a56674 100644 --- a/extras/Build/juce_build_tools/utils/juce_BuildHelperFunctions.cpp +++ b/extras/Build/juce_build_tools/utils/juce_BuildHelperFunctions.cpp @@ -78,7 +78,8 @@ namespace build_tools case Type::StaticLibrary: case Type::DynamicLibrary: case Type::LV2PlugIn: - case Type::LV2TurtleProgram: + case Type::LV2Helper: + case Type::VST3Helper: case Type::SharedCodeTarget: case Type::AggregateTarget: case Type::unspecified: @@ -109,7 +110,8 @@ namespace build_tools case Type::StaticLibrary: case Type::DynamicLibrary: case Type::LV2PlugIn: - case Type::LV2TurtleProgram: + case Type::LV2Helper: + case Type::VST3Helper: case Type::SharedCodeTarget: case Type::AggregateTarget: case Type::unspecified: diff --git a/extras/Build/juce_build_tools/utils/juce_Entitlements.cpp b/extras/Build/juce_build_tools/utils/juce_Entitlements.cpp index 45f94461a84a..cc7840f70fda 100644 --- a/extras/Build/juce_build_tools/utils/juce_Entitlements.cpp +++ b/extras/Build/juce_build_tools/utils/juce_Entitlements.cpp @@ -49,7 +49,10 @@ namespace build_tools if (isiOS) { - if (isAudioPluginProject && shouldEnableIAA) + // The Inter-App Audio entitlement is currently deprecated, but it + // also "provides access to Audio Unit extensions". Without the + // entitlement iOS apps are unable to access AUv3 plug-ins. + if ((isAudioPluginProject && shouldEnableIAA) || isAUPluginHost) entitlements.set ("inter-app-audio", ""); if (isiCloudPermissionsEnabled) diff --git a/extras/Build/juce_build_tools/utils/juce_Entitlements.h b/extras/Build/juce_build_tools/utils/juce_Entitlements.h index b91a52a6906e..144999830157 100644 --- a/extras/Build/juce_build_tools/utils/juce_Entitlements.h +++ b/extras/Build/juce_build_tools/utils/juce_Entitlements.h @@ -36,6 +36,7 @@ namespace build_tools bool isiOS = false; bool isAudioPluginProject = false; bool shouldEnableIAA = false; + bool isAUPluginHost = false; bool isiCloudPermissionsEnabled = false; bool isPushNotificationsEnabled = false; bool isAppGroupsEnabled = false; diff --git a/extras/Build/juce_build_tools/utils/juce_ProjectType.h b/extras/Build/juce_build_tools/utils/juce_ProjectType.h index 8d71a0743be1..cbfd1f235bd3 100644 --- a/extras/Build/juce_build_tools/utils/juce_ProjectType.h +++ b/extras/Build/juce_build_tools/utils/juce_ProjectType.h @@ -82,7 +82,8 @@ namespace build_tools SharedCodeTarget = 20, // internal AggregateTarget = 21, - LV2TurtleProgram = 25, // internal + LV2Helper = 25, // internal + VST3Helper = 26, // internal unspecified = 30 }; @@ -118,7 +119,8 @@ namespace build_tools case LV2PlugIn: return "LV2 Plugin"; case SharedCodeTarget: return "Shared Code"; case AggregateTarget: return "All"; - case LV2TurtleProgram: return "LV2 Manifest Helper"; + case LV2Helper: return "LV2 Manifest Helper"; + case VST3Helper: return "VST3 Manifest Helper"; case unspecified: break; } @@ -141,7 +143,8 @@ namespace build_tools if (name == "LV2 Plugin") return Type::LV2PlugIn; if (name == "Shared Code") return Type::SharedCodeTarget; if (name == "All") return Type::AggregateTarget; - if (name == "LV2 Manifest Helper") return Type::LV2TurtleProgram; + if (name == "LV2 Manifest Helper") return Type::LV2Helper; + if (name == "VST3 Manifest Helper") return Type::VST3Helper; jassertfalse; return Type::ConsoleApp; @@ -164,7 +167,8 @@ namespace build_tools case UnityPlugIn: return pluginBundle; case LV2PlugIn: return pluginBundle; case SharedCodeTarget: return staticLibrary; - case LV2TurtleProgram: return executable; + case LV2Helper: return executable; + case VST3Helper: return executable; case AggregateTarget: case unspecified: break; @@ -249,7 +253,8 @@ namespace build_tools case Target::StandalonePlugIn: case Target::UnityPlugIn: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: + case Target::VST3Helper: case Target::SharedCodeTarget: case Target::AggregateTarget: return true; @@ -295,7 +300,8 @@ namespace build_tools case Target::DynamicLibrary: case Target::unspecified: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: + case Target::VST3Helper: break; } diff --git a/extras/Build/juceaide/CMakeLists.txt b/extras/Build/juceaide/CMakeLists.txt index 422d8d093eb8..245f47f1b244 100644 --- a/extras/Build/juceaide/CMakeLists.txt +++ b/extras/Build/juceaide/CMakeLists.txt @@ -28,7 +28,7 @@ if(JUCE_BUILD_HELPER_TOOLS) # Build the tool for the current system - juce_add_console_app(juceaide) + juce_add_console_app(juceaide _NO_RESOURCERC) target_sources(juceaide PRIVATE Main.cpp) @@ -49,6 +49,8 @@ if(JUCE_BUILD_HELPER_TOOLS) NAMESPACE juce_tools:: FILE "${JUCE_BINARY_DIR}/JUCEToolsExport.cmake") else() + set(extra_compiler_flag_arguments) + # If we're building using the NDK, the gradle wrapper will try to inject its own compiler using # environment variables, which is unfortunate because we really don't want to cross-compile # juceaide. @@ -98,13 +100,9 @@ else() set(ENV{PATH} "$ENV{PATH_ORIG}") endif() else() - # When building with clang-cl in Clion on Windows for an x64 target, the ABI detection phase - # of the inner build can fail unless we pass through these flags too - set(extra_configure_flags - "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" + set(extra_compiler_flag_arguments "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}" - "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}" - "-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}") + "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}") endif() message(STATUS "Configuring juceaide") @@ -118,7 +116,7 @@ else() "-DCMAKE_BUILD_TYPE=Debug" "-DJUCE_BUILD_HELPER_TOOLS=ON" "-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}" - ${extra_configure_flags} + ${extra_compiler_flag_arguments} WORKING_DIRECTORY "${JUCE_SOURCE_DIR}" OUTPUT_VARIABLE command_output ERROR_VARIABLE command_output diff --git a/extras/Build/juceaide/Main.cpp b/extras/Build/juceaide/Main.cpp index d36380a908df..ebfe27a24258 100644 --- a/extras/Build/juceaide/Main.cpp +++ b/extras/Build/juceaide/Main.cpp @@ -333,6 +333,7 @@ juce::build_tools::EntitlementOptions parseEntitlementsOptions (const juce::File updateField ("IS_IOS", result.isiOS); updateField ("IS_PLUGIN", result.isAudioPluginProject); + updateField ("IS_AU_PLUGIN_HOST", result.isAUPluginHost); updateField ("ICLOUD_PERMISSIONS_ENABLED", result.isiCloudPermissionsEnabled); updateField ("PUSH_NOTIFICATIONS_ENABLED", result.isPushNotificationsEnabled); updateField ("APP_GROUPS_ENABLED", result.isAppGroupsEnabled); diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt index 1635dd7f4e65..be222299fc14 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt @@ -1,7 +1,7 @@ # Automatically generated CMakeLists, created by the Projucer # Don't edit this file! Your changes will be overwritten when you re-save the Projucer project! -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.22) project(juce_jni_project) @@ -25,9 +25,9 @@ include_directories( AFTER enable_language(ASM) if(JUCE_BUILD_CONFIGURATION MATCHES "DEBUG") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEBUG=0]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCE_DEBUG=0]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DDEBUG=1]] [[-D_DEBUG=1]]) elseif(JUCE_BUILD_CONFIGURATION MATCHES "RELEASE") - add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70005]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) + add_definitions([[-DJUCE_DISPLAY_SPLASH_SCREEN=0]] [[-DJUCE_USE_DARK_SPLASH_SCREEN=1]] [[-DJUCE_PROJUCER_VERSION=0x70007]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1]] [[-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1]] [[-DJUCE_MODULE_AVAILABLE_juce_core=1]] [[-DJUCE_MODULE_AVAILABLE_juce_cryptography=1]] [[-DJUCE_MODULE_AVAILABLE_juce_data_structures=1]] [[-DJUCE_MODULE_AVAILABLE_juce_events=1]] [[-DJUCE_MODULE_AVAILABLE_juce_graphics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1]] [[-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1]] [[-DJUCE_MODULE_AVAILABLE_juce_opengl=1]] [[-DJUCE_MODULE_AVAILABLE_juce_osc=1]] [[-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1]] [[-DJUCE_STANDALONE_APPLICATION=1]] [[-DJUCER_ANDROIDSTUDIO_7F0E4A25=1]] [[-DJUCE_APP_VERSION=1.0.0]] [[-DJUCE_APP_VERSION_HEX=0x10000]] [[-DNDEBUG=1]]) else() message( FATAL_ERROR "No matching build-configuration found." ) endif() @@ -105,8 +105,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -282,23 +282,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -585,6 +585,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -615,6 +616,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -652,14 +654,34 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -739,6 +761,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -761,9 +785,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -790,16 +814,16 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -834,6 +858,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -873,6 +898,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -898,6 +924,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -907,41 +935,44 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -1114,6 +1145,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -1135,19 +1168,20 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -1299,24 +1333,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -1376,6 +1410,27 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -1430,6 +1485,8 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -1516,63 +1573,77 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -1640,18 +1711,23 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -1698,24 +1774,24 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -1725,9 +1801,9 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" @@ -1865,8 +1941,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_basics/mpe/juce_MPEValue.h" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp" "../../../../../modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h" - "../../../../../modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h" + "../../../../../modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h" "../../../../../modules/juce_audio_basics/sources/juce_AudioSource.h" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp" "../../../../../modules/juce_audio_basics/sources/juce_BufferingAudioSource.h" @@ -2042,23 +2118,23 @@ set_source_files_properties( "../../../../../modules/juce_audio_devices/native/oboe/src/opensles/OutputMixerOpenSLES.h" "../../../../../modules/juce_audio_devices/native/oboe/CMakeLists.txt" "../../../../../modules/juce_audio_devices/native/oboe/README.md" - "../../../../../modules/juce_audio_devices/native/juce_android_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h" - "../../../../../modules/juce_audio_devices/native/juce_android_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_Oboe.cpp" - "../../../../../modules/juce_audio_devices/native/juce_android_OpenSL.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_ios_Audio.h" - "../../../../../modules/juce_audio_devices/native/juce_linux_ALSA.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Bela.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_JackAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_linux_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp" - "../../../../../modules/juce_audio_devices/native/juce_mac_CoreMidi.mm" - "../../../../../modules/juce_audio_devices/native/juce_win32_ASIO.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_DirectSound.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_Midi.cpp" - "../../../../../modules/juce_audio_devices/native/juce_win32_WASAPI.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ALSA_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_ASIO_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Audio_ios.h" + "../../../../../modules/juce_audio_devices/native/juce_Bela_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp" + "../../../../../modules/juce_audio_devices/native/juce_CoreMidi_mac.mm" + "../../../../../modules/juce_audio_devices/native/juce_DirectSound_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h" + "../../../../../modules/juce_audio_devices/native/juce_JackAudio_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_linux.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Midi_windows.cpp" + "../../../../../modules/juce_audio_devices/native/juce_Oboe_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_OpenSL_android.cpp" + "../../../../../modules/juce_audio_devices/native/juce_WASAPI_windows.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp" "../../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.h" "../../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp" @@ -2345,6 +2421,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp" @@ -2375,6 +2452,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/icloneable.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipersistent.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/istringresult.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iupdatehandler.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h" @@ -2412,14 +2490,34 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h" + "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp" @@ -2499,6 +2597,8 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/ARA/juce_ARAPlugInInstanceRoles.h" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterBool.h" "../../../../../modules/juce_audio_processors/utilities/juce_AudioParameterChoice.cpp" @@ -2521,9 +2621,9 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_PluginHostType.h" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" + "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp" - "../../../../../modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -2550,16 +2650,16 @@ set_source_files_properties( "../../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.h" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp" "../../../../../modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h" - "../../../../../modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp" - "../../../../../modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm" - "../../../../../modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" - "../../../../../modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp" - "../../../../../modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" + "../../../../../modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp" "../../../../../modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h" "../../../../../modules/juce_audio_utils/players/juce_SoundPlayer.cpp" @@ -2594,6 +2694,7 @@ set_source_files_properties( "../../../../../modules/juce_core/containers/juce_ScopedValueSetter.h" "../../../../../modules/juce_core/containers/juce_SingleThreadedAbstractFifo.h" "../../../../../modules/juce_core/containers/juce_SortedSet.h" + "../../../../../modules/juce_core/containers/juce_Span.h" "../../../../../modules/juce_core/containers/juce_SparseSet.cpp" "../../../../../modules/juce_core/containers/juce_SparseSet.h" "../../../../../modules/juce_core/containers/juce_Variant.cpp" @@ -2633,6 +2734,7 @@ set_source_files_properties( "../../../../../modules/juce_core/maths/juce_Expression.cpp" "../../../../../modules/juce_core/maths/juce_Expression.h" "../../../../../modules/juce_core/maths/juce_MathsFunctions.h" + "../../../../../modules/juce_core/maths/juce_MathsFunctions_test.cpp" "../../../../../modules/juce_core/maths/juce_NormalisableRange.h" "../../../../../modules/juce_core/maths/juce_Random.cpp" "../../../../../modules/juce_core/maths/juce_Random.h" @@ -2658,6 +2760,8 @@ set_source_files_properties( "../../../../../modules/juce_core/memory/juce_WeakReference.h" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.cpp" "../../../../../modules/juce_core/misc/juce_ConsoleApplication.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers.h" + "../../../../../modules/juce_core/misc/juce_EnumHelpers_test.cpp" "../../../../../modules/juce_core/misc/juce_Functional.h" "../../../../../modules/juce_core/misc/juce_Result.cpp" "../../../../../modules/juce_core/misc/juce_Result.h" @@ -2667,41 +2771,44 @@ set_source_files_properties( "../../../../../modules/juce_core/misc/juce_Uuid.h" "../../../../../modules/juce_core/misc/juce_WindowsRegistry.h" "../../../../../modules/juce_core/native/java/README.txt" - "../../../../../modules/juce_core/native/juce_android_AndroidDocument.cpp" - "../../../../../modules/juce_core/native/juce_android_Files.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.cpp" - "../../../../../modules/juce_core/native/juce_android_JNIHelpers.h" - "../../../../../modules/juce_core/native/juce_android_Misc.cpp" - "../../../../../modules/juce_core/native/juce_android_Network.cpp" - "../../../../../modules/juce_core/native/juce_android_RuntimePermissions.cpp" - "../../../../../modules/juce_core/native/juce_android_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_android_Threads.cpp" + "../../../../../modules/juce_core/native/juce_AndroidDocument_android.cpp" "../../../../../modules/juce_core/native/juce_BasicNativeHeaders.h" - "../../../../../modules/juce_core/native/juce_curl_Network.cpp" - "../../../../../modules/juce_core/native/juce_intel_SharedCode.h" - "../../../../../modules/juce_core/native/juce_linux_CommonFile.cpp" - "../../../../../modules/juce_core/native/juce_linux_Files.cpp" - "../../../../../modules/juce_core/native/juce_linux_Network.cpp" - "../../../../../modules/juce_core/native/juce_linux_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_linux_Threads.cpp" - "../../../../../modules/juce_core/native/juce_mac_CFHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Files.mm" - "../../../../../modules/juce_core/native/juce_mac_Network.mm" - "../../../../../modules/juce_core/native/juce_mac_ObjCHelpers.h" - "../../../../../modules/juce_core/native/juce_mac_Strings.mm" - "../../../../../modules/juce_core/native/juce_mac_SystemStats.mm" - "../../../../../modules/juce_core/native/juce_mac_Threads.mm" - "../../../../../modules/juce_core/native/juce_native_ThreadPriorities.h" - "../../../../../modules/juce_core/native/juce_posix_IPAddress.h" - "../../../../../modules/juce_core/native/juce_posix_NamedPipe.cpp" - "../../../../../modules/juce_core/native/juce_posix_SharedCode.h" - "../../../../../modules/juce_core/native/juce_wasm_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_ComSmartPtr.h" - "../../../../../modules/juce_core/native/juce_win32_Files.cpp" - "../../../../../modules/juce_core/native/juce_win32_Network.cpp" - "../../../../../modules/juce_core/native/juce_win32_Registry.cpp" - "../../../../../modules/juce_core/native/juce_win32_SystemStats.cpp" - "../../../../../modules/juce_core/native/juce_win32_Threads.cpp" + "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" + "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_Files_android.cpp" + "../../../../../modules/juce_core/native/juce_Files_linux.cpp" + "../../../../../modules/juce_core/native/juce_Files_mac.mm" + "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" + "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" + "../../../../../modules/juce_core/native/juce_Misc_android.cpp" + "../../../../../modules/juce_core/native/juce_NamedPipe_posix.cpp" + "../../../../../modules/juce_core/native/juce_Network_android.cpp" + "../../../../../modules/juce_core/native/juce_Network_curl.cpp" + "../../../../../modules/juce_core/native/juce_Network_linux.cpp" + "../../../../../modules/juce_core/native/juce_Network_mac.mm" + "../../../../../modules/juce_core/native/juce_Network_windows.cpp" + "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_generic.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" + "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" + "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" + "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" + "../../../../../modules/juce_core/native/juce_SharedCode_posix.h" + "../../../../../modules/juce_core/native/juce_Strings_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_android.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_linux.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_mac.mm" + "../../../../../modules/juce_core/native/juce_SystemStats_wasm.cpp" + "../../../../../modules/juce_core/native/juce_SystemStats_windows.cpp" + "../../../../../modules/juce_core/native/juce_ThreadPriorities_native.h" + "../../../../../modules/juce_core/native/juce_Threads_android.cpp" + "../../../../../modules/juce_core/native/juce_Threads_linux.cpp" + "../../../../../modules/juce_core/native/juce_Threads_mac.mm" + "../../../../../modules/juce_core/native/juce_Threads_windows.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.cpp" "../../../../../modules/juce_core/network/juce_IPAddress.h" "../../../../../modules/juce_core/network/juce_MACAddress.cpp" @@ -2874,6 +2981,8 @@ set_source_files_properties( "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.cpp" "../../../../../modules/juce_events/broadcasters/juce_ChangeBroadcaster.h" "../../../../../modules/juce_events/broadcasters/juce_ChangeListener.h" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp" + "../../../../../modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp" "../../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.h" "../../../../../modules/juce_events/interprocess/juce_InterprocessConnection.cpp" @@ -2895,19 +3004,20 @@ set_source_files_properties( "../../../../../modules/juce_events/messages/juce_MessageManager.h" "../../../../../modules/juce_events/messages/juce_MountedVolumeListChangeDetector.h" "../../../../../modules/juce_events/messages/juce_NotificationType.h" - "../../../../../modules/juce_events/native/juce_android_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_ios_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_linux_EventLoop.h" - "../../../../../modules/juce_events/native/juce_linux_EventLoopInternal.h" - "../../../../../modules/juce_events/native/juce_linux_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_mac_MessageManager.mm" - "../../../../../modules/juce_events/native/juce_osx_MessageQueue.h" + "../../../../../modules/juce_events/native/juce_EventLoop_linux.h" + "../../../../../modules/juce_events/native/juce_EventLoopInternal_linux.h" + "../../../../../modules/juce_events/native/juce_HiddenMessageWindow_windows.h" + "../../../../../modules/juce_events/native/juce_MessageManager_ios.mm" + "../../../../../modules/juce_events/native/juce_MessageManager_mac.mm" + "../../../../../modules/juce_events/native/juce_MessageQueue_mac.h" + "../../../../../modules/juce_events/native/juce_Messaging_android.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_linux.cpp" + "../../../../../modules/juce_events/native/juce_Messaging_windows.cpp" + "../../../../../modules/juce_events/native/juce_RunningInUnity.h" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.cpp" "../../../../../modules/juce_events/native/juce_ScopedLowPowerModeDisabler.h" - "../../../../../modules/juce_events/native/juce_win32_HiddenMessageWindow.h" - "../../../../../modules/juce_events/native/juce_win32_Messaging.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.cpp" - "../../../../../modules/juce_events/native/juce_win32_WinRTWrapper.h" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.cpp" + "../../../../../modules/juce_events/native/juce_WinRTWrapper_windows.h" "../../../../../modules/juce_events/timers/juce_MultiTimer.cpp" "../../../../../modules/juce_events/timers/juce_MultiTimer.h" "../../../../../modules/juce_events/timers/juce_Timer.cpp" @@ -3059,24 +3169,24 @@ set_source_files_properties( "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.cpp" "../../../../../modules/juce_graphics/images/juce_ImageFileFormat.h" "../../../../../modules/juce_graphics/images/juce_ScaledImage.h" - "../../../../../modules/juce_graphics/native/juce_android_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_android_GraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_android_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_freetype_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_linux_IconHelpers.cpp" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm" - "../../../../../modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h" - "../../../../../modules/juce_graphics/native/juce_mac_Fonts.mm" - "../../../../../modules/juce_graphics/native/juce_mac_IconHelpers.cpp" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm" + "../../../../../modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_android.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_freetype.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_Fonts_mac.mm" + "../../../../../modules/juce_graphics/native/juce_Fonts_windows.cpp" + "../../../../../modules/juce_graphics/native/juce_GraphicsContext_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_android.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_linux.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_mac.cpp" + "../../../../../modules/juce_graphics/native/juce_IconHelpers_windows.cpp" "../../../../../modules/juce_graphics/native/juce_RenderingHelpers.h" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_Fonts.cpp" - "../../../../../modules/juce_graphics/native/juce_win32_IconHelpers.cpp" "../../../../../modules/juce_graphics/placement/juce_Justification.h" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.cpp" "../../../../../modules/juce_graphics/placement/juce_RectanglePlacement.h" @@ -3136,6 +3246,27 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/desktop/juce_Desktop.h" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.cpp" "../../../../../modules/juce_gui_basics/desktop/juce_Displays.h" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp" + "../../../../../modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h" + "../../../../../modules/juce_gui_basics/detail/juce_ComponentHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_FocusRestorer.h" + "../../../../../modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_MouseInputSourceList.h" + "../../../../../modules/juce_gui_basics/detail/juce_PointerState.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScalingHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h" + "../../../../../modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h" + "../../../../../modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h" + "../../../../../modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h" + "../../../../../modules/juce_gui_basics/detail/juce_ViewportHelpers.h" + "../../../../../modules/juce_gui_basics/detail/juce_WindowingHelpers.h" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.cpp" "../../../../../modules/juce_gui_basics/drawables/juce_Drawable.h" "../../../../../modules/juce_gui_basics/drawables/juce_DrawableComposite.cpp" @@ -3190,6 +3321,8 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/keyboard/juce_TextInputTarget.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPosition.h" "../../../../../modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp" + "../../../../../modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp" "../../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h" "../../../../../modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp" @@ -3276,63 +3409,77 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/mouse/juce_MouseInputSource.h" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.cpp" "../../../../../modules/juce_gui_basics/mouse/juce_MouseListener.h" - "../../../../../modules/juce_gui_basics/mouse/juce_PointerState.h" "../../../../../modules/juce_gui_basics/mouse/juce_SelectedItemSet.h" "../../../../../modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h" "../../../../../modules/juce_gui_basics/mouse/juce_TooltipClient.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_android.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_ios.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_mac.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_Accessibility_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.cpp" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityElement_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilitySharedCode_mac.mm" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers.h" "../../../../../modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_android_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_mac_AccessibilitySharedCode.mm" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_Accessibility.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAExpandCollapseProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridItemProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAGridProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAInvokeProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviderBase.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAProviders.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIARangeValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIASelectionProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAToggleProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIATransformProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_UIAWindowProvider.h" - "../../../../../modules/juce_gui_basics/native/accessibility/juce_win32_WindowsUIAWrapper.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_ScopedWindowAssociation.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_X11_Symbols.h" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp" - "../../../../../modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h" - "../../../../../modules/juce_gui_basics/native/juce_android_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_ContentSharer.cpp" - "../../../../../modules/juce_gui_basics/native/juce_ios_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm" - "../../../../../modules/juce_gui_basics/native/juce_linux_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_linux_Windowing.cpp" - "../../../../../modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_FileChooser.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MainMenu.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_MouseCursor.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm" - "../../../../../modules/juce_gui_basics/native/juce_mac_PerScreenDisplayLinks.h" - "../../../../../modules/juce_gui_basics/native/juce_mac_Windowing.mm" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_ComInterfaces_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAExpandCollapseProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridItemProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAGridProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAHelpers_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAInvokeProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviderBase_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAProviders_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIARangeValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIASelectionProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATextProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAToggleProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIATransformProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAValueProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_UIAWindowProvider_windows.h" + "../../../../../modules/juce_gui_basics/native/accessibility/juce_WindowsUIAWrapper_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_CGMetalLayerRenderer_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ContentSharer_ios.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_DragAndDrop_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_FileChooser_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_MainMenu_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_MouseCursor_mac.mm" "../../../../../modules/juce_gui_basics/native/juce_MultiTouchMapper.h" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_NativeMessageBox_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_NativeModalWrapperComponent_ios.h" + "../../../../../modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_PerScreenDisplayLinks_mac.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.cpp" "../../../../../modules/juce_gui_basics/native/juce_ScopedDPIAwarenessDisabler.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_DragAndDrop.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_FileChooser.cpp" - "../../../../../modules/juce_gui_basics/native/juce_win32_ScopedThreadDPIAwarenessSetter.h" - "../../../../../modules/juce_gui_basics/native/juce_win32_Windowing.cpp" + "../../../../../modules/juce_gui_basics/native/juce_ScopedThreadDPIAwarenessSetter_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_ScopedWindowAssociation_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_UIViewComponentPeer_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_Windowing_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowsHooks_windows.h" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_android.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_ios.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_mac.mm" + "../../../../../modules/juce_gui_basics/native/juce_WindowUtils_windows.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XSymbols_linux.h" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp" + "../../../../../modules/juce_gui_basics/native/juce_XWindowSystem_linux.h" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.cpp" "../../../../../modules/juce_gui_basics/positioning/juce_MarkerList.h" "../../../../../modules/juce_gui_basics/positioning/juce_RelativeCoordinate.cpp" @@ -3400,18 +3547,23 @@ set_source_files_properties( "../../../../../modules/juce_gui_basics/windows/juce_DialogWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_DocumentWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.cpp" "../../../../../modules/juce_gui_basics/windows/juce_MessageBoxOptions.h" + "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.cpp" "../../../../../modules/juce_gui_basics/windows/juce_NativeMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_ScopedMessageBox.h" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_ThreadWithProgressWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TooltipWindow.h" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.cpp" "../../../../../modules/juce_gui_basics/windows/juce_TopLevelWindow.h" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.cpp" - "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachement.h" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.cpp" + "../../../../../modules/juce_gui_basics/windows/juce_VBlankAttachment.h" + "../../../../../modules/juce_gui_basics/windows/juce_WindowUtils.h" "../../../../../modules/juce_gui_basics/juce_gui_basics.cpp" "../../../../../modules/juce_gui_basics/juce_gui_basics.mm" "../../../../../modules/juce_gui_basics/juce_gui_basics.h" @@ -3458,24 +3610,24 @@ set_source_files_properties( "../../../../../modules/juce_gui_extra/misc/juce_SystemTrayIconComponent.h" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.cpp" "../../../../../modules/juce_gui_extra/misc/juce_WebBrowserComponent.h" - "../../../../../modules/juce_gui_extra/native/juce_android_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_android_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_ActiveXComponent_windows.cpp" "../../../../../modules/juce_gui_extra/native/juce_AndroidViewComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_ios_UIViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_X11_WebBrowserComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_linux_XEmbedComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_AppleRemote.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h" - "../../../../../modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm" - "../../../../../modules/juce_gui_extra/native/juce_win32_ActiveXComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_SystemTrayIcon.cpp" - "../../../../../modules/juce_gui_extra/native/juce_win32_WebBrowserComponent.cpp" + "../../../../../modules/juce_gui_extra/native/juce_AppleRemote_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_HWNDComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_NSViewComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_NSViewFrameWatcher_mac.h" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_ios.cpp" + "../../../../../modules/juce_gui_extra/native/juce_PushNotifications_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_mac.cpp" + "../../../../../modules/juce_gui_extra/native/juce_SystemTrayIcon_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_UIViewComponent_ios.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_android.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm" + "../../../../../modules/juce_gui_extra/native/juce_WebBrowserComponent_windows.cpp" + "../../../../../modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.cpp" "../../../../../modules/juce_gui_extra/juce_gui_extra.mm" "../../../../../modules/juce_gui_extra/juce_gui_extra.h" @@ -3485,9 +3637,9 @@ set_source_files_properties( "../../../../../modules/juce_opengl/geometry/juce_Vector3D.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_android.h" "../../../../../modules/juce_opengl/native/juce_OpenGL_ios.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_linux_X11.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_osx.h" - "../../../../../modules/juce_opengl/native/juce_OpenGL_win32.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_linux.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_mac.h" + "../../../../../modules/juce_opengl/native/juce_OpenGL_windows.h" "../../../../../modules/juce_opengl/native/juce_OpenGLExtensions.h" "../../../../../modules/juce_opengl/opengl/juce_gl.cpp" "../../../../../modules/juce_opengl/opengl/juce_gl.h" diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle b/extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle index 58c8635537f8..6bbc057bcf7d 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/build.gradle @@ -2,10 +2,12 @@ apply plugin: 'com.android.application' android { compileSdkVersion 33 + ndkVersion "25.2.9519653" namespace "com.juce.networkgraphicsdemo" externalNativeBuild { cmake { path "CMakeLists.txt" + version "3.22.1" } } signingConfigs { diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml index e8e438e00a52..080422620690 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ + diff --git a/extras/NetworkGraphicsDemo/Builds/LinuxMakefile/Makefile b/extras/NetworkGraphicsDemo/Builds/LinuxMakefile/Makefile index 820afe738be4..08a6df089c06 100644 --- a/extras/NetworkGraphicsDemo/Builds/LinuxMakefile/Makefile +++ b/extras/NetworkGraphicsDemo/Builds/LinuxMakefile/Makefile @@ -39,13 +39,13 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl 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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := JUCE\ Network\ Graphics\ Demo JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -60,13 +60,13 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl 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_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := JUCE\ Network\ Graphics\ Demo JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -95,105 +95,110 @@ OBJECTS_APP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } - @$(PKG_CONFIG) --print-errors alsa freetype2 libcurl + @$(PKG_CONFIG) --print-errors alsa freetype2 gl libcurl @echo Linking "NetworkGraphicsDemo - App" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/BinaryData_ce4232d4.o: ../../JuceLibraryCode/BinaryData.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling BinaryData.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_devices_63111d02.o: ../../JuceLibraryCode/include_juce_audio_devices.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_devices.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_formats.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_10c03666.o: ../../JuceLibraryCode/include_juce_audio_processors.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_ara_2a4c6ef7.o: ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_ara.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_12bdca08.o: ../../JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_lv2_libs.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_utils_9f9fb2d6.o: ../../JuceLibraryCode/include_juce_audio_utils.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_utils.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o: ../../JuceLibraryCode/include_juce_cryptography.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_cryptography.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_opengl_a8a032b.o: ../../JuceLibraryCode/include_juce_opengl.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_opengl.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_osc_f3df604d.o: ../../JuceLibraryCode/include_juce_osc.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_osc.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning NetworkGraphicsDemo $(V_AT)$(CLEANCMD) diff --git a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj b/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj index 4f363192ff3d..23c84e45f20f 100644 --- a/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj +++ b/extras/NetworkGraphicsDemo/Builds/MacOSX/NetworkGraphicsDemo.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 77745BF98931B91341FE17F6 /* IOKit.framework */ = {isa = PBXBuildFile; fileRef = F3292E3563DB7ABB076DB400; }; 80B9F7ED2009922C693B7DD4 /* DiscRecording.framework */ = {isa = PBXBuildFile; fileRef = CB82A14817C3E2ABBBBC3864; }; 80EE2C27B466BAFD83881D3F /* Accelerate.framework */ = {isa = PBXBuildFile; fileRef = 2E13A899F4E3C99054A3656F; }; + 88DB5C5128E42AD59AD944D9 /* Security.framework */ = {isa = PBXBuildFile; fileRef = 9D1E94FAB66D1FB2531A3F9F; }; 8ECB0767EE340DD83869E37D /* WebKit.framework */ = {isa = PBXBuildFile; fileRef = EC794872987FEA2E129C589A; }; 95C7D26CC68839FC6BF90AC3 /* include_juce_audio_processors_ara.cpp */ = {isa = PBXBuildFile; fileRef = 52EF9BE720EFF47106DB0351; }; 987CBD5330E76B404F0D966C /* Main.cpp */ = {isa = PBXBuildFile; fileRef = 77C0AC21C1028911123844FC; }; @@ -75,6 +76,7 @@ 9982F39121710EFFD5FEEAEF /* MasterComponent.h */ /* MasterComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MasterComponent.h; path = ../../Source/MasterComponent.h; sourceTree = SOURCE_ROOT; }; 9C67BD1915C7FD5747C2BA8F /* juce_audio_formats */ /* juce_audio_formats */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_formats; path = ../../../../modules/juce_audio_formats; sourceTree = SOURCE_ROOT; }; 9C689AFBF364CB167C422D29 /* juce_gui_extra */ /* juce_gui_extra */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_gui_extra; path = ../../../../modules/juce_gui_extra; sourceTree = SOURCE_ROOT; }; + 9D1E94FAB66D1FB2531A3F9F /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 9E8129263CD42C6029FC2CAD /* AudioToolbox.framework */ /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; A505E1DABB2ED630EFBA96DB /* juce_audio_processors */ /* juce_audio_processors */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_audio_processors; path = ../../../../modules/juce_audio_processors; sourceTree = SOURCE_ROOT; }; A7FF2B353C8568B5A7A80117 /* include_juce_graphics.mm */ /* include_juce_graphics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_graphics.mm; path = ../../JuceLibraryCode/include_juce_graphics.mm; sourceTree = SOURCE_ROOT; }; @@ -116,6 +118,7 @@ 77745BF98931B91341FE17F6, B323E5E5FBD5663B21A8E623, EC14DA30C090DDC62084DB4C, + 88DB5C5128E42AD59AD944D9, 8ECB0767EE340DD83869E37D, ); runOnlyForDeploymentPostprocessing = 0; @@ -159,6 +162,7 @@ F3292E3563DB7ABB076DB400, 996E743A20FC78671766BF59, 935CA85EF98714D3A17AE737, + 9D1E94FAB66D1FB2531A3F9F, EC794872987FEA2E129C589A, ); name = Frameworks; @@ -368,7 +372,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -530,7 +534,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj index d4df0a265b51..27937b3ebc42 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -78,7 +78,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\JUCE Network Graphics Demo.exe @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -120,7 +120,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\JUCE Network Graphics Demo.exe @@ -454,46 +454,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -838,18 +838,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -949,6 +973,9 @@ true + + true + true @@ -979,7 +1006,7 @@ true - + true @@ -1018,22 +1045,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1129,6 +1156,9 @@ true + + true + true @@ -1141,6 +1171,9 @@ true + + true + true @@ -1150,67 +1183,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1429,6 +1468,9 @@ true + + true + true @@ -1453,19 +1495,19 @@ true - + true - + true - + true - + true - + true @@ -1744,40 +1786,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1849,6 +1891,9 @@ true + + true + true @@ -1921,6 +1966,9 @@ true + + true + true @@ -2044,52 +2092,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2191,9 +2266,18 @@ true + + true + + + true + true + + true + true @@ -2203,7 +2287,7 @@ true - + true @@ -2260,43 +2344,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2429,8 +2513,8 @@ - - + + @@ -2525,8 +2609,8 @@ - - + + @@ -2703,6 +2787,7 @@ + @@ -2722,6 +2807,7 @@ + @@ -2758,8 +2844,18 @@ + + + + + + + + + + @@ -2800,6 +2896,7 @@ + @@ -2812,8 +2909,8 @@ + - @@ -2847,6 +2944,7 @@ + @@ -2889,20 +2987,22 @@ + - - - - - - - - + + + + + + + + + @@ -3000,6 +3100,7 @@ + @@ -3013,12 +3114,13 @@ - - - + + + + + - - + @@ -3075,10 +3177,10 @@ - - + + + - @@ -3114,6 +3216,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3144,6 +3266,7 @@ + @@ -3189,36 +3312,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3256,10 +3380,12 @@ + - + + @@ -3287,7 +3413,7 @@ - + @@ -3295,9 +3421,9 @@ - - - + + + @@ -3338,6 +3464,7 @@ + diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters index 0dc2f237dc78..8f75cfd8a0cd 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters @@ -293,12 +293,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -503,6 +521,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -530,9 +551,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -916,49 +934,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1309,18 +1327,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1423,6 +1468,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1453,7 +1501,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1495,34 +1543,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1621,6 +1669,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1633,6 +1684,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1642,82 +1696,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -1945,6 +2005,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -1969,25 +2032,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2269,46 +2332,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2383,6 +2446,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2455,6 +2521,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2578,85 +2647,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2758,9 +2866,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2770,7 +2887,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2830,55 +2947,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3129,10 +3246,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3417,10 +3534,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -3951,6 +4068,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4008,6 +4128,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4116,12 +4239,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4242,6 +4395,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4278,10 +4434,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4383,6 +4539,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4509,6 +4668,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4524,31 +4686,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -4842,6 +5007,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -4881,22 +5049,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5067,16 +5238,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5184,6 +5355,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5274,6 +5505,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5409,9 +5643,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5421,82 +5652,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5610,6 +5847,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5619,7 +5859,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5703,7 +5946,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -5727,13 +5970,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -5852,6 +6095,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj index 12bc5222075c..1422ebfbeb53 100644 --- a/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj +++ b/extras/NetworkGraphicsDemo/Builds/iOS/NetworkGraphicsDemo.xcodeproj/project.pbxproj @@ -385,7 +385,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", @@ -550,7 +550,7 @@ "JUCE_CONTENT_SHARING=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", "JUCE_MODULE_AVAILABLE_juce_audio_formats=1", diff --git a/extras/Projucer/Builds/LinuxMakefile/Makefile b/extras/Projucer/Builds/LinuxMakefile/Makefile index 139692afa65a..e9e4c1259f34 100644 --- a/extras/Projucer/Builds/LinuxMakefile/Makefile +++ b/extras/Projucer/Builds/LinuxMakefile/Makefile @@ -39,7 +39,7 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_build_tools=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_LOG_ASSERTIONS=1" "-DJUCE_USE_CURL=1" "-DJUCE_LOAD_CURL_SYMBOLS_LAZILY=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.5" "-DJUCE_APP_VERSION_HEX=0x70005" $(shell $(PKG_CONFIG) --cflags freetype2) -pthread -I../../JuceLibraryCode -I../../../Build -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_build_tools=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_LOG_ASSERTIONS=1" "-DJUCE_USE_CURL=1" "-DJUCE_LOAD_CURL_SYMBOLS_LAZILY=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.7" "-DJUCE_APP_VERSION_HEX=0x70007" $(shell $(PKG_CONFIG) --cflags freetype2) -pthread -I../../JuceLibraryCode -I../../../Build -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := Projucer @@ -60,7 +60,7 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_build_tools=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_LOG_ASSERTIONS=1" "-DJUCE_USE_CURL=1" "-DJUCE_LOAD_CURL_SYMBOLS_LAZILY=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.5" "-DJUCE_APP_VERSION_HEX=0x70005" $(shell $(PKG_CONFIG) --cflags freetype2) -pthread -I../../JuceLibraryCode -I../../../Build -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_build_tools=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_LOG_ASSERTIONS=1" "-DJUCE_USE_CURL=1" "-DJUCE_LOAD_CURL_SYMBOLS_LAZILY=1" "-DJUCE_ALLOW_STATIC_NULL_VARIABLES=0" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_WEB_BROWSER=0" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=7.0.7" "-DJUCE_APP_VERSION_HEX=0x70007" $(shell $(PKG_CONFIG) --cflags freetype2) -pthread -I../../JuceLibraryCode -I../../../Build -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_APP := Projucer @@ -135,305 +135,310 @@ OBJECTS_APP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } @$(PKG_CONFIG) --print-errors freetype2 @echo Linking "Projucer - App" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/jucer_NewProjectWizard_7817a7e4.o: ../../Source/Application/StartPage/jucer_NewProjectWizard.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_NewProjectWizard.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_StartPageComponent_de6b22ec.o: ../../Source/Application/StartPage/jucer_StartPageComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_StartPageComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_AutoUpdater_ca658dc2.o: ../../Source/Application/jucer_AutoUpdater.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_AutoUpdater.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_CommandLine_f35de107.o: ../../Source/Application/jucer_CommandLine.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_CommandLine.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_Main_f8488f5b.o: ../../Source/Application/jucer_Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_MainWindow_1e163aeb.o: ../../Source/Application/jucer_MainWindow.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_MainWindow.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_DocumentEditorComponent_bc853a2f.o: ../../Source/CodeEditor/jucer_DocumentEditorComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_DocumentEditorComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_OpenDocumentManager_ba866622.o: ../../Source/CodeEditor/jucer_OpenDocumentManager.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_OpenDocumentManager.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_SourceCodeEditor_55965985.o: ../../Source/CodeEditor/jucer_SourceCodeEditor.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_SourceCodeEditor.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ComponentTypeHandler_d7e70242.o: ../../Source/ComponentEditor/Components/jucer_ComponentTypeHandler.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ComponentTypeHandler.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ButtonDocument_b2cabdec.o: ../../Source/ComponentEditor/Documents/jucer_ButtonDocument.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ButtonDocument.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ComponentDocument_1d8c1063.o: ../../Source/ComponentEditor/Documents/jucer_ComponentDocument.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ComponentDocument.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ColouredElement_acb45c39.o: ../../Source/ComponentEditor/PaintElements/jucer_ColouredElement.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ColouredElement.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintElement_db652060.o: ../../Source/ComponentEditor/PaintElements/jucer_PaintElement.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintElement.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintElementGroup_256346c9.o: ../../Source/ComponentEditor/PaintElements/jucer_PaintElementGroup.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintElementGroup.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintElementImage_49702ba5.o: ../../Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintElementImage.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintElementPath_d1b280a5.o: ../../Source/ComponentEditor/PaintElements/jucer_PaintElementPath.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintElementPath.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ComponentLayoutEditor_4fc44b8d.o: ../../Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ComponentLayoutEditor.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ComponentOverlayComponent_5e028963.o: ../../Source/ComponentEditor/UI/jucer_ComponentOverlayComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ComponentOverlayComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_EditingPanelBase_28115dee.o: ../../Source/ComponentEditor/UI/jucer_EditingPanelBase.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_EditingPanelBase.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_JucerDocumentEditor_89371a26.o: ../../Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_JucerDocumentEditor.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintRoutineEditor_43fd8744.o: ../../Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintRoutineEditor.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintRoutinePanel_83779cd7.o: ../../Source/ComponentEditor/UI/jucer_PaintRoutinePanel.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintRoutinePanel.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ResourceEditorPanel_237eee2.o: ../../Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ResourceEditorPanel.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_TestComponent_1a4179c4.o: ../../Source/ComponentEditor/UI/jucer_TestComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_TestComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_BinaryResources_e0f99b46.o: ../../Source/ComponentEditor/jucer_BinaryResources.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_BinaryResources.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ComponentLayout_6ea00129.o: ../../Source/ComponentEditor/jucer_ComponentLayout.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ComponentLayout.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_GeneratedCode_9ca4ef7e.o: ../../Source/ComponentEditor/jucer_GeneratedCode.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_GeneratedCode.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_JucerDocument_ff8afcc2.o: ../../Source/ComponentEditor/jucer_JucerDocument.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_JucerDocument.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ObjectTypes_4406f01c.o: ../../Source/ComponentEditor/jucer_ObjectTypes.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ObjectTypes.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PaintRoutine_e1e891ee.o: ../../Source/ComponentEditor/jucer_PaintRoutine.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PaintRoutine.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_Modules_e20cbd10.o: ../../Source/Project/Modules/jucer_Modules.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_Modules.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_HeaderComponent_1ebf72ba.o: ../../Source/Project/UI/jucer_HeaderComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_HeaderComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_Project_c131864a.o: ../../Source/Project/jucer_Project.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_Project.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ProjectExporter_cf377b25.o: ../../Source/ProjectSaving/jucer_ProjectExporter.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ProjectExporter.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ProjectSaver_4276639b.o: ../../Source/ProjectSaving/jucer_ProjectSaver.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ProjectSaver.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ResourceFile_74b61849.o: ../../Source/ProjectSaving/jucer_ResourceFile.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ResourceFile.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_AppearanceSettings_fa5d736e.o: ../../Source/Settings/jucer_AppearanceSettings.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_AppearanceSettings.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_StoredSettings_c7168d2d.o: ../../Source/Settings/jucer_StoredSettings.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_StoredSettings.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_CodeHelpers_1e797672.o: ../../Source/Utility/Helpers/jucer_CodeHelpers.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_CodeHelpers.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_FileHelpers_54f12f83.o: ../../Source/Utility/Helpers/jucer_FileHelpers.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_FileHelpers.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_MiscUtilities_31fc8dd8.o: ../../Source/Utility/Helpers/jucer_MiscUtilities.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_MiscUtilities.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_NewFileWizard_b233dda1.o: ../../Source/Utility/Helpers/jucer_NewFileWizard.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_NewFileWizard.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_VersionInfo_46f3ed40.o: ../../Source/Utility/Helpers/jucer_VersionInfo.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_VersionInfo.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_PIPGenerator_fd3402c7.o: ../../Source/Utility/PIPs/jucer_PIPGenerator.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_PIPGenerator.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_Icons_d02d18f1.o: ../../Source/Utility/UI/jucer_Icons.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_Icons.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_JucerTreeViewBase_9b9f2ff0.o: ../../Source/Utility/UI/jucer_JucerTreeViewBase.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_JucerTreeViewBase.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_ProjucerLookAndFeel_3b20291d.o: ../../Source/Utility/UI/jucer_ProjucerLookAndFeel.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_ProjucerLookAndFeel.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/jucer_SlidingPanelComponent_4e7dc07e.o: ../../Source/Utility/UI/jucer_SlidingPanelComponent.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling jucer_SlidingPanelComponent.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/BinaryData_ce4232d4.o: ../../JuceLibraryCode/BinaryData.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling BinaryData.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_build_tools_f5069398.o: ../../JuceLibraryCode/include_juce_build_tools.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_build_tools.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o: ../../JuceLibraryCode/include_juce_cryptography.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_cryptography.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning Projucer $(V_AT)$(CLEANCMD) diff --git a/extras/Projucer/Builds/MacOSX/Info-App.plist b/extras/Projucer/Builds/MacOSX/Info-App.plist index 82442e0f434f..618a6773b018 100644 --- a/extras/Projucer/Builds/MacOSX/Info-App.plist +++ b/extras/Projucer/Builds/MacOSX/Info-App.plist @@ -22,9 +22,9 @@ CFBundleSignature ???? CFBundleShortVersionString - 7.0.5 + 7.0.7 CFBundleVersion - 7.0.5 + 7.0.7 NSHumanReadableCopyright Raw Material Software Limited NSHighResolutionCapable diff --git a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj index 68b0ed3a9c71..1712768f9660 100644 --- a/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj +++ b/extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 4E6DC4778D583C48C3CCD4DC /* jucer_ResourceFile.cpp */ = {isa = PBXBuildFile; fileRef = E13A54A6D3A1895EACE53E51; }; 4FAAB649E846BA2764C02ACE /* jucer_PaintElementImage.cpp */ = {isa = PBXBuildFile; fileRef = 72ED72174F9DBD0ABD8AFCED; }; 537ABF1DB09DDBD1542A2B0C /* jucer_ComponentLayoutEditor.cpp */ = {isa = PBXBuildFile; fileRef = EF25A29A2194FC107B40F65F; }; + 54C391DB9AC4AFABD2EFFD7E /* Security.framework */ = {isa = PBXBuildFile; fileRef = 4E410AEB132B44674291105A; }; 5DD883699B85E4C492CAD065 /* include_juce_core.mm */ = {isa = PBXBuildFile; fileRef = DB9C8E35DF815B803CB4A9CF; }; 638C7247B6DBA67EFE46E124 /* jucer_PIPGenerator.cpp */ = {isa = PBXBuildFile; fileRef = 191330B20DAC08B890656EA0; }; 63D97E01F2C4C91037CB65BD /* jucer_TestComponent.cpp */ = {isa = PBXBuildFile; fileRef = 24EB4C2412821B8019D6F754; }; @@ -148,6 +149,7 @@ 35CFCC15CBA46F4513940A2A /* jucer_TextButtonHandler.h */ /* jucer_TextButtonHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_TextButtonHandler.h; path = ../../Source/ComponentEditor/Components/jucer_TextButtonHandler.h; sourceTree = SOURCE_ROOT; }; 364D1A9B113320407A7E57B9 /* JuceHeader.h */ /* JuceHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = SOURCE_ROOT; }; 36E5FBF64A89D5F2A266A5A7 /* jucer_PaintElementUndoableAction.h */ /* jucer_PaintElementUndoableAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_PaintElementUndoableAction.h; path = ../../Source/ComponentEditor/PaintElements/jucer_PaintElementUndoableAction.h; sourceTree = SOURCE_ROOT; }; + 37C52FDE069922DFD4A938C8 /* juce_LinuxSubprocessHelper.cpp */ /* juce_LinuxSubprocessHelper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_LinuxSubprocessHelper.cpp; path = ../../../Build/CMake/juce_LinuxSubprocessHelper.cpp; sourceTree = SOURCE_ROOT; }; 39597BD78897CB711AFA945A /* jucer_EditingPanelBase.h */ /* jucer_EditingPanelBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_EditingPanelBase.h; path = ../../Source/ComponentEditor/UI/jucer_EditingPanelBase.h; sourceTree = SOURCE_ROOT; }; 3D36F0CEB84B27BD02FC461A /* jucer_LabelPropertyComponent.h */ /* jucer_LabelPropertyComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_LabelPropertyComponent.h; path = ../../Source/Utility/UI/PropertyComponents/jucer_LabelPropertyComponent.h; sourceTree = SOURCE_ROOT; }; 3D6FD9C0065BF16568EC0AB7 /* jucer_SlidingPanelComponent.h */ /* jucer_SlidingPanelComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_SlidingPanelComponent.h; path = ../../Source/Utility/UI/jucer_SlidingPanelComponent.h; sourceTree = SOURCE_ROOT; }; @@ -167,6 +169,7 @@ 4AE72953E3B3DF06D3B9BA86 /* jucer_PaintElementPath.cpp */ /* jucer_PaintElementPath.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_PaintElementPath.cpp; path = ../../Source/ComponentEditor/PaintElements/jucer_PaintElementPath.cpp; sourceTree = SOURCE_ROOT; }; 4D5F0CA8D1273144681A1D48 /* jucer_JucerTreeViewBase.cpp */ /* jucer_JucerTreeViewBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_JucerTreeViewBase.cpp; path = ../../Source/Utility/UI/jucer_JucerTreeViewBase.cpp; sourceTree = SOURCE_ROOT; }; 4D698BF12BCD6B0896BCDF17 /* jucer_AutoUpdater.h */ /* jucer_AutoUpdater.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_AutoUpdater.h; path = ../../Source/Application/jucer_AutoUpdater.h; sourceTree = SOURCE_ROOT; }; + 4E410AEB132B44674291105A /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 4E671236FDBD5AD4699740C6 /* jucer_JucerCommandIDs.h */ /* jucer_JucerCommandIDs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_JucerCommandIDs.h; path = ../../Source/ComponentEditor/UI/jucer_JucerCommandIDs.h; sourceTree = SOURCE_ROOT; }; 4ECF029E3A69BF42FED1503D /* jucer_PIPAudioProcessorTemplate.h */ /* jucer_PIPAudioProcessorTemplate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_PIPAudioProcessorTemplate.h; path = ../../Source/BinaryData/Templates/jucer_PIPAudioProcessorTemplate.h; sourceTree = SOURCE_ROOT; }; 4F687965FBE86EAFDB3ACFEC /* BinaryData.h */ /* BinaryData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BinaryData.h; path = ../../JuceLibraryCode/BinaryData.h; sourceTree = SOURCE_ROOT; }; @@ -374,6 +377,7 @@ FA790C59A304579F660F112F /* jucer_ProjectExport_CodeBlocks.h */ /* jucer_ProjectExport_CodeBlocks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_ProjectExport_CodeBlocks.h; path = ../../Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h; sourceTree = SOURCE_ROOT; }; FB80347407261BF6CCEFDE91 /* jucer_ComponentTemplate.cpp */ /* jucer_ComponentTemplate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_ComponentTemplate.cpp; path = ../../Source/BinaryData/Templates/jucer_ComponentTemplate.cpp; sourceTree = SOURCE_ROOT; }; FCEBE24EA79A13713D7CBF26 /* jucer_ComponentColourProperty.h */ /* jucer_ComponentColourProperty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_ComponentColourProperty.h; path = ../../Source/ComponentEditor/Properties/jucer_ComponentColourProperty.h; sourceTree = SOURCE_ROOT; }; + FD6A6FA8BDBDDD441BCD33F9 /* juce_SimpleBinaryBuilder.cpp */ /* juce_SimpleBinaryBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_SimpleBinaryBuilder.cpp; path = ../../Source/BinaryData/juce_SimpleBinaryBuilder.cpp; sourceTree = SOURCE_ROOT; }; FD7885911A317D73E98D49B3 /* jucer_NewProjectWizard.h */ /* jucer_NewProjectWizard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_NewProjectWizard.h; path = ../../Source/Application/StartPage/jucer_NewProjectWizard.h; sourceTree = SOURCE_ROOT; }; FDABEE6B64546586368A4729 /* jucer_AvailableModulesList.h */ /* jucer_AvailableModulesList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_AvailableModulesList.h; path = ../../Source/Project/Modules/jucer_AvailableModulesList.h; sourceTree = SOURCE_ROOT; }; FE20FE5805A02A4843048200 /* jucer_ProjucerLookAndFeel.h */ /* jucer_ProjucerLookAndFeel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_ProjucerLookAndFeel.h; path = ../../Source/Utility/UI/jucer_ProjucerLookAndFeel.h; sourceTree = SOURCE_ROOT; }; @@ -401,6 +405,7 @@ CDEF9FF2D119476D707305DF, 96EC6315E1B3F1A109F84BAF, 11D42F7EC6E6539D79A7F4B1, + 54C391DB9AC4AFABD2EFFD7E, B980464FA2761CCD64B1FAD6, ); runOnlyForDeploymentPostprocessing = 0; @@ -452,6 +457,7 @@ 431D30038CBF67F80E8B3A13, 9F01BA9942D038EA8B5289A8, E5D6C36496F5BC84D7213BE8, + 4E410AEB132B44674291105A, CF6C8BD0DA3D8CD4E99EBADA, ); name = Frameworks; @@ -862,6 +868,8 @@ 41105E536155E394E54BDD35, 5F6584B675E30761521A9F42, C5A1549AD0C20CF42C1FE630, + 37C52FDE069922DFD4A938C8, + FD6A6FA8BDBDDD441BCD33F9, ); name = BinaryData; sourceTree = ""; @@ -1132,7 +1140,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_build_tools=1", "JUCE_MODULE_AVAILABLE_juce_core=1", "JUCE_MODULE_AVAILABLE_juce_cryptography=1", @@ -1150,8 +1158,8 @@ "JUCE_WEB_BROWSER=0", "JUCE_STANDALONE_APPLICATION=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -1173,8 +1181,8 @@ INSTALL_PATH = "$(HOME)/Applications"; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../Build $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.juce.theprojucer; PRODUCT_NAME = "Projucer"; @@ -1201,7 +1209,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_build_tools=1", "JUCE_MODULE_AVAILABLE_juce_core=1", "JUCE_MODULE_AVAILABLE_juce_cryptography=1", @@ -1219,8 +1227,8 @@ "JUCE_WEB_BROWSER=0", "JUCE_STANDALONE_APPLICATION=1", "JUCER_XCODE_MAC_F6D2F4CF=1", - "JUCE_APP_VERSION=7.0.5", - "JUCE_APP_VERSION_HEX=0x70005", + "JUCE_APP_VERSION=7.0.7", + "JUCE_APP_VERSION_HEX=0x70007", "JucePlugin_Build_VST=0", "JucePlugin_Build_VST3=0", "JucePlugin_Build_AU=0", @@ -1242,8 +1250,8 @@ INSTALL_PATH = "$(HOME)/Applications"; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../Build $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.juce.theprojucer; PRODUCT_NAME = "Projucer"; diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj index eaab8066a712..5811a9fc2b39 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebug true NotUsing @@ -79,7 +79,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -107,7 +107,7 @@ Full ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -196,6 +196,12 @@ true + + true + + + true + @@ -356,6 +362,9 @@ true + + true + true @@ -368,6 +377,9 @@ true + + true + true @@ -377,67 +389,73 @@ true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -656,6 +674,9 @@ true + + true + true @@ -680,19 +701,19 @@ true - + true - + true - + true - + true - + true @@ -971,40 +992,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1076,6 +1097,9 @@ true + + true + true @@ -1148,6 +1172,9 @@ true + + true + true @@ -1271,52 +1298,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + + true + + true @@ -1418,9 +1472,18 @@ true + + true + + + true + true + + true + true @@ -1430,7 +1493,7 @@ true - + true @@ -1487,43 +1550,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1728,6 +1791,7 @@ + @@ -1770,20 +1834,22 @@ + - - - - - - - - + + + + + + + + + @@ -1881,6 +1947,7 @@ + @@ -1894,12 +1961,13 @@ - - - + + + + + - - + @@ -1956,10 +2024,10 @@ - - + + + - @@ -1995,6 +2063,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -2025,6 +2113,7 @@ + @@ -2070,36 +2159,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -2137,10 +2227,12 @@ + - + + @@ -2168,7 +2260,7 @@ - + diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters index c01b7709240e..259ebdcaca09 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters @@ -248,6 +248,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -275,9 +278,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -388,6 +388,12 @@ Projucer\BinaryData + + Projucer\BinaryData + + + Projucer\BinaryData + Projucer\CodeEditor @@ -634,6 +640,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -646,6 +655,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -655,82 +667,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -958,6 +976,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -982,25 +1003,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -1282,46 +1303,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -1396,6 +1417,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -1468,6 +1492,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -1591,85 +1618,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -1771,9 +1837,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -1783,7 +1858,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -1843,55 +1918,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -2487,6 +2562,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -2613,6 +2691,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -2628,31 +2709,34 @@ JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2946,6 +3030,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2985,22 +3072,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -3171,16 +3261,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -3288,6 +3378,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -3378,6 +3528,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -3513,9 +3666,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -3525,82 +3675,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native @@ -3714,6 +3870,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3723,7 +3882,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -3807,7 +3969,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native diff --git a/extras/Projucer/Builds/VisualStudio2017/resources.rc b/extras/Projucer/Builds/VisualStudio2017/resources.rc index 9fdaf3939892..76a268333a13 100644 --- a/extras/Projucer/Builds/VisualStudio2017/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2017/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Raw Material Software Limited\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj index 5563032f1c94..729d6b8d59a5 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebug true NotUsing @@ -79,7 +79,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -107,7 +107,7 @@ Full ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -196,6 +196,12 @@ true + + true + + + true + @@ -356,6 +362,9 @@ true + + true + true @@ -368,6 +377,9 @@ true + + true + true @@ -377,67 +389,73 @@ true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -656,6 +674,9 @@ true + + true + true @@ -680,19 +701,19 @@ true - + true - + true - + true - + true - + true @@ -971,40 +992,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1076,6 +1097,9 @@ true + + true + true @@ -1148,6 +1172,9 @@ true + + true + true @@ -1271,52 +1298,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + + true + + true @@ -1418,9 +1472,18 @@ true + + true + + + true + true + + true + true @@ -1430,7 +1493,7 @@ true - + true @@ -1487,43 +1550,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1728,6 +1791,7 @@ + @@ -1770,20 +1834,22 @@ + - - - - - - - - + + + + + + + + + @@ -1881,6 +1947,7 @@ + @@ -1894,12 +1961,13 @@ - - - + + + + + - - + @@ -1956,10 +2024,10 @@ - - + + + - @@ -1995,6 +2063,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -2025,6 +2113,7 @@ + @@ -2070,36 +2159,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -2137,10 +2227,12 @@ + - + + @@ -2168,7 +2260,7 @@ - + diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters index bf82efb3dc3b..4a976f83769b 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters @@ -248,6 +248,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -275,9 +278,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -388,6 +388,12 @@ Projucer\BinaryData + + Projucer\BinaryData + + + Projucer\BinaryData + Projucer\CodeEditor @@ -634,6 +640,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -646,6 +655,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -655,82 +667,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -958,6 +976,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -982,25 +1003,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -1282,46 +1303,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -1396,6 +1417,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -1468,6 +1492,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -1591,85 +1618,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -1771,9 +1837,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -1783,7 +1858,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -1843,55 +1918,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -2487,6 +2562,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -2613,6 +2691,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -2628,31 +2709,34 @@ JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2946,6 +3030,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2985,22 +3072,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -3171,16 +3261,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -3288,6 +3378,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -3378,6 +3528,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -3513,9 +3666,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -3525,82 +3675,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native @@ -3714,6 +3870,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3723,7 +3882,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -3807,7 +3969,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native diff --git a/extras/Projucer/Builds/VisualStudio2019/resources.rc b/extras/Projucer/Builds/VisualStudio2019/resources.rc index 9fdaf3939892..76a268333a13 100644 --- a/extras/Projucer/Builds/VisualStudio2019/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2019/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Raw Material Software Limited\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj index a6b64ae1921d..f1afb08ede81 100644 --- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebug true NotUsing @@ -79,7 +79,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -107,7 +107,7 @@ Full ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreaded true NotUsing @@ -122,7 +122,7 @@ ..\..\JuceLibraryCode;..\..\..\Build;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.5;JUCE_APP_VERSION_HEX=0x70005;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_build_tools=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_LOG_ASSERTIONS=1;JUCE_USE_CURL=1;JUCE_LOAD_CURL_SYMBOLS_LAZILY=1;JUCE_ALLOW_STATIC_NULL_VARIABLES=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_WEB_BROWSER=0;JUCE_STANDALONE_APPLICATION=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=7.0.7;JUCE_APP_VERSION_HEX=0x70007;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\Projucer.exe @@ -196,6 +196,12 @@ true + + true + + + true + @@ -356,6 +362,9 @@ true + + true + true @@ -368,6 +377,9 @@ true + + true + true @@ -377,67 +389,73 @@ true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -656,6 +674,9 @@ true + + true + true @@ -680,19 +701,19 @@ true - + true - + true - + true - + true - + true @@ -971,40 +992,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1076,6 +1097,9 @@ true + + true + true @@ -1148,6 +1172,9 @@ true + + true + true @@ -1271,52 +1298,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + + true + + true @@ -1418,9 +1472,18 @@ true + + true + + + true + true + + true + true @@ -1430,7 +1493,7 @@ true - + true @@ -1487,43 +1550,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1728,6 +1791,7 @@ + @@ -1770,20 +1834,22 @@ + - - - - - - - - + + + + + + + + + @@ -1881,6 +1947,7 @@ + @@ -1894,12 +1961,13 @@ - - - + + + + + - - + @@ -1956,10 +2024,10 @@ - - + + + - @@ -1995,6 +2063,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -2025,6 +2113,7 @@ + @@ -2070,36 +2159,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -2137,10 +2227,12 @@ + - + + @@ -2168,7 +2260,7 @@ - + diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters index 3e3eb44572be..663fe31f3539 100644 --- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters @@ -248,6 +248,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -275,9 +278,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -388,6 +388,12 @@ Projucer\BinaryData + + Projucer\BinaryData + + + Projucer\BinaryData + Projucer\CodeEditor @@ -634,6 +640,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -646,6 +655,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -655,82 +667,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -958,6 +976,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -982,25 +1003,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -1282,46 +1303,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -1396,6 +1417,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -1468,6 +1492,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -1591,85 +1618,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -1771,9 +1837,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -1783,7 +1858,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -1843,55 +1918,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -2487,6 +2562,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -2613,6 +2691,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -2628,31 +2709,34 @@ JUCE Modules\juce_core\misc - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2946,6 +3030,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2985,22 +3072,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -3171,16 +3261,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -3288,6 +3378,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -3378,6 +3528,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -3513,9 +3666,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -3525,82 +3675,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native @@ -3714,6 +3870,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -3723,7 +3882,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -3807,7 +3969,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native diff --git a/extras/Projucer/Builds/VisualStudio2022/resources.rc b/extras/Projucer/Builds/VisualStudio2022/resources.rc index 9fdaf3939892..76a268333a13 100644 --- a/extras/Projucer/Builds/VisualStudio2022/resources.rc +++ b/extras/Projucer/Builds/VisualStudio2022/resources.rc @@ -9,7 +9,7 @@ #include VS_VERSION_INFO VERSIONINFO -FILEVERSION 7,0,5,0 +FILEVERSION 7,0,7,0 BEGIN BLOCK "StringFileInfo" BEGIN @@ -18,9 +18,9 @@ BEGIN VALUE "CompanyName", "Raw Material Software Limited\0" VALUE "LegalCopyright", "Raw Material Software Limited\0" VALUE "FileDescription", "Projucer\0" - VALUE "FileVersion", "7.0.5\0" + VALUE "FileVersion", "7.0.7\0" VALUE "ProductName", "Projucer\0" - VALUE "ProductVersion", "7.0.5\0" + VALUE "ProductVersion", "7.0.7\0" END END diff --git a/extras/Projucer/CMakeLists.txt b/extras/Projucer/CMakeLists.txt index 012eda673f22..c790f0626833 100644 --- a/extras/Projucer/CMakeLists.txt +++ b/extras/Projucer/CMakeLists.txt @@ -147,6 +147,7 @@ juce_add_binary_data(ProjucerData SOURCES Source/BinaryData/gradle/gradle-wrapper.jar Source/BinaryData/gradle/gradlew Source/BinaryData/gradle/gradlew.bat + Source/BinaryData/juce_SimpleBinaryBuilder.cpp ../Build/CMake/JuceLV2Defines.h.in ../Build/CMake/LaunchScreen.storyboard @@ -156,7 +157,8 @@ juce_add_binary_data(ProjucerData SOURCES ../Build/CMake/PIPConsole.cpp.in ../Build/CMake/RecentFilesMenuTemplate.nib ../Build/CMake/UnityPluginGUIScript.cs.in - ../Build/CMake/juce_runtime_arch_detection.cpp) + ../Build/CMake/juce_runtime_arch_detection.cpp + ../Build/CMake/juce_LinuxSubprocessHelper.cpp) target_link_libraries(Projucer PRIVATE ProjucerData diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.cpp b/extras/Projucer/JuceLibraryCode/BinaryData.cpp index 17e72df1eea9..d76dd25fb081 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.cpp +++ b/extras/Projucer/JuceLibraryCode/BinaryData.cpp @@ -8513,6 +8513,433 @@ static const unsigned char temp_binary_data_65[] = const char* juce_runtime_arch_detection_cpp = (const char*) temp_binary_data_65; +//================== juce_LinuxSubprocessHelper.cpp ================== +static const unsigned char temp_binary_data_66[] = +"/*\r\n" +" ==============================================================================\r\n" +"\r\n" +" This file is part of the JUCE library.\r\n" +" Copyright (c) 2022 - Raw Material Software Limited\r\n" +"\r\n" +" JUCE is an open source library subject to commercial or open-source\r\n" +" licensing.\r\n" +"\r\n" +" By using JUCE, you agree to the terms of both the JUCE 7 End-User License\r\n" +" Agreement and JUCE Privacy Policy.\r\n" +"\r\n" +" End User License Agreement: www.juce.com/juce-7-licence\r\n" +" Privacy Policy: www.juce.com/juce-privacy-policy\r\n" +"\r\n" +" Or: You may also use this code under the terms of the GPL v3 (see\r\n" +" www.gnu.org/licenses).\r\n" +"\r\n" +" JUCE IS PROVIDED \"AS IS\" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER\r\n" +" EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE\r\n" +" DISCLAIMED.\r\n" +"\r\n" +" ==============================================================================\r\n" +"*/\r\n" +"\r\n" +"#include \r\n" +"\r\n" +"int main (int argc, const char* const* argv)\r\n" +"{\r\n" +" if (argc >= 3)\r\n" +" if (auto* handle = dlopen (argv[1], RTLD_LAZY))\r\n" +" if (auto* function = reinterpret_cast (dlsym (handle, argv[2])))\r\n" +" return function (argc - 3, argv + 3);\r\n" +"\r\n" +" return 1;\r\n" +"}\r\n"; + +const char* juce_LinuxSubprocessHelper_cpp = (const char*) temp_binary_data_66; + +//================== juce_SimpleBinaryBuilder.cpp ================== +static const unsigned char temp_binary_data_67[] = +"/*\r\n" +" ==============================================================================\r\n" +"\r\n" +" This file is part of the JUCE library.\r\n" +" Copyright (c) 2022 - Raw Material Software Limited\r\n" +"\r\n" +" JUCE is an open source library subject to commercial or open-source\r\n" +" licensing.\r\n" +"\r\n" +" By using JUCE, you agree to the terms of both the JUCE 7 End-User License\r\n" +" Agreement and JUCE Privacy Policy.\r\n" +"\r\n" +" End User License Agreement: www.juce.com/juce-7-licence\r\n" +" Privacy Policy: www.juce.com/juce-privacy-policy\r\n" +"\r\n" +" Or: You may also use this code under the terms of the GPL v3 (see\r\n" +" www.gnu.org/licenses).\r\n" +"\r\n" +" JUCE IS PROVIDED \"AS IS\" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER\r\n" +" EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE\r\n" +" DISCLAIMED.\r\n" +"\r\n" +" ==============================================================================\r\n" +"*/\r\n" +"\r\n" +"#include \r\n" +"#include \r\n" +"\r\n" +"#include \r\n" +"#include \r\n" +"#include \r\n" +"#include \r\n" +"#include \r\n" +"#include \r\n" +"#include \r\n" +"\r\n" +"//==============================================================================\r\n" +"struct FileHelpers\r\n" +"{\r\n" +" static std::string getCurrentWorkingDirectory()\r\n" +" {\r\n" +" std::vector buffer (1024);\r\n" +"\r\n" +" while (getcwd (buffer.data(), buffer.size() - 1) == nullptr && errno == ERANGE)\r\n" +" buffer.resize (buffer.size() * 2 / 3);\r\n" +"\r\n" +" return { buffer.data() };\r\n" +" }\r\n" +"\r\n" +" static bool endsWith (const std::string& s, char c)\r\n" +" {\r\n" +" if (s.length() == 0)\r\n" +" return false;\r\n" +"\r\n" +" return *s.rbegin() == c;\r\n" +" }\r\n" +"\r\n" +" static std::string appendedPaths (const std::string& first, const std::string& second)\r\n" +" {\r\n" +" return endsWith (first, '/') ? first + second : first + \"/\" + second;\r\n" +" }\r\n" +"\r\n" +" static bool exists (const std::string& path)\r\n" +" {\r\n" +" return ! path.empty() && access (path.c_str(), F_OK) == 0;\r\n" +" }\r\n" +"\r\n" +" static bool deleteFile (const std::string& path)\r\n" +" {\r\n" +" if (! exists (path))\r\n" +" return true;\r\n" +"\r\n" +" return remove (path.c_str()) == 0;\r\n" +" }\r\n" +"\r\n" +" static std::string getFilename (const std::string& path)\r\n" +" {\r\n" +" return { std::find_if (path.rbegin(), path.rend(), [] (auto c) { return c == '/'; }).base(),\r\n" +" path.end() };\r\n" +" }\r\n" +"\r\n" +" static bool isDirectory (const std::string& path)\r\n" +" {\r\n" +" #if defined (__FreeBSD__) || defined (__OpenBSD__)\r\n" +" #define JUCE_STAT stat\r\n" +" #else\r\n" +" #define JUCE_STAT stat64\r\n" +" #endif\r\n" +"\r\n" +" struct JUCE_STAT info;\r\n" +"\r\n" +" return ! path.empty()\r\n" +" && JUCE_STAT (path.c_str(), &info) == 0\r\n" +" && ((info.st_mode & S_IFDIR) != 0);\r\n" +" }\r\n" +"\r\n" +" static std::string getParentDirectory (const std::string& path)\r\n" +" {\r\n" +" std::string p { path.begin(),\r\n" +" std::find_if (path.rbegin(),\r\n" +" path.rend(),\r\n" +" [] (auto c) { return c == '/'; }).base() };\r\n" +"\r\n" +" // Trim the ending slash, but only if not root\r\n" +" if (endsWith (p, '/') && p.length() > 1)\r\n" +" return { p.begin(), p.end() - 1 };\r\n" +"\r\n" +" return p;\r\n" +" }\r\n" +"\r\n" +" static bool createDirectory (const std::string& path)\r\n" +" {\r\n" +" if (isDirectory (path))\r\n" +" return true;\r\n" +"\r\n" +" const auto parentDir = getParentDirectory (path);\r\n" +"\r\n" +" if (path == parentDir)\r\n" +" return false;\r\n" +"\r\n" +" if (createDirectory (parentDir))\r\n" +" return mkdir (path.c_str(), 0777) != -1;\r\n" +"\r\n" +" return false;\r\n" +" }\r\n" +"};\r\n" +"\r\n" +"//==============================================================================\r\n" +"struct StringHelpers\r\n" +"{\r\n" +" static bool isQuoteCharacter (char c)\r\n" +" {\r\n" +" return c == '\"' || c == '\\'';\r\n" +" }\r\n" +"\r\n" +" static std::string unquoted (const std::string& str)\r\n" +" {\r\n" +" if (str.length() == 0 || (! isQuoteCharacter (str[0])))\r\n" +" return str;\r\n" +"\r\n" +" return str.substr (1, str.length() - (isQuoteCharacter (str[str.length() - 1]) ? 1 : 0));\r\n" +" }\r\n" +"\r\n" +" static void ltrim (std::string& s)\r\n" +" {\r\n" +" s.erase (s.begin(), std::find_if (s.begin(), s.end(), [] (int c) { return ! std::isspace (c); }));\r\n" +" }\r\n" +"\r\n" +" static void rtrim (std::string& s)\r\n" +" {\r\n" +" s.erase (std::find_if (s.rbegin(), s.rend(), [] (int c) { return ! std::isspace (c); }).base(), s.end());\r\n" +" }\r\n" +"\r\n" +" static std::string trimmed (const std::string& str)\r\n" +" {\r\n" +" auto result = str;\r\n" +" ltrim (result);\r\n" +" rtrim (result);\r\n" +" return result;\r\n" +" }\r\n" +"\r\n" +" static std::string replaced (const std::string& str, char charToReplace, char replaceWith)\r\n" +" {\r\n" +" auto result = str;\r\n" +" std::replace (result.begin(), result.end(), charToReplace, replaceWith);\r\n" +" return result;\r\n" +" }\r\n" +"};\r\n" +"\r\n" +"//==============================================================================\r\n" +"static bool addFile (const std::string& filePath,\r\n" +" const std::string& binaryNamespace,\r\n" +" std::ofstream& headerStream,\r\n" +" std::ofstream& cppStream,\r\n" +" bool verbose)\r\n" +"{\r\n" +" std::ifstream fileStream (filePath, std::ios::in | std::ios::binary | std::ios::ate);\r\n" +"\r\n" +" if (! fileStream.is_open())\r\n" +" {\r\n" +" std::cerr << \"Failed to open input file \" << filePath << std::endl;\r\n" +" return false;\r\n" +" }\r\n" +"\r\n" +" std::vector buffer ((size_t) fileStream.tellg());\r\n" +" fileStream.seekg (0);\r\n" +" fileStream.read (buffer.data(), static_cast (buffer.size()));\r\n" +"\r\n" +" const auto variableName = StringHelpers::replaced (StringHelpers::replaced (FileHelpers::getFilename (filePath),\r\n" +" ' ',\r\n" +" '_'),\r\n" +" '.',\r\n" +" '_');\r\n" +"\r\n" +" if (verbose)\r\n" +" {\r\n" +" std::cout << \"Adding \" << variableName << \": \"\r\n" +" << buffer.size() << \" bytes\" << std::endl;\r\n" +" }\r\n" +"\r\n" +" headerStream << \" extern const char* \" << variableName << \";\" << std::endl\r\n" +" << \" const int \" << variableName << \"Size = \"\r\n" +" << buffer.size() << \";\" << std::endl;\r\n" +"\r\n" +" cppStream << \"static const unsigned char temp0[] = {\";\r\n" +"\r\n" +" auto* data = (const uint8_t*) buffer.data();\r\n" +"\r\n" +" for (size_t i = 0; i < buffer.size() - 1; ++i)\r\n" +" {\r\n" +" cppStream << (int) data[i] << \",\";\r\n" +"\r\n" +" if ((i % 40) == 39)\r\n" +" cppStream << std::endl << \" \";\r\n" +" }\r\n" +"\r\n" +" cppStream << (int) data[buffer.size() - 1] << \",0,0};\" << std::endl;\r\n" +" cppStream << \"const char* \" << binaryNamespace << \"::\" << variableName\r\n" +" << \" = (const char*) temp0\" << \";\" << std::endl << std::endl;\r\n" +"\r\n" +" return true;\r\n" +"}\r\n" +"\r\n" +"//==============================================================================\r\n" +"class Arguments\r\n" +"{\r\n" +"public:\r\n" +" enum class PositionalArguments\r\n" +" {\r\n" +" sourceFile = 0,\r\n" +" targetDirectory,\r\n" +" targetFilename,\r\n" +" binaryNamespace\r\n" +" };\r\n" +"\r\n" +" static std::optional create (int argc, char* argv[])\r\n" +" {\r\n" +" std::vector arguments;\r\n" +" bool verbose = false;\r\n" +"\r\n" +" for (int i = 1; i < argc; ++i)\r\n" +" {\r\n" +" std::string arg { argv[i] };\r\n" +"\r\n" +" if (arg == \"-v\" || arg == \"--verbose\")\r\n" +" verbose = true;\r\n" +" else\r\n" +" arguments.emplace_back (std::move (arg));\r\n" +" }\r\n" +"\r\n" +" if (arguments.size() != static_cast (PositionalArguments::binaryNamespace) + 1)\r\n" +" return std::nullopt;\r\n" +"\r\n" +" return Arguments { std::move (arguments), verbose };\r\n" +" }\r\n" +"\r\n" +" std::string get (PositionalArguments argument) const\r\n" +" {\r\n" +" return arguments[static_cast (argument)];\r\n" +" }\r\n" +"\r\n" +" bool isVerbose() const\r\n" +" {\r\n" +" return verbose;\r\n" +" }\r\n" +"\r\n" +"private:\r\n" +" Arguments (std::vector args, bool verboseIn)\r\n" +" : arguments (std::move (args)), verbose (verboseIn)\r\n" +" {\r\n" +" }\r\n" +"\r\n" +" std::vector arguments;\r\n" +" bool verbose = false;\r\n" +"};\r\n" +"\r\n" +"//==============================================================================\r\n" +"int main (int argc, char* argv[])\r\n" +"{\r\n" +" const auto arguments = Arguments::create (argc, argv);\r\n" +"\r\n" +" if (! arguments.has_value())\r\n" +" {\r\n" +" std::cout << \" Usage: SimpleBinaryBuilder [-v | --verbose] sourcefile targetdirectory targetfilename namespace\"\r\n" +" << std::endl << std::endl\r\n" +" << \" SimpleBinaryBuilder will encode the provided source file into\" << std::endl\r\n" +" << \" two files called (targetfilename).cpp and (targetfilename).h,\" << std::endl\r\n" +" << \" which it will write into the specified target directory.\" << std::endl\r\n" +" << \" The target directory will be automatically created if necessary. The binary\" << std::endl\r\n" +" << \" resource will be available in the given namespace.\" << std::endl << std::endl;\r\n" +"\r\n" +" return 0;\r\n" +" }\r\n" +"\r\n" +" const auto currentWorkingDirectory = FileHelpers::getCurrentWorkingDirectory();\r\n" +"\r\n" +" using ArgType = Arguments::PositionalArguments;\r\n" +"\r\n" +" const auto sourceFile = FileHelpers::appendedPaths (currentWorkingDirectory,\r\n" +" StringHelpers::unquoted (arguments->get (ArgType::sourceFile)));\r\n" +"\r\n" +" if (! FileHelpers::exists (sourceFile))\r\n" +" {\r\n" +" std::cerr << \"Source file doesn't exist: \"\r\n" +" << sourceFile\r\n" +" << std::endl << std::endl;\r\n" +"\r\n" +" return 1;\r\n" +" }\r\n" +"\r\n" +" const auto targetDirectory = FileHelpers::appendedPaths (currentWorkingDirectory,\r\n" +" StringHelpers::unquoted (arguments->get (ArgType::targetDirectory)));\r\n" +"\r\n" +" if (! FileHelpers::exists (targetDirectory))\r\n" +" {\r\n" +" if (! FileHelpers::createDirectory (targetDirectory))\r\n" +" {\r\n" +" std::cerr << \"Failed to create target directory: \" << targetDirectory << std::endl;\r\n" +" return 1;\r\n" +" }\r\n" +" }\r\n" +"\r\n" +" const auto className = StringHelpers::trimmed (arguments->get (ArgType::targetFilename));\r\n" +" const auto binaryNamespace = StringHelpers::trimmed (arguments->get (ArgType::binaryNamespace));\r\n" +"\r\n" +" const auto headerFilePath = FileHelpers::appendedPaths (targetDirectory, className + \".h\");\r\n" +" const auto cppFilePath = FileHelpers::appendedPaths (targetDirectory, className + \".cpp\");\r\n" +"\r\n" +" if (arguments->isVerbose())\r\n" +" {\r\n" +" std::cout << \"Creating \" << headerFilePath\r\n" +" << \" and \" << cppFilePath\r\n" +" << \" from file \" << sourceFile\r\n" +" << \"...\" << std::endl << std::endl;\r\n" +" }\r\n" +"\r\n" +" if (! FileHelpers::deleteFile (headerFilePath))\r\n" +" {\r\n" +" std::cerr << \"Failed to remove old header file: \" << headerFilePath << std::endl;\r\n" +" return 1;\r\n" +" }\r\n" +"\r\n" +" if (! FileHelpers::deleteFile (cppFilePath))\r\n" +" {\r\n" +" std::cerr << \"Failed to remove old source file: \" << cppFilePath << std::endl;\r\n" +" return 1;\r\n" +" }\r\n" +"\r\n" +" std::ofstream header (headerFilePath);\r\n" +"\r\n" +" if (! header.is_open())\r\n" +" {\r\n" +" std::cerr << \"Failed to open \" << headerFilePath << std::endl;\r\n" +"\r\n" +" return 1;\r\n" +" }\r\n" +"\r\n" +" std::ofstream cpp (cppFilePath);\r\n" +"\r\n" +" if (! cpp.is_open())\r\n" +" {\r\n" +" std::cerr << \"Failed to open \" << headerFilePath << std::endl;\r\n" +"\r\n" +" return 1;\r\n" +" }\r\n" +"\r\n" +" header << \"/* (Auto-generated binary data file). */\" << std::endl << std::endl\r\n" +" << \"#pragma once\" << std::endl << std::endl\r\n" +" << \"namespace \" << binaryNamespace << std::endl\r\n" +" << \"{\" << std::endl;\r\n" +"\r\n" +" cpp << \"/* (Auto-generated binary data file). */\" << std::endl << std::endl\r\n" +" << \"#include \" << std::quoted (className + \".h\") << std::endl << std::endl;\r\n" +"\r\n" +" if (! addFile (sourceFile, binaryNamespace, header, cpp, arguments->isVerbose()))\r\n" +" return 1;\r\n" +"\r\n" +" header << \"}\" << std::endl << std::endl;\r\n" +"\r\n" +" return 0;\r\n" +"}\r\n"; + +const char* juce_SimpleBinaryBuilder_cpp = (const char*) temp_binary_data_67; + const char* getNamedResource (const char* resourceNameUTF8, int& numBytes); const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) @@ -8591,6 +9018,8 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) case 0x763d39dc: numBytes = 1050; return colourscheme_dark_xml; case 0xe8b08520: numBytes = 1050; return colourscheme_light_xml; case 0x7c03d519: numBytes = 3005; return juce_runtime_arch_detection_cpp; + case 0x295b6f43: numBytes = 1212; return juce_LinuxSubprocessHelper_cpp; + case 0xef269d3a: numBytes = 12344; return juce_SimpleBinaryBuilder_cpp; default: break; } @@ -8665,7 +9094,9 @@ const char* namedResourceList[] = "jucer_PIPTemplate_h", "colourscheme_dark_xml", "colourscheme_light_xml", - "juce_runtime_arch_detection_cpp" + "juce_runtime_arch_detection_cpp", + "juce_LinuxSubprocessHelper_cpp", + "juce_SimpleBinaryBuilder_cpp" }; const char* originalFilenames[] = @@ -8735,7 +9166,9 @@ const char* originalFilenames[] = "jucer_PIPTemplate.h", "colourscheme_dark.xml", "colourscheme_light.xml", - "juce_runtime_arch_detection.cpp" + "juce_runtime_arch_detection.cpp", + "juce_LinuxSubprocessHelper.cpp", + "juce_SimpleBinaryBuilder.cpp" }; const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8); diff --git a/extras/Projucer/JuceLibraryCode/BinaryData.h b/extras/Projucer/JuceLibraryCode/BinaryData.h index a76767f23807..63f981786e62 100644 --- a/extras/Projucer/JuceLibraryCode/BinaryData.h +++ b/extras/Projucer/JuceLibraryCode/BinaryData.h @@ -206,8 +206,14 @@ namespace BinaryData extern const char* juce_runtime_arch_detection_cpp; const int juce_runtime_arch_detection_cppSize = 3005; + extern const char* juce_LinuxSubprocessHelper_cpp; + const int juce_LinuxSubprocessHelper_cppSize = 1212; + + extern const char* juce_SimpleBinaryBuilder_cpp; + const int juce_SimpleBinaryBuilder_cppSize = 12344; + // Number of elements in the namedResourceList and originalFileNames arrays. - const int namedResourceListSize = 66; + const int namedResourceListSize = 68; // Points to the start of a list of resource names. extern const char* namedResourceList[]; diff --git a/extras/Projucer/JuceLibraryCode/JuceHeader.h b/extras/Projucer/JuceLibraryCode/JuceHeader.h index a7678ade707e..054f15e889bf 100644 --- a/extras/Projucer/JuceLibraryCode/JuceHeader.h +++ b/extras/Projucer/JuceLibraryCode/JuceHeader.h @@ -44,7 +44,7 @@ namespace ProjectInfo { const char* const projectName = "Projucer"; const char* const companyName = "Raw Material Software Limited"; - const char* const versionString = "7.0.5"; - const int versionNumber = 0x70005; + const char* const versionString = "7.0.7"; + const int versionNumber = 0x70007; } #endif diff --git a/extras/Projucer/Projucer.jucer b/extras/Projucer/Projucer.jucer index f836208ca6e8..756083498a16 100644 --- a/extras/Projucer/Projucer.jucer +++ b/extras/Projucer/Projucer.jucer @@ -1,7 +1,7 @@ @@ -299,6 +299,10 @@ file="Source/BinaryData/colourscheme_light.xml"/> + + safeThis { this }; - NewProjectWizard::createNewProject (projectTemplate, - dir.getChildFile (projectNameValue.get().toString()), - projectNameValue.get(), - modulesValue.get(), - exportersValue.get(), - fileOptionsValue.get(), - modulePathValue.getCurrentValue(), - modulePathValue.getWrappedValueTreePropertyWithDefault().isUsingDefault(), - [safeThis, dir] (std::unique_ptr project) + messageBox = NewProjectWizard::createNewProject (projectTemplate, + dir.getChildFile (projectNameValue.get().toString()), + projectNameValue.get(), + modulesValue.get(), + exportersValue.get(), + fileOptionsValue.get(), + modulePathValue.getCurrentValue(), + modulePathValue.getWrappedValueTreePropertyWithDefault().isUsingDefault(), + [safeThis, dir] (ScopedMessageBox mb, std::unique_ptr project) { if (safeThis == nullptr) return; + safeThis->messageBox = std::move (mb); safeThis->projectCreatedCallback (std::move (project)); getAppSettings().lastWizardFolder = dir; }); @@ -249,6 +250,8 @@ class TemplateComponent : public Component return builder.components; } + ScopedMessageBox messageBox; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateComponent) }; diff --git a/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp b/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp index c7e655fec02f..d0811591b3dd 100644 --- a/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp +++ b/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.cpp @@ -237,57 +237,51 @@ File NewProjectWizard::getLastWizardFolder() return lastFolderFallback; } -static void displayFailedFilesMessage (const StringArray& failedFiles) +static ScopedMessageBox displayFailedFilesMessage (const StringArray& failedFiles) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Errors in Creating Project!"), - TRANS("The following files couldn't be written:") - + "\n\n" - + failedFiles.joinIntoString ("\n", 0, 10)); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Errors in Creating Project!"), + TRANS ("The following files couldn't be written:") + + "\n\n" + + failedFiles.joinIntoString ("\n", 0, 10)); + return AlertWindow::showScopedAsync (options, nullptr); } template -static void prepareDirectory (const File& targetFolder, Callback&& callback) +static ScopedMessageBox prepareDirectory (const File& targetFolder, Callback&& callback) { StringArray failedFiles; if (! targetFolder.exists()) { if (! targetFolder.createDirectory()) - { - displayFailedFilesMessage ({ targetFolder.getFullPathName() }); - return; - } + return displayFailedFilesMessage ({ targetFolder.getFullPathName() }); } else if (FileHelpers::containsAnyNonHiddenFiles (targetFolder)) { - AlertWindow::showOkCancelBox (MessageBoxIconType::InfoIcon, - TRANS("New JUCE Project"), - TRANS("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName()) - + TRANS("This folder isn't empty - are you sure you want to create the project there?") - + "\n\n" - + TRANS("Any existing files with the same names may be overwritten by the new files."), - {}, - {}, - nullptr, - ModalCallbackFunction::create ([callback] (int result) - { - if (result != 0) - callback(); - })); - - return; + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::InfoIcon, + TRANS ("New JUCE Project"), + TRANS ("You chose the folder:\n\nXFLDRX\n\n").replace ("XFLDRX", targetFolder.getFullPathName()) + + TRANS ("This folder isn't empty - are you sure you want to create the project there?") + + "\n\n" + + TRANS ("Any existing files with the same names may be overwritten by the new files.")); + return AlertWindow::showScopedAsync (options, [callback] (int result) + { + if (result != 0) + callback(); + }); } callback(); + return ScopedMessageBox(); } -void NewProjectWizard::createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate, - const File& targetFolder, const String& name, var modules, var exporters, var fileOptions, - const String& modulePath, bool useGlobalModulePath, - std::function)> callback) +ScopedMessageBox NewProjectWizard::createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate, + const File& targetFolder, const String& name, var modules, var exporters, var fileOptions, + const String& modulePath, bool useGlobalModulePath, + std::function)> callback) { - prepareDirectory (targetFolder, [=] + return prepareDirectory (targetFolder, [=] { auto project = std::make_unique (targetFolder.getChildFile (File::createLegalFileName (name)) .withFileExtension (Project::projectFileExtension)); @@ -310,18 +304,18 @@ void NewProjectWizard::createNewProject (const NewProjectTemplates::ProjectTempl { uniqueProject->setChangedFlag (false); uniqueProject->loadFrom (uniqueProject->getFile(), true); - callback (std::move (uniqueProject)); + callback ({}, std::move (uniqueProject)); return; } auto failedFilesCopy = failedFiles; failedFilesCopy.add (uniqueProject->getFile().getFullPathName()); - displayFailedFilesMessage (failedFilesCopy); + callback (displayFailedFilesMessage (failedFilesCopy), {}); }); return; } - displayFailedFilesMessage (failedFiles); + callback (displayFailedFilesMessage (failedFiles), {}); }); } diff --git a/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h b/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h index 4ed698b7cfaa..96cdade7fc8a 100644 --- a/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h +++ b/extras/Projucer/Source/Application/StartPage/jucer_NewProjectWizard.h @@ -32,8 +32,8 @@ namespace NewProjectWizard { File getLastWizardFolder(); - void createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate, - const File& targetFolder, const String& name, var modules, var exporters, var fileOptions, - const String& modulePath, bool useGlobalModulePath, - std::function)> callback); + ScopedMessageBox createNewProject (const NewProjectTemplates::ProjectTemplate& projectTemplate, + const File& targetFolder, const String& name, var modules, var exporters, var fileOptions, + const String& modulePath, bool useGlobalModulePath, + std::function)> callback); } diff --git a/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h b/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h index f60c26f370a4..08b96574f4b6 100644 --- a/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h +++ b/extras/Projucer/Source/Application/UserAccount/jucer_LicenseQueryThread.h @@ -363,7 +363,7 @@ class LicenseQueryThread } //============================================================================== - ThreadPool jobPool { 1 }; + ThreadPool jobPool { ThreadPoolOptions{}.withNumberOfThreads (1) }; //============================================================================== JUCE_DECLARE_WEAK_REFERENCEABLE (LicenseQueryThread) diff --git a/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h b/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h index 86de5470e224..55d29eb51665 100644 --- a/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h +++ b/extras/Projucer/Source/Application/Windows/jucer_TranslationToolWindowComponent.h @@ -122,10 +122,11 @@ class TranslationToolComponent : public Component if (postStrings.size() != preStrings.size()) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Error"), - TRANS("The pre- and post-translation text doesn't match!\n\n" - "Perhaps it got mangled by the translator?")); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Error"), + TRANS ("The pre- and post-translation text doesn't match!\n\n" + "Perhaps it got mangled by the translator?")); + messageBox = AlertWindow::showScopedAsync (options, nullptr); return; } @@ -136,10 +137,16 @@ class TranslationToolComponent : public Component void scanProject() { if (Project* project = ProjucerApplication::getApp().mainWindowList.getFrontmostProject()) + { setPreTranslationText (TranslationHelpers::getPreTranslationText (*project)); + } else - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Translation Tool", - "This will only work when you have a project open!"); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Translation Tool", + "This will only work when you have a project open!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } } void scanFolder() @@ -195,4 +202,5 @@ class TranslationToolComponent : public Component loadTranslationButton { "Load existing translation file..."}; std::unique_ptr chooser; + ScopedMessageBox messageBox; }; diff --git a/extras/Projucer/Source/Application/jucer_Application.cpp b/extras/Projucer/Source/Application/jucer_Application.cpp index 1b1dfc1d8082..319b391293ee 100644 --- a/extras/Projucer/Source/Application/jucer_Application.cpp +++ b/extras/Projucer/Source/Application/jucer_Application.cpp @@ -1098,13 +1098,14 @@ void ProjucerApplication::createNewProjectFromClipboard() tempFile.create(); tempFile.appendText (SystemClipboard::getTextFromClipboard()); - auto cleanup = [tempFile] (String errorString) + auto cleanup = [parent = WeakReference { this }, tempFile] (String errorString) { - if (errorString.isNotEmpty()) - { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Error", errorString); - tempFile.deleteFile(); - } + if (parent == nullptr || errorString.isEmpty()) + return; + + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, "Error", errorString); + parent->messageBox = AlertWindow::showScopedAsync (options, nullptr); + tempFile.deleteFile(); }; if (! isPIPFile (tempFile)) @@ -1113,7 +1114,7 @@ void ProjucerApplication::createNewProjectFromClipboard() return; } - openFile (tempFile, [parent = WeakReference { this }, cleanup] (bool openedSuccessfully) + openFile (tempFile, [parent = WeakReference { this }, cleanup] (bool openedSuccessfully) { if (parent == nullptr) return; diff --git a/extras/Projucer/Source/Application/jucer_Application.h b/extras/Projucer/Source/Application/jucer_Application.h index 8468c0541258..9e94627455f6 100644 --- a/extras/Projucer/Source/Application/jucer_Application.h +++ b/extras/Projucer/Source/Application/jucer_Application.h @@ -217,6 +217,7 @@ class ProjucerApplication : public JUCEApplication, int selectedColourSchemeIndex = 0, selectedEditorColourSchemeIndex = 0; std::unique_ptr chooser; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjucerApplication) diff --git a/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp b/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp index 204d649be564..826c0bb4423c 100644 --- a/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp +++ b/extras/Projucer/Source/Application/jucer_AutoUpdater.cpp @@ -56,11 +56,14 @@ void LatestVersionCheckerAndUpdater::run() if (info == nullptr) { if (! backgroundCheck) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Update Server Communication Error", - "Failed to communicate with the JUCE update server.\n" - "Please try again in a few minutes.\n\n" - "If this problem persists you can download the latest version of JUCE from juce.com"); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Update Server Communication Error", + "Failed to communicate with the JUCE update server.\n" + "Please try again in a few minutes.\n\n" + "If this problem persists you can download the latest version of JUCE from juce.com"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } return; } @@ -68,9 +71,12 @@ void LatestVersionCheckerAndUpdater::run() if (! info->isNewerVersionThanCurrent()) { if (! backgroundCheck) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - "No New Version Available", - "Your JUCE version is up to date."); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "No New Version Available", + "Your JUCE version is up to date."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } return; } @@ -109,9 +115,12 @@ void LatestVersionCheckerAndUpdater::run() } if (! backgroundCheck) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Failed to find any new downloads", - "Please try again in a few minutes."); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Failed to find any new downloads", + "Please try again in a few minutes."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } } //============================================================================== @@ -275,33 +284,38 @@ void LatestVersionCheckerAndUpdater::askUserForLocationToDownload (const Version { if (targetFolder.getChildFile (".git").isDirectory()) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, "Downloading New JUCE Version", - targetFolderPath + "\n\nis a GIT repository!\n\nYou should use a \"git pull\" to update it to the latest version."); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Downloading New JUCE Version", + targetFolderPath + "\n\n" + "is a GIT repository!\n\n" + "You should use a \"git pull\" to update it to the latest version."); + if (weakThis != nullptr) + weakThis->messageBox = AlertWindow::showScopedAsync (options, nullptr); return; } - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - "Overwrite Existing JUCE Folder?", - "Do you want to replace the folder\n\n" + targetFolderPath + "\n\nwith the latest version from juce.com?\n\n" - "This will move the existing folder to " + targetFolderPath + "_old.\n\n" - "Replacing the folder that contains the currently running Projucer executable may not work on Windows.", - {}, - {}, - nullptr, - ModalCallbackFunction::create (onResult)); + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + "Overwrite Existing JUCE Folder?", + "Do you want to replace the folder\n\n" + targetFolderPath + "\n\n" + "with the latest version from juce.com?\n\n" + "This will move the existing folder to " + targetFolderPath + "_old.\n\n" + "Replacing the folder that contains the currently running Projucer executable may not work on Windows."); + if (weakThis != nullptr) + weakThis->messageBox = AlertWindow::showScopedAsync (options, onResult); + return; } if (targetFolder.exists()) { - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - "Existing File Or Directory", - "Do you want to move\n\n" + targetFolderPath + "\n\nto\n\n" + targetFolderPath + "_old?", - {}, - {}, - nullptr, - ModalCallbackFunction::create (onResult)); + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + "Existing File Or Directory", + "Do you want to move\n\n" + targetFolderPath + "\n\n" + "to\n\n" + targetFolderPath + "_old?"); + if (weakThis != nullptr) + weakThis->messageBox = AlertWindow::showScopedAsync (options, onResult); + return; } @@ -369,7 +383,7 @@ void LatestVersionCheckerAndUpdater::addNotificationToOpenProjects (const Versio class DownloadAndInstallThread : private ThreadWithProgressWindow { public: - DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function&& cb) + DownloadAndInstallThread (const VersionInfo::Asset& a, const File& t, std::function&& cb) : ThreadWithProgressWindow ("Downloading New Version", true, true), asset (a), targetFolder (t), completionCallback (std::move (cb)) { @@ -387,12 +401,10 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow if (result.wasOk() && ! threadShouldExit()) result = install (zipData); - if (result.failed()) - MessageManager::callAsync ([result] { AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Installation Failed", - result.getErrorMessage()); }); - else - MessageManager::callAsync (completionCallback); + MessageManager::callAsync ([result, callback = completionCallback] + { + callback (result); + }); } Result download (MemoryBlock& dest) @@ -517,7 +529,7 @@ class DownloadAndInstallThread : private ThreadWithProgressWindow VersionInfo::Asset asset; File targetFolder; - std::function completionCallback; + std::function completionCallback; }; static void restartProcess (const File& targetFolder) @@ -548,12 +560,22 @@ static void restartProcess (const File& targetFolder) void LatestVersionCheckerAndUpdater::downloadAndInstall (const VersionInfo::Asset& asset, const File& targetFolder) { - installer.reset (new DownloadAndInstallThread (asset, targetFolder, - [this, targetFolder] - { - installer.reset(); - restartProcess (targetFolder); - })); + installer.reset (new DownloadAndInstallThread (asset, targetFolder, [this, targetFolder] (const auto result) + { + if (result.failed()) + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Installation Failed", + result.getErrorMessage()); + + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } + else + { + installer.reset(); + restartProcess (targetFolder); + } + })); } //============================================================================== diff --git a/extras/Projucer/Source/Application/jucer_AutoUpdater.h b/extras/Projucer/Source/Application/jucer_AutoUpdater.h index cd9dc1778f93..cc4f705e9a78 100644 --- a/extras/Projucer/Source/Application/jucer_AutoUpdater.h +++ b/extras/Projucer/Source/Application/jucer_AutoUpdater.h @@ -57,6 +57,7 @@ class LatestVersionCheckerAndUpdater : public DeletedAtShutdown, std::unique_ptr installer; std::unique_ptr dialogWindow; std::unique_ptr chooser; + ScopedMessageBox messageBox; JUCE_DECLARE_WEAK_REFERENCEABLE (LatestVersionCheckerAndUpdater) }; diff --git a/extras/Projucer/Source/Application/jucer_CommandLine.cpp b/extras/Projucer/Source/Application/jucer_CommandLine.cpp index 39f09e545f79..b100b6f43a92 100644 --- a/extras/Projucer/Source/Application/jucer_CommandLine.cpp +++ b/extras/Projucer/Source/Application/jucer_CommandLine.cpp @@ -645,7 +645,7 @@ namespace { args.checkMinNumArguments (3); auto source = args[1].resolveAsExistingFile(); - auto target = args[2].resolveAsExistingFile(); + auto target = args[2].resolveAsFile(); MemoryOutputStream literal; size_t dataSize = 0; diff --git a/extras/Projucer/Source/Application/jucer_MainWindow.cpp b/extras/Projucer/Source/Application/jucer_MainWindow.cpp index f52fd4ff71fb..78494748a587 100644 --- a/extras/Projucer/Source/Application/jucer_MainWindow.cpp +++ b/extras/Projucer/Source/Application/jucer_MainWindow.cpp @@ -462,9 +462,10 @@ void MainWindow::openPIP (const File& pipFile, std::function callba if (generatorResult != Result::ok()) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "PIP Error.", - generatorResult.getErrorMessage()); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "PIP Error.", + generatorResult.getErrorMessage()); + messageBox = AlertWindow::showScopedAsync (options, nullptr); if (callback != nullptr) callback (false); @@ -474,9 +475,10 @@ void MainWindow::openPIP (const File& pipFile, std::function callba if (! generator->createMainCpp()) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "PIP Error.", - "Failed to create Main.cpp."); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "PIP Error.", + "Failed to create Main.cpp."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); if (callback != nullptr) callback (false); @@ -491,9 +493,10 @@ void MainWindow::openPIP (const File& pipFile, std::function callba if (! openedSuccessfully) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "PIP Error.", - "Failed to open .jucer file."); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "PIP Error.", + "Failed to open .jucer file."); + parent->messageBox = AlertWindow::showScopedAsync (options, nullptr); if (callback != nullptr) callback (false); diff --git a/extras/Projucer/Source/Application/jucer_MainWindow.h b/extras/Projucer/Source/Application/jucer_MainWindow.h index a9234089db36..b7bfad8f8045 100644 --- a/extras/Projucer/Source/Application/jucer_MainWindow.h +++ b/extras/Projucer/Source/Application/jucer_MainWindow.h @@ -104,6 +104,8 @@ class MainWindow : public DocumentWindow, std::unique_ptr blurOverlayComponent; bool loginFormOpen = false; + ScopedMessageBox messageBox; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) }; diff --git a/extras/Projucer/Source/BinaryData/juce_SimpleBinaryBuilder.cpp b/extras/Projucer/Source/BinaryData/juce_SimpleBinaryBuilder.cpp new file mode 100644 index 000000000000..af5f0e9b87ea --- /dev/null +++ b/extras/Projucer/Source/BinaryData/juce_SimpleBinaryBuilder.cpp @@ -0,0 +1,381 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 +#include + +#include +#include +#include +#include +#include +#include +#include + +//============================================================================== +struct FileHelpers +{ + static std::string getCurrentWorkingDirectory() + { + std::vector buffer (1024); + + while (getcwd (buffer.data(), buffer.size() - 1) == nullptr && errno == ERANGE) + buffer.resize (buffer.size() * 2 / 3); + + return { buffer.data() }; + } + + static bool endsWith (const std::string& s, char c) + { + if (s.length() == 0) + return false; + + return *s.rbegin() == c; + } + + static std::string appendedPaths (const std::string& first, const std::string& second) + { + return endsWith (first, '/') ? first + second : first + "/" + second; + } + + static bool exists (const std::string& path) + { + return ! path.empty() && access (path.c_str(), F_OK) == 0; + } + + static bool deleteFile (const std::string& path) + { + if (! exists (path)) + return true; + + return remove (path.c_str()) == 0; + } + + static std::string getFilename (const std::string& path) + { + return { std::find_if (path.rbegin(), path.rend(), [] (auto c) { return c == '/'; }).base(), + path.end() }; + } + + static bool isDirectory (const std::string& path) + { + #if defined (__FreeBSD__) || defined (__OpenBSD__) + #define JUCE_STAT stat + #else + #define JUCE_STAT stat64 + #endif + + struct JUCE_STAT info; + + return ! path.empty() + && JUCE_STAT (path.c_str(), &info) == 0 + && ((info.st_mode & S_IFDIR) != 0); + } + + static std::string getParentDirectory (const std::string& path) + { + std::string p { path.begin(), + std::find_if (path.rbegin(), + path.rend(), + [] (auto c) { return c == '/'; }).base() }; + + // Trim the ending slash, but only if not root + if (endsWith (p, '/') && p.length() > 1) + return { p.begin(), p.end() - 1 }; + + return p; + } + + static bool createDirectory (const std::string& path) + { + if (isDirectory (path)) + return true; + + const auto parentDir = getParentDirectory (path); + + if (path == parentDir) + return false; + + if (createDirectory (parentDir)) + return mkdir (path.c_str(), 0777) != -1; + + return false; + } +}; + +//============================================================================== +struct StringHelpers +{ + static bool isQuoteCharacter (char c) + { + return c == '"' || c == '\''; + } + + static std::string unquoted (const std::string& str) + { + if (str.length() == 0 || (! isQuoteCharacter (str[0]))) + return str; + + return str.substr (1, str.length() - (isQuoteCharacter (str[str.length() - 1]) ? 1 : 0)); + } + + static void ltrim (std::string& s) + { + s.erase (s.begin(), std::find_if (s.begin(), s.end(), [] (int c) { return ! std::isspace (c); })); + } + + static void rtrim (std::string& s) + { + s.erase (std::find_if (s.rbegin(), s.rend(), [] (int c) { return ! std::isspace (c); }).base(), s.end()); + } + + static std::string trimmed (const std::string& str) + { + auto result = str; + ltrim (result); + rtrim (result); + return result; + } + + static std::string replaced (const std::string& str, char charToReplace, char replaceWith) + { + auto result = str; + std::replace (result.begin(), result.end(), charToReplace, replaceWith); + return result; + } +}; + +//============================================================================== +static bool addFile (const std::string& filePath, + const std::string& binaryNamespace, + std::ofstream& headerStream, + std::ofstream& cppStream, + bool verbose) +{ + std::ifstream fileStream (filePath, std::ios::in | std::ios::binary | std::ios::ate); + + if (! fileStream.is_open()) + { + std::cerr << "Failed to open input file " << filePath << std::endl; + return false; + } + + std::vector buffer ((size_t) fileStream.tellg()); + fileStream.seekg (0); + fileStream.read (buffer.data(), static_cast (buffer.size())); + + const auto variableName = StringHelpers::replaced (StringHelpers::replaced (FileHelpers::getFilename (filePath), + ' ', + '_'), + '.', + '_'); + + if (verbose) + { + std::cout << "Adding " << variableName << ": " + << buffer.size() << " bytes" << std::endl; + } + + headerStream << " extern const char* " << variableName << ";" << std::endl + << " const int " << variableName << "Size = " + << buffer.size() << ";" << std::endl; + + cppStream << "static const unsigned char temp0[] = {"; + + auto* data = (const uint8_t*) buffer.data(); + + for (size_t i = 0; i < buffer.size() - 1; ++i) + { + cppStream << (int) data[i] << ","; + + if ((i % 40) == 39) + cppStream << std::endl << " "; + } + + cppStream << (int) data[buffer.size() - 1] << ",0,0};" << std::endl; + cppStream << "const char* " << binaryNamespace << "::" << variableName + << " = (const char*) temp0" << ";" << std::endl << std::endl; + + return true; +} + +//============================================================================== +class Arguments +{ +public: + enum class PositionalArguments + { + sourceFile = 0, + targetDirectory, + targetFilename, + binaryNamespace + }; + + static std::optional create (int argc, char* argv[]) + { + std::vector arguments; + bool verbose = false; + + for (int i = 1; i < argc; ++i) + { + std::string arg { argv[i] }; + + if (arg == "-v" || arg == "--verbose") + verbose = true; + else + arguments.emplace_back (std::move (arg)); + } + + if (arguments.size() != static_cast (PositionalArguments::binaryNamespace) + 1) + return std::nullopt; + + return Arguments { std::move (arguments), verbose }; + } + + std::string get (PositionalArguments argument) const + { + return arguments[static_cast (argument)]; + } + + bool isVerbose() const + { + return verbose; + } + +private: + Arguments (std::vector args, bool verboseIn) + : arguments (std::move (args)), verbose (verboseIn) + { + } + + std::vector arguments; + bool verbose = false; +}; + +//============================================================================== +int main (int argc, char* argv[]) +{ + const auto arguments = Arguments::create (argc, argv); + + if (! arguments.has_value()) + { + std::cout << " Usage: SimpleBinaryBuilder [-v | --verbose] sourcefile targetdirectory targetfilename namespace" + << std::endl << std::endl + << " SimpleBinaryBuilder will encode the provided source file into" << std::endl + << " two files called (targetfilename).cpp and (targetfilename).h," << std::endl + << " which it will write into the specified target directory." << std::endl + << " The target directory will be automatically created if necessary. The binary" << std::endl + << " resource will be available in the given namespace." << std::endl << std::endl; + + return 0; + } + + const auto currentWorkingDirectory = FileHelpers::getCurrentWorkingDirectory(); + + using ArgType = Arguments::PositionalArguments; + + const auto sourceFile = FileHelpers::appendedPaths (currentWorkingDirectory, + StringHelpers::unquoted (arguments->get (ArgType::sourceFile))); + + if (! FileHelpers::exists (sourceFile)) + { + std::cerr << "Source file doesn't exist: " + << sourceFile + << std::endl << std::endl; + + return 1; + } + + const auto targetDirectory = FileHelpers::appendedPaths (currentWorkingDirectory, + StringHelpers::unquoted (arguments->get (ArgType::targetDirectory))); + + if (! FileHelpers::exists (targetDirectory)) + { + if (! FileHelpers::createDirectory (targetDirectory)) + { + std::cerr << "Failed to create target directory: " << targetDirectory << std::endl; + return 1; + } + } + + const auto className = StringHelpers::trimmed (arguments->get (ArgType::targetFilename)); + const auto binaryNamespace = StringHelpers::trimmed (arguments->get (ArgType::binaryNamespace)); + + const auto headerFilePath = FileHelpers::appendedPaths (targetDirectory, className + ".h"); + const auto cppFilePath = FileHelpers::appendedPaths (targetDirectory, className + ".cpp"); + + if (arguments->isVerbose()) + { + std::cout << "Creating " << headerFilePath + << " and " << cppFilePath + << " from file " << sourceFile + << "..." << std::endl << std::endl; + } + + if (! FileHelpers::deleteFile (headerFilePath)) + { + std::cerr << "Failed to remove old header file: " << headerFilePath << std::endl; + return 1; + } + + if (! FileHelpers::deleteFile (cppFilePath)) + { + std::cerr << "Failed to remove old source file: " << cppFilePath << std::endl; + return 1; + } + + std::ofstream header (headerFilePath); + + if (! header.is_open()) + { + std::cerr << "Failed to open " << headerFilePath << std::endl; + + return 1; + } + + std::ofstream cpp (cppFilePath); + + if (! cpp.is_open()) + { + std::cerr << "Failed to open " << headerFilePath << std::endl; + + return 1; + } + + header << "/* (Auto-generated binary data file). */" << std::endl << std::endl + << "#pragma once" << std::endl << std::endl + << "namespace " << binaryNamespace << std::endl + << "{" << std::endl; + + cpp << "/* (Auto-generated binary data file). */" << std::endl << std::endl + << "#include " << std::quoted (className + ".h") << std::endl << std::endl; + + if (! addFile (sourceFile, binaryNamespace, header, cpp, arguments->isVerbose())) + return 1; + + header << "}" << std::endl << std::endl; + + return 0; +} diff --git a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp index 8ed2cdedcda8..7a1901b72a33 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp +++ b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.cpp @@ -176,15 +176,14 @@ void OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Docume return; } - AlertWindow::showYesNoCancelBox (MessageBoxIconType::QuestionIcon, - TRANS("Closing document..."), - TRANS("Do you want to save the changes to \"") - + doc->getName() + "\"?", - TRANS("Save"), - TRANS("Discard changes"), - TRANS("Cancel"), - nullptr, - ModalCallbackFunction::create ([parent = WeakReference { this }, doc, callback] (int r) + auto options = MessageBoxOptions::makeOptionsYesNoCancel (MessageBoxIconType::QuestionIcon, + TRANS ("Closing document..."), + TRANS ("Do you want to save the changes to \"") + + doc->getName() + "\"?", + TRANS ("Save"), + TRANS ("Discard changes"), + TRANS ("Cancel")); + messageBox = AlertWindow::showScopedAsync (options, [parent = WeakReference { this }, doc, callback] (int r) { if (parent == nullptr) return; @@ -204,7 +203,7 @@ void OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Docume if (callback != nullptr) callback (r == 2 ? FileBasedDocument::savedOk : FileBasedDocument::userCancelledSave); - })); + }); } bool OpenDocumentManager::closeDocumentWithoutSaving (Document* doc) diff --git a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h index 862e65bdf78b..161763e4d974 100644 --- a/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h +++ b/extras/Projucer/Source/CodeEditor/jucer_OpenDocumentManager.h @@ -108,8 +108,7 @@ class OpenDocumentManager class DocumentType { public: - DocumentType() {} - virtual ~DocumentType() {} + virtual ~DocumentType() = default; virtual bool canOpenFile (const File& file) = 0; virtual Document* openFile (Project* project, const File& file) = 0; @@ -117,7 +116,6 @@ class OpenDocumentManager void registerType (DocumentType* type, int index = -1); - private: //============================================================================== void closeLastDocumentUsingProjectRecursive (WeakReference, @@ -129,6 +127,7 @@ class OpenDocumentManager OwnedArray types; OwnedArray documents; Array listeners; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenDocumentManager) JUCE_DECLARE_WEAK_REFERENCEABLE (OpenDocumentManager) diff --git a/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h b/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h index 5e04d934f952..56704e73c6f3 100644 --- a/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h +++ b/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h @@ -145,7 +145,7 @@ struct SliderHandler : public ComponentTypeHandler if (needsSliderListener (component)) r << memberVariableName << "->addListener (this);\n"; - if (s->getSkewFactor() != 1.0) + if (! approximatelyEqual (s->getSkewFactor(), 1.0)) r << memberVariableName << "->setSkewFactor (" << s->getSkewFactor() << ");\n"; r << '\n'; diff --git a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h index 105f3f273979..6c791fa10663 100644 --- a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h +++ b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h @@ -77,7 +77,7 @@ class JucerFillType && gradPos1 == other.gradPos1 && gradPos2 == other.gradPos2 && imageResourceName == other.imageResourceName - && imageOpacity == other.imageOpacity + && approximatelyEqual (imageOpacity, other.imageOpacity) && imageAnchor == other.imageAnchor; } @@ -320,7 +320,7 @@ class JucerFillType return gradCol1.isTransparent() && gradCol2.isTransparent(); case imageBrush: - return imageOpacity == 0.0; + return approximatelyEqual (imageOpacity, 0.0); default: jassertfalse; diff --git a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp index 9aaa0d0b2c79..5441440cf656 100644 --- a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp +++ b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp @@ -244,7 +244,7 @@ void PaintElementImage::setOpacity (double newOpacity, const bool undoable) { newOpacity = jlimit (0.0, 1.0, newOpacity); - if (opacity != newOpacity) + if (! approximatelyEqual (opacity, newOpacity)) { if (undoable) { diff --git a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h index aa21079e7f1a..48ddcb6f31c4 100644 --- a/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h +++ b/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h @@ -95,7 +95,7 @@ class PaintElementRoundedRectangle : public ColouredElement void setCornerSize (const double newSize, const bool undoable) { - if (newSize != cornerSize) + if (! approximatelyEqual (newSize, cornerSize)) { if (undoable) { diff --git a/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h b/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h index 0cb8f7f5cebc..d1fe26469d1c 100644 --- a/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h +++ b/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h @@ -132,7 +132,7 @@ class FontPropertyComponent : public ChoicePropertyComponent s << getFontStyleCode (font) << ")"; - if (font.getExtraKerningFactor() != 0.0f) + if (! approximatelyEqual (font.getExtraKerningFactor(), 0.0f)) s << ".withExtraKerningFactor (" << CodeHelpers::floatLiteral (font.getExtraKerningFactor(), 3) << ")"; diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp b/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp index 586e9eab50dc..109a6c8c0680 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp @@ -184,7 +184,7 @@ void PaintRoutineEditor::refreshAllElements() repaint(); } - if (componentOverlayOpacity != document.getComponentOverlayOpacity()) + if (! approximatelyEqual (componentOverlayOpacity, document.getComponentOverlayOpacity())) { componentOverlay = Image(); componentOverlayOpacity = document.getComponentOverlayOpacity(); diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h b/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h index 314dd7dee7c3..3e4299e289eb 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h @@ -420,10 +420,12 @@ class PositionedRectangle /** Compares two objects. */ bool operator== (const PositionedRectangle& other) const noexcept { - return x == other.x && y == other.y - && w == other.w && h == other.h - && xMode == other.xMode && yMode == other.yMode - && wMode == other.wMode && hMode == other.hMode; + const auto tie = [] (const PositionedRectangle& r) + { + return std::tie (r.x, r.y, r.xMode, r.yMode, r.wMode, r.hMode); + }; + + return tie (*this) == tie (other); } /** Compares two objects. */ diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp b/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp index 03d73fa43ed4..f70d9f4c0e76 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp @@ -265,8 +265,11 @@ void ResourceEditorPanel::reloadAll() failed.add (document.getResources().getResourceNames() [i]); if (failed.size() > 0) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Reloading resources"), - TRANS("The following resources couldn't be reloaded from their original files:\n\n") - + failed.joinIntoString (", ")); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Reloading resources"), + TRANS ("The following resources couldn't be reloaded from their original files:\n\n") + + failed.joinIntoString (", ")); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } } diff --git a/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h b/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h index e54678a8dd59..40b0cbc8f323 100644 --- a/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h +++ b/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h @@ -56,4 +56,5 @@ class ResourceEditorPanel : public Component, JucerDocument& document; std::unique_ptr listBox; TextButton addButton, reloadAllButton, delButton; + ScopedMessageBox messageBox; }; diff --git a/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp b/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp index f9e393e4662e..6695ef004881 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp @@ -160,9 +160,10 @@ void BinaryResources::browseForResource (const String& title, { if (! safeThis->add (resourceName, result)) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Adding Resource"), - TRANS("Failed to load the file!")); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Adding Resource"), + TRANS ("Failed to load the file!")); + safeThis->messageBox = AlertWindow::showScopedAsync (options, nullptr); resourceName.clear(); } diff --git a/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h b/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h index 34e5ca26281f..a0f32fc6eb0e 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h +++ b/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h @@ -93,6 +93,7 @@ class BinaryResources JucerDocument* document; OwnedArray resources; std::unique_ptr chooser; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_WEAK_REFERENCEABLE (BinaryResources) diff --git a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp index 9c4b1eec3cc7..4dcccad23b10 100644 --- a/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp +++ b/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp @@ -245,7 +245,7 @@ void JucerDocument::setSnappingGrid (const int numPixels, const bool active, con void JucerDocument::setComponentOverlayOpacity (const float alpha) { - if (alpha != componentOverlayOpacity) + if (! approximatelyEqual (alpha, componentOverlayOpacity)) { componentOverlayOpacity = alpha; changed(); diff --git a/extras/Projucer/Source/Project/Modules/jucer_Modules.cpp b/extras/Projucer/Source/Project/Modules/jucer_Modules.cpp index b5ba791491bf..eb740868979e 100644 --- a/extras/Projucer/Source/Project/Modules/jucer_Modules.cpp +++ b/extras/Projucer/Source/Project/Modules/jucer_Modules.cpp @@ -266,14 +266,20 @@ void LibraryModule::findBrowseableFiles (const File& folder, Array& filesF bool LibraryModule::CompileUnit::isNeededForExporter (ProjectExporter& exporter) const { - if ((hasSuffix (file, "_OSX") && ! exporter.isOSX()) - || (hasSuffix (file, "_iOS") && ! exporter.isiOS()) - || (hasSuffix (file, "_Windows") && ! exporter.isWindows()) - || (hasSuffix (file, "_Linux") && ! exporter.isLinux()) - || (hasSuffix (file, "_Android") && ! exporter.isAndroid())) - return false; + const auto trimmedFileNameLowercase = file.getFileNameWithoutExtension().toLowerCase(); + + const std::tuple shouldBuildForSuffix[] { { "_android", exporter.isAndroid() }, + { "_ios", exporter.isiOS() }, + { "_linux", exporter.isLinux() }, + { "_mac", exporter.isOSX() }, + { "_osx", exporter.isOSX() }, + { "_windows", exporter.isWindows() } }; - auto targetType = Project::getTargetTypeFromFilePath (file, false); + for (const auto& [suffix, shouldBuild] : shouldBuildForSuffix) + if (trimmedFileNameLowercase.endsWith (suffix)) + return shouldBuild; + + const auto targetType = Project::getTargetTypeFromFilePath (file, false); if (targetType != build_tools::ProjectType::Target::unspecified && ! exporter.shouldBuildTargetType (targetType)) return false; @@ -287,14 +293,6 @@ String LibraryModule::CompileUnit::getFilenameForProxyFile() const return "include_" + file.getFileName(); } -bool LibraryModule::CompileUnit::hasSuffix (const File& f, const char* suffix) -{ - auto fileWithoutSuffix = f.getFileNameWithoutExtension() + "."; - - return fileWithoutSuffix.containsIgnoreCase (suffix + String (".")) - || fileWithoutSuffix.containsIgnoreCase (suffix + String ("_")); -} - Array LibraryModule::getAllCompileUnits (build_tools::ProjectType::Target::Type forTarget) const { auto files = getFolder().findChildFiles (File::findFiles, false); @@ -687,19 +685,24 @@ void EnabledModulesList::addModuleOfferingToCopy (const File& f, bool isFromUser if (! m.isValid()) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - "Add Module", "This wasn't a valid module folder!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "Add Module", + "This wasn't a valid module folder!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); return; } if (isModuleEnabled (m.getID())) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - "Add Module", "The project already contains this module!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + "Add Module", + "The project already contains this module!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); return; } - addModule (m.getModuleFolder(), areMostModulesCopiedLocally(), + addModule (m.getModuleFolder(), + areMostModulesCopiedLocally(), isFromUserSpecifiedFolder ? false : areMostModulesUsingGlobalPath()); } diff --git a/extras/Projucer/Source/Project/Modules/jucer_Modules.h b/extras/Projucer/Source/Project/Modules/jucer_Modules.h index 9b2a4a5a839c..345f2dc24d39 100644 --- a/extras/Projucer/Source/Project/Modules/jucer_Modules.h +++ b/extras/Projucer/Source/Project/Modules/jucer_Modules.h @@ -59,7 +59,6 @@ class LibraryModule bool isNeededForExporter (ProjectExporter&) const; String getFilenameForProxyFile() const; - static bool hasSuffix (const File&, const char*); }; Array getAllCompileUnits (build_tools::ProjectType::Target::Type forTarget = @@ -143,6 +142,7 @@ class EnabledModulesList ValueTree state; std::unique_ptr chooser; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EnabledModulesList) }; diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h index 77fe778ef315..adec1a752ec1 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ExporterTreeItems.h @@ -77,7 +77,10 @@ class ExporterItem : public ProjectTreeItemBase, void deleteItem() override { - auto resultCallback = [safeThis = WeakReference { this }] (int result) + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + "Delete Exporter", + "Are you sure you want to delete this export target?"); + messageBox = AlertWindow::showScopedAsync (options, [safeThis = WeakReference { this }] (int result) { if (safeThis == nullptr || result == 0) return; @@ -87,15 +90,7 @@ class ExporterItem : public ProjectTreeItemBase, auto parent = safeThis->exporter->settings.getParent(); parent.removeChild (safeThis->exporter->settings, safeThis->project.getUndoManagerFor (parent)); - }; - - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - "Delete Exporter", - "Are you sure you want to delete this export target?", - "", - "", - nullptr, - ModalCallbackFunction::create (std::move (resultCallback))); + }); } void addSubItems() override @@ -180,6 +175,8 @@ class ExporterItem : public ProjectTreeItemBase, Value targetLocationValue; + ScopedMessageBox messageBox; + void valueChanged (Value& value) override { if (value == exporter->getTargetLocationValue()) @@ -243,13 +240,10 @@ class ConfigItem : public ProjectTreeItemBase void deleteItem() override { - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - "Delete Configuration", - "Are you sure you want to delete this configuration?", - "", - "", - nullptr, - ModalCallbackFunction::create ([parent = WeakReference { this }] (int result) + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + "Delete Configuration", + "Are you sure you want to delete this configuration?"); + messageBox = AlertWindow::showScopedAsync (options, [parent = WeakReference { this }] (int result) { if (parent == nullptr) return; @@ -259,7 +253,7 @@ class ConfigItem : public ProjectTreeItemBase parent->closeSettingsPage(); parent->config->removeFromExporter(); - })); + }); } void showPopupMenu (Point p) override @@ -293,6 +287,7 @@ class ConfigItem : public ProjectTreeItemBase ProjectExporter::BuildConfiguration::Ptr config; ProjectExporter& exporter; ValueTree configTree; + ScopedMessageBox messageBox; //============================================================================== class SettingsComp : public Component @@ -321,7 +316,6 @@ class ConfigItem : public ProjectTreeItemBase JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConfigItem) JUCE_DECLARE_WEAK_REFERENCEABLE (ConfigItem) - }; //============================================================================== diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h index 481e7b1f1384..d1e0b87ce801 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_FileTreeItems.h @@ -138,15 +138,14 @@ class FileTreeItemBase : public JucerTreeViewBase, if (filesToTrash.size() > maxFilesToList) fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files..."; - AlertWindow::showYesNoCancelBox (MessageBoxIconType::NoIcon, - "Delete Project Items", - "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n" - + fileList, - "Just remove references", - "Also move files to Trash", - "Cancel", - tree->getTopLevelComponent(), - ModalCallbackFunction::create ([treeRootItem, filesToTrash, doDelete] (int r) mutable + auto options = MessageBoxOptions::makeOptionsYesNoCancel (MessageBoxIconType::NoIcon, + "Delete Project Items", + "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n" + fileList, + "Just remove references", + "Also move files to Trash", + "Cancel", + tree->getTopLevelComponent()); + messageBox = AlertWindow::showScopedAsync (options, [treeRootItem, filesToTrash, doDelete] (int r) mutable { if (treeRootItem == nullptr) return; @@ -158,7 +157,7 @@ class FileTreeItemBase : public JucerTreeViewBase, filesToTrash.clear(); doDelete (filesToTrash); - })); + }); return; } @@ -471,6 +470,8 @@ class FileTreeItemBase : public JucerTreeViewBase, return -1; } + ScopedMessageBox messageBox; + private: std::unique_ptr chooser; @@ -521,10 +522,13 @@ class SourceFileItem : public FileTreeItemBase { if (newName != File::createLegalFileName (newName)) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "File Rename", - "That filename contained some illegal characters!"); - triggerAsyncRename (item); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "File Rename", + "That filename contained some illegal characters!"); + messageBox = AlertWindow::showScopedAsync (options, [this, item = item] (int) + { + triggerAsyncRename (item); + }); return; } @@ -538,42 +542,40 @@ class SourceFileItem : public FileTreeItemBase if (correspondingItem.isValid()) { - AlertWindow::showOkCancelBox (MessageBoxIconType::NoIcon, - "File Rename", - "Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?", - {}, - {}, - nullptr, - ModalCallbackFunction::create ([parent = WeakReference { this }, - oldFile, newFile, correspondingFile, correspondingItem] (int result) mutable + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::NoIcon, + "File Rename", + "Do you also want to rename the corresponding file \"" + correspondingFile.getFileName() + "\" to match?"); + messageBox = AlertWindow::showScopedAsync (options, [parent = WeakReference { this }, oldFile, newFile, correspondingFile, correspondingItem] (int result) mutable { if (parent == nullptr || result == 0) return; if (! parent->item.renameFile (newFile)) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "File Rename", - "Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); + auto opts = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "File Rename", + "Failed to rename \"" + oldFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); + parent->messageBox = AlertWindow::showScopedAsync (opts, nullptr); return; } if (! correspondingItem.renameFile (newFile.withFileExtension (correspondingFile.getFileExtension()))) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "File Rename", - "Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); + auto opts = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "File Rename", + "Failed to rename \"" + correspondingFile.getFullPathName() + "\"!\n\nCheck your file permissions!"); + parent->messageBox = AlertWindow::showScopedAsync (opts, nullptr); } - - })); + }); } } if (! item.renameFile (newFile)) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "File Rename", - "Failed to rename the file!\n\nCheck your file permissions!"); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "File Rename", + "Failed to rename the file!\n\nCheck your file permissions!"); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } } diff --git a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h index 5360756dac69..cbaae794d26d 100644 --- a/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h +++ b/extras/Projucer/Source/Project/UI/Sidebar/jucer_ModuleTreeItems.h @@ -375,10 +375,11 @@ class ModuleItem : public ProjectTreeItemBase { missingDependencies = enabledModules.getExtraDependenciesNeeded (moduleID); - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Adding Missing Dependencies", - "Couldn't locate some of these modules - you'll need to find their " - "folders manually and add them to the list."); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Adding Missing Dependencies", + "Couldn't locate some of these modules - you'll need to find their " + "folders manually and add them to the list."); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } } @@ -393,6 +394,7 @@ class ModuleItem : public ProjectTreeItemBase String moduleID; StringArray missingDependencies; TextButton fixButton { "Add Required Modules" }; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MissingDependenciesComponent) }; diff --git a/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h index ba618d06a334..79598849ca42 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h +++ b/extras/Projucer/Source/Project/UI/jucer_ContentViewComponents.h @@ -136,7 +136,7 @@ class ListBoxHeader : public Component for (auto w : widths) total += w; - if (total == 1.0f) + if (approximatelyEqual (total, 1.0f)) return; auto diff = 1.0f - total; diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp index 28b72d7b6b9e..0ceae94e7a03 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.cpp @@ -318,25 +318,26 @@ void ProjectContentComponent::closeDocument() hideEditor(); } -static void showSaveWarning (OpenDocumentManager::Document* currentDocument) +static ScopedMessageBox showSaveWarning (OpenDocumentManager::Document* currentDocument) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Save failed!"), - TRANS("Couldn't save the file:") - + "\n" + currentDocument->getFile().getFullPathName()); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("Save failed!"), + TRANS ("Couldn't save the file:") + + "\n" + currentDocument->getFile().getFullPathName()); + return AlertWindow::showScopedAsync (options, nullptr); } void ProjectContentComponent::saveDocumentAsync() { if (currentDocument != nullptr) { - currentDocument->saveAsync ([parent = SafePointer { this }] (bool savedSuccessfully) + currentDocument->saveAsync ([parent = SafePointer { this }] (bool savedSuccessfully) { if (parent == nullptr) return; if (! savedSuccessfully) - showSaveWarning (parent->currentDocument); + parent->messageBox = showSaveWarning (parent->currentDocument); parent->refreshProjectTreeFileStatuses(); }); @@ -351,13 +352,13 @@ void ProjectContentComponent::saveAsAsync() { if (currentDocument != nullptr) { - currentDocument->saveAsAsync ([parent = SafePointer { this }] (bool savedSuccessfully) + currentDocument->saveAsAsync ([parent = SafePointer { this }] (bool savedSuccessfully) { if (parent == nullptr) return; if (! savedSuccessfully) - showSaveWarning (parent->currentDocument); + parent->messageBox = showSaveWarning (parent->currentDocument); parent->refreshProjectTreeFileStatuses(); }); diff --git a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h index cfba44cdc98d..179ed9b5d2e0 100644 --- a/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h +++ b/extras/Projucer/Source/Project/UI/jucer_ProjectContentComponent.h @@ -147,6 +147,7 @@ class ProjectContentComponent : public Component, int lastViewedTab = 0; std::unique_ptr wizardHolder; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectContentComponent) diff --git a/extras/Projucer/Source/Project/jucer_Project.cpp b/extras/Projucer/Source/Project/jucer_Project.cpp index 6f350c4be49a..942baeeb7784 100644 --- a/extras/Projucer/Source/Project/jucer_Project.cpp +++ b/extras/Projucer/Source/Project/jucer_Project.cpp @@ -103,6 +103,7 @@ Project::Project (const File& f) setFile (f); + createEnabledModulesList(); initialiseProjectValues(); initialiseMainGroup(); initialiseAudioPluginValues(); @@ -461,7 +462,8 @@ void Project::removeDefunctExporters() warningMessage << "\n" << TRANS ("These exporters have been removed from the project. If you save the project they will be also erased from the .jucer file."); - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, warningTitle, warningMessage); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, warningTitle, warningMessage); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } } } @@ -677,6 +679,7 @@ Result Project::loadDocument (const File& file) projectRoot = newTree; projectRoot.addListener (this); + createEnabledModulesList(); initialiseProjectValues(); initialiseMainGroup(); initialiseAudioPluginValues(); @@ -903,6 +906,25 @@ void Project::updateModuleWarnings() updateModuleNotFoundWarning (moduleNotFound); } +void Project::updateExporterWarnings() +{ + const Identifier deprecatedExporters[] = { "CODEBLOCKS_WINDOWS", "CODEBLOCKS_LINUX" }; + + for (const auto exporter : getExporters()) + { + for (const auto& name : deprecatedExporters) + { + if (exporter.getType() == name) + { + addProjectMessage (ProjectMessages::Ids::deprecatedExporter, {}); + return; + } + } + } + + removeProjectMessage (ProjectMessages::Ids::deprecatedExporter); +} + void Project::updateCppStandardWarning (bool showWarning) { if (showWarning) @@ -1136,24 +1158,24 @@ void Project::valueTreePropertyChanged (ValueTree& tree, const Identifier& prope changed(); } -void Project::valueTreeChildAdded (ValueTree& parent, ValueTree& child) +void Project::valueTreeChildAddedOrRemoved (ValueTree& parent, ValueTree& child) { - ignoreUnused (parent); - if (child.getType() == Ids::MODULE) updateModuleWarnings(); + else if (parent.getType() == Ids::EXPORTFORMATS) + updateExporterWarnings(); changed(); } -void Project::valueTreeChildRemoved (ValueTree& parent, ValueTree& child, int index) +void Project::valueTreeChildAdded (ValueTree& parent, ValueTree& child) { - ignoreUnused (parent, index); - - if (child.getType() == Ids::MODULE) - updateModuleWarnings(); + valueTreeChildAddedOrRemoved (parent, child); +} - changed(); +void Project::valueTreeChildRemoved (ValueTree& parent, ValueTree& child, int) +{ + valueTreeChildAddedOrRemoved (parent, child); } void Project::valueTreeChildOrderChanged (ValueTree&, int, int) @@ -1259,6 +1281,8 @@ bool Project::shouldBuildTargetType (build_tools::ProjectType::Target::Type targ return shouldBuildVST(); case Target::VST3PlugIn: return shouldBuildVST3(); + case Target::VST3Helper: + return shouldBuildVST3(); case Target::AAXPlugIn: return shouldBuildAAX(); case Target::AudioUnitPlugIn: @@ -1270,7 +1294,7 @@ bool Project::shouldBuildTargetType (build_tools::ProjectType::Target::Type targ case Target::UnityPlugIn: return shouldBuildUnityPlugin(); case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: return shouldBuildLV2(); case Target::AggregateTarget: case Target::SharedCodeTarget: @@ -1567,7 +1591,6 @@ void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props) props.add (new TextPropertyComponent (pluginARACompatibleArchiveIDsValue, "Plugin ARA Compatible Document Archive IDs", 1024, true), "List of compatible ARA Document Archive IDs - one per line"); - } } @@ -2324,27 +2347,27 @@ int Project::getARATransformationFlags() const noexcept } //============================================================================== -bool Project::isAUPluginHost() +bool Project::isAUPluginHost() const { return getEnabledModules().isModuleEnabled ("juce_audio_processors") && isConfigFlagEnabled ("JUCE_PLUGINHOST_AU", false); } -bool Project::isVSTPluginHost() +bool Project::isVSTPluginHost() const { return getEnabledModules().isModuleEnabled ("juce_audio_processors") && isConfigFlagEnabled ("JUCE_PLUGINHOST_VST", false); } -bool Project::isVST3PluginHost() +bool Project::isVST3PluginHost() const { return getEnabledModules().isModuleEnabled ("juce_audio_processors") && isConfigFlagEnabled ("JUCE_PLUGINHOST_VST3", false); } -bool Project::isLV2PluginHost() +bool Project::isLV2PluginHost() const { return getEnabledModules().isModuleEnabled ("juce_audio_processors") && isConfigFlagEnabled ("JUCE_PLUGINHOST_LV2", false); } -bool Project::isARAPluginHost() +bool Project::isARAPluginHost() const { return (isVST3PluginHost() || isAUPluginHost()) && isConfigFlagEnabled ("JUCE_PLUGINHOST_ARA", false); } @@ -2505,12 +2528,21 @@ Array Project::getDefaultARATransformationFlags() const noexcept } //============================================================================== -EnabledModulesList& Project::getEnabledModules() +template +auto& Project::getEnabledModulesImpl (This& t) { - if (enabledModulesList == nullptr) - enabledModulesList.reset (new EnabledModulesList (*this, projectRoot.getOrCreateChildWithName (Ids::MODULES, nullptr))); + // This won't work until you've loaded a project! + jassert (t.enabledModulesList != nullptr); + + return *t.enabledModulesList; +} + + EnabledModulesList& Project::getEnabledModules() { return getEnabledModulesImpl (*this); } +const EnabledModulesList& Project::getEnabledModules() const { return getEnabledModulesImpl (*this); } - return *enabledModulesList; +void Project::createEnabledModulesList() +{ + enabledModulesList = std::make_unique (*this, projectRoot.getOrCreateChildWithName (Ids::MODULES, nullptr)); } static StringArray getModulePathsFromExporters (Project& project, bool onlyThisOS) diff --git a/extras/Projucer/Source/Project/jucer_Project.h b/extras/Projucer/Source/Project/jucer_Project.h index ae976c1e81d4..9320aec6d968 100644 --- a/extras/Projucer/Source/Project/jucer_Project.h +++ b/extras/Projucer/Source/Project/jucer_Project.h @@ -51,6 +51,7 @@ namespace ProjectMessages DECLARE_ID (newVersionAvailable); DECLARE_ID (pluginCodeInvalid); DECLARE_ID (manufacturerCodeInvalid); + DECLARE_ID (deprecatedExporter); DECLARE_ID (notification); DECLARE_ID (warning); @@ -64,7 +65,8 @@ namespace ProjectMessages { static Identifier warnings[] = { Ids::incompatibleLicense, Ids::cppStandard, Ids::moduleNotFound, Ids::jucePath, Ids::jucerFileModified, Ids::missingModuleDependencies, - Ids::oldProjucer, Ids::pluginCodeInvalid, Ids::manufacturerCodeInvalid }; + Ids::oldProjucer, Ids::pluginCodeInvalid, Ids::manufacturerCodeInvalid, + Ids::deprecatedExporter }; if (std::find (std::begin (warnings), std::end (warnings), message) != std::end (warnings)) return Ids::warning; @@ -88,6 +90,7 @@ namespace ProjectMessages if (message == Ids::newVersionAvailable) return "New Version Available"; if (message == Ids::pluginCodeInvalid) return "Invalid Plugin Code"; if (message == Ids::manufacturerCodeInvalid) return "Invalid Manufacturer Code"; + if (message == Ids::deprecatedExporter) return "Deprecated Exporter"; jassertfalse; return {}; @@ -105,6 +108,7 @@ namespace ProjectMessages if (message == Ids::newVersionAvailable) return "A new version of JUCE is available to download."; if (message == Ids::pluginCodeInvalid) return "The plugin code should be exactly four characters in length."; if (message == Ids::manufacturerCodeInvalid) return "The manufacturer code should be exactly four characters in length."; + if (message == Ids::deprecatedExporter) return "The project includes a deprecated exporter."; jassertfalse; return {}; @@ -159,6 +163,7 @@ class Project : public FileBasedDocument, static String getJuceSourceHFilename() { return "JuceHeader.h"; } static String getJuceLV2DefinesFilename() { return "JuceLV2Defines.h"; } static String getLV2FileWriterName() { return "juce_lv2_helper"; } + static String getVST3FileWriterName() { return "juce_vst3_helper"; } //============================================================================== template @@ -339,11 +344,11 @@ class Project : public FileBasedDocument, String getLV2URI() const { return pluginLV2URIValue.get(); } //============================================================================== - bool isAUPluginHost(); - bool isVSTPluginHost(); - bool isVST3PluginHost(); - bool isLV2PluginHost(); - bool isARAPluginHost(); + bool isAUPluginHost() const; + bool isVSTPluginHost() const; + bool isVST3PluginHost() const; + bool isLV2PluginHost() const; + bool isARAPluginHost() const; //============================================================================== bool shouldBuildTargetType (build_tools::ProjectType::Target::Type targetType) const noexcept; @@ -494,7 +499,10 @@ class Project : public FileBasedDocument, bool isConfigFlagEnabled (const String& name, bool defaultIsEnabled = false) const; //============================================================================== - EnabledModulesList& getEnabledModules(); + void createEnabledModulesList(); + + EnabledModulesList& getEnabledModules(); + const EnabledModulesList& getEnabledModules() const; AvailableModulesList& getExporterPathsModulesList() { return exporterPathsModulesList; } void rescanExporterPathModules (bool async = false); @@ -547,6 +555,12 @@ class Project : public FileBasedDocument, void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override; void valueTreeChildOrderChanged (ValueTree&, int, int) override; + void valueTreeChildAddedOrRemoved (ValueTree&, ValueTree&); + + //============================================================================== + template + static auto& getEnabledModulesImpl (This&); + //============================================================================== struct ProjectFileModificationPoller : private Timer { @@ -638,6 +652,7 @@ class Project : public FileBasedDocument, void updateJUCEPathWarning(); void updateModuleWarnings(); + void updateExporterWarnings(); void updateCppStandardWarning (bool showWarning); void updateMissingModuleDependenciesWarning (bool showWarning); void updateOldProjucerWarning (bool showWarning); @@ -652,6 +667,7 @@ class Project : public FileBasedDocument, std::unique_ptr chooser; std::unique_ptr saver; + ScopedMessageBox messageBox; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Project) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h index a030a95940fd..1919acd5fef5 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h @@ -389,7 +389,7 @@ class AndroidProjectExporter : public ProjectExporter mo << "# Automatically generated CMakeLists, created by the Projucer" << newLine << "# Don't edit this file! Your changes will be overwritten when you re-save the Projucer project!" << newLine << newLine - << "cmake_minimum_required(VERSION 3.4.1)" << newLine + << "cmake_minimum_required(VERSION 3.22)" << newLine << newLine << "project(juce_jni_project)" << newLine << newLine; @@ -608,7 +608,6 @@ class AndroidProjectExporter : public ProjectExporter mo << newLine; } - libraries.addArray (userLibraries); mo << "target_link_libraries( ${BINARY_NAME}"; if (libraries.size() > 0) { @@ -623,6 +622,9 @@ class AndroidProjectExporter : public ProjectExporter if (useOboe) mo << " \"oboe\"" << newLine; + for (auto& lib : userLibraries) + mo << " [[" << lib << "]]" << newLine; + mo << ")" << newLine; }); } @@ -680,10 +682,13 @@ class AndroidProjectExporter : public ProjectExporter mo << "android {" << newLine; mo << " compileSdkVersion " << static_cast (androidTargetSDK.get()) << newLine; + // CMake 3.22 will fail to build Android projects that set ANDROID_ARM_MODE unless NDK 24+ is used + mo << " ndkVersion \"25.2.9519653\"" << newLine; mo << " namespace " << project.getBundleIdentifierString().toLowerCase().quoted() << newLine; mo << " externalNativeBuild {" << newLine; mo << " cmake {" << newLine; mo << " path \"CMakeLists.txt\"" << newLine; + mo << " version \"3.22.1\"" << newLine; mo << " }" << newLine; mo << " }" << newLine; @@ -1672,6 +1677,10 @@ class AndroidProjectExporter : public ProjectExporter { auto* app = createApplicationElement (*manifest); + auto* receiver = getOrCreateChildWithName (*app, "receiver"); + setAttributeIfNotPresent (*receiver, "android:name", "com.rmsl.juce.Receiver"); + setAttributeIfNotPresent (*receiver, "android:exported", "false"); + auto* act = createActivityElement (*app); createIntentElement (*act); @@ -1740,9 +1749,14 @@ class AndroidProjectExporter : public ProjectExporter if (permission == "android.permission.READ_EXTERNAL_STORAGE") usesPermission->setAttribute ("android:maxSdkVersion", "32"); + if (permission == "android.permission.BLUETOOTH_SCAN") + usesPermission->setAttribute ("android:usesPermissionFlags", "neverForLocation"); + // These permissions are obsoleted by new more fine-grained permissions in API level 31 if (permission == "android.permission.BLUETOOTH" - || permission == "android.permission.BLUETOOTH_ADMIN") + || permission == "android.permission.BLUETOOTH_ADMIN" + || permission == "android.permission.ACCESS_FINE_LOCATION" + || permission == "android.permission.ACCESS_COARSE_LOCATION") { usesPermission->setAttribute ("android:maxSdkVersion", "30"); } diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h index 8d1c04b31ff6..d425cb02371c 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CodeBlocks.h @@ -38,8 +38,8 @@ class CodeBlocksProjectExporter : public ProjectExporter }; //============================================================================== - static String getDisplayNameWindows() { return "Code::Blocks (Windows)"; } - static String getDisplayNameLinux() { return "Code::Blocks (Linux)"; } + static String getDisplayNameWindows() { return "[Deprecated] Code::Blocks (Windows)"; } + static String getDisplayNameLinux() { return "[Deprecated] Code::Blocks (Linux)"; } static String getValueTreeTypeNameWindows() { return "CODEBLOCKS_WINDOWS"; } static String getValueTreeTypeNameLinux() { return "CODEBLOCKS_LINUX"; } @@ -122,8 +122,9 @@ class CodeBlocksProjectExporter : public ProjectExporter case Target::AAXPlugIn: case Target::UnityPlugIn: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: case Target::VST3PlugIn: + case Target::VST3Helper: case Target::AudioUnitPlugIn: case Target::AudioUnitv3PlugIn: case Target::unspecified: @@ -139,10 +140,8 @@ class CodeBlocksProjectExporter : public ProjectExporter if (isWindows()) { props.add (new ChoicePropertyComponent (targetPlatformValue, "Target platform", - { "Windows NT 4.0", "Windows 2000", "Windows XP", "Windows Server 2003", "Windows Vista", "Windows Server 2008", - "Windows 7", "Windows 8", "Windows 8.1", "Windows 10" }, - { "0x0400", "0x0500", "0x0501", "0x0502", "0x0600", "0x0600", - "0x0601", "0x0602", "0x0603", "0x0A00" }), + { "Windows Vista", "Windows Server 2008", "Windows 7", "Windows 8", "Windows 8.1", "Windows 10" }, + { "0x0600", "0x0600", "0x0601", "0x0602", "0x0603", "0x0A00" }), "This sets the preprocessor macro WINVER to an appropriate value for the corresponding platform."); } } @@ -157,11 +156,15 @@ class CodeBlocksProjectExporter : public ProjectExporter addVersion (xml); createProject (*xml.createNewChildElement ("Project")); writeXmlOrThrow (xml, cbpFile, "UTF-8", 10, true); + + linuxSubprocessHelperProperties.deployLinuxSubprocessHelperSourceFilesIfNecessary(); } //============================================================================== void addPlatformSpecificSettingsForProjectType (const build_tools::ProjectType&) override { + linuxSubprocessHelperProperties.addToExtraSearchPathsIfNecessary(); + // add shared code target first as order matters for Codeblocks if (shouldBuildTargetType (build_tools::ProjectType::Target::SharedCodeTarget)) targets.add (new CodeBlocksTarget (*this, build_tools::ProjectType::Target::SharedCodeTarget)); @@ -225,9 +228,9 @@ class CodeBlocksProjectExporter : public ProjectExporter if (archFlag.startsWith (prefix)) return archFlag.substring (prefix.length()); - else if (archFlag == "-m64") + if (archFlag == "-m64") return "x86_64"; - else if (archFlag == "-m32") + if (archFlag == "-m32") return "i386"; jassertfalse; @@ -246,6 +249,18 @@ class CodeBlocksProjectExporter : public ProjectExporter } //============================================================================== + enum class IsDynamicLibrary + { + no, + yes + }; + + enum class ShouldBeCompiled + { + no, + yes + }; + class CodeBlocksTarget : public build_tools::ProjectType::Target { public: @@ -299,14 +314,130 @@ class CodeBlocksProjectExporter : public ProjectExporter return {}; } - bool isDynamicLibrary() const + IsDynamicLibrary isDynamicLibrary() const { - return (type == DynamicLibrary || type == VSTPlugIn); + return (type == DynamicLibrary || type == VSTPlugIn) ? IsDynamicLibrary::yes + : IsDynamicLibrary::no; } const CodeBlocksProjectExporter& exporter; }; + //============================================================================== + class LinuxSubprocessHelperTarget + { + public: + enum class HelperType + { + linuxSubprocessHelper, + simpleBinaryBuilder + }; + + LinuxSubprocessHelperTarget (const CodeBlocksProjectExporter& exporter, HelperType helperTypeIn) + : owner (exporter), + helperType (helperTypeIn) + { + } + + String getTargetNameForConfiguration (const BuildConfiguration& config) const + { + return getName (helperType) + " | " + config.getName(); + } + + void addTarget (XmlElement& xml, const BuildConfiguration& config) const + { + xml.setAttribute ("title", getTargetNameForConfiguration (config)); + auto* output = xml.createNewChildElement ("Option"); + output->setAttribute ("output", getOutput (helperType, config)); + xml.createNewChildElement ("Option")->setAttribute ("object_output", + "obj/" + File::createLegalFileName (config.getName().trim())); + xml.createNewChildElement ("Option")->setAttribute ("type", getTypeIndex (type)); + xml.createNewChildElement ("Option")->setAttribute ("compiler", "gcc"); + + const auto isDynamicLibrary = IsDynamicLibrary::no; + + { + auto* compiler = xml.createNewChildElement ("Compiler"); + + for (auto flag : owner.getCompilerFlags (config, isDynamicLibrary)) + owner.setAddOption (*compiler, "option", flag); + } + + { + auto* linker = xml.createNewChildElement ("Linker"); + + for (auto& flag : owner.getLinkerFlags (config, isDynamicLibrary)) + owner.setAddOption (*linker, "option", flag); + } + + if (helperType == HelperType::simpleBinaryBuilder) + { + auto* postBuildCommands = xml.createNewChildElement ("ExtraCommands"); + + const auto binaryDataSource = owner.linuxSubprocessHelperProperties + .getLinuxSubprocessHelperBinaryDataSource(); + + owner.setAddOption (*postBuildCommands, + "after", + getOutput (HelperType::simpleBinaryBuilder, config) + + " " + getOutput (HelperType::linuxSubprocessHelper, config) + + " pre_build" + + " " + binaryDataSource.getFileNameWithoutExtension().quoted() + + " LinuxSubprocessHelperBinaryData"); + } + } + + void addCompileUnits (XmlElement& xml) const + { + const auto file = getSource (helperType); + auto* unit = xml.createNewChildElement ("Unit"); + unit->setAttribute ("filename", file.toUnixStyle()); + + for (ConstConfigIterator config (owner); config.next();) + { + auto targetName = getTargetNameForConfiguration (*config); + unit->createNewChildElement ("Option")->setAttribute ("target", targetName); + } + } + + private: + build_tools::RelativePath getSource (HelperType helperTypeForSource) const + { + if (helperTypeForSource == HelperType::linuxSubprocessHelper) + return owner.linuxSubprocessHelperProperties.getLinuxSubprocessHelperSource(); + + return owner.linuxSubprocessHelperProperties.getSimpleBinaryBuilderSource(); + } + + String getName (HelperType helperTypeForName) const + { + return LinuxSubprocessHelperProperties::getBinaryNameFromSource (getSource (helperTypeForName)); + } + + String getOutput (HelperType helperTypeForOutput, const BuildConfiguration& config) const + { + return owner.getOutputPathForConfig (config) + "/" + getName (helperTypeForOutput); + } + + const CodeBlocksProjectExporter& owner; + HelperType helperType; + build_tools::ProjectType::Target::Type type = build_tools::ProjectType::Target::ConsoleApp; + }; + + void addSubprocessHelperBinarySourceCompileUnit (XmlElement& xml) const + { + auto* unit = xml.createNewChildElement ("Unit"); + const auto binaryDataSource = linuxSubprocessHelperProperties.getLinuxSubprocessHelperBinaryDataSource(); + unit->setAttribute ("filename", binaryDataSource.toUnixStyle()); + + for (ConstConfigIterator config (*this); config.next();) + { + const auto& target = getTargetForFile (resolveRelativePath (binaryDataSource), ShouldBeCompiled::yes); + const auto targetName = target.getTargetNameForConfiguration (*config); + unit->createNewChildElement ("Option")->setAttribute ("target", targetName); + } + } + //============================================================================== void addVersion (XmlElement& xml) const { @@ -372,7 +503,7 @@ class CodeBlocksProjectExporter : public ProjectExporter return getCleanedStringArray (defs); } - StringArray getCompilerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const + StringArray getCompilerFlags (const BuildConfiguration& config, IsDynamicLibrary isDynamicLibrary) const { StringArray flags; @@ -409,7 +540,7 @@ class CodeBlocksProjectExporter : public ProjectExporter if (config.exporter.isLinux()) { - if (target.isDynamicLibrary() || getProject().isAudioPluginProject()) + if (isDynamicLibrary == IsDynamicLibrary::yes || getProject().isAudioPluginProject()) flags.add ("-fPIC"); auto packages = config.exporter.getLinuxPackages (PackageDependencyType::compile); @@ -432,7 +563,7 @@ class CodeBlocksProjectExporter : public ProjectExporter return getCleanedStringArray (flags); } - StringArray getLinkerFlags (const BuildConfiguration& config, CodeBlocksTarget& target) const + StringArray getLinkerFlags (const BuildConfiguration& config, IsDynamicLibrary isDynamicLibrary) const { auto flags = makefileExtraLinkerFlags; @@ -449,7 +580,7 @@ class CodeBlocksProjectExporter : public ProjectExporter if (config.exporter.isLinux()) { - if (target.isDynamicLibrary()) + if (isDynamicLibrary == IsDynamicLibrary::yes) flags.add ("-shared"); auto packages = config.exporter.getLinuxPackages (PackageDependencyType::link); @@ -509,21 +640,23 @@ class CodeBlocksProjectExporter : public ProjectExporter return 0; } - String getOutputPathForTarget (CodeBlocksTarget& target, const BuildConfiguration& config) const + String getOutputPathForConfig (const BuildConfiguration& config) const { - String outputPath; if (config.getTargetBinaryRelativePathString().isNotEmpty()) { build_tools::RelativePath binaryPath (config.getTargetBinaryRelativePathString(), build_tools::RelativePath::projectFolder); binaryPath = binaryPath.rebased (projectFolder, getTargetFolder(), build_tools::RelativePath::buildTargetFolder); - outputPath = config.getTargetBinaryRelativePathString(); - } - else - { - outputPath ="bin/" + File::createLegalFileName (config.getName().trim()); + return config.getTargetBinaryRelativePathString(); } - return outputPath + "/" + replacePreprocessorTokens (config, config.getTargetBinaryNameString() + target.getTargetSuffix()); + return "bin/" + File::createLegalFileName (config.getName().trim()); + } + + String getOutputPathForTarget (CodeBlocksTarget& target, const BuildConfiguration& config) const + { + return getOutputPathForConfig (config) + + "/" + + replacePreprocessorTokens (config, config.getTargetBinaryNameString() + target.getTargetSuffix()); } String getSharedCodePath (const BuildConfiguration& config) const @@ -584,7 +717,7 @@ class CodeBlocksProjectExporter : public ProjectExporter flags.add ("-D" + def); } - flags.addArray (getCompilerFlags (config, target)); + flags.addArray (getCompilerFlags (config, target.isDynamicLibrary())); for (auto flag : flags) setAddOption (*compiler, "option", flag); @@ -604,7 +737,7 @@ class CodeBlocksProjectExporter : public ProjectExporter if (getProject().isAudioPluginProject() && target.type != build_tools::ProjectType::Target::SharedCodeTarget) setAddOption (*linker, "option", getSharedCodePath (config).quoted()); - for (auto& flag : getLinkerFlags (config, target)) + for (auto& flag : getLinkerFlags (config, target.isDynamicLibrary())) setAddOption (*linker, "option", flag); const StringArray& libs = isWindows() ? mingwLibs : linuxLibs; @@ -623,9 +756,15 @@ class CodeBlocksProjectExporter : public ProjectExporter auto* build = xml.createNewChildElement ("Build"); for (ConstConfigIterator config (*this); config.next();) + { + if (linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) + for (const auto& helperTarget : helperTargets) + helperTarget.addTarget (*build->createNewChildElement ("Target"), *config); + for (auto target : targets) if (target->type != build_tools::ProjectType::Target::AggregateTarget) createBuildTarget (*build->createNewChildElement ("Target"), *target, *config); + } } void addVirtualTargets (XmlElement& xml) const @@ -636,6 +775,10 @@ class CodeBlocksProjectExporter : public ProjectExporter { StringArray allTargets; + if (linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) + for (const auto& target : helperTargets) + allTargets.add (target.getTargetNameForConfiguration (*config)); + for (auto target : targets) if (target->type != build_tools::ProjectType::Target::AggregateTarget) allTargets.add (target->getTargetNameForConfiguration (*config)); @@ -726,19 +869,26 @@ class CodeBlocksProjectExporter : public ProjectExporter return *targets[0]; } - CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const + CodeBlocksTarget& getTargetForFile (const File& file, ShouldBeCompiled shouldBeCompiled) const { if (getProject().isAudioPluginProject()) { - if (! projectItem.shouldBeCompiled()) + if (shouldBeCompiled == ShouldBeCompiled::no) return getTargetWithType (build_tools::ProjectType::Target::SharedCodeTarget); - return getTargetWithType (getProject().getTargetTypeFromFilePath (projectItem.getFile(), true)); + return getTargetWithType (getProject().getTargetTypeFromFilePath (file, true)); } return getMainTarget(); } + CodeBlocksTarget& getTargetForProjectItem (const Project::Item& projectItem) const + { + return getTargetForFile (projectItem.getFile(), + projectItem.shouldBeCompiled() ? ShouldBeCompiled::yes + : ShouldBeCompiled::no); + } + void addCompileUnits (const Project::Item& projectItem, XmlElement& xml) const { if (projectItem.isGroup()) @@ -787,6 +937,14 @@ class CodeBlocksProjectExporter : public ProjectExporter void addCompileUnits (XmlElement& xml) const { + if (linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) + { + for (const auto& helperTarget : helperTargets) + helperTarget.addCompileUnits (xml); + + addSubprocessHelperBinarySourceCompileUnit (xml); + } + for (int i = 0; i < getAllGroups().size(); ++i) addCompileUnits (getAllGroups().getReference(i), xml); @@ -825,5 +983,9 @@ class CodeBlocksProjectExporter : public ProjectExporter OwnedArray targets; + // The order of these targets is significant, as latter targets depend on earlier ones + const LinuxSubprocessHelperTarget helperTargets[2] { { *this, LinuxSubprocessHelperTarget::HelperType::linuxSubprocessHelper }, + { *this, LinuxSubprocessHelperTarget::HelperType::simpleBinaryBuilder } }; + JUCE_DECLARE_NON_COPYABLE (CodeBlocksProjectExporter) }; diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index c7b85ea20987..a751eb34e036 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -228,9 +228,12 @@ class MSVCProjectExporterBase : public ProjectExporter { using Target = build_tools::ProjectType::Target::Type; - if (type == Target::LV2TurtleProgram) + if (type == Target::LV2Helper) return Project::getLV2FileWriterName() + suffix; + if (type == Target::VST3Helper) + return Project::getVST3FileWriterName() + suffix; + const auto forceUnityPrefix = type == Target::UnityPlugIn; auto target = File::createLegalFileName (getTargetBinaryNameString (forceUnityPrefix).trim()); @@ -655,12 +658,12 @@ class MSVCProjectExporterBase : public ProjectExporter } auto externalLibraries = getExternalLibraries (config, getOwner().getExternalLibrariesStringArray()); - auto additionalDependencies = type != SharedCodeTarget && type != LV2TurtleProgram && ! externalLibraries.isEmpty() + auto additionalDependencies = type != SharedCodeTarget && type != LV2Helper && type != VST3Helper && ! externalLibraries.isEmpty() ? externalLibraries.joinIntoString (";") + ";%(AdditionalDependencies)" : String(); auto librarySearchPaths = config.getLibrarySearchPaths(); - auto additionalLibraryDirs = type != SharedCodeTarget && type != LV2TurtleProgram && librarySearchPaths.size() > 0 + auto additionalLibraryDirs = type != SharedCodeTarget && type != LV2Helper && type != VST3Helper && librarySearchPaths.size() > 0 ? getOwner().replacePreprocessorTokens (config, librarySearchPaths.joinIntoString (";")) + ";%(AdditionalLibraryDirectories)" : String(); @@ -672,7 +675,7 @@ class MSVCProjectExporterBase : public ProjectExporter : "%(IgnoreSpecificDefaultLibraries)"); link->createNewChildElement ("GenerateDebugInformation")->addTextElement ((isDebug || config.shouldGenerateDebugSymbols()) ? "true" : "false"); link->createNewChildElement ("ProgramDatabaseFile")->addTextElement (pdbFilename); - link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp || type == LV2TurtleProgram ? "Console" : "Windows"); + link->createNewChildElement ("SubSystem")->addTextElement (type == ConsoleApp || type == LV2Helper || type == VST3Helper ? "Console" : "Windows"); if (config.getArchitectureString() == "Win32") link->createNewChildElement ("TargetMachine")->addTextElement ("MachineX86"); @@ -718,7 +721,7 @@ class MSVCProjectExporterBase : public ProjectExporter bsc->createNewChildElement ("OutputFile")->addTextElement (getOwner().getIntDirFile (config, config.getOutputFilename (".bsc", true, type))); } - if (type != SharedCodeTarget && type != LV2TurtleProgram) + if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper) { auto* lib = group->createNewChildElement ("Lib"); @@ -729,14 +732,27 @@ class MSVCProjectExporterBase : public ProjectExporter lib->createNewChildElement ("AdditionalLibraryDirectories")->addTextElement (additionalLibraryDirs); } - auto manifestFile = getOwner().getManifestPath(); - if (manifestFile.getRoot() != build_tools::RelativePath::unknown) + if (auto manifestFile = getOwner().getManifestPath(); manifestFile.getRoot() != build_tools::RelativePath::unknown || type == VST3Helper) { auto* bsc = group->createNewChildElement ("Manifest"); - bsc->createNewChildElement ("AdditionalManifestFiles") - ->addTextElement (manifestFile.rebased (getOwner().getProject().getFile().getParentDirectory(), - getOwner().getTargetFolder(), - build_tools::RelativePath::buildTargetFolder).toWindowsStyle()); + auto* additional = bsc->createNewChildElement ("AdditionalManifestFiles"); + + if (manifestFile.getRoot() != build_tools::RelativePath::unknown) + { + additional->addTextElement (manifestFile.rebased (getOwner().getProject().getFile().getParentDirectory(), + getOwner().getTargetFolder(), + build_tools::RelativePath::buildTargetFolder).toWindowsStyle()); + } + + if (type == VST3Helper) + { + const auto manifest = getOwner().getModuleFolderRelativeToProject ("juce_audio_processors").getChildFile ("format_types") + .getChildFile ("VST3_SDK") + .getChildFile ("helper.manifest"); + additional->addTextElement (manifest.rebased (getOwner().getProject().getFile().getParentDirectory(), + getOwner().getTargetFolder(), + build_tools::RelativePath::buildTargetFolder).toWindowsStyle()); + } } if (getTargetFileType() == staticLibrary && config.getArchitectureString() == "Win32") @@ -774,9 +790,15 @@ class MSVCProjectExporterBase : public ProjectExporter addFilesToCompile (group, *cppFiles, *headerFiles, *otherFilesGroup); } - if (type == LV2TurtleProgram) + if (type == LV2Helper) { - const auto location = owner.rebaseFromProjectFolderToBuildTarget (owner.getLV2TurtleDumpProgramSource()) + const auto location = owner.rebaseFromProjectFolderToBuildTarget (owner.getLV2HelperProgramSource()) + .toWindowsStyle(); + cppFiles->createNewChildElement ("ClCompile")->setAttribute ("Include", location); + } + else if (type == VST3Helper) + { + const auto location = owner.rebaseFromProjectFolderToBuildTarget (owner.getVST3HelperProgramSource()) .toWindowsStyle(); cppFiles->createNewChildElement ("ClCompile")->setAttribute ("Include", location); } @@ -1105,7 +1127,7 @@ class MSVCProjectExporterBase : public ProjectExporter .toWindowsStyle()); } - String getConfigTargetPath (const BuildConfiguration& config) const + String getConfigTargetPath (const MSVCBuildConfiguration& config) const { const auto result = getSolutionTargetPath (config) + "\\" + getName(); @@ -1147,7 +1169,6 @@ class MSVCProjectExporterBase : public ProjectExporter if (fileType == pluginBundle) { - if (type == VST3PlugIn) return ".vst3"; if (type == AAXPlugIn) return ".aaxdll"; return ".dll"; @@ -1173,7 +1194,6 @@ class MSVCProjectExporterBase : public ProjectExporter } defines = mergePreprocessorDefs (defines, getOwner().getAllPreprocessorDefs (config, type)); - addExtraPreprocessorDefines (defines); if (getTargetFileType() == staticLibrary || getTargetFileType() == sharedLibraryOrDLL) defines.set("_LIB", ""); @@ -1209,27 +1229,47 @@ class MSVCProjectExporterBase : public ProjectExporter String getExtraPostBuildSteps (const MSVCBuildConfiguration& config) const { + const auto copyBuildOutputIntoBundle = [&] (const StringArray& segments) + { + return "copy /Y " + + getOutputFilePath (config).quoted() + + " " + + getOwner().getOutDirFile (config, segments.joinIntoString ("\\")).quoted(); + }; + + const auto copyBundleToInstallDirectory = [&] (const StringArray& segments, const String& directory) + { + const auto copyStep = "\r\nxcopy /E /H /K /R /Y /I " + + getOwner().getOutDirFile (config, segments[0]).quoted() + + " " + + (directory + "\\" + segments[0] + "\\").quoted(); + + return config.isPluginBinaryCopyStepEnabled() ? copyStep : ""; + }; + if (type == AAXPlugIn) { - build_tools::RelativePath aaxSDK (owner.getAAXPathString(), build_tools::RelativePath::projectFolder); - build_tools::RelativePath aaxLibsFolder = aaxSDK.getChildFile ("Libs"); - build_tools::RelativePath bundleScript = aaxSDK.getChildFile ("Utilities").getChildFile ("CreatePackage.bat"); - build_tools::RelativePath iconFilePath = getAAXIconFile(); + const build_tools::RelativePath aaxSDK (owner.getAAXPathString(), build_tools::RelativePath::projectFolder); + const build_tools::RelativePath aaxLibsFolder = aaxSDK.getChildFile ("Libs"); + const build_tools::RelativePath bundleScript = aaxSDK.getChildFile ("Utilities").getChildFile ("CreatePackage.bat"); + const build_tools::RelativePath iconFilePath = getAAXIconFile(); - auto outputFilename = config.getOutputFilename (".aaxplugin", true, type); - auto bundleDir = getOwner().getOutDirFile (config, outputFilename); - auto bundleContents = bundleDir + "\\Contents"; - auto archDir = bundleContents + String ("\\") + config.getArchitectureString(); - auto executablePath = archDir + String ("\\") + outputFilename; + const auto segments = getAaxBundleStructure (config); - auto pkgScript = String ("copy /Y ") + getOutputFilePath (config).quoted() + String (" ") + executablePath.quoted() + String ("\r\ncall ") - + createRebasedPath (bundleScript) + String (" ") + archDir.quoted() + String (" ") + createRebasedPath (iconFilePath); + const auto pkgScript = copyBuildOutputIntoBundle (segments); - if (config.isPluginBinaryCopyStepEnabled()) - return pkgScript + "\r\n" + "xcopy " + bundleDir.quoted() + " " - + String (config.getAAXBinaryLocationString() + "\\" + outputFilename + "\\").quoted() + " /E /H /K /R /Y"; + const auto archDir = StringArray (segments.strings.data(), segments.size() - 1).joinIntoString ("\\"); + const auto rebasedArchDir = getOwner().getOutDirFile (config, archDir); + const auto fixScript = "\r\ncall " + + createRebasedPath (bundleScript) + + " " + + rebasedArchDir.quoted() + + String (" ") + + createRebasedPath (iconFilePath); - return pkgScript; + const auto copyScript = copyBundleToInstallDirectory (segments, config.getAAXBinaryLocationString()); + + return pkgScript + fixScript + copyScript; } if (type == UnityPlugIn) @@ -1256,7 +1296,7 @@ class MSVCProjectExporterBase : public ProjectExporter const auto* writerTarget = [&]() -> MSVCTargetBase* { for (auto* target : owner.targets) - if (target->type == LV2TurtleProgram) + if (target->type == LV2Helper) return target; return nullptr; @@ -1266,44 +1306,88 @@ class MSVCProjectExporterBase : public ProjectExporter + "\\" + writerTarget->getBinaryNameWithSuffix (config); - const auto copyScript = [&]() -> String + const auto copyStep = "xcopy /E /H /I /K /R /Y \"$(OutDir)\" \"" + + config.getLV2BinaryLocationString() + + '\\' + + config.getTargetBinaryNameString() + + ".lv2\"\r\n"; + + return writer.quoted() + + " \"$(OutDir)$(TargetFileName)\"\r\n" + + (config.isPluginBinaryCopyStepEnabled() ? copyStep : ""); + } + + if (type == VST3PlugIn) + { + const auto segments = getVst3BundleStructure (config); + + const auto manifestScript = [&]() -> String { - if (! config.isPluginBinaryCopyStepEnabled()) + const auto* writerTarget = [&]() -> MSVCTargetBase* + { + for (auto* target : owner.targets) + if (target->type == VST3Helper) + return target; + + return nullptr; + }(); + + if (writerTarget == nullptr) return ""; - return "xcopy /E /H /I /K /R /Y \"$(OutDir)\" \"" + config.getLV2BinaryLocationString() - + '\\' + config.getTargetBinaryNameString() + ".lv2\"\r\n"; + const auto writer = writerTarget->getConfigTargetPath (config) + + "\\" + + writerTarget->getBinaryNameWithSuffix (config); + + // moduleinfotool doesn't handle Windows-style path separators properly when computing the bundle name + const auto normalisedBundlePath = getOwner().getOutDirFile (config, segments[0]).replace ("\\", "/"); + const auto contentsDir = normalisedBundlePath + "\\Contents"; + const auto resourceDir = contentsDir + "\\Resources"; + + return "\r\ndel /s /q " + (contentsDir + "\\moduleinfo.json").quoted() + "\r\n" + "if not exist \"" + resourceDir + "\\\" del /s /q " + resourceDir.quoted() + " && mkdir " + resourceDir.quoted() + "\r\n" + + writer.quoted() + + " -create -version " + + getOwner().project.getVersionString().quoted() + + " -path " + + normalisedBundlePath.quoted() + + " -output " + + (resourceDir + "\\moduleinfo.json").quoted(); }(); - return writer.quoted() + " \"$(OutDir)$(TargetFileName)\"\r\n" + copyScript; - } - - if (config.isPluginBinaryCopyStepEnabled()) - { - auto copyScript = String ("copy /Y \"$(OutDir)$(TargetFileName)\"") + String (" \"$COPYDIR$\\$(TargetFileName)\""); + const auto pkgScript = copyBuildOutputIntoBundle (segments); + const auto copyScript = copyBundleToInstallDirectory (segments, config.getVST3BinaryLocationString()); - if (type == VSTPlugIn) return copyScript.replace ("$COPYDIR$", config.getVSTBinaryLocationString()); - if (type == VST3PlugIn) return copyScript.replace ("$COPYDIR$", config.getVST3BinaryLocationString()); + return pkgScript + manifestScript + copyScript; } + if (type == VSTPlugIn && config.isPluginBinaryCopyStepEnabled()) + return "copy /Y \"$(OutDir)$(TargetFileName)\" \"" + config.getVSTBinaryLocationString() + "\\$(TargetFileName)\""; + return {}; } String getExtraPreBuildSteps (const MSVCBuildConfiguration& config) const { - if (type == AAXPlugIn) + const auto createBundleStructure = [&] (const StringArray& segments) { + auto directory = getOwner().getOutDirFile (config, ""); String script; - auto bundleDir = getOwner().getOutDirFile (config, config.getOutputFilename (".aaxplugin", false, type)); - auto bundleContents = bundleDir + "\\Contents"; - auto archDir = bundleContents + String ("\\") + config.getArchitectureString(); - - for (auto& folder : StringArray { bundleDir, bundleContents, archDir }) - script += String ("if not exist \"") + folder + String ("\" mkdir \"") + folder + String ("\"\r\n"); + std::for_each (segments.begin(), std::prev (segments.end()), [&] (const auto& s) + { + directory += (directory.isEmpty() ? "" : "\\") + s; + script += "if not exist \"" + directory + "\\\" del /s /q " + directory.quoted() + " && mkdir " + directory.quoted() + "\r\n"; + }); return script; - } + }; + + if (type == AAXPlugIn) + return createBundleStructure (getAaxBundleStructure (config)); + + if (type == VST3PlugIn) + return createBundleStructure (getVst3BundleStructure (config)); return {}; } @@ -1324,15 +1408,6 @@ class MSVCProjectExporterBase : public ProjectExporter return preBuild + String (preBuild.isNotEmpty() && extraPreBuild.isNotEmpty() ? "\r\n" : "") + extraPreBuild; } - void addExtraPreprocessorDefines (StringPairArray& defines) const - { - if (type == AAXPlugIn) - { - auto aaxLibsFolder = build_tools::RelativePath (owner.getAAXPathString(), build_tools::RelativePath::projectFolder).getChildFile ("Libs"); - defines.set ("JucePlugin_AAXLibs_path", createRebasedPath (aaxLibsFolder)); - } - } - String getBinaryNameWithSuffix (const MSVCBuildConfiguration& config) const { return config.getOutputFilename (getTargetSuffix(), true, type); @@ -1343,11 +1418,11 @@ class MSVCProjectExporterBase : public ProjectExporter return getOwner().getOutDirFile (config, getBinaryNameWithSuffix (config)); } - StringArray getLibrarySearchPaths (const BuildConfiguration& config) const + StringArray getLibrarySearchPaths (const MSVCBuildConfiguration& config) const { auto librarySearchPaths = config.getLibrarySearchPaths(); - if (type != SharedCodeTarget && type != LV2TurtleProgram) + if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper) if (auto* shared = getOwner().getSharedCodeTarget()) librarySearchPaths.add (shared->getConfigTargetPath (config)); @@ -1370,7 +1445,7 @@ class MSVCProjectExporterBase : public ProjectExporter result.addArray (msBuildEscape (getOwner().getModuleLibs())); - if (type != SharedCodeTarget && type != LV2TurtleProgram) + if (type != SharedCodeTarget && type != LV2Helper && type != VST3Helper) if (auto* shared = getOwner().getSharedCodeTarget()) result.add (msBuildEscape (shared->getBinaryNameWithSuffix (config))); @@ -1410,6 +1485,26 @@ class MSVCProjectExporterBase : public ProjectExporter } protected: + StringArray getAaxBundleStructure (const MSVCBuildConfiguration& config) const + { + const auto dllName = config.getOutputFilename (".aaxplugin", false, type); + return { dllName, "Contents", config.getArchitectureString(), dllName }; + } + + StringArray getVst3BundleStructure (const MSVCBuildConfiguration& config) const + { + static const std::map suffixes + { + { "Win32", "x86" }, + { "x64", "x86_64" }, + }; + + const auto iter = suffixes.find (config.getArchitectureString()); + + const auto dllName = config.getOutputFilename (".vst3", false, type); + return { dllName, "Contents", iter != suffixes.cend() ? iter->second + "-win" : "win", dllName }; + } + const MSVCProjectExporterBase& owner; String projectGuid; }; @@ -1449,10 +1544,11 @@ class MSVCProjectExporterBase : public ProjectExporter case Target::AggregateTarget: case Target::VSTPlugIn: case Target::VST3PlugIn: + case Target::VST3Helper: case Target::AAXPlugIn: case Target::UnityPlugIn: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: case Target::DynamicLibrary: return true; case Target::AudioUnitPlugIn: @@ -1652,7 +1748,8 @@ class MSVCProjectExporterBase : public ProjectExporter void writeProjectDependencies (OutputStream& out) const { const auto sharedCodeGuid = getTargetGuid (MSVCTargetBase::SharedCodeTarget); - const auto turtleGuid = getTargetGuid (MSVCTargetBase::LV2TurtleProgram); + const auto lv2HelperGuid = getTargetGuid (MSVCTargetBase::LV2Helper); + const auto vst3HelperGuid = getTargetGuid (MSVCTargetBase::VST3Helper); for (int addingOtherTargets = 0; addingOtherTargets < (sharedCodeGuid.isNotEmpty() ? 2 : 1); ++addingOtherTargets) { @@ -1668,13 +1765,17 @@ class MSVCProjectExporterBase : public ProjectExporter if (sharedCodeGuid.isNotEmpty() && target->type != MSVCTargetBase::SharedCodeTarget - && target->type != MSVCTargetBase::LV2TurtleProgram) + && target->type != MSVCTargetBase::LV2Helper + && target->type != MSVCTargetBase::VST3Helper) { out << "\tProjectSection(ProjectDependencies) = postProject" << newLine << "\t\t" << sharedCodeGuid << " = " << sharedCodeGuid << newLine; - if (target->type == MSVCTargetBase::LV2PlugIn && turtleGuid.isNotEmpty()) - out << "\t\t" << turtleGuid << " = " << turtleGuid << newLine; + if (target->type == MSVCTargetBase::LV2PlugIn && lv2HelperGuid.isNotEmpty()) + out << "\t\t" << lv2HelperGuid << " = " << lv2HelperGuid << newLine; + + if (target->type == MSVCTargetBase::VST3PlugIn && vst3HelperGuid.isNotEmpty()) + out << "\t\t" << vst3HelperGuid << " = " << vst3HelperGuid << newLine; out << "\tEndProjectSection" << newLine; } diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h index f506f7502135..d4be74ed19ba 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h @@ -129,14 +129,14 @@ class MakefileProjectExporter : public ProjectExporter { public: MakefileTarget (build_tools::ProjectType::Target::Type targetType, const MakefileProjectExporter& exporter) - : build_tools::ProjectType::Target (targetType), owner (exporter) + : Target (targetType), owner (exporter) {} StringArray getCompilerFlags() const { StringArray result; - if (getTargetFileType() == sharedLibraryOrDLL || getTargetFileType() == pluginBundle) + if (getTargetFileType() == sharedLibraryOrDLL || getTargetFileType() == pluginBundle || type == SharedCodeTarget) { result.add ("-fPIC"); result.add ("-fvisibility=hidden"); @@ -221,10 +221,14 @@ class MakefileProjectExporter : public ProjectExporter s.add ("JUCE_LV2DIR := " + escapeQuotesAndSpaces (targetName) + ".lv2"); targetName = "$(JUCE_LV2DIR)/" + targetName + ".so"; } - else if (type == LV2TurtleProgram) + else if (type == LV2Helper) { targetName = Project::getLV2FileWriterName(); } + else if (type == VST3Helper) + { + targetName = Project::getVST3FileWriterName(); + } s.add ("JUCE_TARGET_" + getTargetVarName() + String (" := ") + escapeQuotesAndSpaces (targetName)); @@ -295,8 +299,27 @@ class MakefileProjectExporter : public ProjectExporter for (auto& [path, flags] : filesToCompile) { - out << "$(JUCE_OBJDIR)/" << escapeQuotesAndSpaces (owner.getObjectFileFor (path)) << ": " << escapeQuotesAndSpaces (path.toUnixStyle()) << newLine - << "\t-$(V_AT)mkdir -p $(JUCE_OBJDIR)" << newLine + const auto additionalTargetDependencies = [&path = path, this] + { + if ( owner.linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper() + && path.getFileName().contains ("include_juce_gui_extra.cpp")) + { + return owner.linuxSubprocessHelperProperties + .getLinuxSubprocessHelperBinaryDataSource() + .toUnixStyle(); + } + + return String{}; + }(); + + const auto prependedWithSpaceIfNotEmpty = [] (auto s) + { + return s.isEmpty() ? s : " " + s; + }; + + out << "$(JUCE_OBJDIR)/" << escapeQuotesAndSpaces (owner.getObjectFileFor (path)) << ": " << escapeQuotesAndSpaces (path.toUnixStyle()) + << prependedWithSpaceIfNotEmpty (additionalTargetDependencies) << newLine + << "\t-$(V_AT)mkdir -p $(@D)" << newLine << "\t@echo \"Compiling " << path.getFileName() << "\"" << newLine << (path.hasFileExtension ("c;s;S") ? "\t$(V_AT)$(CC) $(JUCE_CFLAGS) " : "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) ") << "$(" << cppflagsVarName << ") $(" << cflagsVarName << ")" @@ -312,9 +335,12 @@ class MakefileProjectExporter : public ProjectExporter String getPhonyName() const { - if (type == LV2TurtleProgram) + if (type == LV2Helper) return "LV2_MANIFEST_HELPER"; + if (type == VST3Helper) + return "VST3_MANIFEST_HELPER"; + return String (getName()).upToFirstOccurrenceOf (" ", false, false); } @@ -323,13 +349,15 @@ class MakefileProjectExporter : public ProjectExporter jassert (type != AggregateTarget); out << getBuildProduct() << " : " - << "$(OBJECTS_" << getTargetVarName() << ") $(RESOURCES)"; + << "$(OBJECTS_" << getTargetVarName() << ") $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES)"; if (type != SharedCodeTarget && owner.shouldBuildTargetType (SharedCodeTarget)) out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_SHARED_CODE)"; if (type == LV2PlugIn) out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_LV2_MANIFEST_HELPER)"; + else if (type == VST3PlugIn) + out << " $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER)"; out << newLine; @@ -369,7 +397,7 @@ class MakefileProjectExporter : public ProjectExporter if (owner.shouldBuildTargetType (SharedCodeTarget)) out << "$(JUCE_OUTDIR)/$(JUCE_TARGET_SHARED_CODE) "; - out << "$(JUCE_LDFLAGS) "; + out << "$(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) "; if (getTargetFileType() == sharedLibraryOrDLL || getTargetFileType() == pluginBundle || type == GUIApp || type == StandalonePlugIn) @@ -380,7 +408,14 @@ class MakefileProjectExporter : public ProjectExporter if (type == VST3PlugIn) { - out << "\t-$(V_AT)[ ! \"$(JUCE_VST3DESTDIR)\" ] || (mkdir -p $(JUCE_VST3DESTDIR) && cp -R $(JUCE_COPYCMD_VST3))" << newLine; + out << "\t-$(V_AT)mkdir -p $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/Resources" << newLine + << "\t-$(V_AT)rm -f $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/moduleinfo.json" << newLine + << "\t$(V_AT) $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER) " + "-create " + "-version " << owner.project.getVersionString().quoted() << " " + "-path $(JUCE_OUTDIR)/$(JUCE_VST3DIR) " + "-output $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/Resources/moduleinfo.json" << newLine + << "\t-$(V_AT)[ ! \"$(JUCE_VST3DESTDIR)\" ] || (mkdir -p $(JUCE_VST3DESTDIR) && cp -R $(JUCE_COPYCMD_VST3))" << newLine; } else if (type == VSTPlugIn) { @@ -467,11 +502,12 @@ class MakefileProjectExporter : public ProjectExporter case Target::AggregateTarget: case Target::VSTPlugIn: case Target::VST3PlugIn: + case Target::VST3Helper: case Target::StandalonePlugIn: case Target::DynamicLibrary: case Target::UnityPlugIn: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: return true; case Target::AAXPlugIn: case Target::AudioUnitPlugIn: @@ -530,11 +566,15 @@ class MakefileProjectExporter : public ProjectExporter build_tools::overwriteFileIfDifferentOrThrow (helperDir.getChildFile ("arch_detection.cpp"), BinaryData::juce_runtime_arch_detection_cpp); } + + linuxSubprocessHelperProperties.deployLinuxSubprocessHelperSourceFilesIfNecessary(); } //============================================================================== void addPlatformSpecificSettingsForProjectType (const build_tools::ProjectType&) override { + linuxSubprocessHelperProperties.addToExtraSearchPathsIfNecessary(); + callForAllSupportedTargets ([this] (build_tools::ProjectType::Target::Type targetType) { targets.insert (targetType == build_tools::ProjectType::Target::AggregateTarget ? 0 : -1, @@ -886,7 +926,21 @@ class MakefileProjectExporter : public ProjectExporter out << newLine; - out << " CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)" << newLine + const auto preBuildDirectory = [&]() -> String + { + if (linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) + { + using LSHP = LinuxSubprocessHelperProperties; + const auto dataSource = linuxSubprocessHelperProperties.getLinuxSubprocessHelperBinaryDataSource(); + + if (auto preBuildDir = LSHP::getParentDirectoryRelativeToBuildTargetFolder (dataSource)) + return " " + *preBuildDir; + } + + return ""; + }(); + + out << " CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)" << preBuildDirectory << newLine << "endif" << newLine << newLine; } @@ -964,6 +1018,94 @@ class MakefileProjectExporter : public ProjectExporter out << newLine; } + /* These targets are responsible for building the juce_linux_subprocess_helper, the + juce_simple_binary_builder, and then using the binary builder to create embeddable .h and .cpp + files from the linux subprocess helper. + */ + void writeSubprocessHelperTargets (OutputStream& out) const + { + using LSHP = LinuxSubprocessHelperProperties; + + const auto ensureDirs = [] (auto& outStream, std::vector dirs) + { + for (const auto& dir : dirs) + outStream << "\t-$(V_AT)mkdir -p " << dir << newLine; + }; + + const auto makeTarget = [&ensureDirs] (auto& outStream, String input, String output) + { + const auto isObjectTarget = output.endsWith (".o"); + const auto isSourceInput = input.endsWith (".cpp"); + + const auto targetOutput = isObjectTarget ? "$(JUCE_OBJDIR)/" + output : output; + + outStream << (isObjectTarget ? "$(JUCE_OBJDIR)/" : "") << output << ": " << input << newLine; + + const auto createBuildTargetRelative = [] (auto path) + { + return build_tools::RelativePath { path, build_tools::RelativePath::buildTargetFolder }; + }; + + if (isObjectTarget) + ensureDirs (outStream, { "$(JUCE_OBJDIR)" }); + else if (auto outputParentFolder = LSHP::getParentDirectoryRelativeToBuildTargetFolder (createBuildTargetRelative (output))) + ensureDirs (outStream, { *outputParentFolder }); + + outStream << (isObjectTarget ? "\t@echo \"Compiling " : "\t@echo \"Linking ") + << (isObjectTarget ? input : output) << "\"" << newLine + << "\t$(V_AT)$(CXX) $(JUCE_CXXFLAGS) -o " << targetOutput.quoted() + << " " << (isSourceInput ? "-c \"$<\"" : input.quoted()); + + if (! isObjectTarget) + outStream << " $(JUCE_LDFLAGS)"; + + outStream << " $(TARGET_ARCH)" << newLine << newLine; + + return targetOutput; + }; + + const auto subprocessHelperSource = linuxSubprocessHelperProperties.getLinuxSubprocessHelperSource(); + + const auto subprocessHelperObj = makeTarget (out, + subprocessHelperSource.toUnixStyle(), + getObjectFileFor (subprocessHelperSource)); + + const auto subprocessHelperPath = makeTarget (out, + subprocessHelperObj, + "$(JUCE_BINDIR)/" + LSHP::getBinaryNameFromSource (subprocessHelperSource)); + + const auto binaryBuilderSource = linuxSubprocessHelperProperties.getSimpleBinaryBuilderSource(); + + const auto binaryBuilderObj = makeTarget (out, + binaryBuilderSource.toUnixStyle(), + getObjectFileFor (binaryBuilderSource)); + + const auto binaryBuilderPath = makeTarget (out, + binaryBuilderObj, + "$(JUCE_BINDIR)/" + LSHP::getBinaryNameFromSource (binaryBuilderSource)); + + const auto binaryDataSource = linuxSubprocessHelperProperties.getLinuxSubprocessHelperBinaryDataSource(); + jassert (binaryDataSource.getRoot() == build_tools::RelativePath::buildTargetFolder); + + out << binaryDataSource.toUnixStyle() << ": " << subprocessHelperPath + << " " << binaryBuilderPath + << newLine; + + const auto binarySourceDir = [&]() -> String + { + if (const auto p = LSHP::getParentDirectoryRelativeToBuildTargetFolder (binaryDataSource)) + return *p; + + return "."; + }(); + + out << "\t$(V_AT)" << binaryBuilderPath.quoted() << " " << subprocessHelperPath.quoted() + << " " << binarySourceDir.quoted() << " " << binaryDataSource.getFileNameWithoutExtension().quoted() + << " LinuxSubprocessHelperBinaryData" << newLine; + + out << newLine; + } + void writeMakefile (OutputStream& out) const { out << "# Automatically generated makefile, created by the Projucer" << newLine @@ -1039,11 +1181,26 @@ class MakefileProjectExporter : public ProjectExporter } } - if (targetType == MakefileTarget::LV2TurtleProgram) + if (( targetType == MakefileTarget::SharedCodeTarget + || targetType == MakefileTarget::StaticLibrary + || targetType == MakefileTarget::DynamicLibrary) + && linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) { - targetFiles.emplace_back (getLV2TurtleDumpProgramSource().rebased (projectFolder, - getTargetFolder(), - build_tools::RelativePath::buildTargetFolder), + targetFiles.emplace_back (linuxSubprocessHelperProperties.getLinuxSubprocessHelperBinaryDataSource(), ""); + } + + if (targetType == MakefileTarget::LV2Helper) + { + targetFiles.emplace_back (getLV2HelperProgramSource().rebased (projectFolder, + getTargetFolder(), + build_tools::RelativePath::buildTargetFolder), + String{}); + } + else if (targetType == MakefileTarget::VST3Helper) + { + targetFiles.emplace_back (getVST3HelperProgramSource().rebased (projectFolder, + getTargetFolder(), + build_tools::RelativePath::buildTargetFolder), String{}); } @@ -1060,6 +1217,16 @@ class MakefileProjectExporter : public ProjectExporter for (auto target : targets) target->addFiles (out, getFilesForTarget (filesToCompile, target, project)); + // libexecinfo is a separate library on BSD + out << "$(JUCE_OBJDIR)/execinfo.cmd:" << newLine + << "\t-$(V_AT)mkdir -p $(@D)" << newLine + << "\t-@if [ -z \"$(V_AT)\" ]; then echo \"Checking if we need to link libexecinfo\"; fi" << newLine + << "\t$(V_AT)printf \"int main() { return 0; }\" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- \"-lexecinfo\" > \"$@\" || touch \"$@\"" << newLine + << newLine; + + if (linuxSubprocessHelperProperties.shouldUseLinuxSubprocessHelper()) + writeSubprocessHelperTargets (out); + out << "clean:" << newLine << "\t@echo Cleaning " << projectName << newLine << "\t$(V_AT)$(CLEANCMD)" << newLine diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h index 3d29ce30eee4..a3f237cd13b1 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h @@ -298,10 +298,10 @@ class XcodeProjectExporter : public ProjectExporter case Target::AudioUnitPlugIn: case Target::UnityPlugIn: case Target::LV2PlugIn: - case Target::LV2TurtleProgram: + case Target::LV2Helper: + case Target::VST3Helper: return ! iOS; case Target::unspecified: - default: break; } @@ -771,10 +771,16 @@ class XcodeProjectExporter : public ProjectExporter "Since JUCE 4.2, this is instead done using \"AU/VST/VST2/AAX Binary Location\" in the Xcode (OS X) configuration settings.\n\n" "Click 'Update' to remove the script (otherwise your plug-in may not compile correctly)."; - if (AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - "Project settings: " + project.getDocumentTitle(), - alertWindowText, "Update", "Cancel", nullptr, nullptr)) - postbuildCommandValue.resetToDefault(); + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + "Project settings: " + project.getDocumentTitle(), + alertWindowText, + "Update", + "Cancel"); + messageBox = AlertWindow::showScopedAsync (options, [this] (int result) + { + if (result != 0) + postbuildCommandValue.resetToDefault(); + }); } } @@ -1062,11 +1068,16 @@ class XcodeProjectExporter : public ProjectExporter break; case ConsoleApp: - case LV2TurtleProgram: + case LV2Helper: + case VST3Helper: xcodeFileType = "compiled.mach-o.executable"; xcodeBundleExtension = String(); xcodeProductType = "com.apple.product-type.tool"; xcodeCopyToProductInstallPathAfterBuild = false; + + if (type == VST3Helper) + xcodeFrameworks.add ("Cocoa"); + break; case StaticLibrary: @@ -1210,9 +1221,12 @@ class XcodeProjectExporter : public ProjectExporter if (xcodeFileType == "archive.ar") return getStaticLibbedFilename (binaryName); - if (type == LV2TurtleProgram) + if (type == LV2Helper) return Project::getLV2FileWriterName(); + if (type == VST3Helper) + return Project::getVST3FileWriterName(); + return binaryName + xcodeBundleExtension; }(); @@ -1251,36 +1265,42 @@ class XcodeProjectExporter : public ProjectExporter if (! owner.project.isAudioPluginProject()) return; - if (type == XcodeTarget::StandalonePlugIn) // depends on AUv3 and shared code - { - if (auto* auv3Target = owner.getTargetOfType (XcodeTarget::AudioUnitv3PlugIn)) - dependencyIDs.add (auv3Target->addDependencyFor (*this)); - - if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget)) - dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this)); - } - else if (type == XcodeTarget::AggregateTarget) // depends on all other targets + if (type == XcodeTarget::AggregateTarget) // depends on all other targets { for (auto* target : owner.targets) if (target->type != XcodeTarget::AggregateTarget) dependencyIDs.add (target->addDependencyFor (*this)); + + return; } - else if (type == XcodeTarget::LV2PlugIn) + + if (type == XcodeTarget::LV2Helper || type == XcodeTarget::VST3Helper) { - if (auto* helperTarget = owner.getTargetOfType (XcodeTarget::LV2TurtleProgram)) - dependencyIDs.add (helperTarget->addDependencyFor (*this)); + return; + } + if (type != XcodeTarget::SharedCodeTarget) // everything else depends on the sharedCodeTarget + { if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget)) dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this)); } - else if (type == XcodeTarget::LV2TurtleProgram) + + if (type == LV2PlugIn) { - // No thanks + if (auto* helperTarget = owner.getTargetOfType (LV2Helper)) + dependencyIDs.add (helperTarget->addDependencyFor (*this)); } - else if (type != XcodeTarget::SharedCodeTarget) // shared code doesn't depend on anything; all other targets depend only on the shared code + + if (type == VST3PlugIn) { - if (auto* sharedCodeTarget = owner.getTargetOfType (XcodeTarget::SharedCodeTarget)) - dependencyIDs.add (sharedCodeTarget->addDependencyFor (*this)); + if (auto* helperTarget = owner.getTargetOfType (VST3Helper)) + dependencyIDs.add (helperTarget->addDependencyFor (*this)); + } + + if (type == XcodeTarget::StandalonePlugIn) + { + if (auto* auv3Target = owner.getTargetOfType (XcodeTarget::AudioUnitv3PlugIn)) + dependencyIDs.add (auv3Target->addDependencyFor (*this)); } } @@ -1299,6 +1319,11 @@ class XcodeProjectExporter : public ProjectExporter owner.addObject (v); } + bool shouldUseHardenedRuntime() const + { + return type != VST3Helper && type != LV2Helper && owner.isHardenedRuntimeEnabled(); + } + //============================================================================== String getTargetAttributes() const { @@ -1316,10 +1341,12 @@ class XcodeProjectExporter : public ProjectExporter capabilities["ApplicationGroups.iOS"] = owner.iOS && owner.isAppGroupsEnabled(); capabilities["InAppPurchase"] = owner.isInAppPurchasesEnabled(); - capabilities["InterAppAudio"] = owner.iOS && type == Target::StandalonePlugIn && owner.getProject().shouldEnableIAA(); + capabilities["InterAppAudio"] = owner.iOS && ((type == Target::StandalonePlugIn + && owner.getProject().shouldEnableIAA()) + || owner.getProject().isAUPluginHost()); capabilities["Push"] = owner.isPushNotificationsEnabled(); capabilities["Sandbox"] = type == Target::AudioUnitv3PlugIn || owner.isAppSandboxEnabled(); - capabilities["HardenedRuntime"] = owner.isHardenedRuntimeEnabled(); + capabilities["HardenedRuntime"] = shouldUseHardenedRuntime(); if (owner.iOS && owner.isiCloudPermissionsEnabled()) capabilities["com.apple.iCloud"] = true; @@ -1375,9 +1402,10 @@ class XcodeProjectExporter : public ProjectExporter if (owner.isPushNotificationsEnabled() || owner.isAppGroupsEnabled() || owner.isAppSandboxEnabled() - || owner.isHardenedRuntimeEnabled() + || shouldUseHardenedRuntime() || owner.isNetworkingMulticastEnabled() - || (owner.isiOS() && owner.isiCloudPermissionsEnabled())) + || (owner.isiOS() && owner.isiCloudPermissionsEnabled()) + || (owner.isiOS() && owner.getProject().isAUPluginHost())) return true; if (owner.project.isAudioPluginProject() @@ -1470,9 +1498,12 @@ class XcodeProjectExporter : public ProjectExporter const auto productName = [&] { - if (type == LV2TurtleProgram) + if (type == LV2Helper) return Project::getLV2FileWriterName().quoted(); + if (type == VST3Helper) + return Project::getVST3FileWriterName().quoted(); + return owner.replacePreprocessorTokens (config, config.getTargetBinaryNameString (type == UnityPlugIn)).quoted(); }(); @@ -1661,7 +1692,7 @@ class XcodeProjectExporter : public ProjectExporter s.set ("CONFIGURATION_BUILD_DIR", addQuotesIfRequired (adjustedConfigBuildDir)); - if (owner.isHardenedRuntimeEnabled()) + if (shouldUseHardenedRuntime()) s.set ("ENABLE_HARDENED_RUNTIME", "YES"); String gccVersion ("com.apple.compilers.llvm.clang.1_0"); @@ -1715,8 +1746,8 @@ class XcodeProjectExporter : public ProjectExporter s.set ("COMBINE_HIDPI_IMAGES", "YES"); { - StringArray linkerFlags, librarySearchPaths; - getLinkerSettings (config, linkerFlags, librarySearchPaths); + StringArray linkerFlags; + getLinkerSettings (config, linkerFlags); for (const auto& weakFramework : owner.xcodeWeakFrameworks) linkerFlags.add ("-weak_framework " + weakFramework); @@ -1724,6 +1755,7 @@ class XcodeProjectExporter : public ProjectExporter if (linkerFlags.size() > 0) s.set ("OTHER_LDFLAGS", linkerFlags.joinIntoString (" ").quoted()); + StringArray librarySearchPaths; librarySearchPaths.addArray (config.getLibrarySearchPaths()); if (type == LV2PlugIn) @@ -1805,7 +1837,8 @@ class XcodeProjectExporter : public ProjectExporter case LV2PlugIn: return config.isPluginBinaryCopyStepEnabled() ? config.getLV2PluginBinaryLocationString() : String(); case SharedCodeTarget: return owner.isiOS() ? "@executable_path/Frameworks" : "@executable_path/../Frameworks"; case StaticLibrary: - case LV2TurtleProgram: + case LV2Helper: + case VST3Helper: case DynamicLibrary: case AudioUnitv3PlugIn: case StandalonePlugIn: @@ -1816,23 +1849,13 @@ class XcodeProjectExporter : public ProjectExporter } //============================================================================== - void getLinkerSettings (const BuildConfiguration& config, StringArray& flags, StringArray& librarySearchPaths) const + void getLinkerSettings (const BuildConfiguration& config, StringArray& flags) const { if (getTargetFileType() == pluginBundle) flags.add (owner.isiOS() ? "-bitcode_bundle" : "-bundle"); - if (type != Target::SharedCodeTarget && type != Target::LV2TurtleProgram) + if (type != Target::SharedCodeTarget && type != Target::LV2Helper && type != Target::VST3Helper) { - Array extraLibs; - - addExtraLibsForTargetType (config, extraLibs); - - for (auto& lib : extraLibs) - { - flags.add (getLinkerFlagForLib (lib.getFileNameWithoutExtension())); - librarySearchPaths.add (owner.getSearchPathForStaticLibrary (lib)); - } - if (owner.project.isAudioPluginProject()) { if (owner.getTargetOfType (Target::SharedCodeTarget) != nullptr) @@ -1857,7 +1880,7 @@ class XcodeProjectExporter : public ProjectExporter flags = getCleanedStringArray (flags); } - //========================================================================== + //============================================================================== void writeInfoPlistFile() const { if (! shouldCreatePList()) @@ -2013,19 +2036,6 @@ class XcodeProjectExporter : public ProjectExporter xcodeFrameworks.add ("AudioUnit"); } - void addExtraLibsForTargetType (const BuildConfiguration& config, Array& extraLibs) const - { - if (type == AAXPlugIn) - { - auto aaxLibsFolder = build_tools::RelativePath (owner.getAAXPathString(), build_tools::RelativePath::projectFolder).getChildFile ("Libs"); - - String libraryPath (config.isDebug() ? "Debug" : "Release"); - libraryPath += "/libAAXLibrary_libcpp.a"; - - extraLibs.add (aaxLibsFolder.getChildFile (libraryPath)); - } - } - //============================================================================== const XcodeProjectExporter& owner; @@ -2117,10 +2127,10 @@ class XcodeProjectExporter : public ProjectExporter target->addMainBuildProduct(); - if (target->type == XcodeTarget::LV2TurtleProgram + if (target->type == XcodeTarget::LV2Helper && project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client")) { - const auto path = rebaseFromProjectFolderToBuildTarget (getLV2TurtleDumpProgramSource()); + const auto path = rebaseFromProjectFolderToBuildTarget (getLV2HelperProgramSource()); addFile (FileOptions().withRelativePath ({ expandPath (path.toUnixStyle()), path.getRoot() }) .withSkipPCHEnabled (true) .withCompilationEnabled (true) @@ -2129,6 +2139,18 @@ class XcodeProjectExporter : public ProjectExporter .withXcodeTarget (target)); } + if (target->type == XcodeTarget::VST3Helper + && project.getEnabledModules().isModuleEnabled ("juce_audio_plugin_client")) + { + const auto path = rebaseFromProjectFolderToBuildTarget (getVST3HelperProgramSource()); + addFile (FileOptions().withRelativePath ({ expandPath (path.toUnixStyle()), path.getRoot() }) + .withSkipPCHEnabled (true) + .withCompilationEnabled (true) + .withInhibitWarningsEnabled (true) + .withCompilerFlags ("-std=c++17 -fobjc-arc") + .withXcodeTarget (target)); + } + auto targetName = String (target->getName()); auto fileID = createID (targetName + "__targetbuildref"); auto fileRefID = createID ("__productFileID" + targetName); @@ -2279,7 +2301,8 @@ class XcodeProjectExporter : public ProjectExporter if (! projectType.isStaticLibrary() && target->type != XcodeTarget::SharedCodeTarget - && target->type != XcodeTarget::LV2TurtleProgram + && target->type != XcodeTarget::LV2Helper + && target->type != XcodeTarget::VST3Helper && ! skipAUv3) target->addBuildPhase ("PBXResourcesBuildPhase", resourceIDs); @@ -2299,42 +2322,63 @@ class XcodeProjectExporter : public ProjectExporter if (! projectType.isStaticLibrary() && target->type != XcodeTarget::SharedCodeTarget - && target->type != XcodeTarget::LV2TurtleProgram) + && target->type != XcodeTarget::LV2Helper) + { target->addBuildPhase ("PBXFrameworksBuildPhase", target->frameworkIDs); + } } - if (target->type == XcodeTarget::LV2PlugIn) + // When building LV2 and VST3 plugins on Arm macs, we need to load and run the plugin + // bundle during a post-build step in order to generate the plugin's supporting files. + // Arm macs will only load shared libraries if they are signed, but Xcode runs its + // signing step after any post-build scripts. As a workaround, we check whether the + // plugin is signed and generate an adhoc certificate if necessary, before running + // the manifest-generator. + if (target->type == XcodeTarget::VST3PlugIn || target->type == XcodeTarget::LV2PlugIn) { - // When building LV2 plugins on Arm macs, we need to load and run the plugin bundle - // during a post-build step in order to generate the plugin's supporting files. Arm - // macs will only load shared libraries if they are signed, but Xcode runs its - // signing step after any post-build scripts. As a workaround, we check whether the - // plugin is signed and generate an adhoc certificate if necessary, before running - // the manifest-generator. - auto script = "set -e\n" - "xcrun codesign --verify \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\" " - "|| xcrun codesign -s - \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\"\n" - "\"$CONFIGURATION_BUILD_DIR/../" - + Project::getLV2FileWriterName() - + "\" \"$CONFIGURATION_BUILD_DIR/$PRODUCT_NAME\"\n"; + String script = "set -e\n"; + + // Delete manifest if it's left over from an old build + if (target->type == XcodeTarget::VST3PlugIn) + script << "rm -f \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/moduleinfo.json\"\n"; + + // Sign the bundle so that it can be loaded by the manifest generator tools + script << "xcrun codesign --verify \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" " + "|| xcrun codesign -f -s - \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\"\n"; - for (ConstConfigIterator config (*this); config.next();) + if (target->type == XcodeTarget::LV2PlugIn) { - auto& xcodeConfig = dynamic_cast (*config); - const auto installPath = target->getInstallPathForConfiguration (xcodeConfig); + // Note: LV2 has a non-standard config build dir + script << "\"$CONFIGURATION_BUILD_DIR/../" + + Project::getLV2FileWriterName() + + "\" \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\"\n"; - if (installPath.isNotEmpty()) + for (ConstConfigIterator config (*this); config.next();) { - const auto destination = installPath.replace ("$(HOME)", "$HOME"); - - script << "if [ \"$CONFIGURATION\" = \"" << config->getName() << "\" ]; then\n" - "mkdir -p \"" << destination << "\"\n" - "/bin/ln -sfh \"$CONFIGURATION_BUILD_DIR\" \"" << destination << "\"\n" - "fi\n"; + auto& xcodeConfig = dynamic_cast (*config); + const auto installPath = target->getInstallPathForConfiguration (xcodeConfig); + + if (installPath.isNotEmpty()) + { + const auto destination = installPath.replace ("$(HOME)", "$HOME"); + + script << R"(if [ "$CONFIGURATION" = ")" << config->getName() << "\" ]; then\n" + "mkdir -p \"" << destination << "\"\n" + "/bin/ln -sfh \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" \"" << destination << "\"\n" + "fi\n"; + } } } + else if (target->type == XcodeTarget::VST3PlugIn) + { + script << "\"$CONFIGURATION_BUILD_DIR/" << Project::getVST3FileWriterName() << "\" " + "-create " + "-version " << project.getVersionString().quoted() << " " + "-path \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME\" " + "-output \"$CONFIGURATION_BUILD_DIR/$FULL_PRODUCT_NAME/Contents/Resources/moduleinfo.json\"\n"; + } - target->addShellScriptBuildPhase ("Generate manifest", script); + target->addShellScriptBuildPhase ("Update manifest", script); } target->addShellScriptBuildPhase ("Post-build script", getPostBuildScript()); @@ -2939,7 +2983,7 @@ class XcodeProjectExporter : public ProjectExporter output << "\t};\n\trootObject = " << createID ("__root") << " /* Project object */;\n}\n"; } - String addFileReference (String pathString, String fileType = {}) const + String addFileReference (String pathString, const String& fileType = {}) const { String sourceTree ("SOURCE_ROOT"); build_tools::RelativePath path (pathString, build_tools::RelativePath::unknown); @@ -2957,7 +3001,7 @@ class XcodeProjectExporter : public ProjectExporter return addFileOrFolderReference (pathString, sourceTree, fileType.isEmpty() ? getFileType (pathString) : fileType); } - String addFileOrFolderReference (const String& pathString, String sourceTree, String fileType) const + String addFileOrFolderReference (const String& pathString, const String& sourceTree, const String& fileType) const { auto fileRefID = createFileRefID (pathString); auto filename = build_tools::RelativePath (pathString, build_tools::RelativePath::unknown).getFileName(); @@ -3155,6 +3199,7 @@ class XcodeProjectExporter : public ProjectExporter options.isiOS = isiOS(); options.isAudioPluginProject = project.isAudioPluginProject(); options.shouldEnableIAA = project.shouldEnableIAA(); + options.isAUPluginHost = project.isAUPluginHost(); options.isiCloudPermissionsEnabled = isiCloudPermissionsEnabled(); options.isPushNotificationsEnabled = isPushNotificationsEnabled(); options.isAppGroupsEnabled = isAppGroupsEnabled(); @@ -3655,6 +3700,7 @@ class XcodeProjectExporter : public ProjectExporter iosContentSharingValue, iosBackgroundAudioValue, iosBackgroundBleValue, iosPushNotificationsValue, iosAppGroupsValue, iCloudPermissionsValue, networkingMulticastValue, iosDevelopmentTeamIDValue, iosAppGroupsIDValue, keepCustomXcodeSchemesValue, useHeaderMapValue, customLaunchStoryboardValue, exporterBundleIdentifierValue, suppressPlistResourceUsageValue, useLegacyBuildSystemValue, buildNumber; + ScopedMessageBox messageBox; struct SandboxFileAccessProperty { diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp index 915e4d5bdaa3..5b7080ef94f9 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp @@ -234,6 +234,32 @@ build_tools::RelativePath ProjectExporter::rebaseFromProjectFolderToBuildTarget return path.rebased (project.getProjectFolder(), getTargetFolder(), build_tools::RelativePath::buildTargetFolder); } +build_tools::RelativePath ProjectExporter::rebaseFromBuildTargetToProjectFolder (const build_tools::RelativePath& path) const +{ + jassert (path.getRoot() == build_tools::RelativePath::buildTargetFolder); + return path.rebased (getTargetFolder(), project.getProjectFolder(), build_tools::RelativePath::projectFolder); +} + +File ProjectExporter::resolveRelativePath (const build_tools::RelativePath& path) const +{ + if (path.isAbsolute()) + return path.toUnixStyle(); + + switch (path.getRoot()) + { + case build_tools::RelativePath::buildTargetFolder: + return getTargetFolder().getChildFile (path.toUnixStyle()); + + case build_tools::RelativePath::projectFolder: + return project.getProjectFolder().getChildFile (path.toUnixStyle()); + + case build_tools::RelativePath::unknown: + jassertfalse; + } + + return path.toUnixStyle(); +} + bool ProjectExporter::shouldFileBeCompiledByDefault (const File& file) const { return file.hasFileExtension (cOrCppFileExtensions) @@ -497,6 +523,8 @@ void ProjectExporter::addTargetSpecificPreprocessorDefs (StringPairArray& defs, { defs.set ("JucePlugin_Enable_ARA", "1"); } + + linuxSubprocessHelperProperties.setCompileDefinitionIfNecessary (defs); } void ProjectExporter::addDefaultPreprocessorDefs (StringPairArray& defs) const @@ -545,7 +573,7 @@ Project::Item& ProjectExporter::getModulesGroup() } //============================================================================== -static bool isWebBrowserComponentEnabled (Project& project) +static bool isWebBrowserComponentEnabled (const Project& project) { static String guiExtrasModule ("juce_gui_extra"); @@ -608,6 +636,7 @@ void ProjectExporter::addToModuleLibPaths (const build_tools::RelativePath& path void ProjectExporter::addToExtraSearchPaths (const build_tools::RelativePath& pathFromProjectFolder, int index) { + jassert (pathFromProjectFolder.getRoot() == build_tools::RelativePath::projectFolder); addProjectPathToBuildPathList (extraSearchPaths, pathFromProjectFolder, index); } @@ -893,17 +922,35 @@ ProjectExporter::BuildConfiguration::BuildConfiguration (Project& p, const Value configLinkerFlagsValue (config, Ids::extraLinkerFlags, getUndoManager()) { auto& llvmFlags = recommendedCompilerWarningFlags[CompilerNames::llvm] = BuildConfiguration::CompilerWarningFlags::getRecommendedForGCCAndLLVM(); - llvmFlags.common.addArray ({ "-Wshorten-64-to-32", "-Wconversion", "-Wint-conversion", - "-Wconditional-uninitialized", "-Wconstant-conversion", "-Wbool-conversion", - "-Wextra-semi", "-Wshift-sign-overflow", - "-Wshadow-all", "-Wnullable-to-nonnull-conversion", - "-Wmissing-prototypes" }); - llvmFlags.cpp.addArray ({ "-Wunused-private-field", "-Winconsistent-missing-destructor-override" }); - llvmFlags.objc.addArray ({ "-Wunguarded-availability", "-Wunguarded-availability-new" }); + + llvmFlags.common.addArray ({ "-Wshadow-all", + "-Wshorten-64-to-32", + "-Wconversion", + "-Wint-conversion", + "-Wconditional-uninitialized", + "-Wconstant-conversion", + "-Wbool-conversion", + "-Wextra-semi", + "-Wshift-sign-overflow", + "-Wmissing-prototypes", + "-Wnullable-to-nonnull-conversion", + "-Wpedantic", + "-Wdeprecated" }); + + llvmFlags.cpp.addArray ({ "-Wunused-private-field", + "-Winconsistent-missing-destructor-override" }); + + llvmFlags.objc.addArray ({ "-Wunguarded-availability", + "-Wunguarded-availability-new" }); auto& gccFlags = recommendedCompilerWarningFlags[CompilerNames::gcc] = BuildConfiguration::CompilerWarningFlags::getRecommendedForGCCAndLLVM(); - gccFlags.common.addArray ({ "-Wextra", "-Wsign-compare", "-Wno-implicit-fallthrough", "-Wno-maybe-uninitialized", - "-Wredundant-decls", "-Wno-strict-overflow", "-Wshadow" }); + gccFlags.common.addArray ({ "-Wextra", + "-Wsign-compare", + "-Wno-implicit-fallthrough", + "-Wno-maybe-uninitialized", + "-Wredundant-decls", + "-Wno-strict-overflow", + "-Wshadow" }); } String ProjectExporter::BuildConfiguration::getGCCOptimisationFlag() const @@ -1083,3 +1130,115 @@ String ProjectExporter::getExternalLibraryFlags (const BuildConfiguration& confi return {}; } + +//============================================================================== +LinuxSubprocessHelperProperties::LinuxSubprocessHelperProperties (ProjectExporter& projectExporter) + : owner (projectExporter) +{} + +bool LinuxSubprocessHelperProperties::shouldUseLinuxSubprocessHelper() const +{ + const auto& project = owner.getProject(); + const auto& projectType = project.getProjectType(); + + return owner.isLinux() + && isWebBrowserComponentEnabled (project) + && ! (projectType.isCommandLineApp()) + && ! (projectType.isGUIApplication()); +} + +void LinuxSubprocessHelperProperties::deployLinuxSubprocessHelperSourceFilesIfNecessary() const +{ + if (shouldUseLinuxSubprocessHelper()) + { + const auto deployHelperSourceFile = [] (auto& sourcePath, auto& contents) + { + if (! sourcePath.isRoot() && ! sourcePath.getParentDirectory().exists()) + { + sourcePath.getParentDirectory().createDirectory(); + } + + build_tools::overwriteFileIfDifferentOrThrow (sourcePath, contents); + }; + + const std::pair sources[] + { + { owner.resolveRelativePath (getSimpleBinaryBuilderSource()), BinaryData::juce_SimpleBinaryBuilder_cpp }, + { owner.resolveRelativePath (getLinuxSubprocessHelperSource()), BinaryData::juce_LinuxSubprocessHelper_cpp } + }; + + for (const auto& [path, source] : sources) + { + deployHelperSourceFile (path, source); + } + } +} + +build_tools::RelativePath LinuxSubprocessHelperProperties::getLinuxSubprocessHelperSource() const +{ + return build_tools::RelativePath { "make_helpers", build_tools::RelativePath::buildTargetFolder } + .getChildFile ("juce_LinuxSubprocessHelper.cpp"); +} + +void LinuxSubprocessHelperProperties::setCompileDefinitionIfNecessary (StringPairArray& defs) const +{ + if (shouldUseLinuxSubprocessHelper()) + defs.set (useLinuxSubprocessHelperCompileDefinition, "1"); +} + +build_tools::RelativePath LinuxSubprocessHelperProperties::getSimpleBinaryBuilderSource() const +{ + return build_tools::RelativePath { "make_helpers", build_tools::RelativePath::buildTargetFolder } + .getChildFile ("juce_SimpleBinaryBuilder.cpp"); +} + +build_tools::RelativePath LinuxSubprocessHelperProperties::getLinuxSubprocessHelperBinaryDataSource() const +{ + return build_tools::RelativePath ("pre_build", juce::build_tools::RelativePath::buildTargetFolder) + .getChildFile ("juce_LinuxSubprocessHelperBinaryData.cpp"); +} + +void LinuxSubprocessHelperProperties::addToExtraSearchPathsIfNecessary() const +{ + if (shouldUseLinuxSubprocessHelper()) + { + const auto subprocessHelperBinaryDir = getLinuxSubprocessHelperBinaryDataSource().getParentDirectory(); + owner.addToExtraSearchPaths (owner.rebaseFromBuildTargetToProjectFolder (subprocessHelperBinaryDir)); + } +} + +std::optional LinuxSubprocessHelperProperties::getParentDirectoryRelativeToBuildTargetFolder (build_tools::RelativePath rp) +{ + jassert (rp.getRoot() == juce::build_tools::RelativePath::buildTargetFolder); + const auto parentDir = rp.getParentDirectory().toUnixStyle(); + return parentDir == rp.toUnixStyle() ? std::nullopt : std::make_optional (parentDir); +} + +String LinuxSubprocessHelperProperties::makeSnakeCase (const String& s) +{ + String result; + result.preallocateBytes (128); + + bool previousCharacterUnderscore = false; + + for (const auto c : s) + { + if ( CharacterFunctions::isUpperCase (c) + && result.length() != 0 + && ! (previousCharacterUnderscore)) + { + result << "_"; + } + + result << CharacterFunctions::toLowerCase (c); + + previousCharacterUnderscore = c == '_'; + } + + return result; +} + +String LinuxSubprocessHelperProperties::getBinaryNameFromSource (const build_tools::RelativePath& rp) +{ + return makeSnakeCase (rp.getFileNameWithoutExtension()); +} diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h index a25d1fe86b41..c8d0deefd422 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.h @@ -32,6 +32,37 @@ class ProjectSaver; +class LinuxSubprocessHelperProperties +{ +public: + explicit LinuxSubprocessHelperProperties (ProjectExporter& projectExporter); + + bool shouldUseLinuxSubprocessHelper() const; + + void deployLinuxSubprocessHelperSourceFilesIfNecessary() const; + + build_tools::RelativePath getLinuxSubprocessHelperSource() const; + + void setCompileDefinitionIfNecessary (StringPairArray& defs) const; + + build_tools::RelativePath getSimpleBinaryBuilderSource() const; + + build_tools::RelativePath getLinuxSubprocessHelperBinaryDataSource() const; + + void addToExtraSearchPathsIfNecessary() const; + + static std::optional getParentDirectoryRelativeToBuildTargetFolder (build_tools::RelativePath rp); + + static String makeSnakeCase (const String& s); + + static String getBinaryNameFromSource (const build_tools::RelativePath& rp); + + static constexpr const char* useLinuxSubprocessHelperCompileDefinition = "JUCE_USE_EXTERNAL_TEMPORARY_SUBPROCESS"; + +private: + ProjectExporter& owner; +}; + //============================================================================== class ProjectExporter : private Value::Listener { @@ -164,6 +195,8 @@ class ProjectExporter : private Value::Listener void updateOldModulePaths(); build_tools::RelativePath rebaseFromProjectFolderToBuildTarget (const build_tools::RelativePath& path) const; + build_tools::RelativePath rebaseFromBuildTargetToProjectFolder (const build_tools::RelativePath& path) const; + File resolveRelativePath (const build_tools::RelativePath&) const; void addToExtraSearchPaths (const build_tools::RelativePath& pathFromProjectFolder, int index = -1); void addToModuleLibPaths (const build_tools::RelativePath& pathFromProjectFolder); @@ -183,11 +216,19 @@ class ProjectExporter : private Value::Listener void createPropertyEditors (PropertyListBuilder&); void addSettingsForProjectType (const build_tools::ProjectType&); - build_tools::RelativePath getLV2TurtleDumpProgramSource() const + build_tools::RelativePath getLV2HelperProgramSource() const { return getModuleFolderRelativeToProject ("juce_audio_plugin_client") .getChildFile ("LV2") - .getChildFile ("juce_LV2TurtleDumpProgram.cpp"); + .getChildFile ("juce_LV2ManifestHelper.cpp"); + } + + build_tools::RelativePath getVST3HelperProgramSource() const + { + const auto suffix = isOSX() ? "mm" : "cpp"; + return getModuleFolderRelativeToProject ("juce_audio_plugin_client") + .getChildFile ("VST3") + .getChildFile (String ("juce_VST3ManifestHelper.") + suffix); } //============================================================================== @@ -219,6 +260,9 @@ class ProjectExporter : private Value::Listener StringArray extraSearchPaths; StringArray moduleLibSearchPaths; + //============================================================================== + const LinuxSubprocessHelperProperties linuxSubprocessHelperProperties { *this }; + //============================================================================== class BuildConfiguration : public ReferenceCountedObject { @@ -284,10 +328,26 @@ class ProjectExporter : private Value::Listener static CompilerWarningFlags getRecommendedForGCCAndLLVM() { CompilerWarningFlags result; - result.common = { "-Wall", "-Wstrict-aliasing", "-Wuninitialized", "-Wunused-parameter", - "-Wswitch-enum", "-Wsign-conversion", "-Wsign-compare", - "-Wunreachable-code", "-Wcast-align", "-Wno-ignored-qualifiers" }; - result.cpp = { "-Woverloaded-virtual", "-Wreorder", "-Wzero-as-null-pointer-constant" }; + result.common = { + "-Wall", + "-Wcast-align", + "-Wfloat-equal", + "-Wno-ignored-qualifiers", + "-Wsign-compare", + "-Wsign-conversion", + "-Wstrict-aliasing", + "-Wswitch-enum", + "-Wuninitialized", + "-Wunreachable-code", + "-Wunused-parameter", + "-Wmissing-field-initializers" + }; + + result.cpp = { + "-Woverloaded-virtual", + "-Wreorder", + "-Wzero-as-null-pointer-constant" + }; return result; } diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp b/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp index a86479561aa2..1f67c0fd9310 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp +++ b/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.cpp @@ -64,14 +64,14 @@ class NewCppFileWizard : public NewFileWizard::Type void createNewFile (Project&, Project::Item parent) override { - askUserToChooseNewFile ("SourceCode.cpp", "*.cpp", parent, [parent] (File newFile) + askUserToChooseNewFile ("SourceCode.cpp", "*.cpp", parent, [this, parent] (File newFile) { if (newFile != File()) - create (parent, newFile, "jucer_NewCppFileTemplate_cpp"); + create (*this, parent, newFile, "jucer_NewCppFileTemplate_cpp"); }); } - static bool create (Project::Item parent, const File& newFile, const char* templateName) + static bool create (NewFileWizard::Type& wizard, Project::Item parent, const File& newFile, const char* templateName) { if (fillInNewCppFileTemplate (newFile, parent, templateName)) { @@ -79,7 +79,7 @@ class NewCppFileWizard : public NewFileWizard::Type return true; } - showFailedToWriteMessage (newFile); + wizard.showFailedToWriteMessage (newFile); return false; } }; @@ -92,14 +92,14 @@ class NewHeaderFileWizard : public NewFileWizard::Type void createNewFile (Project&, Project::Item parent) override { - askUserToChooseNewFile ("SourceCode.h", "*.h", parent, [parent] (File newFile) + askUserToChooseNewFile ("SourceCode.h", "*.h", parent, [this, parent] (File newFile) { if (newFile != File()) - create (parent, newFile, "jucer_NewCppFileTemplate_h"); + create (*this, parent, newFile, "jucer_NewCppFileTemplate_h"); }); } - static bool create (Project::Item parent, const File& newFile, const char* templateName) + static bool create (NewFileWizard::Type& wizard, Project::Item parent, const File& newFile, const char* templateName) { if (fillInNewCppFileTemplate (newFile, parent, templateName)) { @@ -107,7 +107,7 @@ class NewHeaderFileWizard : public NewFileWizard::Type return true; } - showFailedToWriteMessage (newFile); + wizard.showFailedToWriteMessage (newFile); return false; } }; @@ -120,10 +120,10 @@ class NewCppAndHeaderFileWizard : public NewFileWizard::Type void createNewFile (Project&, Project::Item parent) override { - askUserToChooseNewFile ("SourceCode.h", "*.h;*.cpp", parent, [parent] (File newFile) + askUserToChooseNewFile ("SourceCode.h", "*.h;*.cpp", parent, [this, parent] (File newFile) { - if (NewCppFileWizard::create (parent, newFile.withFileExtension ("h"), "jucer_NewCppFileTemplate_h")) - NewCppFileWizard::create (parent, newFile.withFileExtension ("cpp"), "jucer_NewCppFileTemplate_cpp"); + if (NewCppFileWizard::create (*this, parent, newFile.withFileExtension ("h"), "jucer_NewCppFileTemplate_h")) + NewCppFileWizard::create (*this, parent, newFile.withFileExtension ("cpp"), "jucer_NewCppFileTemplate_cpp"); }); } }; @@ -139,7 +139,7 @@ class NewComponentFileWizard : public NewFileWizard::Type createNewFileInternal (parent); } - static bool create (const String& className, Project::Item parent, + static bool create (NewFileWizard::Type& wizard, const String& className, Project::Item parent, const File& newFile, const char* templateName) { auto content = fillInBasicTemplateFields (newFile, parent, templateName) @@ -154,15 +154,15 @@ class NewComponentFileWizard : public NewFileWizard::Type return true; } - showFailedToWriteMessage (newFile); + wizard.showFailedToWriteMessage (newFile); return false; } private: virtual void createFiles (Project::Item parent, const String& className, const File& newFile) { - if (create (className, parent, newFile.withFileExtension ("h"), "jucer_NewComponentTemplate_h")) - create (className, parent, newFile.withFileExtension ("cpp"), "jucer_NewComponentTemplate_cpp"); + if (create (*this, className, parent, newFile.withFileExtension ("h"), "jucer_NewComponentTemplate_h")) + create (*this, className, parent, newFile.withFileExtension ("cpp"), "jucer_NewComponentTemplate_cpp"); } static String getClassNameFieldName() { return "Class Name"; } @@ -227,17 +227,17 @@ class NewSingleFileComponentFileWizard : public NewComponentFileWizard void createFiles (Project::Item parent, const String& className, const File& newFile) override { - create (className, parent, newFile.withFileExtension ("h"), "jucer_NewInlineComponentTemplate_h"); + create (*this, className, parent, newFile.withFileExtension ("h"), "jucer_NewInlineComponentTemplate_h"); } }; - //============================================================================== void NewFileWizard::Type::showFailedToWriteMessage (const File& file) { - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - "Failed to Create File!", - "Couldn't write to the file: " + file.getFullPathName()); + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + "Failed to Create File!", + "Couldn't write to the file: " + file.getFullPathName()); + messageBox = AlertWindow::showScopedAsync (options, nullptr); } void NewFileWizard::Type::askUserToChooseNewFile (const String& suggestedFilename, const String& wildcard, diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.h b/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.h index 8b84ba2b4172..7df471132b83 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_NewFileWizard.h @@ -39,23 +39,23 @@ class NewFileWizard class Type { public: - Type() {} - virtual ~Type() {} + virtual ~Type() = default; //============================================================================== virtual String getName() = 0; virtual void createNewFile (Project&, Project::Item projectGroupToAddTo) = 0; + void showFailedToWriteMessage (const File& file); + protected: //============================================================================== void askUserToChooseNewFile (const String& suggestedFilename, const String& wildcard, const Project::Item& projectGroupToAddTo, std::function callback); - static void showFailedToWriteMessage (const File& file); - private: std::unique_ptr chooser; + ScopedMessageBox messageBox; }; //============================================================================== diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h index 88800347539f..590e64562404 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h @@ -391,6 +391,7 @@ namespace Ids DECLARE_ID (lv2Uri); DECLARE_ID (lv2UriUi); DECLARE_ID (lv2BinaryLocation); + DECLARE_ID (vst3ManifestEnabled); DECLARE_ID (osxSDK); DECLARE_ID (osxCompatibility); diff --git a/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp b/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp index ea203361c5b3..0bd88d0f600d 100644 --- a/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp +++ b/extras/Projucer/Source/Utility/PIPs/jucer_PIPGenerator.cpp @@ -62,18 +62,15 @@ static String ensureCorrectWhitespace (StringRef input) static bool isJUCEExample (const File& pipFile) { - int numLinesToTest = 10; // license should be at the top of the file so no need to - // check all lines - - for (auto line : StringArray::fromLines (pipFile.loadFileAsString())) - { - if (line.contains ("This file is part of the JUCE examples.")) - return true; - - --numLinesToTest; - } - - return false; + const auto numLinesToTest = 10; // license should be at the top of the file so no need to check all lines + const auto lines = StringArray::fromLines (pipFile.loadFileAsString()); + + return std::any_of (lines.begin(), + lines.begin() + (std::min (lines.size(), numLinesToTest)), + [] (const auto& line) + { + return line.contains ("This file is part of the JUCE examples."); + }); } static bool isValidExporterIdentifier (const Identifier& exporterIdentifier) diff --git a/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.cpp b/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.cpp index 0ee08357630f..ceb641a416ad 100644 --- a/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.cpp +++ b/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.cpp @@ -367,71 +367,9 @@ void ProjucerLookAndFeel::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle g.strokePath (getArrowPath (area, isOpen ? 2 : 1, false, Justification::centredRight), PathStrokeType (2.0f)); } -void ProjucerLookAndFeel::drawProgressBar (Graphics& g, ProgressBar& progressBar, - int width, int height, double progress, const String& textToShow) +ProgressBar::Style ProjucerLookAndFeel::getDefaultProgressBarStyle (const ProgressBar&) { - ignoreUnused (width, height, progress); - - const auto background = progressBar.findColour (ProgressBar::backgroundColourId); - const auto foreground = progressBar.findColour (defaultButtonBackgroundColourId); - - const auto sideLength = jmin (width, height); - - auto barBounds = progressBar.getLocalBounds().withSizeKeepingCentre (sideLength, sideLength).reduced (1).toFloat(); - - auto rotationInDegrees = static_cast ((Time::getMillisecondCounter() / 10) % 360); - auto normalisedRotation = rotationInDegrees / 360.0f; - - const auto rotationOffset = 22.5f; - const auto maxRotation = 315.0f; - - auto startInDegrees = rotationInDegrees; - auto endInDegrees = startInDegrees + rotationOffset; - - if (normalisedRotation >= 0.25f && normalisedRotation < 0.5f) - { - const auto rescaledRotation = (normalisedRotation * 4.0f) - 1.0f; - endInDegrees = startInDegrees + rotationOffset + (maxRotation * rescaledRotation); - } - else if (normalisedRotation >= 0.5f && normalisedRotation <= 1.0f) - { - endInDegrees = startInDegrees + rotationOffset + maxRotation; - const auto rescaledRotation = 1.0f - ((normalisedRotation * 2.0f) - 1.0f); - startInDegrees = endInDegrees - rotationOffset - (maxRotation * rescaledRotation); - } - - g.setColour (background); - Path arcPath2; - arcPath2.addCentredArc (barBounds.getCentreX(), - barBounds.getCentreY(), - barBounds.getWidth() * 0.5f, - barBounds.getHeight() * 0.5f, 0.0f, - 0.0f, - MathConstants::twoPi, - true); - g.strokePath (arcPath2, PathStrokeType (2.0f)); - - g.setColour (foreground); - Path arcPath; - arcPath.addCentredArc (barBounds.getCentreX(), - barBounds.getCentreY(), - barBounds.getWidth() * 0.5f, - barBounds.getHeight() * 0.5f, - 0.0f, - degreesToRadians (startInDegrees), - degreesToRadians (endInDegrees), - true); - - arcPath.applyTransform (AffineTransform::rotation (normalisedRotation * MathConstants::pi * 2.25f, - barBounds.getCentreX(), barBounds.getCentreY())); - g.strokePath (arcPath, PathStrokeType (2.0f)); - - if (textToShow.isNotEmpty()) - { - g.setColour (progressBar.findColour (TextButton::textColourOffId)); - g.setFont (Font (12.0f, 2)); - g.drawText (textToShow, barBounds, Justification::centred, false); - } + return ProgressBar::Style::circular; } //============================================================================== @@ -583,5 +521,6 @@ void ProjucerLookAndFeel::setupColours() setColour (TreeView::selectedItemBackgroundColourId, findColour (defaultHighlightColourId)); setColour (PopupMenu::highlightedBackgroundColourId, findColour (defaultHighlightColourId).withAlpha (0.75f)); setColour (PopupMenu::highlightedTextColourId, findColour (defaultHighlightedTextColourId)); + setColour (ProgressBar::foregroundColourId, findColour (defaultButtonBackgroundColourId)); setColour (0x1000440, /*LassoComponent::lassoFillColourId*/ findColour (defaultHighlightColourId).withAlpha (0.3f)); } diff --git a/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.h b/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.h index c3a75da556a5..1338440206bb 100644 --- a/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.h +++ b/extras/Projucer/Source/Utility/UI/jucer_ProjucerLookAndFeel.h @@ -74,7 +74,7 @@ class ProjucerLookAndFeel : public LookAndFeel_V4 void drawTreeviewPlusMinusBox (Graphics&, const Rectangle& area, Colour backgroundColour, bool isItemOpen, bool isMouseOver) override; - void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override; + ProgressBar::Style getDefaultProgressBarStyle (const ProgressBar&) override; //============================================================================== static Path getArrowPath (Rectangle arrowZone, const int direction, diff --git a/extras/UnitTestRunner/Builds/LinuxMakefile/Makefile b/extras/UnitTestRunner/Builds/LinuxMakefile/Makefile index 5d735a95ff20..1571afd5ff23 100644 --- a/extras/UnitTestRunner/Builds/LinuxMakefile/Makefile +++ b/extras/UnitTestRunner/Builds/LinuxMakefile/Makefile @@ -39,13 +39,13 @@ ifeq ($(CONFIG),Debug) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_CONSOLEAPP := UnitTestRunner JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -60,13 +60,13 @@ ifeq ($(CONFIG),Release) TARGET_ARCH := endif - JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70005" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) + JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DJUCE_DISPLAY_SPLASH_SCREEN=0" "-DJUCE_USE_DARK_SPLASH_SCREEN=1" "-DJUCE_PROJUCER_VERSION=0x70007" "-DJUCE_MODULE_AVAILABLE_juce_analytics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_devices=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_formats=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_processors=1" "-DJUCE_MODULE_AVAILABLE_juce_audio_utils=1" "-DJUCE_MODULE_AVAILABLE_juce_core=1" "-DJUCE_MODULE_AVAILABLE_juce_cryptography=1" "-DJUCE_MODULE_AVAILABLE_juce_data_structures=1" "-DJUCE_MODULE_AVAILABLE_juce_dsp=1" "-DJUCE_MODULE_AVAILABLE_juce_events=1" "-DJUCE_MODULE_AVAILABLE_juce_graphics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_basics=1" "-DJUCE_MODULE_AVAILABLE_juce_gui_extra=1" "-DJUCE_MODULE_AVAILABLE_juce_opengl=1" "-DJUCE_MODULE_AVAILABLE_juce_osc=1" "-DJUCE_MODULE_AVAILABLE_juce_product_unlocking=1" "-DJUCE_MODULE_AVAILABLE_juce_video=1" "-DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1" "-DJUCE_PLUGINHOST_VST3=1" "-DJUCE_PLUGINHOST_LV2=1" "-DJUCE_STRICT_REFCOUNTEDPOINTER=1" "-DJUCE_STANDALONE_APPLICATION=1" "-DJUCE_UNIT_TESTS=1" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=1.0.0" "-DJUCE_APP_VERSION_HEX=0x10000" $(shell $(PKG_CONFIG) --cflags alsa freetype2 gl libcurl webkit2gtk-4.0 gtk+-x11-3.0) -pthread -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../../../modules/juce_audio_processors/format_types/LV2_SDK -I../../../../modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) JUCE_CPPFLAGS_CONSOLEAPP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0" JUCE_TARGET_CONSOLEAPP := UnitTestRunner JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS) JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS) - JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 libcurl) -fvisibility=hidden -lrt -ldl -lpthread -lGL $(LDFLAGS) + JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell $(PKG_CONFIG) --libs alsa freetype2 gl libcurl) -fvisibility=hidden -lrt -ldl -lpthread $(LDFLAGS) CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) endif @@ -98,120 +98,125 @@ OBJECTS_CONSOLEAPP := \ all : $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) -$(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) : $(OBJECTS_CONSOLEAPP) $(RESOURCES) +$(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) : $(OBJECTS_CONSOLEAPP) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES) @command -v $(PKG_CONFIG) >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } - @$(PKG_CONFIG) --print-errors alsa freetype2 libcurl + @$(PKG_CONFIG) --print-errors alsa freetype2 gl libcurl @echo Linking "UnitTestRunner - ConsoleApp" -$(V_AT)mkdir -p $(JUCE_BINDIR) -$(V_AT)mkdir -p $(JUCE_LIBDIR) -$(V_AT)mkdir -p $(JUCE_OUTDIR) - $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) $(OBJECTS_CONSOLEAPP) $(JUCE_LDFLAGS) $(RESOURCES) $(TARGET_ARCH) + $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_CONSOLEAPP) $(OBJECTS_CONSOLEAPP) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(RESOURCES) $(TARGET_ARCH) $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling Main.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o: ../../JuceLibraryCode/include_juce_analytics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_analytics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_devices_63111d02.o: ../../JuceLibraryCode/include_juce_audio_devices.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_devices.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_formats.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_10c03666.o: ../../JuceLibraryCode/include_juce_audio_processors.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_ara_2a4c6ef7.o: ../../JuceLibraryCode/include_juce_audio_processors_ara.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_ara.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_processors_lv2_libs_12bdca08.o: ../../JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_processors_lv2_libs.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_audio_utils_9f9fb2d6.o: ../../JuceLibraryCode/include_juce_audio_utils.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_audio_utils.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_core.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_cryptography_8cb807a8.o: ../../JuceLibraryCode/include_juce_cryptography.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_cryptography.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_data_structures.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_dsp_aeb2060f.o: ../../JuceLibraryCode/include_juce_dsp.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_dsp.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_events.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_graphics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_basics.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_gui_extra_6dee1c1a.o: ../../JuceLibraryCode/include_juce_gui_extra.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_gui_extra.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_opengl_a8a032b.o: ../../JuceLibraryCode/include_juce_opengl.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_opengl.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_osc_f3df604d.o: ../../JuceLibraryCode/include_juce_osc.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_osc.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_product_unlocking_8278fcdc.o: ../../JuceLibraryCode/include_juce_product_unlocking.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_product_unlocking.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" $(JUCE_OBJDIR)/include_juce_video_be78589.o: ../../JuceLibraryCode/include_juce_video.cpp - -$(V_AT)mkdir -p $(JUCE_OBJDIR) + -$(V_AT)mkdir -p $(@D) @echo "Compiling include_juce_video.cpp" $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_CONSOLEAPP) $(JUCE_CFLAGS_CONSOLEAPP) -o "$@" -c "$<" +$(JUCE_OBJDIR)/execinfo.cmd: + -$(V_AT)mkdir -p $(@D) + -@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi + $(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@" + clean: @echo Cleaning UnitTestRunner $(V_AT)$(CLEANCMD) diff --git a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj index ba35702c1115..6282fb135ef1 100644 --- a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj +++ b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 1B09834E81EAF5BCB87FAAF4 /* include_juce_product_unlocking.mm */ = {isa = PBXBuildFile; fileRef = B96EC82EC3D2813B50386198; }; 1D06F1A254F84A7AE3E90DF2 /* include_juce_opengl.mm */ = {isa = PBXBuildFile; fileRef = 1CA82C74AEC08421812BDCAC; }; 263250D6F359CE403B0566FF /* IOKit.framework */ = {isa = PBXBuildFile; fileRef = 8C449538B266A891147103D6; }; + 2AD7D2E1785FCABA09AE3764 /* Security.framework */ = {isa = PBXBuildFile; fileRef = 5CF6DD6C5477309A1E9AB644; }; 32010EA67EEFE024B9CE1CB5 /* DiscRecording.framework */ = {isa = PBXBuildFile; fileRef = B4202EE1243A8FCA29996D05; }; 33D24B475EA928745A87EDDB /* include_juce_audio_devices.mm */ = {isa = PBXBuildFile; fileRef = 00CDB93410EA5AECBA5ADA95; }; 3822F598DA7044E5DB7633A9 /* include_juce_audio_utils.mm */ = {isa = PBXBuildFile; fileRef = 846E187EC2E797B982861CA4; }; @@ -74,6 +75,7 @@ 4CA19EC18C2BC536B3636842 /* include_juce_dsp.mm */ /* include_juce_dsp.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_dsp.mm; path = ../../JuceLibraryCode/include_juce_dsp.mm; sourceTree = SOURCE_ROOT; }; 583EA0E5C4B75A629AEF1157 /* include_juce_gui_basics.mm */ /* include_juce_gui_basics.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = include_juce_gui_basics.mm; path = ../../JuceLibraryCode/include_juce_gui_basics.mm; sourceTree = SOURCE_ROOT; }; 5C7BDD8DF72F2FC2D44D757A /* RecentFilesMenuTemplate.nib */ /* RecentFilesMenuTemplate.nib */ = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = SOURCE_ROOT; }; + 5CF6DD6C5477309A1E9AB644 /* Security.framework */ /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 748F996DD2778AD1442AECA6 /* juce_product_unlocking */ /* juce_product_unlocking */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_product_unlocking; path = ../../../../modules/juce_product_unlocking; sourceTree = SOURCE_ROOT; }; 7898C73DCA6FA9D9CF669D32 /* AudioToolbox.framework */ /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 7C4E4601FFB642386AD27B07 /* juce_events */ /* juce_events */ = {isa = PBXFileReference; lastKnownFileType = folder; name = juce_events; path = ../../../../modules/juce_events; sourceTree = SOURCE_ROOT; }; @@ -126,6 +128,7 @@ 263250D6F359CE403B0566FF, 17A09B4AF453B148CD7349F4, 1A038A2954FB9A4F208BE3F2, + 2AD7D2E1785FCABA09AE3764, 4BC57B0D2215621D90C8881C, ); runOnlyForDeploymentPostprocessing = 0; @@ -150,6 +153,7 @@ 8C449538B266A891147103D6, FCB76958E12B2D7F8277CD59, F260758DB97CF0F5C85218C1, + 5CF6DD6C5477309A1E9AB644, D2EBC6292AE5AFC46EB10DAC, ); name = Frameworks; @@ -406,7 +410,7 @@ "NDEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -462,8 +466,8 @@ LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.juce.UnitTestRunner; PRODUCT_NAME = "UnitTestRunner"; @@ -537,7 +541,7 @@ "DEBUG=1", "JUCE_DISPLAY_SPLASH_SCREEN=0", "JUCE_USE_DARK_SPLASH_SCREEN=1", - "JUCE_PROJUCER_VERSION=0x70005", + "JUCE_PROJUCER_VERSION=0x70007", "JUCE_MODULE_AVAILABLE_juce_analytics=1", "JUCE_MODULE_AVAILABLE_juce_audio_basics=1", "JUCE_MODULE_AVAILABLE_juce_audio_devices=1", @@ -592,8 +596,8 @@ INSTALL_PATH = "/usr/bin"; MACOSX_DEPLOYMENT_TARGET = 10.13; MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules"; - OTHER_CFLAGS = "-Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; - OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wswitch-enum -Wsign-conversion -Wsign-compare -Wunreachable-code -Wcast-align -Wno-ignored-qualifiers -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wshadow-all -Wnullable-to-nonnull-conversion -Wmissing-prototypes -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; + OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new"; OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit"; PRODUCT_BUNDLE_IDENTIFIER = com.juce.UnitTestRunner; PRODUCT_NAME = "UnitTestRunner"; diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj index beb5b01d2763..6c28e2f5a8ec 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -80,7 +80,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -108,7 +108,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -124,7 +124,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2017_78A5024=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -470,46 +470,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -854,18 +854,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -965,6 +989,9 @@ true + + true + true @@ -995,7 +1022,7 @@ true - + true @@ -1034,22 +1061,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1145,6 +1172,9 @@ true + + true + true @@ -1157,6 +1187,9 @@ true + + true + true @@ -1166,67 +1199,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1478,13 +1517,13 @@ true - + true - + true - + true @@ -1553,6 +1592,9 @@ true + + true + true @@ -1577,19 +1619,19 @@ true - + true - + true - + true - + true - + true @@ -1868,40 +1910,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1973,6 +2015,9 @@ true + + true + true @@ -2045,6 +2090,9 @@ true + + true + true @@ -2168,52 +2216,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2315,9 +2390,18 @@ true + + true + + + true + true + + true + true @@ -2327,7 +2411,7 @@ true - + true @@ -2384,43 +2468,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2501,10 +2585,10 @@ true - + true - + true @@ -2587,8 +2671,8 @@ - - + + @@ -2683,8 +2767,8 @@ - - + + @@ -2861,6 +2945,7 @@ + @@ -2880,6 +2965,7 @@ + @@ -2916,8 +3002,18 @@ + + + + + + + + + + @@ -2958,6 +3054,7 @@ + @@ -2970,8 +3067,8 @@ + - @@ -3005,6 +3102,7 @@ + @@ -3047,20 +3145,22 @@ + - - - - - - - - + + + + + + + + + @@ -3168,10 +3268,10 @@ - - - - + + + + @@ -3205,6 +3305,7 @@ + @@ -3218,12 +3319,13 @@ - - - + + + + + - - + @@ -3280,10 +3382,10 @@ - - + + + - @@ -3319,6 +3421,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3349,6 +3471,7 @@ + @@ -3394,36 +3517,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3461,10 +3585,12 @@ + - + + @@ -3492,7 +3618,7 @@ - + @@ -3500,9 +3626,9 @@ - - - + + + @@ -3535,14 +3661,14 @@ - - - - - - - - + + + + + + + + @@ -3558,6 +3684,7 @@ + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters index e0a95f8886b9..16bc7c745b18 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -985,49 +1003,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1378,18 +1396,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1492,6 +1537,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1522,7 +1570,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1564,34 +1612,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1690,6 +1738,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1702,6 +1753,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1711,82 +1765,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2047,13 +2107,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2125,6 +2185,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2149,25 +2212,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2449,46 +2512,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2563,6 +2626,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2635,6 +2701,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2758,85 +2827,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2938,9 +3046,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2950,7 +3067,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3010,55 +3127,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3145,10 +3262,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3357,10 +3474,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3645,10 +3762,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4179,6 +4296,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4236,6 +4356,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4344,12 +4467,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4470,6 +4623,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4506,10 +4662,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4611,6 +4767,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4737,6 +4896,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4752,31 +4914,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5100,16 +5265,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5211,6 +5376,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5250,22 +5418,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5436,16 +5607,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5553,6 +5724,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5643,6 +5874,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5778,9 +6012,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5790,82 +6021,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5979,6 +6216,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5988,7 +6228,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6072,7 +6315,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6096,13 +6339,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6201,28 +6444,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6266,6 +6509,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj index 3f268eba698d..a9a78eba799d 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -80,7 +80,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -108,7 +108,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -124,7 +124,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2019_78A5026=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -470,46 +470,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -854,18 +854,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -965,6 +989,9 @@ true + + true + true @@ -995,7 +1022,7 @@ true - + true @@ -1034,22 +1061,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1145,6 +1172,9 @@ true + + true + true @@ -1157,6 +1187,9 @@ true + + true + true @@ -1166,67 +1199,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1478,13 +1517,13 @@ true - + true - + true - + true @@ -1553,6 +1592,9 @@ true + + true + true @@ -1577,19 +1619,19 @@ true - + true - + true - + true - + true - + true @@ -1868,40 +1910,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1973,6 +2015,9 @@ true + + true + true @@ -2045,6 +2090,9 @@ true + + true + true @@ -2168,52 +2216,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2315,9 +2390,18 @@ true + + true + + + true + true + + true + true @@ -2327,7 +2411,7 @@ true - + true @@ -2384,43 +2468,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2501,10 +2585,10 @@ true - + true - + true @@ -2587,8 +2671,8 @@ - - + + @@ -2683,8 +2767,8 @@ - - + + @@ -2861,6 +2945,7 @@ + @@ -2880,6 +2965,7 @@ + @@ -2916,8 +3002,18 @@ + + + + + + + + + + @@ -2958,6 +3054,7 @@ + @@ -2970,8 +3067,8 @@ + - @@ -3005,6 +3102,7 @@ + @@ -3047,20 +3145,22 @@ + - - - - - - - - + + + + + + + + + @@ -3168,10 +3268,10 @@ - - - - + + + + @@ -3205,6 +3305,7 @@ + @@ -3218,12 +3319,13 @@ - - - + + + + + - - + @@ -3280,10 +3382,10 @@ - - + + + - @@ -3319,6 +3421,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3349,6 +3471,7 @@ + @@ -3394,36 +3517,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3461,10 +3585,12 @@ + - + + @@ -3492,7 +3618,7 @@ - + @@ -3500,9 +3626,9 @@ - - - + + + @@ -3535,14 +3661,14 @@ - - - - - - - - + + + + + + + + @@ -3558,6 +3684,7 @@ + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters index 2d93b6b18366..939d8d5fe2f8 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -985,49 +1003,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1378,18 +1396,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1492,6 +1537,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1522,7 +1570,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1564,34 +1612,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1690,6 +1738,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1702,6 +1753,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1711,82 +1765,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2047,13 +2107,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2125,6 +2185,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2149,25 +2212,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2449,46 +2512,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2563,6 +2626,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2635,6 +2701,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2758,85 +2827,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2938,9 +3046,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2950,7 +3067,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3010,55 +3127,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3145,10 +3262,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3357,10 +3474,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3645,10 +3762,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4179,6 +4296,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4236,6 +4356,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4344,12 +4467,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4470,6 +4623,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4506,10 +4662,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4611,6 +4767,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4737,6 +4896,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4752,31 +4914,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5100,16 +5265,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5211,6 +5376,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5250,22 +5418,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5436,16 +5607,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5553,6 +5724,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5643,6 +5874,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5778,9 +6012,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5790,82 +6021,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5979,6 +6216,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5988,7 +6228,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6072,7 +6315,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6096,13 +6339,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6201,28 +6444,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6266,6 +6509,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj index 5cde0f75a1e4..d1277724afbe 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -80,7 +80,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -108,7 +108,7 @@ Full ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -124,7 +124,7 @@ ..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\..\..\modules\juce_audio_processors\format_types\LV2_SDK;..\..\..\..\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CONSOLE;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_analytics=1;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_osc=1;JUCE_MODULE_AVAILABLE_juce_product_unlocking=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_PLUGINHOST_VST3=1;JUCE_PLUGINHOST_LV2=1;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_STANDALONE_APPLICATION=1;JUCE_UNIT_TESTS=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;%(PreprocessorDefinitions) $(OutDir)\UnitTestRunner.exe @@ -470,46 +470,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -854,18 +854,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -965,6 +989,9 @@ true + + true + true @@ -995,7 +1022,7 @@ true - + true @@ -1034,22 +1061,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1145,6 +1172,9 @@ true + + true + true @@ -1157,6 +1187,9 @@ true + + true + true @@ -1166,67 +1199,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1478,13 +1517,13 @@ true - + true - + true - + true @@ -1553,6 +1592,9 @@ true + + true + true @@ -1577,19 +1619,19 @@ true - + true - + true - + true - + true - + true @@ -1868,40 +1910,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1973,6 +2015,9 @@ true + + true + true @@ -2045,6 +2090,9 @@ true + + true + true @@ -2168,52 +2216,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2315,9 +2390,18 @@ true + + true + + + true + true + + true + true @@ -2327,7 +2411,7 @@ true - + true @@ -2384,43 +2468,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2501,10 +2585,10 @@ true - + true - + true @@ -2587,8 +2671,8 @@ - - + + @@ -2683,8 +2767,8 @@ - - + + @@ -2861,6 +2945,7 @@ + @@ -2880,6 +2965,7 @@ + @@ -2916,8 +3002,18 @@ + + + + + + + + + + @@ -2958,6 +3054,7 @@ + @@ -2970,8 +3067,8 @@ + - @@ -3005,6 +3102,7 @@ + @@ -3047,20 +3145,22 @@ + - - - - - - - - + + + + + + + + + @@ -3168,10 +3268,10 @@ - - - - + + + + @@ -3205,6 +3305,7 @@ + @@ -3218,12 +3319,13 @@ - - - + + + + + - - + @@ -3280,10 +3382,10 @@ - - + + + - @@ -3319,6 +3421,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3349,6 +3471,7 @@ + @@ -3394,36 +3517,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3461,10 +3585,12 @@ + - + + @@ -3492,7 +3618,7 @@ - + @@ -3500,9 +3626,9 @@ - - - + + + @@ -3535,14 +3661,14 @@ - - - - - - - - + + + + + + + + @@ -3558,6 +3684,7 @@ + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters index d785e613fb2f..bb7217c9ff1a 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -302,12 +302,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -536,6 +554,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -563,9 +584,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -985,49 +1003,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1378,18 +1396,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1492,6 +1537,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1522,7 +1570,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1564,34 +1612,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1690,6 +1738,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1702,6 +1753,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1711,82 +1765,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -2047,13 +2107,13 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -2125,6 +2185,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -2149,25 +2212,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2449,46 +2512,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2563,6 +2626,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2635,6 +2701,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2758,85 +2827,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2938,9 +3046,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2950,7 +3067,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -3010,55 +3127,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3145,10 +3262,10 @@ JUCE Modules\juce_product_unlocking\marketplace - + JUCE Modules\juce_product_unlocking\native - + JUCE Modules\juce_product_unlocking\native @@ -3357,10 +3474,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3645,10 +3762,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -4179,6 +4296,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -4236,6 +4356,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4344,12 +4467,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4470,6 +4623,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4506,10 +4662,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4611,6 +4767,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4737,6 +4896,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4752,31 +4914,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -5100,16 +5265,16 @@ JUCE Modules\juce_dsp\maths - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native - + JUCE Modules\juce_dsp\native @@ -5211,6 +5376,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -5250,22 +5418,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5436,16 +5607,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5553,6 +5724,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5643,6 +5874,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5778,9 +6012,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5790,82 +6021,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5979,6 +6216,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5988,7 +6228,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -6072,7 +6315,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -6096,13 +6339,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -6201,28 +6444,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -6266,6 +6509,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj index b08545b45605..79e431f0ba33 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj @@ -64,7 +64,7 @@ Disabled ProgramDatabase ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) MultiThreadedDebugDLL true NotUsing @@ -78,7 +78,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) $(OutDir)\juce_dll.lib @@ -106,7 +106,7 @@ Full ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) MultiThreadedDLL true NotUsing @@ -120,7 +120,7 @@ ..\..\JuceLibraryCode;..\..\..\..\modules;%(AdditionalIncludeDirectories) - _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70005;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_DISPLAY_SPLASH_SCREEN=0;JUCE_USE_DARK_SPLASH_SCREEN=1;JUCE_PROJUCER_VERSION=0x70007;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_cryptography=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_MODULE_AVAILABLE_juce_opengl=1;JUCE_MODULE_AVAILABLE_juce_video=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_STANDALONE_APPLICATION=1;JUCE_DLL_BUILD=1;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions) $(OutDir)\juce_dll.lib @@ -453,46 +453,46 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -837,18 +837,42 @@ true + + true + true true + + true + true + + true + + + true + + + true + true + + true + + + true + + + true + true @@ -948,6 +972,9 @@ true + + true + true @@ -978,7 +1005,7 @@ true - + true @@ -1017,22 +1044,22 @@ true - + true - + true - + true - + true - + true - + true @@ -1128,6 +1155,9 @@ true + + true + true @@ -1140,6 +1170,9 @@ true + + true + true @@ -1149,67 +1182,73 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + + true + + + true + + true @@ -1428,6 +1467,9 @@ true + + true + true @@ -1452,19 +1494,19 @@ true - + true - + true - + true - + true - + true @@ -1743,40 +1785,40 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -1848,6 +1890,9 @@ true + + true + true @@ -1920,6 +1965,9 @@ true + + true + true @@ -2043,52 +2091,79 @@ true + + true + + + true + + + true + + + true + true - + + true + + + true + + + true + + + true + + + true + + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2190,9 +2265,18 @@ true + + true + + + true + true + + true + true @@ -2202,7 +2286,7 @@ true - + true @@ -2259,43 +2343,43 @@ true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true - + true @@ -2405,8 +2489,8 @@ - - + + @@ -2501,8 +2585,8 @@ - - + + @@ -2679,6 +2763,7 @@ + @@ -2698,6 +2783,7 @@ + @@ -2734,8 +2820,18 @@ + + + + + + + + + + @@ -2776,6 +2872,7 @@ + @@ -2788,8 +2885,8 @@ + - @@ -2823,6 +2920,7 @@ + @@ -2865,20 +2963,22 @@ + - - - - - - - - + + + + + + + + + @@ -2976,6 +3076,7 @@ + @@ -2989,12 +3090,13 @@ - - - + + + + + - - + @@ -3051,10 +3153,10 @@ - - + + + - @@ -3090,6 +3192,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -3120,6 +3242,7 @@ + @@ -3165,36 +3288,37 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + @@ -3232,10 +3356,12 @@ + - + + @@ -3263,7 +3389,7 @@ - + @@ -3271,9 +3397,9 @@ - - - + + + @@ -3291,14 +3417,14 @@ - - - - - - - - + + + + + + + + @@ -3314,6 +3440,7 @@ + diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters index 33d4edb9ef64..4a13cce29dde 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters @@ -287,12 +287,30 @@ {DAF30656-5915-0E45-C4E4-54439617D525} + + {600076D4-829D-CE7A-272C-832A4BBC40AB} + + + {C02D05C7-CD20-9901-2F02-95A9BD7FA797} + + + {47771136-6D29-90C7-2C6E-1728E7D1C485} + + + {3E938566-9812-78C0-9E81-75858F44C51F} + {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} {9C713CBA-A9E2-5F4E-F83C-2CAB8533913C} + + {D5B5DC1F-B81B-0449-5E26-15D1367B0C8C} + + + {2741675A-628F-4473-FF8D-45CD2C214CDA} + {63571A07-9AA3-5BB0-1103-0B42A2E6BC9E} @@ -497,6 +515,9 @@ {B331BC33-9770-3DB5-73F2-BC2469ECCF7F} + + {3B09E947-B78C-1758-E072-7FD67F8DCB00} + {46A17AC9-0BFF-B5CE-26D6-B9D1992C88AC} @@ -524,9 +545,6 @@ {C0E5DD5D-F8F1-DD25-67D7-291946AB3828} - - {FE7E6CD5-C7A0-DB20-4E7E-D6E7F08C4578} - {895C2D33-E08D-B1BA-BB36-FC4CA65090C8} @@ -913,49 +931,49 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -1306,18 +1324,45 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -1420,6 +1465,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -1450,7 +1498,7 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -1492,34 +1540,34 @@ JUCE Modules\juce_audio_utils\gui - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native - + JUCE Modules\juce_audio_utils\native @@ -1618,6 +1666,9 @@ JUCE Modules\juce_core\maths + + JUCE Modules\juce_core\maths + JUCE Modules\juce_core\maths @@ -1630,6 +1681,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -1639,82 +1693,88 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native @@ -1942,6 +2002,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -1966,25 +2029,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native @@ -2266,46 +2329,46 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -2380,6 +2443,9 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -2452,6 +2518,9 @@ JUCE Modules\juce_gui_basics\keyboard + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -2575,85 +2644,124 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native\accessibility + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -2755,9 +2863,18 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -2767,7 +2884,7 @@ JUCE Modules\juce_gui_basics\windows - + JUCE Modules\juce_gui_basics\windows @@ -2827,55 +2944,55 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native - + JUCE Modules\juce_gui_extra\native @@ -3096,10 +3213,10 @@ JUCE Modules\juce_audio_basics\mpe - + JUCE Modules\juce_audio_basics\native - + JUCE Modules\juce_audio_basics\native @@ -3384,10 +3501,10 @@ JUCE Modules\juce_audio_devices\native\oboe\src\opensles - + JUCE Modules\juce_audio_devices\native - + JUCE Modules\juce_audio_devices\native @@ -3918,6 +4035,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\base\source @@ -3975,6 +4095,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base @@ -4083,12 +4206,42 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\hosting + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst @@ -4209,6 +4362,9 @@ JUCE Modules\juce_audio_processors\utilities\ARA + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors\utilities @@ -4245,10 +4401,10 @@ JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities - + JUCE Modules\juce_audio_processors\utilities @@ -4350,6 +4506,9 @@ JUCE Modules\juce_core\containers + + JUCE Modules\juce_core\containers + JUCE Modules\juce_core\containers @@ -4476,6 +4635,9 @@ JUCE Modules\juce_core\misc + + JUCE Modules\juce_core\misc + JUCE Modules\juce_core\misc @@ -4491,31 +4653,34 @@ JUCE Modules\juce_core\misc - + + JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native - + JUCE Modules\juce_core\native @@ -4809,6 +4974,9 @@ JUCE Modules\juce_events\broadcasters + + JUCE Modules\juce_events\broadcasters + JUCE Modules\juce_events\interprocess @@ -4848,22 +5016,25 @@ JUCE Modules\juce_events\messages - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + JUCE Modules\juce_events\native - + + JUCE Modules\juce_events\native + + JUCE Modules\juce_events\native @@ -5034,16 +5205,16 @@ JUCE Modules\juce_graphics\images - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native - + JUCE Modules\juce_graphics\native @@ -5151,6 +5322,66 @@ JUCE Modules\juce_gui_basics\desktop + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + + + JUCE Modules\juce_gui_basics\detail + JUCE Modules\juce_gui_basics\drawables @@ -5241,6 +5472,9 @@ JUCE Modules\juce_gui_basics\layout + + JUCE Modules\juce_gui_basics\layout + JUCE Modules\juce_gui_basics\layout @@ -5376,9 +5610,6 @@ JUCE Modules\juce_gui_basics\mouse - - JUCE Modules\juce_gui_basics\mouse - JUCE Modules\juce_gui_basics\mouse @@ -5388,82 +5619,88 @@ JUCE Modules\juce_gui_basics\mouse - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - + JUCE Modules\juce_gui_basics\native\accessibility - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - - JUCE Modules\juce_gui_basics\native\x11 + + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + JUCE Modules\juce_gui_basics\native - + + JUCE Modules\juce_gui_basics\native + + + JUCE Modules\juce_gui_basics\native + + JUCE Modules\juce_gui_basics\native @@ -5577,6 +5814,9 @@ JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows + JUCE Modules\juce_gui_basics\windows @@ -5586,7 +5826,10 @@ JUCE Modules\juce_gui_basics\windows - + + JUCE Modules\juce_gui_basics\windows + + JUCE Modules\juce_gui_basics\windows @@ -5670,7 +5913,7 @@ JUCE Modules\juce_gui_extra\misc - + JUCE Modules\juce_gui_extra\native @@ -5694,13 +5937,13 @@ JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native - + JUCE Modules\juce_opengl\native @@ -5754,28 +5997,28 @@ JUCE Modules\juce_video\capture - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native - + JUCE Modules\juce_video\native @@ -5819,6 +6062,9 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces + + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\moduleinfo + JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk diff --git a/modules/juce_analytics/juce_analytics.h b/modules/juce_analytics/juce_analytics.h index 745371f53039..1f8ee761c0aa 100644 --- a/modules/juce_analytics/juce_analytics.h +++ b/modules/juce_analytics/juce_analytics.h @@ -35,7 +35,7 @@ ID: juce_analytics vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE analytics classes description: Classes to collect analytics and send to destinations website: http://www.juce.com/juce diff --git a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp index 2a359f3b3447..7f053d318d07 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp +++ b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp @@ -107,6 +107,34 @@ String AudioChannelSet::getChannelTypeName (AudioChannelSet::ChannelType type) case ambisonicACN33: return NEEDS_TRANS("Ambisonic 33"); case ambisonicACN34: return NEEDS_TRANS("Ambisonic 34"); case ambisonicACN35: return NEEDS_TRANS("Ambisonic 35"); + case ambisonicACN36: return NEEDS_TRANS("Ambisonic 36"); + case ambisonicACN37: return NEEDS_TRANS("Ambisonic 37"); + case ambisonicACN38: return NEEDS_TRANS("Ambisonic 38"); + case ambisonicACN39: return NEEDS_TRANS("Ambisonic 39"); + case ambisonicACN40: return NEEDS_TRANS("Ambisonic 40"); + case ambisonicACN41: return NEEDS_TRANS("Ambisonic 41"); + case ambisonicACN42: return NEEDS_TRANS("Ambisonic 42"); + case ambisonicACN43: return NEEDS_TRANS("Ambisonic 43"); + case ambisonicACN44: return NEEDS_TRANS("Ambisonic 44"); + case ambisonicACN45: return NEEDS_TRANS("Ambisonic 45"); + case ambisonicACN46: return NEEDS_TRANS("Ambisonic 46"); + case ambisonicACN47: return NEEDS_TRANS("Ambisonic 47"); + case ambisonicACN48: return NEEDS_TRANS("Ambisonic 48"); + case ambisonicACN49: return NEEDS_TRANS("Ambisonic 49"); + case ambisonicACN50: return NEEDS_TRANS("Ambisonic 50"); + case ambisonicACN51: return NEEDS_TRANS("Ambisonic 51"); + case ambisonicACN52: return NEEDS_TRANS("Ambisonic 52"); + case ambisonicACN53: return NEEDS_TRANS("Ambisonic 53"); + case ambisonicACN54: return NEEDS_TRANS("Ambisonic 54"); + case ambisonicACN55: return NEEDS_TRANS("Ambisonic 55"); + case ambisonicACN56: return NEEDS_TRANS("Ambisonic 56"); + case ambisonicACN57: return NEEDS_TRANS("Ambisonic 57"); + case ambisonicACN58: return NEEDS_TRANS("Ambisonic 58"); + case ambisonicACN59: return NEEDS_TRANS("Ambisonic 59"); + case ambisonicACN60: return NEEDS_TRANS("Ambisonic 60"); + case ambisonicACN61: return NEEDS_TRANS("Ambisonic 61"); + case ambisonicACN62: return NEEDS_TRANS("Ambisonic 62"); + case ambisonicACN63: return NEEDS_TRANS("Ambisonic 63"); case bottomFrontLeft: return NEEDS_TRANS("Bottom Front Left"); case bottomFrontCentre: return NEEDS_TRANS("Bottom Front Centre"); case bottomFrontRight: return NEEDS_TRANS("Bottom Front Right"); @@ -191,6 +219,34 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT case ambisonicACN33: return "ACN33"; case ambisonicACN34: return "ACN34"; case ambisonicACN35: return "ACN35"; + case ambisonicACN36: return "ACN36"; + case ambisonicACN37: return "ACN37"; + case ambisonicACN38: return "ACN38"; + case ambisonicACN39: return "ACN39"; + case ambisonicACN40: return "ACN40"; + case ambisonicACN41: return "ACN41"; + case ambisonicACN42: return "ACN42"; + case ambisonicACN43: return "ACN43"; + case ambisonicACN44: return "ACN44"; + case ambisonicACN45: return "ACN45"; + case ambisonicACN46: return "ACN46"; + case ambisonicACN47: return "ACN47"; + case ambisonicACN48: return "ACN48"; + case ambisonicACN49: return "ACN49"; + case ambisonicACN50: return "ACN50"; + case ambisonicACN51: return "ACN51"; + case ambisonicACN52: return "ACN52"; + case ambisonicACN53: return "ACN53"; + case ambisonicACN54: return "ACN54"; + case ambisonicACN55: return "ACN55"; + case ambisonicACN56: return "ACN56"; + case ambisonicACN57: return "ACN57"; + case ambisonicACN58: return "ACN58"; + case ambisonicACN59: return "ACN59"; + case ambisonicACN60: return "ACN60"; + case ambisonicACN61: return "ACN61"; + case ambisonicACN62: return "ACN62"; + case ambisonicACN63: return "ACN63"; case topSideLeft: return "Tsl"; case topSideRight: return "Tsr"; case bottomFrontLeft: return "Bfl"; @@ -208,9 +264,6 @@ String AudioChannelSet::getAbbreviatedChannelTypeName (AudioChannelSet::ChannelT default: break; } - if (type >= ambisonicACN4 && type <= ambisonicACN35) - return "ACN" + String (type - ambisonicACN4 + 4); - return {}; } @@ -283,6 +336,34 @@ AudioChannelSet::ChannelType AudioChannelSet::getChannelTypeFromAbbreviation (co if (abbr == "ACN33") return ambisonicACN33; if (abbr == "ACN34") return ambisonicACN34; if (abbr == "ACN35") return ambisonicACN35; + if (abbr == "ACN36") return ambisonicACN36; + if (abbr == "ACN37") return ambisonicACN37; + if (abbr == "ACN38") return ambisonicACN38; + if (abbr == "ACN39") return ambisonicACN39; + if (abbr == "ACN40") return ambisonicACN40; + if (abbr == "ACN41") return ambisonicACN41; + if (abbr == "ACN42") return ambisonicACN42; + if (abbr == "ACN43") return ambisonicACN43; + if (abbr == "ACN44") return ambisonicACN44; + if (abbr == "ACN45") return ambisonicACN45; + if (abbr == "ACN46") return ambisonicACN46; + if (abbr == "ACN47") return ambisonicACN47; + if (abbr == "ACN48") return ambisonicACN48; + if (abbr == "ACN49") return ambisonicACN49; + if (abbr == "ACN50") return ambisonicACN50; + if (abbr == "ACN51") return ambisonicACN51; + if (abbr == "ACN52") return ambisonicACN52; + if (abbr == "ACN53") return ambisonicACN53; + if (abbr == "ACN54") return ambisonicACN54; + if (abbr == "ACN55") return ambisonicACN55; + if (abbr == "ACN56") return ambisonicACN56; + if (abbr == "ACN57") return ambisonicACN57; + if (abbr == "ACN58") return ambisonicACN58; + if (abbr == "ACN59") return ambisonicACN59; + if (abbr == "ACN60") return ambisonicACN60; + if (abbr == "ACN61") return ambisonicACN61; + if (abbr == "ACN62") return ambisonicACN62; + if (abbr == "ACN63") return ambisonicACN63; if (abbr == "Tsl") return topSideLeft; if (abbr == "Tsr") return topSideRight; if (abbr == "Bfl") return bottomFrontLeft; @@ -338,6 +419,8 @@ String AudioChannelSet::getDescription() const if (*this == createLCRS()) return "LCRS"; if (*this == create5point0()) return "5.0 Surround"; + if (*this == create5point0point2()) return "5.0.2 Surround"; + if (*this == create5point0point4()) return "5.0.4 Surround"; if (*this == create5point1()) return "5.1 Surround"; if (*this == create5point1point2()) return "5.1.2 Surround"; if (*this == create5point1point4()) return "5.1.4 Surround"; @@ -351,9 +434,13 @@ String AudioChannelSet::getDescription() const if (*this == create7point1SDDS()) return "7.1 Surround SDDS"; if (*this == create7point0point2()) return "7.0.2 Surround"; if (*this == create7point0point4()) return "7.0.4 Surround"; + if (*this == create7point0point6()) return "7.0.6 Surround"; if (*this == create7point1point2()) return "7.1.2 Surround"; if (*this == create7point1point4()) return "7.1.4 Surround"; if (*this == create7point1point6()) return "7.1.6 Surround"; + if (*this == create9point0point4()) return "9.0.4 Surround"; + if (*this == create9point1point4()) return "9.1.4 Surround"; + if (*this == create9point0point6()) return "9.0.6 Surround"; if (*this == create9point1point6()) return "9.1.6 Surround"; if (*this == quadraphonic()) return "Quadraphonic"; @@ -386,11 +473,11 @@ String AudioChannelSet::getDescription() const bool AudioChannelSet::isDiscreteLayout() const noexcept { - for (auto& speaker : getChannelTypes()) - if (speaker <= ambisonicACN35) - return false; + const auto channelTypes = getChannelTypes(); - return true; + return std::none_of (std::begin (channelTypes), + std::end (channelTypes), + [] (const auto& t) { return t < discreteChannel0; }); } int AudioChannelSet::size() const noexcept @@ -467,26 +554,44 @@ AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet AudioChannelSet AudioChannelSet::pentagonal() { return AudioChannelSet ({ left, right, centre, leftSurroundRear, rightSurroundRear }); } AudioChannelSet AudioChannelSet::hexagonal() { return AudioChannelSet ({ left, right, centre, centreSurround, leftSurroundRear, rightSurroundRear }); } AudioChannelSet AudioChannelSet::octagonal() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround, wideLeft, wideRight }); } +AudioChannelSet AudioChannelSet::create5point0point2() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, topSideLeft, topSideRight }); } AudioChannelSet AudioChannelSet::create5point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight }); } +AudioChannelSet AudioChannelSet::create5point0point4() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::create5point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::create7point0point2() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); } AudioChannelSet AudioChannelSet::create7point1point2() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topSideLeft, topSideRight }); } AudioChannelSet AudioChannelSet::create7point0point4() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::create7point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create7point0point6() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::create7point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point0point4() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point1point4() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point0point6() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::create9point1point6() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight }); } AudioChannelSet AudioChannelSet::ambisonic (int order) { - jassert (isPositiveAndBelow (order, 6)); + jassert (isPositiveAndBelow (order, 8)); + + static constexpr std::pair continuousRanges[] { { ambisonicACN0, ambisonicACN3 }, + { ambisonicACN4, ambisonicACN35 }, + { ambisonicACN36, ambisonicACN63 } }; - if (order == 0) - return AudioChannelSet ((uint32) (1 << ambisonicACN0)); + AudioChannelSet set; - AudioChannelSet set ((1u << ambisonicACN0) | (1u << ambisonicACN1) | (1u << ambisonicACN2) | (1u << ambisonicACN3)); + const auto setBits = [&set] (auto range, auto maxNumToSet) + { + const auto numToSet = std::min (maxNumToSet, range.second - range.first + 1); + set.channels.setRange (range.first, numToSet, true); + return numToSet; + }; - auto numAmbisonicChannels = (order + 1) * (order + 1); - set.channels.setRange (ambisonicACN4, numAmbisonicChannels - 4, true); + const auto numAmbisonicChannels = square (order + 1); + + for (int rangeIdx = 0, bitsSet = 0; bitsSet < numAmbisonicChannels; ++rangeIdx) + { + bitsSet += setBits (continuousRanges[rangeIdx], numAmbisonicChannels - bitsSet); + } return set; } @@ -631,15 +736,13 @@ int32 AudioChannelSet::getWaveChannelMask() const noexcept } //============================================================================== -int JUCE_CALLTYPE AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels) +int AudioChannelSet::getAmbisonicOrderForNumChannels (int numChannels, int maxOrderToCheck) { - auto sqrtMinusOne = std::sqrt (static_cast (numChannels)) - 1.0f; - auto ambisonicOrder = jmax (0, static_cast (std::floor (sqrtMinusOne))); + for (auto i = 0; i <= maxOrderToCheck; ++i) + if (numChannels == square (i + 1)) + return i; - if (ambisonicOrder > 5) - return -1; - - return (static_cast (ambisonicOrder) == sqrtMinusOne ? ambisonicOrder : -1); + return -1; } diff --git a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h index 3c96befa278a..989669ddccd2 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h +++ b/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h @@ -196,12 +196,24 @@ class JUCE_API AudioChannelSet */ static AudioChannelSet JUCE_CALLTYPE create7point1SDDS(); + /** Creates a set for a 5.0.2 surround setup (left, right, centre, leftSurround, rightSurround, topSideLeft, topSideRight). + + Is equivalent to: AAX_eStemFormat_5_0_2 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create5point0point2(); + /** Creates a set for a 5.1.2 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topSideLeft, topSideRight). Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_2 (CoreAudio). */ static AudioChannelSet JUCE_CALLTYPE create5point1point2(); + /** Creates a set for a 5.0.4 surround setup (left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: AAX_eStemFormat_5_0_4 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create5point0point4(); + /** Creates a set for a 5.1.4 surround setup (left, right, centre, LFE, leftSurround, rightSurround, topFrontLeft, topFrontRight, topRearLeft, topRearRight). Is equivalent to: kAudioChannelLayoutTag_Atmos_5_1_4 (CoreAudio). @@ -232,12 +244,36 @@ class JUCE_API AudioChannelSet */ static AudioChannelSet JUCE_CALLTYPE create7point1point4(); + /** Creates a set for 7.0.6 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). + + Is equivalent to: AAX_eStemFormat_7_0_6 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create7point0point6(); + /** Creates a set for Dolby Atmos 7.1.6 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, LFE, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). Is equivalent to: k71_6 (VST), n/a (AAX), n/a (CoreAudio) */ static AudioChannelSet JUCE_CALLTYPE create7point1point6(); + /** Creates a set for a 9.0.4 surround setup (left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: k90_4 (VST3), AAX_eStemFormat_9_0_4 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create9point0point4(); + + /** Creates a set for a 9.1.4 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: k91_4 (VST3), AAX_eStemFormat_9_1_4 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create9point1point4(); + + /** Creates a set for a 9.0.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). + + Is equivalent to: k90_6 (VST3), AAX_eStemFormat_9_0_6 (AAX). + */ + static AudioChannelSet JUCE_CALLTYPE create9point0point6(); + /** Creates a set for a 9.1.6 surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). Note that the VST3 layout arranges the front speakers "L Lc C Rc R", but the JUCE layout @@ -419,6 +455,40 @@ class JUCE_API AudioChannelSet bottomRearCentre = 70, /**< Bottom Rear Center (Brc) */ bottomRearRight = 71, /**< Bottom Rear Right (Brr) */ + //============================================================================== + + // sixth-order ambisonic + ambisonicACN36 = 72, /**< Sixth-order ambisonic channel number 36. */ + ambisonicACN37 = 73, /**< Sixth-order ambisonic channel number 37. */ + ambisonicACN38 = 74, /**< Sixth-order ambisonic channel number 38. */ + ambisonicACN39 = 75, /**< Sixth-order ambisonic channel number 39. */ + ambisonicACN40 = 76, /**< Sixth-order ambisonic channel number 40. */ + ambisonicACN41 = 77, /**< Sixth-order ambisonic channel number 41. */ + ambisonicACN42 = 78, /**< Sixth-order ambisonic channel number 42. */ + ambisonicACN43 = 79, /**< Sixth-order ambisonic channel number 43. */ + ambisonicACN44 = 80, /**< Sixth-order ambisonic channel number 44. */ + ambisonicACN45 = 81, /**< Sixth-order ambisonic channel number 45. */ + ambisonicACN46 = 82, /**< Sixth-order ambisonic channel number 46. */ + ambisonicACN47 = 83, /**< Sixth-order ambisonic channel number 47. */ + ambisonicACN48 = 84, /**< Sixth-order ambisonic channel number 48. */ + + // seventh-order ambisonic + ambisonicACN49 = 85, /**< Seventh-order ambisonic channel number 49. */ + ambisonicACN50 = 86, /**< Seventh-order ambisonic channel number 50. */ + ambisonicACN51 = 87, /**< Seventh-order ambisonic channel number 51. */ + ambisonicACN52 = 88, /**< Seventh-order ambisonic channel number 52. */ + ambisonicACN53 = 89, /**< Seventh-order ambisonic channel number 53. */ + ambisonicACN54 = 90, /**< Seventh-order ambisonic channel number 54. */ + ambisonicACN55 = 91, /**< Seventh-order ambisonic channel number 55. */ + ambisonicACN56 = 92, /**< Seventh-order ambisonic channel number 56. */ + ambisonicACN57 = 93, /**< Seventh-order ambisonic channel number 57. */ + ambisonicACN58 = 94, /**< Seventh-order ambisonic channel number 58. */ + ambisonicACN59 = 95, /**< Seventh-order ambisonic channel number 59. */ + ambisonicACN60 = 96, /**< Seventh-order ambisonic channel number 60. */ + ambisonicACN61 = 97, /**< Seventh-order ambisonic channel number 61. */ + ambisonicACN62 = 98, /**< Seventh-order ambisonic channel number 62. */ + ambisonicACN63 = 99, /**< Seventh-order ambisonic channel number 63. */ + //============================================================================== discreteChannel0 = 128 /**< Non-typed individual channels are indexed upwards from this value. */ }; @@ -435,7 +505,7 @@ class JUCE_API AudioChannelSet //============================================================================== enum { - maxChannelsOfNamedLayout = 36 + maxChannelsOfNamedLayout = 64 }; /** Adds a channel to the set. */ @@ -505,6 +575,12 @@ class JUCE_API AudioChannelSet */ int32 getWaveChannelMask() const noexcept; + //============================================================================== + /** Returns the ambisonic order that includes exactly numChannels, or -1 if no + supported ambisonic order contains exactly numChannels. + */ + static int getAmbisonicOrderForNumChannels (int numChannels, int maxOrderToCheck = 7); + //============================================================================== bool operator== (const AudioChannelSet&) const noexcept; bool operator!= (const AudioChannelSet&) const noexcept; @@ -518,8 +594,6 @@ class JUCE_API AudioChannelSet explicit AudioChannelSet (uint32); explicit AudioChannelSet (const std::initializer_list&); - //============================================================================== - static int JUCE_CALLTYPE getAmbisonicOrderForNumChannels (int); }; } // namespace juce diff --git a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp index c72e3e3c9372..f5e9c668fce9 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp +++ b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.cpp @@ -599,7 +599,7 @@ class AudioConversionTests : public UnitTest for (int ch = 0; ch < numChannels; ++ch) for (int i = 0; i < numSamples; ++i) - expect (destBuffer.getSample (0, ch + (i * numChannels)) == sourceBuffer.getSample (ch, i)); + expectEquals (destBuffer.getSample (0, ch + (i * numChannels)), sourceBuffer.getSample (ch, i)); } beginTest ("Deinterleaving"); @@ -620,7 +620,7 @@ class AudioConversionTests : public UnitTest for (int ch = 0; ch < numChannels; ++ch) for (int i = 0; i < numSamples; ++i) - expect (sourceBuffer.getSample (0, ch + (i * numChannels)) == destBuffer.getSample (ch, i)); + expectEquals (sourceBuffer.getSample (0, ch + (i * numChannels)), destBuffer.getSample (ch, i)); } } }; diff --git a/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp b/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp index 2144fa66b5b9..98ce1a592d6a 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp +++ b/modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp @@ -60,7 +60,7 @@ void AudioProcessLoadMeasurer::registerRenderTime (double milliseconds, int numS void AudioProcessLoadMeasurer::registerRenderTimeLocked (double milliseconds, int numSamples) { - if (msPerSample == 0) + if (approximatelyEqual (msPerSample, 0.0)) return; const auto maxMilliseconds = numSamples * msPerSample; diff --git a/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h b/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h index d583a59399af..a1d18595a21d 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h +++ b/modules/juce_audio_basics/buffers/juce_AudioSampleBuffer.h @@ -686,11 +686,11 @@ class AudioBuffer jassert (isPositiveAndBelow (channel, numChannels)); jassert (startSample >= 0 && numSamples >= 0 && startSample + numSamples <= size); - if (gain != Type (1) && ! isClear) + if (! approximatelyEqual (gain, Type (1)) && ! isClear) { auto* d = channels[channel] + startSample; - if (gain == Type()) + if (approximatelyEqual (gain, Type())) FloatVectorOperations::clear (d, numSamples); else FloatVectorOperations::multiply (d, gain, numSamples); @@ -728,7 +728,7 @@ class AudioBuffer { if (! isClear) { - if (startGain == endGain) + if (approximatelyEqual (startGain, endGain)) { applyGain (channel, startSample, numSamples, startGain); } @@ -798,7 +798,7 @@ class AudioBuffer jassert (isPositiveAndBelow (sourceChannel, source.numChannels)); jassert (sourceStartSample >= 0 && sourceStartSample + numSamples <= source.size); - if (gainToApplyToSource != 0 && numSamples > 0 && ! source.isClear) + if (! approximatelyEqual (gainToApplyToSource, (Type) 0) && numSamples > 0 && ! source.isClear) { auto* d = channels[destChannel] + destStartSample; auto* s = source.channels[sourceChannel] + sourceStartSample; @@ -809,14 +809,14 @@ class AudioBuffer { isClear = false; - if (gainToApplyToSource != Type (1)) + if (! approximatelyEqual (gainToApplyToSource, Type (1))) FloatVectorOperations::copyWithMultiply (d, s, gainToApplyToSource, numSamples); else FloatVectorOperations::copy (d, s, numSamples); } else { - if (gainToApplyToSource != Type (1)) + if (! approximatelyEqual (gainToApplyToSource, Type (1))) FloatVectorOperations::addWithMultiply (d, s, gainToApplyToSource, numSamples); else FloatVectorOperations::add (d, s, numSamples); @@ -850,7 +850,7 @@ class AudioBuffer jassert (destStartSample >= 0 && numSamples >= 0 && destStartSample + numSamples <= size); jassert (source != nullptr); - if (gainToApplyToSource != 0 && numSamples > 0) + if (! approximatelyEqual (gainToApplyToSource, Type()) && numSamples > 0) { auto* d = channels[destChannel] + destStartSample; @@ -858,14 +858,14 @@ class AudioBuffer { isClear = false; - if (gainToApplyToSource != Type (1)) + if (! approximatelyEqual (gainToApplyToSource, Type (1))) FloatVectorOperations::copyWithMultiply (d, source, gainToApplyToSource, numSamples); else FloatVectorOperations::copy (d, source, numSamples); } else { - if (gainToApplyToSource != Type (1)) + if (! approximatelyEqual (gainToApplyToSource, Type (1))) FloatVectorOperations::addWithMultiply (d, source, gainToApplyToSource, numSamples); else FloatVectorOperations::add (d, source, numSamples); @@ -899,7 +899,7 @@ class AudioBuffer Type startGain, Type endGain) noexcept { - if (startGain == endGain) + if (approximatelyEqual (startGain, endGain)) { addFrom (destChannel, destStartSample, source, numSamples, startGain); } @@ -912,7 +912,7 @@ class AudioBuffer if (numSamples > 0) { isClear = false; - const auto increment = (endGain - startGain) / numSamples; + const auto increment = (endGain - startGain) / (Type) numSamples; auto* d = channels[destChannel] + destStartSample; while (--numSamples >= 0) @@ -1023,9 +1023,9 @@ class AudioBuffer { auto* d = channels[destChannel] + destStartSample; - if (gain != Type (1)) + if (! approximatelyEqual (gain, Type (1))) { - if (gain == Type()) + if (approximatelyEqual (gain, Type())) { if (! isClear) FloatVectorOperations::clear (d, numSamples); @@ -1071,7 +1071,7 @@ class AudioBuffer Type startGain, Type endGain) noexcept { - if (startGain == endGain) + if (approximatelyEqual (startGain, endGain)) { copyFrom (destChannel, destStartSample, source, numSamples, startGain); } @@ -1084,7 +1084,7 @@ class AudioBuffer if (numSamples > 0) { isClear = false; - const auto increment = (endGain - startGain) / numSamples; + const auto increment = (endGain - startGain) / (Type) numSamples; auto* d = channels[destChannel] + destStartSample; while (--numSamples >= 0) @@ -1280,6 +1280,31 @@ class AudioBuffer JUCE_LEAK_DETECTOR (AudioBuffer) }; +//============================================================================== +template +bool operator== (const AudioBuffer& a, const AudioBuffer& b) +{ + if (a.getNumChannels() != b.getNumChannels()) + return false; + + for (auto c = 0; c < a.getNumChannels(); ++c) + { + const auto begin = [c] (auto& x) { return x.getReadPointer (c); }; + const auto end = [c] (auto& x) { return x.getReadPointer (c) + x.getNumSamples(); }; + + if (! std::equal (begin (a), end (a), begin (b), end (b))) + return false; + } + + return true; +} + +template +bool operator!= (const AudioBuffer& a, const AudioBuffer& b) +{ + return ! (a == b); +} + //============================================================================== /** A multi-channel buffer of 32-bit floating point audio samples. diff --git a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp index 2a576dc989b5..1079e872a942 100644 --- a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp +++ b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp @@ -1676,7 +1676,7 @@ class FloatVectorOperationsTests : public UnitTest static bool areAllValuesEqual (const ValueType* d, int num, ValueType target) { while (--num >= 0) - if (*d++ != target) + if (! exactlyEqual (*d++, target)) return false; return true; diff --git a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h index 9c6ed4990936..ce342b63717e 100644 --- a/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h +++ b/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h @@ -98,7 +98,7 @@ struct FloatVectorOperationsBase /** Multiplies the destination values by the source values. */ static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src, CountType numValues) noexcept; - /** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */ + /** Multiplies each source1 value by the corresponding source2 value, then stores it in the destination array. */ static void JUCE_CALLTYPE multiply (FloatType* dest, const FloatType* src1, const FloatType* src2, CountType numValues) noexcept; /** Multiplies each of the destination values by a fixed multiplier. */ diff --git a/modules/juce_audio_basics/juce_audio_basics.cpp b/modules/juce_audio_basics/juce_audio_basics.cpp index 570974762e59..260635fad6f7 100644 --- a/modules/juce_audio_basics/juce_audio_basics.cpp +++ b/modules/juce_audio_basics/juce_audio_basics.cpp @@ -88,6 +88,7 @@ #include "sources/juce_PositionableAudioSource.cpp" #include "synthesisers/juce_Synthesiser.cpp" #include "audio_play_head/juce_AudioPlayHead.cpp" +#include "midi/juce_MidiDataConcatenator.h" #include "midi/ump/juce_UMP.h" #include "midi/ump/juce_UMPUtils.cpp" diff --git a/modules/juce_audio_basics/juce_audio_basics.h b/modules/juce_audio_basics/juce_audio_basics.h index 85c0c437ed65..6a8c999da6c2 100644 --- a/modules/juce_audio_basics/juce_audio_basics.h +++ b/modules/juce_audio_basics/juce_audio_basics.h @@ -32,7 +32,7 @@ ID: juce_audio_basics vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE audio and MIDI data classes description: Classes for audio buffer manipulation, midi message handling, synthesis, etc. website: http://www.juce.com/juce diff --git a/modules/juce_audio_basics/midi/juce_MidiFile.cpp b/modules/juce_audio_basics/midi/juce_MidiFile.cpp index 67795b45c425..51bfcdda3a5a 100644 --- a/modules/juce_audio_basics/midi/juce_MidiFile.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiFile.cpp @@ -160,7 +160,7 @@ namespace MidiFileHelpers for (int i = 0; i < numEvents; ++i) { - auto& m = tempoEvents.getEventPointer(i)->message; + auto& m = tempoEvents.getEventPointer (i)->message; auto eventTime = m.getTimeStamp(); if (eventTime >= time) @@ -174,9 +174,9 @@ namespace MidiFileHelpers while (i + 1 < numEvents) { - auto& m2 = tempoEvents.getEventPointer(i + 1)->message; + auto& m2 = tempoEvents.getEventPointer (i + 1)->message; - if (m2.getTimeStamp() != eventTime) + if (! approximatelyEqual (m2.getTimeStamp(), eventTime)) break; if (m2.isTempoMetaEvent()) diff --git a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp index 129ad9e08586..95d0122201fd 100644 --- a/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiMessageSequence.cpp @@ -266,7 +266,7 @@ void MidiMessageSequence::updateMatchedPairs() noexcept void MidiMessageSequence::addTimeToMessages (double delta) noexcept { - if (delta != 0) + if (! approximatelyEqual (delta, 0.0)) for (auto* m : list) m->message.addToTimeStamp (delta); } @@ -554,7 +554,7 @@ struct MidiMessageSequenceTest : public UnitTest { const auto isEqual = [this] (const ControlValue& cv, const MidiMessage& msg) { - return msg.getTimeStamp() == time + return exactlyEqual (msg.getTimeStamp(), time) && msg.isController() && msg.getChannel() == channel && msg.getControllerNumber() == cv.control diff --git a/modules/juce_audio_basics/midi/juce_MidiRPN.cpp b/modules/juce_audio_basics/midi/juce_MidiRPN.cpp index ae5fc500f286..f16e73a76e60 100644 --- a/modules/juce_audio_basics/midi/juce_MidiRPN.cpp +++ b/modules/juce_audio_basics/midi/juce_MidiRPN.cpp @@ -23,42 +23,46 @@ namespace juce { -MidiRPNDetector::MidiRPNDetector() noexcept -{ -} - -MidiRPNDetector::~MidiRPNDetector() noexcept -{ -} - bool MidiRPNDetector::parseControllerMessage (int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage& result) noexcept +{ + auto parsed = tryParse (midiChannel, controllerNumber, controllerValue); + + if (! parsed.has_value()) + return false; + + result = *parsed; + return true; +} + +std::optional MidiRPNDetector::tryParse (int midiChannel, + int controllerNumber, + int controllerValue) { jassert (midiChannel > 0 && midiChannel <= 16); jassert (controllerNumber >= 0 && controllerNumber < 128); jassert (controllerValue >= 0 && controllerValue < 128); - return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue, result); + return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue); } void MidiRPNDetector::reset() noexcept { - for (int i = 0; i < 16; ++i) + for (auto& state : states) { - states[i].parameterMSB = 0xff; - states[i].parameterLSB = 0xff; - states[i].resetValue(); - states[i].isNRPN = false; + state.parameterMSB = 0xff; + state.parameterLSB = 0xff; + state.resetValue(); + state.isNRPN = false; } } //============================================================================== -bool MidiRPNDetector::ChannelState::handleController (int channel, - int controllerNumber, - int value, - MidiRPNMessage& result) noexcept +std::optional MidiRPNDetector::ChannelState::handleController (int channel, + int controllerNumber, + int value) noexcept { switch (controllerNumber) { @@ -68,13 +72,11 @@ bool MidiRPNDetector::ChannelState::handleController (int channel, case 0x64: parameterLSB = uint8 (value); resetValue(); isNRPN = false; break; case 0x65: parameterMSB = uint8 (value); resetValue(); isNRPN = false; break; - case 0x06: valueMSB = uint8 (value); return sendIfReady (channel, result); - case 0x26: valueLSB = uint8 (value); break; - - default: break; + case 0x06: valueMSB = uint8 (value); valueLSB = 0xff; return sendIfReady (channel); + case 0x26: valueLSB = uint8 (value); return sendIfReady (channel); } - return false; + return {}; } void MidiRPNDetector::ChannelState::resetValue() noexcept @@ -84,32 +86,28 @@ void MidiRPNDetector::ChannelState::resetValue() noexcept } //============================================================================== -bool MidiRPNDetector::ChannelState::sendIfReady (int channel, MidiRPNMessage& result) noexcept +std::optional MidiRPNDetector::ChannelState::sendIfReady (int channel) noexcept { - if (parameterMSB < 0x80 && parameterLSB < 0x80) - { - if (valueMSB < 0x80) - { - result.channel = channel; - result.parameterNumber = (parameterMSB << 7) + parameterLSB; - result.isNRPN = isNRPN; + if (parameterMSB >= 0x80 || parameterLSB >= 0x80 || valueMSB >= 0x80) + return {}; - if (valueLSB < 0x80) - { - result.value = (valueMSB << 7) + valueLSB; - result.is14BitValue = true; - } - else - { - result.value = valueMSB; - result.is14BitValue = false; - } + MidiRPNMessage result{}; + result.channel = channel; + result.parameterNumber = (parameterMSB << 7) + parameterLSB; + result.isNRPN = isNRPN; - return true; - } + if (valueLSB < 0x80) + { + result.value = (valueMSB << 7) + valueLSB; + result.is14BitValue = true; + } + else + { + result.value = valueMSB; + result.is14BitValue = false; } - return false; + return result; } //============================================================================== @@ -132,25 +130,26 @@ MidiBuffer MidiRPNGenerator::generate (int midiChannel, jassert (parameterNumber >= 0 && parameterNumber < 16384); jassert (value >= 0 && value < (use14BitValue ? 16384 : 128)); - uint8 parameterLSB = uint8 (parameterNumber & 0x0000007f); - uint8 parameterMSB = uint8 (parameterNumber >> 7); + auto parameterLSB = uint8 (parameterNumber & 0x0000007f); + auto parameterMSB = uint8 (parameterNumber >> 7); uint8 valueLSB = use14BitValue ? uint8 (value & 0x0000007f) : 0x00; uint8 valueMSB = use14BitValue ? uint8 (value >> 7) : uint8 (value); - uint8 channelByte = uint8 (0xb0 + midiChannel - 1); + auto channelByte = uint8 (0xb0 + midiChannel - 1); MidiBuffer buffer; buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x62 : 0x64, parameterLSB), 0); buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x63 : 0x65, parameterMSB), 0); - // sending the value LSB is optional, but must come before sending the value MSB: + buffer.addEvent (MidiMessage (channelByte, 0x06, valueMSB), 0); + + // According to the MIDI spec, whenever a MSB is received, the corresponding LSB will + // be reset. Therefore, the LSB should be sent after the MSB. if (use14BitValue) buffer.addEvent (MidiMessage (channelByte, 0x26, valueLSB), 0); - buffer.addEvent (MidiMessage (channelByte, 0x06, valueMSB), 0); - return buffer; } @@ -168,134 +167,196 @@ class MidiRPNDetectorTests : public UnitTest void runTest() override { - beginTest ("7-bit RPN"); + // From the MIDI 1.0 spec: + // If 128 steps of resolution is sufficient the second byte (LSB) of the data value can be + // omitted. If both the MSB and LSB are sent initially, a subsequent fine adjustment only + // requires the sending of the LSB. The MSB does not have to be retransmitted. If a + // subsequent major adjustment is necessary the MSB must be transmitted again. When an MSB + // is received, the receiver should set its concept of the LSB to zero. + + beginTest ("Individual MSB is parsed as 7-bit"); + { + MidiRPNDetector detector; + expect (! detector.tryParse (2, 101, 0)); + expect (! detector.tryParse (2, 100, 7)); + + auto parsed = detector.tryParse (2, 6, 42); + expect (parsed.has_value()); + + expectEquals (parsed->channel, 2); + expectEquals (parsed->parameterNumber, 7); + expectEquals (parsed->value, 42); + expect (! parsed->isNRPN); + expect (! parsed->is14BitValue); + } + + beginTest ("LSB without preceding MSB is ignored"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (2, 101, 0, rpn)); - expect (! detector.parseControllerMessage (2, 100, 7, rpn)); - expect (detector.parseControllerMessage (2, 6, 42, rpn)); - - expectEquals (rpn.channel, 2); - expectEquals (rpn.parameterNumber, 7); - expectEquals (rpn.value, 42); - expect (! rpn.isNRPN); - expect (! rpn.is14BitValue); + expect (! detector.tryParse (2, 101, 0)); + expect (! detector.tryParse (2, 100, 7)); + expect (! detector.tryParse (2, 38, 42)); } - beginTest ("14-bit RPN"); + beginTest ("LSB following MSB is parsed as 14-bit"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (1, 100, 44, rpn)); - expect (! detector.parseControllerMessage (1, 101, 2, rpn)); - expect (! detector.parseControllerMessage (1, 38, 94, rpn)); - expect (detector.parseControllerMessage (1, 6, 1, rpn)); - - expectEquals (rpn.channel, 1); - expectEquals (rpn.parameterNumber, 300); - expectEquals (rpn.value, 222); - expect (! rpn.isNRPN); - expect (rpn.is14BitValue); + expect (! detector.tryParse (1, 101, 2)); + expect (! detector.tryParse (1, 100, 44)); + + expect (detector.tryParse (1, 6, 1).has_value()); + + auto lsbParsed = detector.tryParse (1, 38, 94); + expect (lsbParsed.has_value()); + + expectEquals (lsbParsed->channel, 1); + expectEquals (lsbParsed->parameterNumber, 300); + expectEquals (lsbParsed->value, 222); + expect (! lsbParsed->isNRPN); + expect (lsbParsed->is14BitValue); + } + + beginTest ("Multiple LSB following MSB re-use the MSB"); + { + MidiRPNDetector detector; + expect (! detector.tryParse (1, 101, 2)); + expect (! detector.tryParse (1, 100, 43)); + + expect (detector.tryParse (1, 6, 1).has_value()); + + expect (detector.tryParse (1, 38, 94).has_value()); + expect (detector.tryParse (1, 38, 95).has_value()); + expect (detector.tryParse (1, 38, 96).has_value()); + + auto lsbParsed = detector.tryParse (1, 38, 97); + expect (lsbParsed.has_value()); + + expectEquals (lsbParsed->channel, 1); + expectEquals (lsbParsed->parameterNumber, 299); + expectEquals (lsbParsed->value, 225); + expect (! lsbParsed->isNRPN); + expect (lsbParsed->is14BitValue); + } + + beginTest ("Sending a new MSB resets the LSB"); + { + MidiRPNDetector detector; + expect (! detector.tryParse (1, 101, 3)); + expect (! detector.tryParse (1, 100, 43)); + + expect (detector.tryParse (1, 6, 1).has_value()); + expect (detector.tryParse (1, 38, 94).has_value()); + + auto newMsb = detector.tryParse (1, 6, 2); + expect (newMsb.has_value()); + + expectEquals (newMsb->channel, 1); + expectEquals (newMsb->parameterNumber, 427); + expectEquals (newMsb->value, 2); + expect (! newMsb->isNRPN); + expect (! newMsb->is14BitValue); } beginTest ("RPNs on multiple channels simultaneously"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (1, 100, 44, rpn)); - expect (! detector.parseControllerMessage (2, 101, 0, rpn)); - expect (! detector.parseControllerMessage (1, 101, 2, rpn)); - expect (! detector.parseControllerMessage (2, 100, 7, rpn)); - expect (! detector.parseControllerMessage (1, 38, 94, rpn)); - expect (detector.parseControllerMessage (2, 6, 42, rpn)); - - expectEquals (rpn.channel, 2); - expectEquals (rpn.parameterNumber, 7); - expectEquals (rpn.value, 42); - expect (! rpn.isNRPN); - expect (! rpn.is14BitValue); - - expect (detector.parseControllerMessage (1, 6, 1, rpn)); - - expectEquals (rpn.channel, 1); - expectEquals (rpn.parameterNumber, 300); - expectEquals (rpn.value, 222); - expect (! rpn.isNRPN); - expect (rpn.is14BitValue); + expect (! detector.tryParse (1, 100, 44)); + expect (! detector.tryParse (2, 101, 0)); + expect (! detector.tryParse (1, 101, 2)); + expect (! detector.tryParse (2, 100, 7)); + expect (detector.tryParse (1, 6, 1).has_value()); + + auto channelTwo = detector.tryParse (2, 6, 42); + expect (channelTwo.has_value()); + + expectEquals (channelTwo->channel, 2); + expectEquals (channelTwo->parameterNumber, 7); + expectEquals (channelTwo->value, 42); + expect (! channelTwo->isNRPN); + expect (! channelTwo->is14BitValue); + + auto channelOne = detector.tryParse (1, 38, 94); + expect (channelOne.has_value()); + + expectEquals (channelOne->channel, 1); + expectEquals (channelOne->parameterNumber, 300); + expectEquals (channelOne->value, 222); + expect (! channelOne->isNRPN); + expect (channelOne->is14BitValue); } beginTest ("14-bit RPN with value within 7-bit range"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (16, 100, 0 , rpn)); - expect (! detector.parseControllerMessage (16, 101, 0, rpn)); - expect (! detector.parseControllerMessage (16, 38, 3, rpn)); - expect (detector.parseControllerMessage (16, 6, 0, rpn)); - - expectEquals (rpn.channel, 16); - expectEquals (rpn.parameterNumber, 0); - expectEquals (rpn.value, 3); - expect (! rpn.isNRPN); - expect (rpn.is14BitValue); + expect (! detector.tryParse (16, 100, 0)); + expect (! detector.tryParse (16, 101, 0)); + expect (detector.tryParse (16, 6, 0).has_value()); + + auto parsed = detector.tryParse (16, 38, 3); + expect (parsed.has_value()); + + expectEquals (parsed->channel, 16); + expectEquals (parsed->parameterNumber, 0); + expectEquals (parsed->value, 3); + expect (! parsed->isNRPN); + expect (parsed->is14BitValue); } beginTest ("invalid RPN (wrong order)"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (2, 6, 42, rpn)); - expect (! detector.parseControllerMessage (2, 101, 0, rpn)); - expect (! detector.parseControllerMessage (2, 100, 7, rpn)); + expect (! detector.tryParse (2, 6, 42)); + expect (! detector.tryParse (2, 101, 0)); + expect (! detector.tryParse (2, 100, 7)); } beginTest ("14-bit RPN interspersed with unrelated CC messages"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (16, 3, 80, rpn)); - expect (! detector.parseControllerMessage (16, 100, 0 , rpn)); - expect (! detector.parseControllerMessage (16, 4, 81, rpn)); - expect (! detector.parseControllerMessage (16, 101, 0, rpn)); - expect (! detector.parseControllerMessage (16, 5, 82, rpn)); - expect (! detector.parseControllerMessage (16, 5, 83, rpn)); - expect (! detector.parseControllerMessage (16, 38, 3, rpn)); - expect (! detector.parseControllerMessage (16, 4, 84, rpn)); - expect (! detector.parseControllerMessage (16, 3, 85, rpn)); - expect (detector.parseControllerMessage (16, 6, 0, rpn)); - - expectEquals (rpn.channel, 16); - expectEquals (rpn.parameterNumber, 0); - expectEquals (rpn.value, 3); - expect (! rpn.isNRPN); - expect (rpn.is14BitValue); + expect (! detector.tryParse (16, 3, 80)); + expect (! detector.tryParse (16, 100, 0)); + expect (! detector.tryParse (16, 4, 81)); + expect (! detector.tryParse (16, 101, 0)); + expect (! detector.tryParse (16, 5, 82)); + expect (! detector.tryParse (16, 5, 83)); + expect (detector.tryParse (16, 6, 0).has_value()); + expect (! detector.tryParse (16, 4, 84).has_value()); + expect (! detector.tryParse (16, 3, 85).has_value()); + + auto parsed = detector.tryParse (16, 38, 3); + expect (parsed.has_value()); + + expectEquals (parsed->channel, 16); + expectEquals (parsed->parameterNumber, 0); + expectEquals (parsed->value, 3); + expect (! parsed->isNRPN); + expect (parsed->is14BitValue); } beginTest ("14-bit NRPN"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (1, 98, 44, rpn)); - expect (! detector.parseControllerMessage (1, 99 , 2, rpn)); - expect (! detector.parseControllerMessage (1, 38, 94, rpn)); - expect (detector.parseControllerMessage (1, 6, 1, rpn)); - - expectEquals (rpn.channel, 1); - expectEquals (rpn.parameterNumber, 300); - expectEquals (rpn.value, 222); - expect (rpn.isNRPN); - expect (rpn.is14BitValue); + expect (! detector.tryParse (1, 98, 44)); + expect (! detector.tryParse (1, 99 , 2)); + expect (detector.tryParse (1, 6, 1).has_value()); + + auto parsed = detector.tryParse (1, 38, 94); + expect (parsed.has_value()); + + expectEquals (parsed->channel, 1); + expectEquals (parsed->parameterNumber, 300); + expectEquals (parsed->value, 222); + expect (parsed->isNRPN); + expect (parsed->is14BitValue); } beginTest ("reset"); { MidiRPNDetector detector; - MidiRPNMessage rpn; - expect (! detector.parseControllerMessage (2, 101, 0, rpn)); + expect (! detector.tryParse (2, 101, 0)); detector.reset(); - expect (! detector.parseControllerMessage (2, 100, 7, rpn)); - expect (! detector.parseControllerMessage (2, 6, 42, rpn)); + expect (! detector.tryParse (2, 100, 7)); + expect (! detector.tryParse (2, 6, 42)); } } }; @@ -346,25 +407,24 @@ class MidiRPNGeneratorTests : public UnitTest //============================================================================== void expectContainsRPN (const MidiBuffer& midiBuffer, MidiRPNMessage expected) { - MidiRPNMessage result = MidiRPNMessage(); + std::optional result; MidiRPNDetector detector; for (const auto metadata : midiBuffer) { const auto midiMessage = metadata.getMessage(); - if (detector.parseControllerMessage (midiMessage.getChannel(), - midiMessage.getControllerNumber(), - midiMessage.getControllerValue(), - result)) - break; + result = detector.tryParse (midiMessage.getChannel(), + midiMessage.getControllerNumber(), + midiMessage.getControllerValue()); } - expectEquals (result.channel, expected.channel); - expectEquals (result.parameterNumber, expected.parameterNumber); - expectEquals (result.value, expected.value); - expect (result.isNRPN == expected.isNRPN); - expect (result.is14BitValue == expected.is14BitValue); + expect (result.has_value()); + expectEquals (result->channel, expected.channel); + expectEquals (result->parameterNumber, expected.parameterNumber); + expectEquals (result->value, expected.value); + expect (result->isNRPN == expected.isNRPN); + expect (result->is14BitValue == expected.is14BitValue); } }; diff --git a/modules/juce_audio_basics/midi/juce_MidiRPN.h b/modules/juce_audio_basics/midi/juce_MidiRPN.h index f1fb9ff01e3d..1f4fcf3c9c2c 100644 --- a/modules/juce_audio_basics/midi/juce_MidiRPN.h +++ b/modules/juce_audio_basics/midi/juce_MidiRPN.h @@ -68,10 +68,10 @@ class JUCE_API MidiRPNDetector { public: /** Constructor. */ - MidiRPNDetector() noexcept; + MidiRPNDetector() noexcept = default; /** Destructor. */ - ~MidiRPNDetector() noexcept; + ~MidiRPNDetector() noexcept = default; /** Resets the RPN detector's internal state, so that it forgets about previously received MIDI CC messages. @@ -79,26 +79,39 @@ class JUCE_API MidiRPNDetector void reset() noexcept; //============================================================================== - /** Takes the next in a stream of incoming MIDI CC messages and returns true - if it forms the last of a sequence that makes an RPN or NPRN. - - If this returns true, then the RPNMessage object supplied will be - filled-out with the message's details. - (If it returns false then the RPNMessage object will be unchanged). - */ + /** @see tryParse() */ + [[deprecated ("Use tryParse() instead")]] bool parseControllerMessage (int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage& result) noexcept; + /** Takes the next in a stream of incoming MIDI CC messages and returns + a MidiRPNMessage if the current message produces a well-formed RPN or NRPN. + + Note that senders are expected to send the MSB before the LSB, but senders are + not required to send a LSB at all. Therefore, tryParse() will return a non-null + optional on all MSB messages (provided a parameter number has been set), and will + also return a non-null optional for each LSB that follows the initial MSB. + + This behaviour allows senders to transmit a single MSB followed by multiple LSB + messages to facilitate fine-tuning of parameters. + + The result of parsing a MSB will always be a 7-bit value. + The result of parsing a LSB that follows an MSB will always be a 14-bit value. + */ + std::optional tryParse (int midiChannel, + int controllerNumber, + int controllerValue); + private: //============================================================================== struct ChannelState { - bool handleController (int channel, int controllerNumber, - int value, MidiRPNMessage&) noexcept; + std::optional handleController (int channel, int controllerNumber, + int value) noexcept; void resetValue() noexcept; - bool sendIfReady (int channel, MidiRPNMessage&) noexcept; + std::optional sendIfReady (int channel) noexcept; uint8 parameterMSB = 0xff, parameterLSB = 0xff, valueMSB = 0xff, valueLSB = 0xff; bool isNRPN = false; diff --git a/modules/juce_audio_basics/midi/ump/juce_UMP.h b/modules/juce_audio_basics/midi/ump/juce_UMP.h index 0fd724ae3f91..ea656a653f26 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMP.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMP.h @@ -20,8 +20,6 @@ ============================================================================== */ -#include "../juce_MidiDataConcatenator.h" - #include "juce_UMPProtocols.h" #include "juce_UMPUtils.h" #include "juce_UMPacket.h" diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h b/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h index 8980e1e7e40b..f28cc7656010 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPConversion.h @@ -27,6 +27,44 @@ namespace juce namespace universal_midi_packets { +/** Represents a MIDI message that happened at a particular time. + + Unlike MidiMessage, BytestreamMidiView is non-owning. +*/ +struct BytestreamMidiView +{ + constexpr BytestreamMidiView (Span bytesIn, double timestampIn) + : bytes (bytesIn), timestamp (timestampIn) {} + + /** Creates a view over the provided message. + + Note that the argument is a pointer, not a reference, in order to avoid taking a reference + to a temporary. + */ + explicit BytestreamMidiView (const MidiMessage* msg) + : bytes (unalignedPointerCast (msg->getRawData()), + static_cast (msg->getRawDataSize())), + timestamp (msg->getTimeStamp()) {} + + explicit BytestreamMidiView (const MidiMessageMetadata msg) + : bytes (unalignedPointerCast (msg.data), + static_cast (msg.numBytes)), + timestamp (msg.samplePosition) {} + + MidiMessage getMessage() const + { + return MidiMessage (bytes.data(), (int) bytes.size(), timestamp); + } + + bool isSysEx() const + { + return ! bytes.empty() && bytes.front() == std::byte { 0xf0 }; + } + + Span bytes; + double timestamp = 0.0; +}; + /** Functions to assist conversion of UMP messages to/from other formats, especially older 'bytestream' formatted MidiMessages. @@ -40,13 +78,17 @@ struct Conversion `callback` is a function which accepts a single View argument. */ template - static void toMidi1 (const MidiMessage& m, PacketCallbackFunction&& callback) + static void toMidi1 (const BytestreamMidiView& m, PacketCallbackFunction&& callback) { - const auto* data = m.getRawData(); + const auto size = m.bytes.size(); + + if (size <= 0) + return; + + const auto* data = m.bytes.data(); const auto firstByte = data[0]; - const auto size = m.getRawDataSize(); - if (firstByte != 0xf0) + if (firstByte != std::byte { 0xf0 }) { const auto mask = [size]() -> uint32_t { @@ -61,15 +103,15 @@ struct Conversion return 0x00000000; }(); - const auto extraByte = (uint8_t) ((((firstByte & 0xf0) == 0xf0) ? 0x1 : 0x2) << 0x4); + const auto extraByte = ((((firstByte & std::byte { 0xf0 }) == std::byte { 0xf0 }) ? std::byte { 0x1 } : std::byte { 0x2 }) << 0x4); const PacketX1 packet { mask & Utils::bytesToWord (extraByte, data[0], data[1], data[2]) }; callback (View (packet.data())); return; } - const auto numSysExBytes = m.getSysExDataSize(); + const auto numSysExBytes = (ssize_t) (size - 2); const auto numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes); - auto* dataOffset = m.getSysExData(); + auto* dataOffset = data + 1; if (numMessages <= 1) { @@ -78,9 +120,9 @@ struct Conversion return; } - constexpr auto byteIncrement = 6; + constexpr ssize_t byteIncrement = 6; - for (auto i = numSysExBytes; i > 0; i -= byteIncrement, dataOffset += byteIncrement) + for (auto i = static_cast (numSysExBytes); i > 0; i -= byteIncrement, dataOffset += byteIncrement) { const auto func = [&] { @@ -99,20 +141,6 @@ struct Conversion } } - /** Converts a MidiMessage to one or more messages in UMP format, using - the MIDI 1.0 Protocol. - - `packets` is an out-param to allow the caller to control - allocation/deallocation. Returning a new Packets object would - require every call to toMidi1 to allocate. With this version, no - allocations will occur, provided that `packets` has adequate reserved - space. - */ - static void toMidi1 (const MidiMessage& m, Packets& packets) - { - toMidi1 (m, [&] (const View& view) { packets.add (view); }); - } - /** Widens a 7-bit MIDI 1.0 value to a 8-bit MIDI 2.0 value. */ static uint8_t scaleTo8 (uint8_t word7Bit) { @@ -198,7 +226,7 @@ struct Conversion } const auto status = Utils::getStatus (firstWord); - const auto typeAndGroup = (uint8_t) ((0x2 << 0x4) | Utils::getGroup (firstWord)); + const auto typeAndGroup = ((std::byte { 0x2 } << 0x4) | std::byte { Utils::getGroup (firstWord) }); switch (status) { @@ -207,18 +235,18 @@ struct Conversion case 0xa: // poly pressure case 0xb: // control change { - const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); - const auto byte2 = (uint8_t) ((firstWord >> 0x08) & 0xff); - const auto byte3 = scaleTo7 (v[1]); + const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff); + const auto byte2 = std::byte ((firstWord >> 0x08) & 0xff); + const auto byte3 = std::byte { scaleTo7 (v[1]) }; // If this is a note-on, and the scaled byte is 0, // the scaled velocity should be 1 instead of 0 - const auto needsCorrection = status == 0x9 && byte3 == 0; - const auto correctedByte = (uint8_t) (needsCorrection ? 1 : byte3); + const auto needsCorrection = status == 0x9 && byte3 == std::byte { 0 }; + const auto correctedByte = needsCorrection ? std::byte { 1 } : byte3; const auto shouldIgnore = status == 0xb && [&] { - switch (byte2) + switch (uint8_t (byte2)) { case 0: case 6: @@ -247,13 +275,13 @@ struct Conversion case 0xd: // channel pressure { - const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); - const auto byte2 = scaleTo7 (v[1]); + const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff); + const auto byte2 = std::byte { scaleTo7 (v[1]) }; const PacketX1 packet { Utils::bytesToWord (typeAndGroup, statusAndChannel, byte2, - 0) }; + std::byte { 0 }) }; callback (View (packet.data())); return; } @@ -261,17 +289,17 @@ struct Conversion case 0x2: // rpn case 0x3: // nrpn { - const auto ccX = (uint8_t) (status == 0x2 ? 101 : 99); - const auto ccY = (uint8_t) (status == 0x2 ? 100 : 98); - const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord)); + const auto ccX = status == 0x2 ? std::byte { 101 } : std::byte { 99 }; + const auto ccY = status == 0x2 ? std::byte { 100 } : std::byte { 98 }; + const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord)); const auto data = scaleTo14 (v[1]); const PacketX1 packets[] { - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, (uint8_t) ((firstWord >> 0x8) & 0x7f)) }, - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, (uint8_t) ((firstWord >> 0x0) & 0x7f)) }, - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 6, (uint8_t) ((data >> 0x7) & 0x7f)) }, - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 38, (uint8_t) ((data >> 0x0) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, std::byte ((firstWord >> 0x8) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, std::byte ((firstWord >> 0x0) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 6 }, std::byte ((data >> 0x7) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 38 }, std::byte ((data >> 0x0) & 0x7f)) }, }; for (const auto& packet : packets) @@ -284,24 +312,24 @@ struct Conversion { if (firstWord & 1) { - const auto statusAndChannel = (uint8_t) ((0xb << 0x4) | Utils::getChannel (firstWord)); + const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord)); const auto secondWord = v[1]; const PacketX1 packets[] { - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 0, (uint8_t) ((secondWord >> 0x8) & 0x7f)) }, - PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, 32, (uint8_t) ((secondWord >> 0x0) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 0 }, std::byte ((secondWord >> 0x8) & 0x7f)) }, + PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 32 }, std::byte ((secondWord >> 0x0) & 0x7f)) }, }; for (const auto& packet : packets) callback (View (packet.data())); } - const auto statusAndChannel = (uint8_t) ((0xc << 0x4) | Utils::getChannel (firstWord)); + const auto statusAndChannel = std::byte ((0xc << 0x4) | Utils::getChannel (firstWord)); const PacketX1 packet { Utils::bytesToWord (typeAndGroup, statusAndChannel, - (uint8_t) ((v[1] >> 0x18) & 0x7f), - 0) }; + std::byte ((v[1] >> 0x18) & 0x7f), + std::byte { 0 }) }; callback (View (packet.data())); return; } @@ -309,11 +337,11 @@ struct Conversion case 0xe: // pitch bend { const auto data = scaleTo14 (v[1]); - const auto statusAndChannel = (uint8_t) ((firstWord >> 0x10) & 0xff); + const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff); const PacketX1 packet { Utils::bytesToWord (typeAndGroup, statusAndChannel, - (uint8_t) (data & 0x7f), - (uint8_t) ((data >> 7) & 0x7f)) }; + std::byte (data & 0x7f), + std::byte ((data >> 7) & 0x7f)) }; callback (View (packet.data())); return; } diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h b/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h index 3639cceb8300..8f51f13af7fa 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPConverters.h @@ -35,7 +35,7 @@ namespace universal_midi_packets struct ToUMP1Converter { template - void convert (const MidiMessage& m, Fn&& fn) + void convert (const BytestreamMidiView& m, Fn&& fn) { Conversion::toMidi1 (m, std::forward (fn)); } @@ -56,7 +56,7 @@ namespace universal_midi_packets struct ToUMP2Converter { template - void convert (const MidiMessage& m, Fn&& fn) + void convert (const BytestreamMidiView& m, Fn&& fn) { Conversion::toMidi1 (m, [&] (const View& v) { @@ -88,6 +88,15 @@ namespace universal_midi_packets */ class GenericUMPConverter { + template + static void visit (This& t, Args&&... args) + { + if (t.mode == PacketProtocol::MIDI_1_0) + convertImpl (std::get<0> (t.converters), std::forward (args)...); + else + convertImpl (std::get<1> (t.converters), std::forward (args)...); + } + public: explicit GenericUMPConverter (PacketProtocol m) : mode (m) {} @@ -97,33 +106,43 @@ namespace universal_midi_packets std::get<1> (converters).reset(); } - template - void convert (const MidiMessage& m, Fn&& fn) + template + static void convertImpl (Converter& converter, const BytestreamMidiView& m, Fn&& fn) { - switch (mode) + converter.convert (m, std::forward (fn)); + } + + template + static void convertImpl (Converter& converter, const View& m, Fn&& fn) + { + converter.convert (m, std::forward (fn)); + } + + template + static void convertImpl (Converter& converter, Iterator b, Iterator e, Fn&& fn) + { + std::for_each (b, e, [&] (const auto& v) { - case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (m, std::forward (fn)); - case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (m, std::forward (fn)); - } + convertImpl (converter, v, fn); + }); + } + + template + void convert (const BytestreamMidiView& m, Fn&& fn) + { + visit (*this, m, std::forward (fn)); } template void convert (const View& v, Fn&& fn) { - switch (mode) - { - case PacketProtocol::MIDI_1_0: return std::get<0> (converters).convert (v, std::forward (fn)); - case PacketProtocol::MIDI_2_0: return std::get<1> (converters).convert (v, std::forward (fn)); - } + visit (*this, v, std::forward (fn)); } template void convert (Iterator begin, Iterator end, Fn&& fn) { - std::for_each (begin, end, [&] (const View& v) - { - convert (v, fn); - }); + visit (*this, begin, end, std::forward (fn)); } PacketProtocol getProtocol() const noexcept { return mode; } diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h b/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h index b2512d2f3ee3..f5eb8873d0f8 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPDispatcher.h @@ -123,7 +123,7 @@ class BytestreamToUMPDispatcher void handleIncomingMidiMessage (void*, const MidiMessage& msg) const { - Conversion::toMidi1 (msg, [&] (const View& view) + Conversion::toMidi1 (BytestreamMidiView (&msg), [&] (const View& view) { dispatch.converter.convert (view, *callbackPtr); }); diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h b/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h index 788d34a41f6e..9f1e265634fa 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPFactory.h @@ -45,7 +45,7 @@ struct Factory static PacketX2 makeSysEx (uint8_t group, uint8_t status, uint8_t numBytes, - const uint8_t* data) + const std::byte* data) { jassert (numBytes <= 6); @@ -250,28 +250,28 @@ struct Factory static PacketX2 makeSysExIn1Packet (uint8_t group, uint8_t numBytes, - const uint8_t* data) + const std::byte* data) { return Detail::makeSysEx (group, 0x0, numBytes, data); } static PacketX2 makeSysExStart (uint8_t group, uint8_t numBytes, - const uint8_t* data) + const std::byte* data) { return Detail::makeSysEx (group, 0x1, numBytes, data); } static PacketX2 makeSysExContinue (uint8_t group, uint8_t numBytes, - const uint8_t* data) + const std::byte* data) { return Detail::makeSysEx (group, 0x2, numBytes, data); } static PacketX2 makeSysExEnd (uint8_t group, uint8_t numBytes, - const uint8_t* data) + const std::byte* data) { return Detail::makeSysEx (group, 0x3, numBytes, data); } diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h index f3d4e01cc60c..e1b268b53fa8 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h @@ -73,7 +73,10 @@ class Midi1ToBytestreamTranslator { // Utility messages don't translate to bytestream format if (Utils::getMessageType (firstWord) != 0x00) - callback (fromUmp (PacketX1 { firstWord }, time)); + { + const auto message = fromUmp (PacketX1 { firstWord }, time); + callback (BytestreamMidiView (&message)); + } break; } @@ -162,16 +165,14 @@ class Midi1ToBytestreamTranslator void startSysExMessage (double time) { pendingSysExTime = time; - pendingSysExData.push_back (0xf0); + pendingSysExData.push_back (std::byte { 0xf0 }); } template void terminateSysExMessage (MessageCallback&& callback) { - pendingSysExData.push_back (0xf7); - callback (MidiMessage (pendingSysExData.data(), - int (pendingSysExData.size()), - pendingSysExTime)); + pendingSysExData.push_back (std::byte { 0xf7 }); + callback (BytestreamMidiView (pendingSysExData, pendingSysExTime)); pendingSysExData.clear(); } @@ -206,7 +207,7 @@ class Midi1ToBytestreamTranslator return Utils::getMessageType (word) == 0x1 && ((word >> 0x10) & 0xff) >= 0xf8; } - std::vector pendingSysExData; + std::vector pendingSysExData; double pendingSysExTime = 0.0; }; diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp index d4c5e2757fc9..6964809263fa 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp +++ b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp @@ -28,14 +28,14 @@ namespace universal_midi_packets PacketX2 Midi1ToMidi2DefaultTranslator::processNoteOnOrOff (const HelperValues helpers) { const auto velocity = helpers.byte2; - const auto needsConversion = (helpers.byte0 >> 0x4) == 0x9 && velocity == 0; - const auto firstByte = needsConversion ? (uint8_t) ((0x8 << 0x4) | (helpers.byte0 & 0xf)) + const auto needsConversion = (helpers.byte0 & std::byte { 0xf0 }) == std::byte { 0x90 } && velocity == std::byte { 0 }; + const auto firstByte = needsConversion ? (std::byte { 0x80 } | (helpers.byte0 & std::byte { 0xf })) : helpers.byte0; return PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, firstByte, helpers.byte1, 0), - (uint32_t) (Conversion::scaleTo16 (velocity) << 0x10) + Utils::bytesToWord (helpers.typeAndGroup, firstByte, helpers.byte1, std::byte { 0 }), + (uint32_t) (Conversion::scaleTo16 (uint8_t (velocity)) << 0x10) }; } @@ -43,8 +43,8 @@ PacketX2 Midi1ToMidi2DefaultTranslator::processPolyPressure (const HelperValues { return PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, helpers.byte1, 0), - Conversion::scaleTo32 (helpers.byte2) + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, helpers.byte1, std::byte { 0 }), + Conversion::scaleTo32 (uint8_t (helpers.byte2)) }; } @@ -52,7 +52,7 @@ bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues hel PacketX2& packet) { const auto statusAndChannel = helpers.byte0; - const auto cc = helpers.byte1; + const auto cc = uint8_t (helpers.byte1); const auto shouldAccumulate = [&] { @@ -70,8 +70,8 @@ bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues hel return false; }(); - const auto group = (uint8_t) (helpers.typeAndGroup & 0xf); - const auto channel = (uint8_t) (statusAndChannel & 0xf); + const auto group = (uint8_t) (helpers.typeAndGroup & std::byte { 0xf }); + const auto channel = (uint8_t) (statusAndChannel & std::byte { 0xf }); const auto byte = helpers.byte2; if (shouldAccumulate) @@ -86,13 +86,13 @@ bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues hel const auto msb = bytes[2]; const auto lsb = bytes[3]; - const auto value = (uint16_t) (((msb & 0x7f) << 7) | (lsb & 0x7f)); + const auto value = uint16_t ((uint16_t (msb & std::byte { 0x7f }) << 7) | uint16_t (lsb & std::byte { 0x7f })); const auto newStatus = (uint8_t) (accumulator.getKind() == PnKind::nrpn ? 0x3 : 0x2); packet = PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, (uint8_t) ((newStatus << 0x4) | channel), bank, index), + Utils::bytesToWord (helpers.typeAndGroup, std::byte ((newStatus << 0x4) | channel), bank, index), Conversion::scaleTo32 (value) }; return true; @@ -103,35 +103,41 @@ bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues hel if (cc == 0) { - groupBanks[group][channel].setMsb (byte); + groupBanks[group][channel].setMsb (uint8_t (byte)); return false; } if (cc == 32) { - groupBanks[group][channel].setLsb (byte); + groupBanks[group][channel].setLsb (uint8_t (byte)); return false; } packet = PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, statusAndChannel, cc, 0), - Conversion::scaleTo32 (helpers.byte2) + Utils::bytesToWord (helpers.typeAndGroup, statusAndChannel, std::byte { cc }, std::byte { 0 }), + Conversion::scaleTo32 (uint8_t (helpers.byte2)) }; return true; } PacketX2 Midi1ToMidi2DefaultTranslator::processProgramChange (const HelperValues helpers) const { - const auto group = (uint8_t) (helpers.typeAndGroup & 0xf); - const auto channel = (uint8_t) (helpers.byte0 & 0xf); + const auto group = (uint8_t) (helpers.typeAndGroup & std::byte { 0xf }); + const auto channel = (uint8_t) (helpers.byte0 & std::byte { 0xf }); const auto bank = groupBanks[group][channel]; const auto valid = bank.isValid(); return PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, valid ? 1 : 0), - Utils::bytesToWord (helpers.byte1, 0, valid ? bank.getMsb() : 0, valid ? bank.getLsb() : 0) + Utils::bytesToWord (helpers.typeAndGroup, + helpers.byte0, + std::byte { 0 }, + valid ? std::byte { 1 } : std::byte { 0 }), + Utils::bytesToWord (helpers.byte1, + std::byte { 0 }, + valid ? std::byte { bank.getMsb() } : std::byte { 0 }, + valid ? std::byte { bank.getLsb() } : std::byte { 0 }) }; } @@ -139,8 +145,8 @@ PacketX2 Midi1ToMidi2DefaultTranslator::processChannelPressure (const HelperValu { return PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0), - Conversion::scaleTo32 (helpers.byte1) + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, std::byte { 0 }, std::byte { 0 }), + Conversion::scaleTo32 (uint8_t (helpers.byte1)) }; } @@ -148,16 +154,16 @@ PacketX2 Midi1ToMidi2DefaultTranslator::processPitchBend (const HelperValues hel { const auto lsb = helpers.byte1; const auto msb = helpers.byte2; - const auto value = (uint16_t) (msb << 7 | lsb); + const auto value = uint16_t (uint16_t (msb) << 7 | uint16_t (lsb)); return PacketX2 { - Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, 0, 0), + Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, std::byte { 0 }, std::byte { 0 }), Conversion::scaleTo32 (value) }; } -bool Midi1ToMidi2DefaultTranslator::PnAccumulator::addByte (uint8_t cc, uint8_t byte) +bool Midi1ToMidi2DefaultTranslator::PnAccumulator::addByte (uint8_t cc, std::byte byte) { const auto isStart = cc == 99 || cc == 101; diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h index b2a47836b5f5..b644b839e617 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.h @@ -61,10 +61,10 @@ class Midi1ToMidi2DefaultTranslator const HelperValues helperValues { - (uint8_t) ((0x4 << 0x4) | Utils::getGroup (firstWord)), - (uint8_t) ((firstWord >> 0x10) & 0xff), - (uint8_t) ((firstWord >> 0x08) & 0x7f), - (uint8_t) ((firstWord >> 0x00) & 0x7f), + std::byte ((0x4 << 0x4) | Utils::getGroup (firstWord)), + std::byte ((firstWord >> 0x10) & 0xff), + std::byte ((firstWord >> 0x08) & 0x7f), + std::byte ((firstWord >> 0x00) & 0x7f), }; switch (Utils::getStatus (firstWord)) @@ -128,10 +128,10 @@ class Midi1ToMidi2DefaultTranslator struct HelperValues { - uint8_t typeAndGroup; - uint8_t byte0; - uint8_t byte1; - uint8_t byte2; + std::byte typeAndGroup; + std::byte byte0; + std::byte byte1; + std::byte byte2; }; static PacketX2 processNoteOnOrOff (const HelperValues helpers); @@ -147,13 +147,13 @@ class Midi1ToMidi2DefaultTranslator class PnAccumulator { public: - bool addByte (uint8_t cc, uint8_t byte); + bool addByte (uint8_t cc, std::byte byte); - const std::array& getBytes() const noexcept { return bytes; } + const std::array& getBytes() const noexcept { return bytes; } PnKind getKind() const noexcept { return kind; } private: - std::array bytes; + std::array bytes; uint8_t index = 0; PnKind kind = PnKind::nrpn; }; diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp index 9f8e2ef8665f..eaea29f13a65 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp +++ b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.cpp @@ -39,12 +39,12 @@ SysEx7::PacketBytes SysEx7::getDataBytes (const PacketX2& packet) return { - { { packet.getU8<2>(), - packet.getU8<3>(), - packet.getU8<4>(), - packet.getU8<5>(), - packet.getU8<6>(), - packet.getU8<7>() } }, + { { std::byte { packet.getU8<2>() }, + std::byte { packet.getU8<3>() }, + std::byte { packet.getU8<4>() }, + std::byte { packet.getU8<5>() }, + std::byte { packet.getU8<6>() }, + std::byte { packet.getU8<7>() } } }, jmin (numBytes, maxBytes) }; } diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h index 0d6e80013654..c08313c0cf5b 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPSysEx7.h @@ -63,7 +63,7 @@ struct SysEx7 /** Holds the bytes from a single SysEx-7 packet. */ struct PacketBytes { - std::array data; + std::array data; uint8_t size; }; diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h b/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h index 2b86a71ff7f2..53b097b99ffd 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMPUtils.h @@ -35,9 +35,12 @@ namespace universal_midi_packets struct Utils { /** Joins 4 bytes into a single 32-bit word. */ - static constexpr uint32_t bytesToWord (uint8_t a, uint8_t b, uint8_t c, uint8_t d) + static constexpr uint32_t bytesToWord (std::byte a, std::byte b, std::byte c, std::byte d) { - return uint32_t (a << 0x18 | b << 0x10 | c << 0x08 | d << 0x00); + return uint32_t (a) << 0x18 + | uint32_t (b) << 0x10 + | uint32_t (c) << 0x08 + | uint32_t (d) << 0x00; } /** Returns the expected number of 32-bit words in a Universal MIDI Packet, given diff --git a/modules/juce_audio_basics/midi/ump/juce_UMP_test.cpp b/modules/juce_audio_basics/midi/ump/juce_UMP_test.cpp index fd52554bbe86..b34ed0fb0365 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMP_test.cpp +++ b/modules/juce_audio_basics/midi/ump/juce_UMP_test.cpp @@ -48,18 +48,18 @@ class UniversalMidiPacketTests : public UnitTest forEachNonSysExTestMessage (random, [&] (const MidiMessage& m) { - Packets packets; - Conversion::toMidi1 (m, packets); + const auto packets = toMidi1 (m); expect (packets.size() == 1); // Make sure that the message type is correct - expect (Utils::getMessageType (packets.data()[0]) == ((m.getRawData()[0] >> 0x4) == 0xf ? 0x1 : 0x2)); + const auto msgType = Utils::getMessageType (packets.data()[0]); + expect (msgType == ((m.getRawData()[0] >> 0x4) == 0xf ? 0x1 : 0x2)); translator.dispatch (View {packets.data() }, 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - expect (equal (m, roundTripped)); + expect (equal (m, roundTripped.getMessage())); }); }); } @@ -68,8 +68,7 @@ class UniversalMidiPacketTests : public UnitTest { { // Zero length message - Packets packets; - Conversion::toMidi1 (createRandomSysEx (random, 0), packets); + const auto packets = toMidi1 (createRandomSysEx (random, 0)); expect (packets.size() == 2); expect (packets.data()[0] == 0x30000000); @@ -78,51 +77,50 @@ class UniversalMidiPacketTests : public UnitTest { const auto message = createRandomSysEx (random, 1); - Packets packets; - Conversion::toMidi1 (message, packets); + const auto packets = toMidi1 (message); expect (packets.size() == 2); const auto* sysEx = message.getSysExData(); - expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x01, sysEx[0], 0)); + expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 }, + std::byte { 0x01 }, + std::byte { sysEx[0] }, + std::byte { 0 })); expect (packets.data()[1] == 0x00000000); } { const auto message = createRandomSysEx (random, 6); - Packets packets; - Conversion::toMidi1 (message, packets); + const auto packets = toMidi1 (message); expect (packets.size() == 2); const auto* sysEx = message.getSysExData(); - expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x06, sysEx[0], sysEx[1])); - expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); + expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x06 }, std::byte { sysEx[0] }, std::byte { sysEx[1] })); + expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] })); } { const auto message = createRandomSysEx (random, 12); - Packets packets; - Conversion::toMidi1 (message, packets); + const auto packets = toMidi1 (message); expect (packets.size() == 4); const auto* sysEx = message.getSysExData(); - expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x16, sysEx[0], sysEx[1])); - expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); - expect (packets.data()[2] == Utils::bytesToWord (0x30, 0x36, sysEx[6], sysEx[7])); - expect (packets.data()[3] == Utils::bytesToWord (sysEx[8], sysEx[9], sysEx[10], sysEx[11])); + expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x16 }, std::byte { sysEx[0] }, std::byte { sysEx[1] })); + expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] })); + expect (packets.data()[2] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x36 }, std::byte { sysEx[6] }, std::byte { sysEx[7] })); + expect (packets.data()[3] == Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] })); } { const auto message = createRandomSysEx (random, 13); - Packets packets; - Conversion::toMidi1 (message, packets); + const auto packets = toMidi1 (message); expect (packets.size() == 6); const auto* sysEx = message.getSysExData(); - expect (packets.data()[0] == Utils::bytesToWord (0x30, 0x16, sysEx[0], sysEx[1])); - expect (packets.data()[1] == Utils::bytesToWord (sysEx[2], sysEx[3], sysEx[4], sysEx[5])); - expect (packets.data()[2] == Utils::bytesToWord (0x30, 0x26, sysEx[6], sysEx[7])); - expect (packets.data()[3] == Utils::bytesToWord (sysEx[8], sysEx[9], sysEx[10], sysEx[11])); - expect (packets.data()[4] == Utils::bytesToWord (0x30, 0x31, sysEx[12], 0)); + expect (packets.data()[0] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x16 }, std::byte { sysEx[0] }, std::byte { sysEx[1] })); + expect (packets.data()[1] == Utils::bytesToWord (std::byte { sysEx[2] }, std::byte { sysEx[3] }, std::byte { sysEx[4] }, std::byte { sysEx[5] })); + expect (packets.data()[2] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x26 }, std::byte { sysEx[6] }, std::byte { sysEx[7] })); + expect (packets.data()[3] == Utils::bytesToWord (std::byte { sysEx[8] }, std::byte { sysEx[9] }, std::byte { sysEx[10] }, std::byte { sysEx[11] })); + expect (packets.data()[4] == Utils::bytesToWord (std::byte { 0x30 }, std::byte { 0x31 }, std::byte { sysEx[12] }, std::byte { 0 })); expect (packets.data()[5] == 0x00000000); } } @@ -133,15 +131,15 @@ class UniversalMidiPacketTests : public UnitTest const auto checkRoundTrip = [&] (const MidiBuffer& expected) { for (const auto meta : expected) - Conversion::toMidi1 (meta.getMessage(), packets); + Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto p) { packets.add (p); }); MidiBuffer output; converter.dispatch (packets.data(), packets.data() + packets.size(), 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp)); }); packets.clear(); @@ -161,8 +159,7 @@ class UniversalMidiPacketTests : public UnitTest beginTest ("UMP SysEx7 messages interspersed with utility messages convert to bytestream"); { const auto sysEx = createRandomSysEx (random, 100); - Packets originalPackets; - Conversion::toMidi1 (sysEx, originalPackets); + const auto originalPackets = toMidi1 (sysEx); Packets modifiedPackets; @@ -183,9 +180,9 @@ class UniversalMidiPacketTests : public UnitTest converter.dispatch (modifiedPackets.data(), modifiedPackets.data() + modifiedPackets.size(), 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp)); }); // All Utility messages should have been ignored @@ -198,8 +195,7 @@ class UniversalMidiPacketTests : public UnitTest beginTest ("UMP SysEx7 messages interspersed with System Realtime messages convert to bytestream"); { const auto sysEx = createRandomSysEx (random, 200); - Packets originalPackets; - Conversion::toMidi1 (sysEx, originalPackets); + const auto originalPackets = toMidi1 (sysEx); Packets modifiedPackets; MidiBuffer realtimeMessages; @@ -222,9 +218,9 @@ class UniversalMidiPacketTests : public UnitTest converter.dispatch (modifiedPackets.data(), modifiedPackets.data() + modifiedPackets.size(), 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp)); }); const auto numOutputs = output.getNumEvents(); @@ -258,8 +254,7 @@ class UniversalMidiPacketTests : public UnitTest beginTest ("UMP SysEx7 messages interspersed with System Realtime and Utility messages convert to bytestream"); { const auto sysEx = createRandomSysEx (random, 300); - Packets originalPackets; - Conversion::toMidi1 (sysEx, originalPackets); + const auto originalPackets = toMidi1 (sysEx); Packets modifiedPackets; MidiBuffer realtimeMessages; @@ -290,9 +285,9 @@ class UniversalMidiPacketTests : public UnitTest converter.dispatch (modifiedPackets.data(), modifiedPackets.data() + modifiedPackets.size(), 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp)); }); const auto numOutputs = output.getNumEvents(); @@ -336,19 +331,14 @@ class UniversalMidiPacketTests : public UnitTest Packets p; for (const auto meta : noteOn) - Conversion::toMidi1 (meta.getMessage(), p); + Conversion::toMidi1 (ump::BytestreamMidiView (meta), [&] (const auto packet) { p.add (packet); }); return p; }(); const auto sysEx = createRandomSysEx (random, 300); - const auto originalPackets = [&] - { - Packets p; - Conversion::toMidi1 (sysEx, p); - return p; - }(); + const auto originalPackets = toMidi1 (sysEx); const auto modifiedPackets = [&] { @@ -378,9 +368,9 @@ class UniversalMidiPacketTests : public UnitTest converter.dispatch (p.data(), p.data() + p.size(), 0, - [&] (const MidiMessage& roundTripped) + [&] (const BytestreamMidiView& roundTripped) { - output.addEvent (roundTripped, int (roundTripped.getTimeStamp())); + output.addEvent (roundTripped.getMessage(), int (roundTripped.timestamp)); }); }; @@ -390,8 +380,7 @@ class UniversalMidiPacketTests : public UnitTest expect (equal (output, noteOn)); const auto newSysEx = createRandomSysEx (random, 300); - Packets newSysExPackets; - Conversion::toMidi1 (newSysEx, newSysExPackets); + const auto newSysExPackets = toMidi1 (newSysEx); // If we push another midi event without interrupting it, // it should get through without being modified, @@ -678,12 +667,17 @@ class UniversalMidiPacketTests : public UnitTest beginTest ("MIDI 2 -> 1 messages which don't convert"); { - const uint8_t opcodes[] { 0x0, 0x1, 0x4, 0x5, 0x6, 0xf }; + const std::byte opcodes[] { std::byte { 0x0 }, + std::byte { 0x1 }, + std::byte { 0x4 }, + std::byte { 0x5 }, + std::byte { 0x6 }, + std::byte { 0xf } }; for (const auto opcode : opcodes) { Packets midi2; - midi2.add (PacketX2 { Utils::bytesToWord (0x40, (uint8_t) (opcode << 0x4), 0, 0), 0x0 }); + midi2.add (PacketX2 { Utils::bytesToWord (std::byte { 0x40 }, std::byte { opcode << 0x4 }, std::byte { 0 }, std::byte { 0 }), 0x0 }); checkMidi2ToMidi1Conversion (midi2, {}); } } @@ -785,7 +779,7 @@ class UniversalMidiPacketTests : public UnitTest for (const auto cc : CCs) { Packets midi1; - midi1.add (PacketX1 { Utils::bytesToWord (0x20, 0xb0, cc, 0x00) }); + midi1.add (PacketX1 { Utils::bytesToWord (std::byte { 0x20 }, std::byte { 0xb0 }, std::byte { cc }, std::byte { 0x00 }) }); checkMidi1ToMidi2Conversion (midi1, {}); } @@ -874,6 +868,13 @@ class UniversalMidiPacketTests : public UnitTest } private: + static Packets toMidi1 (const MidiMessage& msg) + { + Packets packets; + Conversion::toMidi1 (ump::BytestreamMidiView (&msg), [&] (const auto p) { packets.add (p); }); + return packets; + } + static Packets convertMidi2ToMidi1 (const Packets& midi2) { Packets r; @@ -934,10 +935,10 @@ class UniversalMidiPacketTests : public UnitTest { const auto status = random.nextInt (3); - return PacketX1 { Utils::bytesToWord (0, - uint8_t (status << 0x4), - uint8_t (status == 0 ? 0 : random.nextInt (0x100)), - uint8_t (status == 0 ? 0 : random.nextInt (0x100))) }; + return PacketX1 { Utils::bytesToWord (std::byte { 0 }, + std::byte (status << 0x4), + std::byte (status == 0 ? 0 : random.nextInt (0x100)), + std::byte (status == 0 ? 0 : random.nextInt (0x100))) }; } PacketX1 createRandomRealtimeUMP (Random& random) @@ -946,19 +947,19 @@ class UniversalMidiPacketTests : public UnitTest { switch (random.nextInt (6)) { - case 0: return 0xf8; - case 1: return 0xfa; - case 2: return 0xfb; - case 3: return 0xfc; - case 4: return 0xfe; - case 5: return 0xff; + case 0: return std::byte { 0xf8 }; + case 1: return std::byte { 0xfa }; + case 2: return std::byte { 0xfb }; + case 3: return std::byte { 0xfc }; + case 4: return std::byte { 0xfe }; + case 5: return std::byte { 0xff }; } jassertfalse; - return 0x00; + return std::byte { 0x00 }; }(); - return PacketX1 { Utils::bytesToWord (0x10, uint8_t (status), 0x00, 0x00) }; + return PacketX1 { Utils::bytesToWord (std::byte { 0x10 }, status, std::byte { 0x00 }, std::byte { 0x00 }) }; } template diff --git a/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp b/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp index 4f1c2afc3f33..455555586ee1 100644 --- a/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPESynthesiserBase.cpp @@ -107,7 +107,7 @@ void MPESynthesiserBase::renderNextBlock (AudioBuffer& outputAudio, int numSamples) { // you must set the sample rate before using this! - jassert (sampleRate != 0); + jassert (! approximatelyEqual (sampleRate, 0.0)); const ScopedLock sl (noteStateLock); @@ -144,7 +144,7 @@ template void MPESynthesiserBase::renderNextBlock (AudioBuffer&, //============================================================================== void MPESynthesiserBase::setCurrentPlaybackSampleRate (const double newRate) { - if (sampleRate != newRate) + if (! approximatelyEqual (sampleRate, newRate)) { const ScopedLock sl (noteStateLock); instrument.releaseAllNotes(); diff --git a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp index e51f314dae75..b86e179b193e 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp +++ b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp @@ -108,14 +108,11 @@ void MPEZoneLayout::processNextMidiEvent (const MidiMessage& message) if (! message.isController()) return; - MidiRPNMessage rpn; - - if (rpnDetector.parseControllerMessage (message.getChannel(), + if (auto parsed = rpnDetector.tryParse (message.getChannel(), message.getControllerNumber(), - message.getControllerValue(), - rpn)) + message.getControllerValue())) { - processRpnMessage (rpn); + processRpnMessage (*parsed); } } diff --git a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h index a9703ac767c6..dc89dcc28d11 100644 --- a/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h +++ b/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.h @@ -35,6 +35,8 @@ namespace juce It also defines a pitchbend range (in semitones) to be applied for per-note pitchbends and master pitchbends, respectively. + + @tags{Audio} */ struct MPEZone { diff --git a/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h b/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h similarity index 97% rename from modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h rename to modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h index afd0e00173d3..44ebd4d93c09 100644 --- a/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h +++ b/modules/juce_audio_basics/native/juce_CoreAudioLayouts_mac.h @@ -263,13 +263,13 @@ struct CoreAudioLayouts } } - auto numChannels = tag & 0xffff; + const auto numChannels = tag & 0xffff; + if (tag >= coreAudioHOASN3DLayoutTag && tag <= (coreAudioHOASN3DLayoutTag | 0xffff)) { - auto sqrtMinusOne = std::sqrt (static_cast (numChannels)) - 1.0f; - auto ambisonicOrder = jmax (0, static_cast (std::floor (sqrtMinusOne))); + const auto ambisonicOrder = AudioChannelSet::getAmbisonicOrderForNumChannels (static_cast (numChannels)); - if (static_cast (ambisonicOrder) == sqrtMinusOne) + if (ambisonicOrder != -1) return AudioChannelSet::ambisonic (ambisonicOrder).getChannelTypes(); } diff --git a/modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h b/modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h similarity index 100% rename from modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h rename to modules/juce_audio_basics/native/juce_CoreAudioTimeConversions_mac.h diff --git a/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp b/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp index b0593bb349c8..cda04184c7a5 100644 --- a/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp +++ b/modules/juce_audio_basics/sources/juce_BufferingAudioSource.cpp @@ -51,7 +51,7 @@ void BufferingAudioSource::prepareToPlay (int samplesPerBlockExpected, double ne { auto bufferSizeNeeded = jmax (samplesPerBlockExpected * 2, numberOfSamplesToBuffer); - if (newSampleRate != sampleRate + if (! approximatelyEqual (newSampleRate, sampleRate) || bufferSizeNeeded != buffer.getNumSamples() || ! isPrepared) { diff --git a/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp b/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp index 2c8387f5bf3c..db30a341eda0 100644 --- a/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp +++ b/modules/juce_audio_basics/sources/juce_MemoryAudioSource.cpp @@ -108,26 +108,6 @@ void MemoryAudioSource::setLooping (bool shouldLoop) //============================================================================== #if JUCE_UNIT_TESTS -static bool operator== (const AudioBuffer& a, const AudioBuffer& b) -{ - if (a.getNumChannels() != b.getNumChannels()) - return false; - - for (int channel = 0; channel < a.getNumChannels(); ++channel) - { - auto* aPtr = a.getReadPointer (channel); - auto* bPtr = b.getReadPointer (channel); - - if (std::vector (aPtr, aPtr + a.getNumSamples()) - != std::vector (bPtr, bPtr + b.getNumSamples())) - { - return false; - } - } - - return true; -} - struct MemoryAudioSourceTests : public UnitTest { MemoryAudioSourceTests() : UnitTest ("MemoryAudioSource", UnitTestCategories::audio) {} @@ -184,7 +164,7 @@ struct MemoryAudioSourceTests : public UnitTest play (source, channelInfo); for (int sample = 0; sample < buffer.getNumSamples(); ++sample) - expect (bufferToFill.getSample (0, sample + buffer.getNumSamples()) == buffer.getSample (0, sample)); + expectEquals (bufferToFill.getSample (0, sample + buffer.getNumSamples()), buffer.getSample (0, sample)); expect (! isSilent (bufferToFill)); } @@ -219,7 +199,7 @@ struct MemoryAudioSourceTests : public UnitTest for (int i = 0; i < 100; ++i) { play (source, channelInfo); - expect (bufferToFill.getSample (0, 0) == buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); + expectEquals (bufferToFill.getSample (0, 0), buffer.getSample (0, (i * blockSize) % buffer.getNumSamples())); } } } diff --git a/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp b/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp index e4887270f4bb..e936ae2ac45c 100644 --- a/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp +++ b/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp @@ -88,7 +88,7 @@ void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& inf localRatio = ratio; } - if (lastRatio != localRatio) + if (! approximatelyEqual (lastRatio, localRatio)) { createLowPass (localRatio); lastRatio = localRatio; diff --git a/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp b/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp index 0ad3e0b97d89..4b9aef4a4bb9 100644 --- a/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp +++ b/modules/juce_audio_basics/sources/juce_ToneGeneratorAudioSource.cpp @@ -62,7 +62,7 @@ void ToneGeneratorAudioSource::releaseResources() void ToneGeneratorAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { - if (phasePerSample == 0.0) + if (approximatelyEqual (phasePerSample, 0.0)) phasePerSample = MathConstants::twoPi / (sampleRate / frequency); for (int i = 0; i < info.numSamples; ++i) diff --git a/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp b/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp index f9aaff23f0d2..f6e611e1ce46 100644 --- a/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp +++ b/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp @@ -153,7 +153,7 @@ void Synthesiser::setMinimumRenderingSubdivisionSize (int numSamples, bool shoul //============================================================================== void Synthesiser::setCurrentPlaybackSampleRate (const double newRate) { - if (sampleRate != newRate) + if (! approximatelyEqual (sampleRate, newRate)) { const ScopedLock sl (lock); allNotesOff (0, false); @@ -171,7 +171,7 @@ void Synthesiser::processNextBlock (AudioBuffer& outputAudio, int numSamples) { // must set the sample rate before using this! - jassert (sampleRate != 0); + jassert (! exactlyEqual (sampleRate, 0.0)); const int targetChannels = outputAudio.getNumChannels(); auto midiIterator = midiData.findNextSamplePosition (startSample); diff --git a/modules/juce_audio_basics/utilities/juce_Decibels.h b/modules/juce_audio_basics/utilities/juce_Decibels.h index e5eb8026220e..937cf0a6b71c 100644 --- a/modules/juce_audio_basics/utilities/juce_Decibels.h +++ b/modules/juce_audio_basics/utilities/juce_Decibels.h @@ -60,6 +60,20 @@ class Decibels : minusInfinityDb; } + /** Restricts a gain value based on a lower bound specified in dBFS. + + This is useful if you want to make sure a gain value never reaches zero. + */ + template + static Type gainWithLowerBound (Type gain, Type lowerBoundDb) + { + // You probably want to use a negative decibel value or the gain will + // be restricted to boosting only! + jassert (lowerBoundDb < (Type) 0.0); + + return jmax ((Type) gain, Decibels::decibelsToGain (lowerBoundDb, lowerBoundDb - (Type) 1.0)); + } + //============================================================================== /** Converts a decibel reading to a string. diff --git a/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp b/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp index fedeb759ea89..c1e32254db39 100644 --- a/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp +++ b/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp @@ -23,6 +23,8 @@ namespace juce { +constexpr auto minimumDecibels = -300.0f; + IIRCoefficients::IIRCoefficients() noexcept { zeromem (coefficients, sizeof (coefficients)); @@ -44,7 +46,7 @@ IIRCoefficients& IIRCoefficients::operator= (const IIRCoefficients& other) noexc IIRCoefficients::IIRCoefficients (double c1, double c2, double c3, double c4, double c5, double c6) noexcept { - auto a = 1.0 / c4; + const auto a = 1.0 / c4; coefficients[0] = (float) (c1 * a); coefficients[1] = (float) (c2 * a); @@ -67,9 +69,9 @@ IIRCoefficients IIRCoefficients::makeLowPass (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); + const auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); + const auto nSquared = n * n; + const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); return IIRCoefficients (c1, c1 * 2.0, @@ -93,9 +95,9 @@ IIRCoefficients IIRCoefficients::makeHighPass (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto n = std::tan (MathConstants::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); + const auto n = std::tan (MathConstants::pi * frequency / sampleRate); + const auto nSquared = n * n; + const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); return IIRCoefficients (c1, c1 * -2.0, @@ -119,9 +121,9 @@ IIRCoefficients IIRCoefficients::makeBandPass (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); + const auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); + const auto nSquared = n * n; + const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); return IIRCoefficients (c1 * n / Q, 0.0, @@ -145,9 +147,9 @@ IIRCoefficients IIRCoefficients::makeNotchFilter (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + n / Q + nSquared); + const auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); + const auto nSquared = n * n; + const auto c1 = 1.0 / (1.0 + n / Q + nSquared); return IIRCoefficients (c1 * (1.0 + nSquared), 2.0 * c1 * (1.0 - nSquared), @@ -171,9 +173,9 @@ IIRCoefficients IIRCoefficients::makeAllPass (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); + const auto n = 1.0 / std::tan (MathConstants::pi * frequency / sampleRate); + const auto nSquared = n * n; + const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); return IIRCoefficients (c1 * (1.0 - n / Q + nSquared), c1 * 2.0 * (1.0 - nSquared), @@ -192,13 +194,13 @@ IIRCoefficients IIRCoefficients::makeLowShelf (double sampleRate, jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto A = jmax (0.0f, std::sqrt (gainFactor)); - auto aminus1 = A - 1.0; - auto aplus1 = A + 1.0; - auto omega = (MathConstants::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate; - auto coso = std::cos (omega); - auto beta = std::sin (omega) * std::sqrt (A) / Q; - auto aminus1TimesCoso = aminus1 * coso; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels)); + const auto aminus1 = A - 1.0; + const auto aplus1 = A + 1.0; + const auto omega = (MathConstants::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate; + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return IIRCoefficients (A * (aplus1 - aminus1TimesCoso + beta), A * 2.0 * (aminus1 - aplus1 * coso), @@ -217,13 +219,13 @@ IIRCoefficients IIRCoefficients::makeHighShelf (double sampleRate, jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto A = jmax (0.0f, std::sqrt (gainFactor)); - auto aminus1 = A - 1.0; - auto aplus1 = A + 1.0; - auto omega = (MathConstants::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate; - auto coso = std::cos (omega); - auto beta = std::sin (omega) * std::sqrt (A) / Q; - auto aminus1TimesCoso = aminus1 * coso; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels)); + const auto aminus1 = A - 1.0; + const auto aplus1 = A + 1.0; + const auto omega = (MathConstants::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate; + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return IIRCoefficients (A * (aplus1 + aminus1TimesCoso + beta), A * -2.0 * (aminus1 + aplus1 * coso), @@ -242,12 +244,12 @@ IIRCoefficients IIRCoefficients::makePeakFilter (double sampleRate, jassert (frequency > 0.0 && frequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto A = jmax (0.0f, std::sqrt (gainFactor)); - auto omega = (MathConstants::twoPi * jmax (frequency, 2.0)) / sampleRate; - auto alpha = 0.5 * std::sin (omega) / Q; - auto c2 = -2.0 * std::cos (omega); - auto alphaTimesA = alpha * A; - auto alphaOverA = alpha / A; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels)); + const auto omega = (MathConstants::twoPi * jmax (frequency, 2.0)) / sampleRate; + const auto alpha = 0.5 * std::sin (omega) / Q; + const auto c2 = -2.0 * std::cos (omega); + const auto alphaTimesA = alpha * A; + const auto alphaOverA = alpha / A; return IIRCoefficients (1.0 + alphaTimesA, c2, diff --git a/modules/juce_audio_basics/utilities/juce_Interpolators.h b/modules/juce_audio_basics/utilities/juce_Interpolators.h index 0b2d454cdbf6..ccee0fcdf602 100644 --- a/modules/juce_audio_basics/utilities/juce_Interpolators.h +++ b/modules/juce_audio_basics/utilities/juce_Interpolators.h @@ -73,7 +73,7 @@ class Interpolators sign = (sincPosition < 0 ? -1 : 1); } - if (sincPosition == 0.0f) + if (approximatelyEqual (sincPosition, 0.0f)) result += inputs[samplePosition]; else if (sincPosition < floatCrossings && sincPosition > -floatCrossings) result += inputs[samplePosition] * windowedSinc (firstFrac, index); diff --git a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h index e210705ebddf..4c0b21197b89 100644 --- a/modules/juce_audio_basics/utilities/juce_SmoothedValue.h +++ b/modules/juce_audio_basics/utilities/juce_SmoothedValue.h @@ -237,7 +237,8 @@ class SmoothedValue : public SmoothedValueBase && initialValue == 0)); + jassert (! (std::is_same_v + && approximatelyEqual (initialValue, (FloatType) 0))); // Visual Studio can't handle base class initialisation with CRTP this->currentValue = initialValue; @@ -270,7 +271,7 @@ class SmoothedValue : public SmoothedValueBase target) + if (approximatelyEqual (newValue, this->target)) return; if (stepsToTarget <= 0) @@ -280,7 +281,8 @@ class SmoothedValue : public SmoothedValueBase && newValue == 0)); + jassert (! (std::is_same_v + && approximatelyEqual (newValue, (FloatType) 0))); this->target = newValue; this->countdown = stepsToTarget; diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index e2645ef018d6..4a1a9aed5e63 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -220,6 +220,12 @@ void AudioDeviceManager::audioDeviceListChanged() sendChangeMessage(); } +void AudioDeviceManager::midiDeviceListChanged() +{ + openLastRequestedMidiDevices (midiDeviceInfosFromXml, defaultMidiOutputDeviceInfo); + sendChangeMessage(); +} + //============================================================================== static void addIfNotNull (OwnedArray& list, AudioIODeviceType* const device) { @@ -430,65 +436,62 @@ String AudioDeviceManager::initialiseFromXML (const XmlElement& xml, if (error.isNotEmpty() && selectDefaultDeviceOnFailure) error = initialise (numInputChansNeeded, numOutputChansNeeded, nullptr, false, preferredDefaultDeviceName); - midiDeviceInfosFromXml.clear(); enabledMidiInputs.clear(); - for (auto* c : xml.getChildWithTagNameIterator ("MIDIINPUT")) - midiDeviceInfosFromXml.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") }); - - auto isIdentifierAvailable = [] (const Array& available, const String& identifier) + const auto midiInputs = [&] { - for (auto& device : available) - if (device.identifier == identifier) - return true; + Array result; - return false; - }; + for (auto* c : xml.getChildWithTagNameIterator ("MIDIINPUT")) + result.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") }); - auto getUpdatedIdentifierForName = [&] (const Array& available, const String& name) -> String - { - for (auto& device : available) - if (device.name == name) - return device.identifier; + return result; + }(); - return {}; - }; + const MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"), + xml.getStringAttribute ("defaultMidiOutputDevice")); - auto inputs = MidiInput::getAvailableDevices(); + openLastRequestedMidiDevices (midiInputs, defaultOutputDeviceInfo); - for (auto& info : midiDeviceInfosFromXml) + return error; +} + +void AudioDeviceManager::openLastRequestedMidiDevices (const Array& desiredInputs, const MidiDeviceInfo& defaultOutput) +{ + const auto openDeviceIfAvailable = [&] (const Array& devices, + const MidiDeviceInfo& deviceToOpen, + auto&& doOpen) { - if (isIdentifierAvailable (inputs, info.identifier)) + const auto iterWithMatchingIdentifier = std::find_if (devices.begin(), devices.end(), [&] (const auto& x) { - setMidiInputDeviceEnabled (info.identifier, true); + return x.identifier == deviceToOpen.identifier; + }); + + if (iterWithMatchingIdentifier != devices.end()) + { + doOpen (deviceToOpen.identifier); + return; } - else + + const auto iterWithMatchingName = std::find_if (devices.begin(), devices.end(), [&] (const auto& x) { - auto identifier = getUpdatedIdentifierForName (inputs, info.name); + return x.name == deviceToOpen.name; + }); - if (identifier.isNotEmpty()) - setMidiInputDeviceEnabled (identifier, true); - } - } + if (iterWithMatchingName != devices.end()) + doOpen (iterWithMatchingName->identifier); + }; - MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"), - xml.getStringAttribute ("defaultMidiOutputDevice")); + midiDeviceInfosFromXml = desiredInputs; - auto outputs = MidiOutput::getAvailableDevices(); + const auto inputs = MidiInput::getAvailableDevices(); - if (isIdentifierAvailable (outputs, defaultOutputDeviceInfo.identifier)) - { - setDefaultMidiOutputDevice (defaultOutputDeviceInfo.identifier); - } - else - { - auto identifier = getUpdatedIdentifierForName (outputs, defaultOutputDeviceInfo.name); + for (const auto& info : midiDeviceInfosFromXml) + openDeviceIfAvailable (inputs, info, [&] (const auto identifier) { setMidiInputDeviceEnabled (identifier, true); }); - if (identifier.isNotEmpty()) - setDefaultMidiOutputDevice (identifier); - } + const auto outputs = MidiOutput::getAvailableDevices(); - return error; + openDeviceIfAvailable (outputs, defaultOutput, [&] (const auto identifier) { setDefaultMidiOutputDevice (identifier); }); } String AudioDeviceManager::initialiseWithDefaultDevices (int numInputChannelsNeeded, diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index c655254ecff9..b3fd6e819330 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -499,6 +499,10 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster std::unique_ptr lastExplicitSettings; mutable bool listNeedsScanning = true; AudioBuffer tempBuffer; + MidiDeviceListConnection midiDeviceListConnection = MidiDeviceListConnection::make ([this] + { + midiDeviceListChanged(); + }); struct MidiCallbackInfo { @@ -537,6 +541,7 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster void audioDeviceErrorInt (const String&); void handleIncomingMidiMessageInt (MidiInput*, const MidiMessage&); void audioDeviceListChanged(); + void midiDeviceListChanged(); String restartDevice (int blockSizeToUse, double sampleRateToUse, const BigInteger& ins, const BigInteger& outs); @@ -554,6 +559,7 @@ class JUCE_API AudioDeviceManager : public ChangeBroadcaster String initialiseDefault (const String& preferredDefaultDeviceName, const AudioDeviceSetup*); String initialiseFromXML (const XmlElement&, bool selectDefaultDeviceOnFailure, const String& preferredDefaultDeviceName, const AudioDeviceSetup*); + void openLastRequestedMidiDevices (const Array&, const MidiDeviceInfo&); AudioIODeviceType* findType (const String& inputName, const String& outputName); AudioIODeviceType* findType (const String& typeName); diff --git a/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h b/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h index 1405f7e29d72..da5bfed58174 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioIODevice.h @@ -25,7 +25,11 @@ namespace juce class AudioIODevice; -/** Additional information that may be passed to the AudioIODeviceCallback. */ +/** + Additional information that may be passed to the AudioIODeviceCallback. + + @tags{Audio} +*/ struct AudioIODeviceCallbackContext { /** If the host provides this information, this field will be set to point to diff --git a/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h b/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h index aa08cece415b..d4cc17397bef 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioIODeviceType.h @@ -116,7 +116,7 @@ class JUCE_API AudioIODeviceType /** A class for receiving events when audio devices are inserted or removed. - You can register an AudioIODeviceType::Listener with an~AudioIODeviceType object + You can register an AudioIODeviceType::Listener with an AudioIODeviceType object using the AudioIODeviceType::addListener() method, and it will be called when devices of that type are added or removed. diff --git a/modules/juce_audio_devices/juce_audio_devices.cpp b/modules/juce_audio_devices/juce_audio_devices.cpp index 5449282bbc35..ba60b96e3f40 100644 --- a/modules/juce_audio_devices/juce_audio_devices.cpp +++ b/modules/juce_audio_devices/juce_audio_devices.cpp @@ -46,9 +46,11 @@ #include "juce_audio_devices.h" #include "audio_io/juce_SampleRateHelpers.cpp" +#include "midi_io/juce_MidiDevices.cpp" //============================================================================== #if JUCE_MAC || JUCE_IOS + #include #include #include "midi_io/ump/juce_UMPBytestreamInputHandler.h" #include "midi_io/ump/juce_UMPU32InputHandler.h" @@ -63,8 +65,8 @@ #undef Point #undef Component - #include "native/juce_mac_CoreAudio.cpp" - #include "native/juce_mac_CoreMidi.mm" + #include "native/juce_CoreAudio_mac.cpp" + #include "native/juce_CoreMidi_mac.mm" #elif JUCE_IOS #import @@ -75,18 +77,18 @@ #import #endif - #include "native/juce_ios_Audio.cpp" - #include "native/juce_mac_CoreMidi.mm" + #include "native/juce_Audio_ios.cpp" + #include "native/juce_CoreMidi_mac.mm" //============================================================================== #elif JUCE_WINDOWS #if JUCE_WASAPI #include - #include "native/juce_win32_WASAPI.cpp" + #include "native/juce_WASAPI_windows.cpp" #endif #if JUCE_DIRECTSOUND - #include "native/juce_win32_DirectSound.cpp" + #include "native/juce_DirectSound_windows.cpp" #endif #if JUCE_USE_WINRT_MIDI && (JUCE_MSVC || JUCE_CLANG) @@ -113,7 +115,7 @@ #endif #include - #include "native/juce_win32_Midi.cpp" + #include "native/juce_Midi_windows.cpp" #if JUCE_ASIO /* This is very frustrating - we only need to use a handful of definitions from @@ -136,7 +138,7 @@ needed - so to simplify things, you could just copy these into your JUCE directory). */ #include - #include "native/juce_win32_ASIO.cpp" + #include "native/juce_ASIO_windows.cpp" #endif //============================================================================== @@ -150,8 +152,10 @@ If you don't have the ALSA library and don't want to build JUCE with audio support, just set the JUCE_ALSA flag to 0. */ + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-length-array") #include - #include "native/juce_linux_ALSA.cpp" + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + #include "native/juce_ALSA_linux.cpp" #endif #if JUCE_JACK @@ -164,7 +168,7 @@ JUCE with low latency audio support, just set the JUCE_JACK flag to 0. */ #include - #include "native/juce_linux_JackAudio.cpp" + #include "native/juce_JackAudio_linux.cpp" #endif #if (JUCE_LINUX && JUCE_BELA) @@ -175,14 +179,14 @@ #include #include #include - #include "native/juce_linux_Bela.cpp" + #include "native/juce_Bela_linux.cpp" #endif #undef SIZEOF #if ! JUCE_BELA #include - #include "native/juce_linux_Midi.cpp" + #include "native/juce_Midi_linux.cpp" #endif //============================================================================== @@ -194,19 +198,19 @@ namespace juce RealtimeThreadFactory getAndroidRealtimeThreadFactory(); } // namespace juce -#include "native/juce_android_Audio.cpp" +#include "native/juce_Audio_android.cpp" #include - #include "native/juce_android_Midi.cpp" + #include "native/juce_Midi_android.cpp" #if JUCE_USE_ANDROID_OPENSLES || JUCE_USE_ANDROID_OBOE - #include "native/juce_android_HighPerformanceAudioHelpers.h" + #include "native/juce_HighPerformanceAudioHelpers_android.h" #if JUCE_USE_ANDROID_OPENSLES #include #include #include - #include "native/juce_android_OpenSL.cpp" + #include "native/juce_OpenSL_android.cpp" #endif #if JUCE_USE_ANDROID_OBOE @@ -222,7 +226,7 @@ namespace juce #include JUCE_END_IGNORE_WARNINGS_GCC_LIKE - #include "native/juce_android_Oboe.cpp" + #include "native/juce_Oboe_android.cpp" #endif #else // No audio library, so no way to create realtime threads. @@ -249,6 +253,5 @@ namespace juce #include "audio_io/juce_AudioIODevice.cpp" #include "audio_io/juce_AudioIODeviceType.cpp" #include "midi_io/juce_MidiMessageCollector.cpp" -#include "midi_io/juce_MidiDevices.cpp" #include "sources/juce_AudioSourcePlayer.cpp" #include "sources/juce_AudioTransportSource.cpp" diff --git a/modules/juce_audio_devices/juce_audio_devices.h b/modules/juce_audio_devices/juce_audio_devices.h index b2685820add4..9e0e9a5d6d45 100644 --- a/modules/juce_audio_devices/juce_audio_devices.h +++ b/modules/juce_audio_devices/juce_audio_devices.h @@ -32,7 +32,7 @@ ID: juce_audio_devices vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE audio and MIDI I/O device classes description: Classes to play and record from audio and MIDI I/O devices website: http://www.juce.com/juce @@ -186,5 +186,5 @@ namespace juce #include "audio_io/juce_AudioDeviceManager.h" #if JUCE_IOS - #include "native/juce_ios_Audio.h" + #include "native/juce_Audio_ios.h" #endif diff --git a/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp b/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp index b2baf8c1a1eb..e96a9d63c0f4 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp +++ b/modules/juce_audio_devices/midi_io/juce_MidiDevices.cpp @@ -23,6 +23,81 @@ namespace juce { +class MidiDeviceListConnectionBroadcaster : private AsyncUpdater +{ +public: + ~MidiDeviceListConnectionBroadcaster() override + { + cancelPendingUpdate(); + } + + MidiDeviceListConnection::Key add (std::function callback) + { + JUCE_ASSERT_MESSAGE_THREAD + return callbacks.emplace (key++, std::move (callback)).first->first; + } + + void remove (const MidiDeviceListConnection::Key k) + { + JUCE_ASSERT_MESSAGE_THREAD + callbacks.erase (k); + } + + void notify() + { + if (MessageManager::getInstance()->isThisTheMessageThread()) + { + cancelPendingUpdate(); + + const State newState; + + if (std::exchange (lastNotifiedState, newState) != newState) + for (auto it = callbacks.begin(); it != callbacks.end();) + NullCheckedInvocation::invoke ((it++)->second); + } + else + { + triggerAsyncUpdate(); + } + } + + static auto& get() + { + static MidiDeviceListConnectionBroadcaster result; + return result; + } + +private: + MidiDeviceListConnectionBroadcaster() = default; + + class State + { + Array ins = MidiInput::getAvailableDevices(), outs = MidiOutput::getAvailableDevices(); + auto tie() const { return std::tie (ins, outs); } + + public: + bool operator== (const State& other) const { return tie() == other.tie(); } + bool operator!= (const State& other) const { return tie() != other.tie(); } + }; + + void handleAsyncUpdate() override + { + notify(); + } + + std::map> callbacks; + State lastNotifiedState; + MidiDeviceListConnection::Key key = 0; +}; + +//============================================================================== +MidiDeviceListConnection::~MidiDeviceListConnection() noexcept +{ + if (broadcaster != nullptr) + broadcaster->remove (key); +} + +//============================================================================== void MidiInputCallback::handlePartialSysexMessage ([[maybe_unused]] MidiInput* source, [[maybe_unused]] const uint8* messageData, [[maybe_unused]] int numBytesSoFar, diff --git a/modules/juce_audio_devices/midi_io/juce_MidiDevices.h b/modules/juce_audio_devices/midi_io/juce_MidiDevices.h index 5dab3f9258de..ab90cf0ca18b 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiDevices.h +++ b/modules/juce_audio_devices/midi_io/juce_MidiDevices.h @@ -22,6 +22,87 @@ namespace juce { + +class MidiDeviceListConnectionBroadcaster; + +/** + To find out when the available MIDI devices change, call MidiDeviceListConnection::make(), + passing a lambda that will be called on each configuration change. + + To stop the lambda receiving callbacks, destroy the MidiDeviceListConnection instance returned + from make(), or call reset() on it. + + @code + // Start listening for configuration changes + auto connection = MidiDeviceListConnection::make ([] + { + // This will print a message when devices are connected/disconnected + DBG ("MIDI devices changed"); + }); + + // Stop listening + connection.reset(); + @endcode + + @tags{Audio} +*/ +class MidiDeviceListConnection +{ +public: + using Key = uint64_t; + + /** Constructs an inactive connection. + */ + MidiDeviceListConnection() = default; + + MidiDeviceListConnection (const MidiDeviceListConnection&) = delete; + MidiDeviceListConnection (MidiDeviceListConnection&& other) noexcept + : broadcaster (std::exchange (other.broadcaster, nullptr)), + key (std::exchange (other.key, Key{})) + { + } + + MidiDeviceListConnection& operator= (const MidiDeviceListConnection&) = delete; + MidiDeviceListConnection& operator= (MidiDeviceListConnection&& other) noexcept + { + MidiDeviceListConnection (std::move (other)).swap (*this); + return *this; + } + + ~MidiDeviceListConnection() noexcept; + + /** Clears this connection. + + If this object had an active connection, that connection will be deactivated, and the + corresponding callback will be removed from the MidiDeviceListConnectionBroadcaster. + */ + void reset() noexcept + { + MidiDeviceListConnection().swap (*this); + } + + /** Registers a function to be called whenever the midi device list changes. + + The callback will only be active for as long as the return MidiDeviceListConnection remains + alive. To stop receiving device change notifications, destroy the Connection object, e.g. + by allowing it to fall out of scope. + */ + static MidiDeviceListConnection make (std::function); + +private: + MidiDeviceListConnection (MidiDeviceListConnectionBroadcaster* b, const Key k) + : broadcaster (b), key (k) {} + + void swap (MidiDeviceListConnection& other) noexcept + { + std::swap (other.broadcaster, broadcaster); + std::swap (other.key, key); + } + + MidiDeviceListConnectionBroadcaster* broadcaster = nullptr; + Key key = {}; +}; + //============================================================================== /** This struct contains information about a MIDI input or output device. @@ -61,8 +142,9 @@ struct MidiDeviceInfo String identifier; //============================================================================== - bool operator== (const MidiDeviceInfo& other) const noexcept { return name == other.name && identifier == other.identifier; } - bool operator!= (const MidiDeviceInfo& other) const noexcept { return ! operator== (other); } + auto tie() const { return std::tie (name, identifier); } + bool operator== (const MidiDeviceInfo& other) const noexcept { return tie() == other.tie(); } + bool operator!= (const MidiDeviceInfo& other) const noexcept { return tie() != other.tie(); } }; class MidiInputCallback; diff --git a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp index 8eced815daa8..2fea9724d86c 100644 --- a/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp +++ b/modules/juce_audio_devices/midi_io/juce_MidiMessageCollector.cpp @@ -56,7 +56,7 @@ void MidiMessageCollector::addMessageToQueue (const MidiMessage& message) // the messages that come in here need to be time-stamped correctly - see MidiInput // for details of what the number should be. - jassert (message.getTimeStamp() != 0); + jassert (! approximatelyEqual (message.getTimeStamp(), 0.0)); auto sampleNumber = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate); diff --git a/modules/juce_audio_devices/midi_io/ump/juce_UMPU32InputHandler.h b/modules/juce_audio_devices/midi_io/ump/juce_UMPU32InputHandler.h index 2733f053ac6c..15ee58d3ad96 100644 --- a/modules/juce_audio_devices/midi_io/ump/juce_UMPU32InputHandler.h +++ b/modules/juce_audio_devices/midi_io/ump/juce_UMPU32InputHandler.h @@ -82,9 +82,9 @@ struct U32ToBytestreamHandler : public U32InputHandler void pushMidiData (const uint32_t* begin, const uint32_t* end, double time) override { - dispatcher.dispatch (begin, end, time, [this] (const MidiMessage& m) + dispatcher.dispatch (begin, end, time, [this] (const BytestreamMidiView& m) { - callback.handleIncomingMidiMessage (&input, m); + callback.handleIncomingMidiMessage (&input, m.getMessage()); }); } diff --git a/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java b/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java index 0fd83c65cf73..337119b080c9 100644 --- a/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java +++ b/modules/juce_audio_devices/native/java/app/com/rmsl/juce/JuceMidiSupport.java @@ -24,6 +24,7 @@ import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; @@ -43,6 +44,7 @@ import android.bluetooth.BluetoothDevice; import android.media.midi.MidiOutputPort; import android.media.midi.MidiReceiver; +import android.os.Build; import android.os.ParcelUuid; import android.util.Log; import android.util.Pair; @@ -56,6 +58,7 @@ import java.util.List; import static android.content.Context.MIDI_SERVICE; +import static android.content.Context.BLUETOOTH_SERVICE; public class JuceMidiSupport { @@ -77,10 +80,18 @@ public interface JuceMidiPort String getName (); } + static BluetoothAdapter getDefaultBluetoothAdapter (Context ctx) + { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) + return BluetoothAdapter.getDefaultAdapter(); + + return ((BluetoothManager) ctx.getSystemService (BLUETOOTH_SERVICE)).getAdapter(); + } + //============================================================================== - public static class BluetoothManager extends ScanCallback + public static class BluetoothMidiManager extends ScanCallback { - BluetoothManager (Context contextToUse) + BluetoothMidiManager (Context contextToUse) { appContext = contextToUse; } @@ -92,7 +103,7 @@ public String[] getMidiBluetoothAddresses () public String getHumanReadableStringForBluetoothAddress (String address) { - BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter ().getRemoteDevice (address); + BluetoothDevice btDevice = getDefaultBluetoothAdapter (appContext).getRemoteDevice (address); return btDevice.getName (); } @@ -103,11 +114,11 @@ public int getBluetoothDeviceStatus (String address) public void startStopScan (boolean shouldStart) { - BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter (); + BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter (appContext); if (bluetoothAdapter == null) { - Log.d ("JUCE", "BluetoothManager error: could not get default Bluetooth adapter"); + Log.d ("JUCE", "BluetoothMidiManager error: could not get default Bluetooth adapter"); return; } @@ -115,7 +126,7 @@ public void startStopScan (boolean shouldStart) if (bluetoothLeScanner == null) { - Log.d ("JUCE", "BluetoothManager error: could not get Bluetooth LE scanner"); + Log.d ("JUCE", "BluetoothMidiManager error: could not get Bluetooth LE scanner"); return; } @@ -140,7 +151,7 @@ public void startStopScan (boolean shouldStart) public boolean pairBluetoothMidiDevice (String address) { - BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter ().getRemoteDevice (address); + BluetoothDevice btDevice = getDefaultBluetoothAdapter (appContext).getRemoteDevice (address); if (btDevice == null) { @@ -543,12 +554,8 @@ public MidiDeviceManager (Context contextToUse) return; } - openPorts = new HashMap> (); - midiDevices = new ArrayList> (); - openTasks = new HashMap (); - btDevicesPairing = new HashMap (); - MidiDeviceInfo[] foundDevices = manager.getDevices (); + for (MidiDeviceInfo info : foundDevices) onDeviceAdded (info); @@ -810,6 +817,7 @@ public void removePort (MidiPortPath path) openPorts.remove (path); } + @Override public void onDeviceAdded (MidiDeviceInfo info) { // only add standard midi devices @@ -819,6 +827,7 @@ public void onDeviceAdded (MidiDeviceInfo info) manager.openDevice (info, this, null); } + @Override public void onDeviceRemoved (MidiDeviceInfo info) { synchronized (MidiDeviceManager.class) @@ -856,8 +865,11 @@ public void onDeviceRemoved (MidiDeviceInfo info) midiDevices.remove (devicePair); } } + + handleDevicesChanged(); } + @Override public void onDeviceStatusChanged (MidiDeviceStatus status) { } @@ -933,6 +945,7 @@ public void onDeviceOpenedDelayed (MidiDevice theDevice) BluetoothGatt gatt = openTasks.get (deviceID).getGatt (); openTasks.remove (deviceID); midiDevices.add (new Pair (theDevice, gatt)); + handleDevicesChanged(); } } else { @@ -973,7 +986,6 @@ public String getPortName (MidiPortPath path) { for (MidiDeviceInfo info : deviceInfos) { - int localIndex = 0; if (info.getId () == path.deviceId) { for (MidiDeviceInfo.PortInfo portInfo : info.getPorts ()) @@ -1048,11 +1060,11 @@ private Pair getMidiDevicePairForId (int deviceId) } private MidiManager manager; - private HashMap btDevicesPairing; - private HashMap openTasks; - private ArrayList> midiDevices; + private HashMap btDevicesPairing = new HashMap(); + private HashMap openTasks = new HashMap(); + private ArrayList> midiDevices = new ArrayList>(); private MidiDeviceInfo[] deviceInfos; - private HashMap> openPorts; + private HashMap> openPorts = new HashMap>(); private Context appContext = null; } @@ -1070,9 +1082,9 @@ public static MidiDeviceManager getAndroidMidiDeviceManager (Context context) return midiDeviceManager; } - public static BluetoothManager getAndroidBluetoothManager (Context context) + public static BluetoothMidiManager getAndroidBluetoothManager (Context context) { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter (); + BluetoothAdapter adapter = getDefaultBluetoothAdapter (context); if (adapter == null) return null; @@ -1083,12 +1095,15 @@ public static BluetoothManager getAndroidBluetoothManager (Context context) synchronized (JuceMidiSupport.class) { if (bluetoothManager == null) - bluetoothManager = new BluetoothManager (context); + bluetoothManager = new BluetoothMidiManager (context); } return bluetoothManager; } + // To be called when devices become (un)available + private native static void handleDevicesChanged(); + private static MidiDeviceManager midiDeviceManager = null; - private static BluetoothManager bluetoothManager = null; + private static BluetoothMidiManager bluetoothManager = null; } diff --git a/modules/juce_audio_devices/native/juce_linux_ALSA.cpp b/modules/juce_audio_devices/native/juce_ALSA_linux.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_linux_ALSA.cpp rename to modules/juce_audio_devices/native/juce_ALSA_linux.cpp diff --git a/modules/juce_audio_devices/native/juce_win32_ASIO.cpp b/modules/juce_audio_devices/native/juce_ASIO_windows.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_win32_ASIO.cpp rename to modules/juce_audio_devices/native/juce_ASIO_windows.cpp diff --git a/modules/juce_audio_devices/native/juce_android_Audio.cpp b/modules/juce_audio_devices/native/juce_Audio_android.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_android_Audio.cpp rename to modules/juce_audio_devices/native/juce_Audio_android.cpp diff --git a/modules/juce_audio_devices/native/juce_ios_Audio.cpp b/modules/juce_audio_devices/native/juce_Audio_ios.cpp similarity index 96% rename from modules/juce_audio_devices/native/juce_ios_Audio.cpp rename to modules/juce_audio_devices/native/juce_Audio_ios.cpp index 9789e2a31c1f..4c94a1655d05 100644 --- a/modules/juce_audio_devices/native/juce_ios_Audio.cpp +++ b/modules/juce_audio_devices/native/juce_Audio_ios.cpp @@ -20,7 +20,7 @@ ============================================================================== */ -#include +#include namespace juce { @@ -196,7 +196,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE //============================================================================== #if JUCE_MODULE_AVAILABLE_juce_graphics - #include + #include #endif namespace juce { @@ -938,7 +938,7 @@ struct iOSAudioIODevice::Pimpl : public AsyncUpdater { if (! firstHostTime) { - if ((time->mSampleTime - lastSampleTime) != lastNumFrames) + if (! approximatelyEqual ((time->mSampleTime - lastSampleTime), (double) lastNumFrames)) xrun++; } else @@ -1159,7 +1159,7 @@ struct iOSAudioIODevice::Pimpl : public AsyncUpdater &desc, &dataSize); - if (desc.mSampleRate != 0 && desc.mSampleRate != sampleRate) + if (! approximatelyEqual (desc.mSampleRate, 0.0) && ! approximatelyEqual (desc.mSampleRate, sampleRate)) { JUCE_IOS_AUDIO_LOG ("Stream format has changed: Sample rate " << desc.mSampleRate); triggerAsyncUpdate(); diff --git a/modules/juce_audio_devices/native/juce_ios_Audio.h b/modules/juce_audio_devices/native/juce_Audio_ios.h similarity index 100% rename from modules/juce_audio_devices/native/juce_ios_Audio.h rename to modules/juce_audio_devices/native/juce_Audio_ios.h diff --git a/modules/juce_audio_devices/native/juce_linux_Bela.cpp b/modules/juce_audio_devices/native/juce_Bela_linux.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_linux_Bela.cpp rename to modules/juce_audio_devices/native/juce_Bela_linux.cpp diff --git a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp similarity index 94% rename from modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp rename to modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp index 90d54e382b9c..e3b687022432 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp @@ -20,7 +20,7 @@ ============================================================================== */ -#include +#include namespace juce { @@ -966,7 +966,7 @@ class CoreAudioInternal : private Timer, jassert (timestamp == nullptr || (((timestamp->mFlags & kAudioTimeStampSampleTimeValid) != 0) && ((timestamp->mFlags & kAudioTimeStampHostTimeValid) != 0))); - if (previousSampleTime == invalidSampleTime) + if (exactlyEqual (previousSampleTime, invalidSampleTime)) previousSampleTime = timestamp != nullptr ? timestamp->mSampleTime : 0.0; if (timestamp != nullptr && std::fabs (previousSampleTime - timestamp->mSampleTime) >= 1.0) @@ -1091,7 +1091,7 @@ class CoreAudioInternal : private Timer, if (! updateDetailsFromDevice()) owner.stopInternal(); - else if ((oldBufferSize != bufferSize || oldSampleRate != sampleRate) && owner.shouldRestartDevice()) + else if ((oldBufferSize != bufferSize || ! approximatelyEqual (oldSampleRate, sampleRate)) && owner.shouldRestartDevice()) owner.restart(); } @@ -1113,39 +1113,51 @@ class CoreAudioInternal : private Timer, return noErr; } - static OSStatus deviceListenerProc (AudioDeviceID /*inDevice*/, UInt32 /*inLine*/, - const AudioObjectPropertyAddress* pa, void* inClientData) + static OSStatus deviceListenerProc (AudioDeviceID /*inDevice*/, + UInt32 numAddresses, + const AudioObjectPropertyAddress* pa, + void* inClientData) { - auto intern = static_cast (inClientData); + auto& intern = *static_cast (inClientData); - switch (pa->mSelector) + const auto xruns = std::count_if (pa, pa + numAddresses, [] (const AudioObjectPropertyAddress& x) { - case kAudioDeviceProcessorOverload: - intern->xruns++; - break; + return x.mSelector == kAudioDeviceProcessorOverload; + }); - case kAudioDevicePropertyBufferSize: - case kAudioDevicePropertyBufferFrameSize: - case kAudioDevicePropertyNominalSampleRate: - case kAudioDevicePropertyStreamFormat: - case kAudioDevicePropertyDeviceIsAlive: - case kAudioStreamPropertyPhysicalFormat: - intern->deviceDetailsChanged(); - break; + intern.xruns += xruns; - case kAudioDevicePropertyDeviceHasChanged: - case kAudioObjectPropertyOwnedObjects: - intern->deviceRequestedRestart(); - break; + const auto detailsChanged = std::any_of (pa, pa + numAddresses, [] (const AudioObjectPropertyAddress& x) + { + constexpr UInt32 selectors[] + { + kAudioDevicePropertyBufferSize, + kAudioDevicePropertyBufferFrameSize, + kAudioDevicePropertyNominalSampleRate, + kAudioDevicePropertyStreamFormat, + kAudioDevicePropertyDeviceIsAlive, + kAudioStreamPropertyPhysicalFormat, + }; + + return std::find (std::begin (selectors), std::end (selectors), x.mSelector) != std::end (selectors); + }); - case kAudioDevicePropertyBufferSizeRange: - case kAudioDevicePropertyVolumeScalar: - case kAudioDevicePropertyMute: - case kAudioDevicePropertyPlayThru: - case kAudioDevicePropertyDataSource: - case kAudioDevicePropertyDeviceIsRunning: - break; - } + const auto requestedRestart = std::any_of (pa, pa + numAddresses, [] (const AudioObjectPropertyAddress& x) + { + constexpr UInt32 selectors[] + { + kAudioDevicePropertyDeviceHasChanged, + kAudioObjectPropertyOwnedObjects, + }; + + return std::find (std::begin (selectors), std::end (selectors), x.mSelector) != std::end (selectors); + }); + + if (detailsChanged) + intern.deviceDetailsChanged(); + + if (requestedRestart) + intern.deviceRequestedRestart(); return noErr; } @@ -1378,19 +1390,18 @@ class CoreAudioIODevice : public AudioIODevice, start (previousCallback); } - static OSStatus hardwareListenerProc (AudioDeviceID /*inDevice*/, UInt32 /*inLine*/, const AudioObjectPropertyAddress* pa, void* inClientData) + static OSStatus hardwareListenerProc (AudioDeviceID /*inDevice*/, + UInt32 numAddresses, + const AudioObjectPropertyAddress* pa, + void* inClientData) { - switch (pa->mSelector) + const auto detailsChanged = std::any_of (pa, pa + numAddresses, [] (const AudioObjectPropertyAddress& x) { - case kAudioHardwarePropertyDevices: - static_cast (inClientData)->deviceDetailsChanged(); - break; + return x.mSelector == kAudioHardwarePropertyDevices; + }); - case kAudioHardwarePropertyDefaultOutputDevice: - case kAudioHardwarePropertyDefaultInputDevice: - case kAudioHardwarePropertyDefaultSystemOutputDevice: - break; - } + if (detailsChanged) + static_cast (inClientData)->deviceDetailsChanged(); return noErr; } @@ -1577,7 +1588,7 @@ class AudioIODeviceCombiner : public AudioIODevice, { auto deviceSampleRate = d->getCurrentSampleRate(); - if (deviceSampleRate != sampleRateRequested) + if (! approximatelyEqual (deviceSampleRate, sampleRateRequested)) { if (! getAvailableSampleRates().contains (deviceSampleRate)) return; @@ -1912,7 +1923,7 @@ class AudioIODeviceCombiner : public AudioIODevice, for (auto& d : getDeviceWrappers()) { - if (d->getCurrentSampleRate() != currentSampleRate) + if (! approximatelyEqual (d->getCurrentSampleRate(), currentSampleRate)) { d->setCurrentSampleRate (currentSampleRate); anySampleRateChanges = true; diff --git a/modules/juce_audio_devices/native/juce_mac_CoreMidi.mm b/modules/juce_audio_devices/native/juce_CoreMidi_mac.mm similarity index 91% rename from modules/juce_audio_devices/native/juce_mac_CoreMidi.mm rename to modules/juce_audio_devices/native/juce_CoreMidi_mac.mm index fd61986e7a97..490026719e10 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreMidi.mm +++ b/modules/juce_audio_devices/native/juce_CoreMidi_mac.mm @@ -71,10 +71,8 @@ static bool checkError (OSStatus err, [[maybe_unused]] int lineNum) { virtual ~SenderBase() noexcept = default; - virtual void send (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& m) = 0; + virtual void send (MIDIPortRef port, MIDIEndpointRef endpoint, const ump::BytestreamMidiView& m) = 0; virtual void send (MIDIPortRef port, MIDIEndpointRef endpoint, ump::Iterator b, ump::Iterator e) = 0; - - virtual ump::MidiProtocol getProtocol() const noexcept = 0; }; template @@ -84,11 +82,7 @@ static bool checkError (OSStatus err, [[maybe_unused]] int lineNum) template <> struct API_AVAILABLE (macos (11.0), ios (14.0)) Sender : public SenderBase { - explicit Sender (MIDIEndpointRef ep) - : umpConverter (getProtocolForEndpoint (ep)) - {} - - void send (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& m) override + void send (MIDIPortRef port, MIDIEndpointRef endpoint, const ump::BytestreamMidiView& m) override { newSendImpl (port, endpoint, m); } @@ -98,14 +92,8 @@ void send (MIDIPortRef port, MIDIEndpointRef endpoint, ump::Iterator b, ump::Ite newSendImpl (port, endpoint, b, e); } - ump::MidiProtocol getProtocol() const noexcept override - { - return umpConverter.getProtocol() == ump::PacketProtocol::MIDI_2_0 ? ump::MidiProtocol::UMP_MIDI_2_0 - : ump::MidiProtocol::UMP_MIDI_1_0; - } - private: - ump::GenericUMPConverter umpConverter; + ump::ToUMP1Converter umpConverter; static ump::PacketProtocol getProtocolForEndpoint (MIDIEndpointRef ep) noexcept { @@ -119,9 +107,6 @@ void send (MIDIPortRef port, MIDIEndpointRef endpoint, ump::Iterator b, ump::Ite template void newSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, Params&&... params) { - // The converter protocol got out-of-sync with the device protocol - jassert (getProtocolForEndpoint (endpoint) == umpConverter.getProtocol()); - #if JUCE_IOS const MIDITimeStamp timeStamp = mach_absolute_time(); #else @@ -133,9 +118,10 @@ void newSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, Params&&... params const auto init = [&] { - end = MIDIEventListInit (&stackList, - umpConverter.getProtocol() == ump::PacketProtocol::MIDI_2_0 ? kMIDIProtocol_2_0 - : kMIDIProtocol_1_0); + // At the moment, we can only send MIDI 1.0 protocol. If the device is using MIDI + // 2.0 protocol (as may be the case for the IAC driver), we trust in the system to + // translate it. + end = MIDIEventListInit (&stackList, kMIDIProtocol_1_0); }; const auto send = [&] @@ -159,16 +145,19 @@ void newSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, Params&&... params init(); - umpConverter.convert (params..., [&] (const ump::View& view) + ump::GenericUMPConverter::convertImpl (umpConverter, params..., [&] (const auto& v) { - add (view); + umpConverter.convert (v, [&] (const ump::View& view) + { + add (view); - if (end != nullptr) - return; + if (end != nullptr) + return; - send(); - init(); - add (view); + send(); + init(); + add (view); + }); }); send(); @@ -180,9 +169,7 @@ void newSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, Params&&... params template <> struct Sender : public SenderBase { - explicit Sender (MIDIEndpointRef) {} - - void send (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& m) override + void send (MIDIPortRef port, MIDIEndpointRef endpoint, const ump::BytestreamMidiView& m) override { oldSendImpl (port, endpoint, m); } @@ -191,22 +178,17 @@ void send (MIDIPortRef port, MIDIEndpointRef endpoint, ump::Iterator b, ump::Ite { std::for_each (b, e, [&] (const ump::View& v) { - bytestreamConverter.convert (v, 0.0, [&] (const MidiMessage& m) + bytestreamConverter.convert (v, 0.0, [&] (const ump::BytestreamMidiView& m) { send (port, endpoint, m); }); }); } - ump::MidiProtocol getProtocol() const noexcept override - { - return ump::MidiProtocol::bytestream; - } - private: ump::ToBytestreamConverter bytestreamConverter { 2048 }; - void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& message) + void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const ump::BytestreamMidiView& message) { #if JUCE_IOS const MIDITimeStamp timeStamp = mach_absolute_time(); @@ -217,7 +199,7 @@ void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& HeapBlock allocatedPackets; MIDIPacketList stackPacket; auto* packetToSend = &stackPacket; - auto dataSize = (size_t) message.getRawDataSize(); + auto dataSize = message.bytes.size(); if (message.isSysEx()) { @@ -234,7 +216,7 @@ void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& { p->timeStamp = timeStamp; p->length = (UInt16) jmin (maxPacketSize, bytesLeft); - memcpy (p->data, message.getRawData() + pos, p->length); + memcpy (p->data, message.bytes.data() + pos, p->length); pos += p->length; bytesLeft -= p->length; p = MIDIPacketNext (p); @@ -254,7 +236,7 @@ void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& auto& p = *(packetToSend->packet); p.timeStamp = timeStamp; p.length = (UInt16) dataSize; - memcpy (p.data, message.getRawData(), dataSize); + memcpy (p.data, message.bytes.data(), dataSize); } else { @@ -274,11 +256,11 @@ void oldSendImpl (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& template <> struct Sender { - explicit Sender (MIDIEndpointRef ep) - : sender (makeImpl (ep)) + Sender() + : sender (makeImpl()) {} - void send (MIDIPortRef port, MIDIEndpointRef endpoint, const MidiMessage& m) + void send (MIDIPortRef port, MIDIEndpointRef endpoint, const ump::BytestreamMidiView& m) { sender->send (port, endpoint, m); } @@ -288,18 +270,13 @@ void send (MIDIPortRef port, MIDIEndpointRef endpoint, ump::Iterator b, ump::Ite sender->send (port, endpoint, b, e); } - ump::MidiProtocol getProtocol() const noexcept - { - return sender->getProtocol(); - } - private: - static std::unique_ptr makeImpl (MIDIEndpointRef ep) + static std::unique_ptr makeImpl() { if (@available (macOS 11, iOS 14, *)) - return std::make_unique> (ep); + return std::make_unique>(); - return std::make_unique> (ep); + return std::make_unique>(); } std::unique_ptr sender; @@ -369,7 +346,7 @@ Resource release() noexcept { public: MidiPortAndEndpoint (ScopedPortRef p, ScopedEndpointRef ep) noexcept - : port (std::move (p)), endpoint (std::move (ep)), sender (*endpoint) + : port (std::move (p)), endpoint (std::move (ep)) {} ~MidiPortAndEndpoint() noexcept @@ -379,7 +356,7 @@ Resource release() noexcept endpoint.release(); } - void send (const MidiMessage& m) + void send (const ump::BytestreamMidiView& m) { sender.send (*port, *endpoint, m); } @@ -392,11 +369,6 @@ void send (ump::Iterator b, ump::Iterator e) bool canStop() const noexcept { return *port != 0; } void stop() const { CHECK_ERROR (MIDIPortDisconnectSource (*port, *endpoint)); } - ump::MidiProtocol getProtocol() const noexcept - { - return sender.getProtocol(); - } - private: ScopedPortRef port; ScopedEndpointRef endpoint; @@ -579,9 +551,10 @@ static void enableSimulatorMidiSession() #endif } - static void globalSystemChangeCallback (const MIDINotification*, void*) + static void globalSystemChangeCallback (const MIDINotification* notification, void*) { - // TODO.. Should pass-on this notification.. + if (notification != nullptr && notification->messageID == kMIDIMsgSetupChanged) + MidiDeviceListConnectionBroadcaster::get().notify(); } static String getGlobalMidiClientName() @@ -594,9 +567,7 @@ static String getGlobalMidiClientName() static MIDIClientRef getGlobalMidiClient() { - static MIDIClientRef globalMidiClient = 0; - - if (globalMidiClient == 0) + static const auto globalMidiClient = [&] { // Since OSX 10.6, the MIDIClientCreate function will only work // correctly when called from the message thread! @@ -605,8 +576,10 @@ static MIDIClientRef getGlobalMidiClient() enableSimulatorMidiSession(); CFUniquePtr name (getGlobalMidiClientName().toCFString()); - CHECK_ERROR (MIDIClientCreate (name.get(), &globalSystemChangeCallback, nullptr, &globalMidiClient)); - } + MIDIClientRef result{}; + CHECK_ERROR (MIDIClientCreate (name.get(), globalSystemChangeCallback, nullptr, &result)); + return result; + }(); return globalMidiClient; } @@ -1297,7 +1270,13 @@ static CreatorFunctionPointers getCreatorFunctionPointers() void MidiOutput::sendMessageNow (const MidiMessage& message) { - internal->send (message); + internal->send (ump::BytestreamMidiView (&message)); +} + +MidiDeviceListConnection MidiDeviceListConnection::make (std::function cb) +{ + auto& broadcaster = MidiDeviceListConnectionBroadcaster::get(); + return { &broadcaster, broadcaster.add (std::move (cb)) }; } #undef CHECK_ERROR diff --git a/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp b/modules/juce_audio_devices/native/juce_DirectSound_windows.cpp similarity index 95% rename from modules/juce_audio_devices/native/juce_win32_DirectSound.cpp rename to modules/juce_audio_devices/native/juce_DirectSound_windows.cpp index 017bee61e893..28a102ac417d 100644 --- a/modules/juce_audio_devices/native/juce_win32_DirectSound.cpp +++ b/modules/juce_audio_devices/native/juce_DirectSound_windows.cpp @@ -1035,8 +1035,14 @@ class DSoundAudioIODevice : public AudioIODevice, }; //============================================================================== -struct DSoundDeviceList +class DSoundDeviceList { + auto tie() const + { + return std::tie (outputDeviceNames, inputDeviceNames, outputGuids, inputGuids); + } + +public: StringArray outputDeviceNames, inputDeviceNames; Array outputGuids, inputGuids; @@ -1054,13 +1060,8 @@ struct DSoundDeviceList } } - bool operator!= (const DSoundDeviceList& other) const noexcept - { - return outputDeviceNames != other.outputDeviceNames - || inputDeviceNames != other.inputDeviceNames - || outputGuids != other.outputGuids - || inputGuids != other.inputGuids; - } + bool operator== (const DSoundDeviceList& other) const noexcept { return tie() == other.tie(); } + bool operator!= (const DSoundDeviceList& other) const noexcept { return tie() != other.tie(); } private: static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array& guids) @@ -1213,13 +1214,11 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels, } //============================================================================== -class DSoundAudioIODeviceType : public AudioIODeviceType, - private DeviceChangeDetector +class DSoundAudioIODeviceType : public AudioIODeviceType { public: DSoundAudioIODeviceType() - : AudioIODeviceType ("DirectSound"), - DeviceChangeDetector (L"DirectSound") + : AudioIODeviceType ("DirectSound") { initialiseDSoundFunctions(); } @@ -1274,19 +1273,17 @@ class DSoundAudioIODeviceType : public AudioIODeviceType, } private: + DeviceChangeDetector detector { L"DirectSound", [this] { systemDeviceChanged(); } }; DSoundDeviceList deviceList; bool hasScanned = false; - void systemDeviceChanged() override + void systemDeviceChanged() { DSoundDeviceList newList; newList.scan(); - if (newList != deviceList) - { - deviceList = newList; + if (std::exchange (deviceList, newList) != newList) callDeviceChangeListeners(); - } } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType) diff --git a/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h b/modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h similarity index 96% rename from modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h rename to modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h index c76f96d6e97a..7f93f9f7ea49 100644 --- a/modules/juce_audio_devices/native/juce_android_HighPerformanceAudioHelpers.h +++ b/modules/juce_audio_devices/native/juce_HighPerformanceAudioHelpers_android.h @@ -65,7 +65,7 @@ namespace AndroidHighPerformanceAudioHelpers static bool canUseHighPerformanceAudioPath (int nativeBufferSize, int requestedBufferSize, int requestedSampleRate) { return ((requestedBufferSize % nativeBufferSize) == 0) - && (requestedSampleRate == getNativeSampleRate()) + && approximatelyEqual ((double) requestedSampleRate, getNativeSampleRate()) && isProAudioDevice(); } diff --git a/modules/juce_audio_devices/native/juce_linux_JackAudio.cpp b/modules/juce_audio_devices/native/juce_JackAudio_linux.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_linux_JackAudio.cpp rename to modules/juce_audio_devices/native/juce_JackAudio_linux.cpp diff --git a/modules/juce_audio_devices/native/juce_Midi_android.cpp b/modules/juce_audio_devices/native/juce_Midi_android.cpp new file mode 100644 index 000000000000..2b4f417668de --- /dev/null +++ b/modules/juce_audio_devices/native/juce_Midi_android.cpp @@ -0,0 +1,1171 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +// This byte-code is generated from native/java/com/rmsl/juce/JuceMidiSupport.java with min sdk version 23 +// See juce_core/native/java/README.txt on how to generate this byte-code. +constexpr unsigned char javaMidiByteCode[] +{ + 0x1f, 0x8b, 0x08, 0x08, 0xa3, 0xf2, 0xc6, 0x63, 0x00, 0x03, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x00, 0x95, 0x7c, + 0x09, 0x7c, 0xdb, 0x47, 0x95, 0xff, 0x9b, 0x9f, 0x7e, 0xb2, 0x6c, 0xf9, + 0x92, 0x64, 0x27, 0x76, 0x1c, 0xc7, 0x96, 0x8f, 0xc4, 0xf7, 0x15, 0xc7, + 0xa9, 0x13, 0x3b, 0xa9, 0xef, 0xc4, 0xb1, 0x73, 0xd4, 0x56, 0xd2, 0x36, + 0x2e, 0xdb, 0x2a, 0xb6, 0x12, 0xab, 0xb1, 0x25, 0x45, 0x92, 0xd3, 0x04, + 0x4a, 0x9b, 0x1e, 0x6c, 0x12, 0x08, 0x10, 0x4a, 0x9b, 0x96, 0x12, 0xd8, + 0xd2, 0x1b, 0x28, 0xd0, 0x76, 0x39, 0xca, 0x6e, 0x77, 0x29, 0x6c, 0x97, + 0x2d, 0xf7, 0xd5, 0x85, 0x70, 0x2d, 0xa5, 0x84, 0xa5, 0x94, 0x02, 0x61, + 0xf7, 0xbf, 0x6c, 0xe8, 0xbf, 0x90, 0xfd, 0xbe, 0x99, 0xf9, 0x49, 0x3f, + 0x3b, 0x6e, 0x53, 0x92, 0xcf, 0x57, 0x6f, 0xe6, 0xcd, 0x9b, 0x99, 0x37, + 0x33, 0x6f, 0xde, 0xbc, 0xf9, 0xfd, 0x24, 0x4f, 0x85, 0x0e, 0xb9, 0x5b, + 0xdb, 0x3b, 0xe8, 0xae, 0x83, 0xd9, 0xd5, 0xe5, 0x6f, 0x37, 0xff, 0xb8, + 0x6a, 0xcf, 0xe9, 0xa7, 0xdf, 0xb2, 0xa7, 0xbd, 0xf5, 0xf0, 0x6b, 0xab, + 0x1b, 0x4f, 0x9c, 0xba, 0xff, 0x6c, 0xe9, 0x30, 0x51, 0x8c, 0x88, 0x0e, + 0xed, 0x5a, 0xe3, 0x23, 0xfd, 0x6f, 0x74, 0x33, 0xd1, 0x32, 0xa1, 0xf8, + 0x9b, 0x80, 0xe7, 0x4d, 0xa2, 0xab, 0x40, 0xcf, 0x39, 0x89, 0x2a, 0x40, + 0x3d, 0x6e, 0xa2, 0xbf, 0x07, 0x2d, 0xce, 0x26, 0xca, 0x02, 0x7d, 0xdc, + 0x83, 0x3a, 0x97, 0x11, 0x7d, 0xdb, 0x4b, 0x74, 0xa6, 0x89, 0xe8, 0x47, + 0xc0, 0x4f, 0x81, 0x17, 0x81, 0x5f, 0x02, 0xd9, 0xcd, 0x44, 0x4b, 0x80, + 0x15, 0x40, 0x05, 0x50, 0x03, 0x34, 0x01, 0xfd, 0xc0, 0x6d, 0xc0, 0x73, + 0xc0, 0x59, 0xe0, 0x57, 0xc0, 0x6f, 0x80, 0x73, 0x80, 0xb7, 0x85, 0xa8, + 0x13, 0xe8, 0x02, 0x7a, 0x81, 0x00, 0x30, 0x0d, 0x1c, 0x04, 0x4e, 0x00, + 0xef, 0x05, 0xde, 0x0f, 0xdc, 0x03, 0x7c, 0x08, 0x78, 0x00, 0x78, 0x04, + 0x78, 0x0c, 0x78, 0x12, 0x38, 0x03, 0xfc, 0x19, 0xf0, 0xb7, 0x12, 0x8d, + 0x00, 0x37, 0x02, 0x1f, 0x05, 0xbe, 0x05, 0xbc, 0x0a, 0x94, 0xb7, 0x11, + 0x6d, 0x01, 0x66, 0x81, 0x93, 0xc0, 0x3f, 0x01, 0x2f, 0x02, 0x7f, 0x06, + 0xca, 0x56, 0x63, 0x3c, 0xc0, 0x01, 0xe0, 0x1e, 0xe0, 0x69, 0xe0, 0xb7, + 0xc0, 0xaa, 0x76, 0xa2, 0xcd, 0xc0, 0x2c, 0x70, 0x12, 0x78, 0x0c, 0xf8, + 0x22, 0xf0, 0x03, 0xe0, 0x1c, 0x60, 0xae, 0xc1, 0xbc, 0x01, 0xcd, 0xc0, + 0x14, 0x70, 0x37, 0xf0, 0x35, 0xe0, 0x4f, 0xc0, 0xa6, 0x0e, 0xa2, 0x77, + 0x03, 0xcf, 0x00, 0xbf, 0x03, 0xf2, 0xd7, 0x12, 0xb5, 0x03, 0xe3, 0xc0, + 0x41, 0xe0, 0x2e, 0xe0, 0x09, 0xe0, 0x39, 0xe0, 0xc7, 0xc0, 0x39, 0xc0, + 0xc4, 0x9c, 0x16, 0x03, 0x2d, 0xc0, 0x36, 0x60, 0x16, 0xb8, 0x1d, 0xf8, + 0x20, 0xf0, 0x29, 0xe0, 0x59, 0xe0, 0x87, 0xc0, 0xef, 0x00, 0x47, 0x27, + 0xfa, 0x06, 0x1a, 0x80, 0x0d, 0xc0, 0x36, 0x20, 0x08, 0x1c, 0x02, 0xde, + 0x05, 0x7c, 0x13, 0x78, 0x11, 0x38, 0x07, 0xfc, 0x09, 0xf0, 0xaf, 0x23, + 0xaa, 0x02, 0x6a, 0x80, 0x46, 0x60, 0x35, 0xb0, 0x1e, 0xd8, 0x08, 0xf4, + 0x03, 0xc3, 0xc0, 0x0e, 0x60, 0x27, 0xb0, 0x1b, 0xb8, 0x0e, 0xd8, 0x0b, + 0xcc, 0x02, 0x49, 0xe0, 0x10, 0xf0, 0x36, 0xe0, 0x66, 0xe0, 0x36, 0xe0, + 0x28, 0xf0, 0x71, 0xe0, 0x47, 0x00, 0xad, 0xc7, 0x7a, 0x03, 0xf5, 0xc0, + 0x5a, 0xa0, 0x1f, 0xd8, 0x0c, 0xec, 0x04, 0x82, 0x40, 0x18, 0x48, 0x02, + 0x27, 0x81, 0xfb, 0x81, 0xa7, 0x80, 0xaf, 0x02, 0x3f, 0x01, 0xce, 0x02, + 0xbf, 0x01, 0xfe, 0x1b, 0x78, 0x15, 0x10, 0x5d, 0x44, 0x6e, 0xa0, 0x08, + 0xa8, 0x00, 0x9a, 0x81, 0x36, 0xa0, 0x0b, 0xd8, 0x0c, 0x04, 0x80, 0x6b, + 0x80, 0x13, 0xc0, 0x29, 0xe0, 0xf3, 0xc0, 0x8f, 0x80, 0x9f, 0x03, 0xbf, + 0x05, 0xfe, 0x0b, 0xf8, 0x0b, 0xb7, 0xd1, 0x8d, 0x36, 0x80, 0x76, 0x60, + 0x07, 0xb0, 0x0f, 0xb8, 0x11, 0x38, 0x05, 0x7c, 0x02, 0xf8, 0x1c, 0xf0, + 0x55, 0xe0, 0x3f, 0x81, 0x3f, 0x00, 0x62, 0x03, 0x51, 0x2e, 0xb0, 0x14, + 0xe8, 0x05, 0x36, 0x03, 0xdb, 0x81, 0xab, 0x80, 0x1b, 0x81, 0x87, 0x80, + 0x6f, 0x01, 0x2f, 0x03, 0xc6, 0x46, 0xd8, 0x38, 0x50, 0x0c, 0xd4, 0x00, + 0xeb, 0x80, 0x7e, 0x60, 0x0c, 0x98, 0x04, 0xe6, 0x80, 0x9b, 0x80, 0x3b, + 0x81, 0x07, 0x80, 0xc7, 0x80, 0xcf, 0x02, 0xff, 0x02, 0x7c, 0x1d, 0xf8, + 0x77, 0xe0, 0x45, 0xe0, 0x15, 0xe0, 0x8f, 0xc0, 0x5f, 0x00, 0xd7, 0xe5, + 0xe8, 0x1f, 0x58, 0x06, 0x34, 0x02, 0xeb, 0x80, 0xcb, 0x81, 0x41, 0xe0, + 0x6a, 0x20, 0x0e, 0x1c, 0x03, 0xfe, 0x0e, 0x78, 0x0a, 0xf8, 0x2a, 0xf0, + 0x53, 0xe0, 0x15, 0xe0, 0x35, 0xa0, 0xa0, 0x87, 0xa8, 0x1a, 0xe8, 0x02, + 0x06, 0x80, 0x31, 0x60, 0x0a, 0xb8, 0x09, 0x38, 0x01, 0xdc, 0x0b, 0xdc, + 0x0f, 0x3c, 0x05, 0x7c, 0x03, 0xf8, 0x21, 0xf0, 0x12, 0x20, 0x7a, 0x89, + 0x96, 0x03, 0x2d, 0xc0, 0xe5, 0xc0, 0x16, 0x60, 0x27, 0x70, 0x0d, 0x70, + 0x00, 0x78, 0x37, 0xf0, 0x30, 0xf0, 0x04, 0xf0, 0x8f, 0xc0, 0x33, 0xc0, + 0x19, 0xe0, 0x05, 0xe0, 0x15, 0xc0, 0xd5, 0x47, 0x94, 0x03, 0x2c, 0x01, + 0xca, 0x81, 0x1a, 0xa0, 0x09, 0x18, 0x06, 0xc6, 0x81, 0x29, 0xe0, 0x00, + 0x70, 0x0b, 0x70, 0x14, 0x78, 0x0f, 0xf0, 0x01, 0xe0, 0x51, 0xe0, 0x93, + 0xc0, 0x53, 0xc0, 0x33, 0xc0, 0x57, 0x80, 0xef, 0x01, 0x2f, 0x03, 0xce, + 0x7e, 0xb4, 0x05, 0xac, 0x02, 0x5a, 0x80, 0x3c, 0x98, 0x58, 0x01, 0x29, + 0x5f, 0x54, 0x09, 0x54, 0x01, 0xd5, 0xc0, 0x4a, 0x60, 0x15, 0x50, 0x03, + 0xd4, 0x02, 0x75, 0x40, 0x3d, 0xd0, 0x00, 0x34, 0x02, 0x70, 0x45, 0x04, + 0xd7, 0x42, 0x70, 0x0b, 0x04, 0x17, 0x40, 0xd8, 0xea, 0x84, 0x6d, 0x4d, + 0xd8, 0xba, 0x84, 0x2d, 0x4a, 0xd8, 0x96, 0x84, 0x6d, 0x47, 0xd8, 0x4e, + 0x84, 0x2d, 0x42, 0xda, 0x94, 0x09, 0xe6, 0x43, 0x30, 0x09, 0xc2, 0x52, + 0x13, 0x96, 0x86, 0x30, 0xbd, 0x84, 0xa1, 0x12, 0x54, 0x23, 0xa8, 0x43, + 0x03, 0xc0, 0x20, 0x30, 0xa4, 0xfd, 0x25, 0xdc, 0x27, 0xc1, 0xad, 0xd2, + 0x16, 0x60, 0x84, 0xfd, 0x29, 0xb0, 0x15, 0xd8, 0x06, 0x6c, 0x07, 0x76, + 0x00, 0x57, 0x00, 0x63, 0xc0, 0x38, 0x10, 0x00, 0x76, 0x02, 0x57, 0x02, + 0x57, 0x03, 0xbb, 0x81, 0x6b, 0x80, 0xbf, 0x01, 0xae, 0x05, 0x82, 0xc0, + 0x1e, 0x60, 0x12, 0xb8, 0x1e, 0x78, 0x2b, 0xf0, 0x76, 0xe0, 0x26, 0xe0, + 0x66, 0xe0, 0x08, 0x70, 0x0b, 0x70, 0x2b, 0xa9, 0xb9, 0xb1, 0xfe, 0xe5, + 0x6b, 0xba, 0x03, 0x83, 0xf7, 0xe8, 0xf4, 0x55, 0x48, 0x2f, 0x03, 0x35, + 0x74, 0xbe, 0x4c, 0xa7, 0xaf, 0xd3, 0x7c, 0x87, 0x8d, 0xef, 0xd0, 0x75, + 0x99, 0x6f, 0x6a, 0xbe, 0x5f, 0xa7, 0xa7, 0x35, 0x3f, 0xcb, 0x26, 0x8f, + 0xe3, 0x80, 0x92, 0x9a, 0x9f, 0xa3, 0xf9, 0x25, 0x5a, 0xa7, 0x1b, 0x35, + 0xdf, 0xd2, 0x89, 0xd3, 0x1e, 0x5b, 0xba, 0xc0, 0x26, 0xbf, 0x44, 0xcb, + 0x97, 0xe8, 0x32, 0xab, 0x6e, 0xa9, 0xad, 0xaf, 0x32, 0xad, 0x5b, 0x89, + 0xd6, 0x89, 0x65, 0xca, 0x74, 0x7a, 0x87, 0x4e, 0x57, 0xe8, 0x71, 0xb1, + 0x4c, 0xb5, 0x96, 0x29, 0xd5, 0xe9, 0xdb, 0x91, 0x5e, 0xa1, 0xd3, 0x27, + 0xb4, 0xfc, 0x2a, 0x5b, 0xdd, 0x1a, 0x5d, 0x77, 0x39, 0x29, 0x5b, 0xba, + 0x47, 0xeb, 0xd0, 0x6a, 0xd3, 0xb3, 0xcd, 0xa6, 0xdb, 0x6a, 0x9b, 0x6e, + 0x9c, 0xbe, 0x0f, 0xfc, 0x72, 0x9d, 0x7e, 0xb4, 0x31, 0xcd, 0xb7, 0xe6, + 0xb3, 0xdd, 0xd6, 0x4e, 0xbb, 0x4d, 0x7f, 0x4e, 0x3f, 0x6e, 0x4b, 0x5b, + 0x63, 0x5c, 0x6b, 0xeb, 0x6b, 0xbd, 0xad, 0x2f, 0xb6, 0xcd, 0xa7, 0x34, + 0xbf, 0x5b, 0xf3, 0xd9, 0x46, 0x2e, 0xd7, 0xe9, 0xfd, 0x3a, 0xcd, 0x75, + 0x67, 0x74, 0xfa, 0x19, 0xa4, 0x67, 0x75, 0xfa, 0x39, 0xa4, 0x23, 0x3a, + 0xfd, 0x3c, 0xd2, 0x51, 0x9d, 0x3e, 0x8b, 0xf4, 0x41, 0x9d, 0x7e, 0xa5, + 0x51, 0xc5, 0x02, 0x9c, 0x3e, 0x8f, 0xf4, 0x01, 0xab, 0x7d, 0x6c, 0xa8, + 0xa4, 0x4e, 0xe7, 0x20, 0x3d, 0xa7, 0xd3, 0x85, 0xb6, 0xb4, 0xbf, 0x29, + 0xdd, 0x66, 0xa3, 0x2d, 0x7d, 0x9d, 0xad, 0xaf, 0x35, 0x36, 0x7e, 0x77, + 0x53, 0xba, 0xdf, 0x01, 0x1b, 0x7f, 0x87, 0x2d, 0x7d, 0x95, 0xad, 0xdf, + 0xeb, 0x6c, 0xfc, 0x69, 0x5b, 0xdd, 0x18, 0xd2, 0x37, 0x58, 0x63, 0xb7, + 0xc9, 0x1f, 0x43, 0xfa, 0x90, 0x4e, 0x9f, 0xb4, 0xd5, 0x7d, 0xdc, 0xa6, + 0x0f, 0xaf, 0x9d, 0x25, 0xff, 0xa8, 0x8d, 0xbf, 0xc3, 0x96, 0x3e, 0x6d, + 0xeb, 0xeb, 0x41, 0xa4, 0x13, 0x56, 0x3b, 0x48, 0x1f, 0xd6, 0xe9, 0xa7, + 0x9a, 0xd2, 0x73, 0xf5, 0x0c, 0xd2, 0x71, 0x9d, 0xfe, 0x7a, 0x93, 0xda, + 0xc3, 0x3d, 0x7a, 0x8d, 0xde, 0xa6, 0xd3, 0xbc, 0x46, 0x37, 0xea, 0xf4, + 0x59, 0x5b, 0xfa, 0x3e, 0x5b, 0xda, 0xb2, 0x9f, 0x7e, 0x5d, 0x97, 0xd3, + 0x03, 0x36, 0x7b, 0x18, 0xb4, 0xd9, 0xc3, 0x90, 0xe6, 0x97, 0xe8, 0xf4, + 0x8d, 0xda, 0x9e, 0xa7, 0x79, 0x5d, 0x60, 0x8d, 0x1f, 0xd1, 0xd4, 0x21, + 0x78, 0xaf, 0x78, 0xe8, 0x28, 0x31, 0x6d, 0xa7, 0x77, 0x4a, 0xba, 0x8e, + 0x4e, 0x48, 0x9a, 0x45, 0x42, 0xb0, 0x9f, 0x5d, 0x46, 0x7f, 0x4b, 0x4c, + 0x7b, 0xe8, 0xab, 0x92, 0x0a, 0xfa, 0x96, 0xa4, 0x35, 0xf4, 0x3f, 0x92, + 0xd6, 0xd2, 0xab, 0xc4, 0xbe, 0x78, 0x89, 0x94, 0xab, 0xd2, 0xfc, 0x2a, + 0xcd, 0x5f, 0xa9, 0xf3, 0x4c, 0x3d, 0x82, 0xf7, 0x9a, 0x49, 0xef, 0x25, + 0xa6, 0x5e, 0xfa, 0x9e, 0xa4, 0xaa, 0x7c, 0x95, 0x2e, 0xaf, 0xd1, 0xfa, + 0xd4, 0xc0, 0x13, 0xbf, 0x47, 0xd2, 0x01, 0xba, 0x57, 0xd2, 0x62, 0xfa, + 0x8e, 0xa4, 0x6b, 0xe9, 0xdf, 0x75, 0xf9, 0x7f, 0x6b, 0xfa, 0xff, 0x48, + 0xed, 0xd5, 0x0f, 0x48, 0xda, 0x43, 0x5f, 0xd7, 0xf9, 0x3f, 0x11, 0x9f, + 0x05, 0x15, 0xf4, 0x2e, 0x49, 0x6b, 0xe8, 0x79, 0x62, 0x9f, 0x97, 0x45, + 0x8f, 0x49, 0xea, 0xa0, 0x4f, 0x4a, 0x9a, 0x41, 0xff, 0x42, 0xec, 0xf3, + 0x32, 0xe9, 0x2e, 0x49, 0xab, 0xe8, 0x21, 0x4d, 0xff, 0x89, 0xd8, 0xe7, + 0x35, 0xd0, 0xfb, 0x35, 0xfd, 0xa0, 0xa4, 0x4e, 0x7a, 0x5c, 0xd2, 0xed, + 0x74, 0x01, 0xd4, 0x09, 0x7e, 0x06, 0x68, 0x26, 0x6a, 0x3c, 0x48, 0xec, + 0x17, 0x87, 0x29, 0x47, 0x30, 0xbd, 0x8c, 0xf2, 0x41, 0xdd, 0xba, 0x3c, + 0x3b, 0x45, 0xb3, 0xe9, 0xa4, 0xa4, 0x6e, 0xca, 0x42, 0x79, 0xae, 0x6e, + 0x2f, 0x4f, 0x97, 0xe7, 0x81, 0x73, 0x52, 0xd2, 0x1c, 0x72, 0x09, 0x45, + 0x33, 0x05, 0xfb, 0xcc, 0x3c, 0xfa, 0x28, 0x31, 0xad, 0xa4, 0x67, 0x41, + 0xbd, 0x5a, 0x2f, 0x2f, 0x3c, 0xeb, 0xe7, 0x24, 0xf5, 0xd0, 0xef, 0x24, + 0xf5, 0xd2, 0x7f, 0x81, 0xfa, 0xb4, 0xfe, 0x1c, 0xdc, 0x7f, 0x41, 0xd3, + 0x7f, 0x25, 0xe5, 0x6f, 0x3f, 0x2b, 0xe9, 0x38, 0x7d, 0x51, 0x52, 0x1f, + 0x7d, 0x49, 0xf3, 0xb9, 0x7c, 0x89, 0x6e, 0x77, 0x09, 0x4e, 0x2f, 0x13, + 0xfd, 0x2e, 0xd5, 0x7a, 0x15, 0xe3, 0xb4, 0x7a, 0x52, 0xd2, 0x36, 0x7a, + 0x45, 0xd2, 0x2e, 0xfa, 0xad, 0xa4, 0x1b, 0xe9, 0x35, 0x49, 0x37, 0xd0, + 0x12, 0xc1, 0xf6, 0xa7, 0xea, 0x2f, 0x83, 0xc5, 0xdf, 0xa9, 0xe9, 0x07, + 0xa5, 0x2d, 0xaa, 0x76, 0x4a, 0xa1, 0xff, 0x03, 0xd2, 0x66, 0x0b, 0xe8, + 0x7e, 0x62, 0x5f, 0x69, 0xd0, 0x3d, 0xd2, 0x1e, 0x87, 0x64, 0x79, 0x05, + 0xd6, 0x53, 0x51, 0x41, 0x1f, 0x97, 0x74, 0x15, 0x7d, 0x5a, 0xd2, 0x5d, + 0xf4, 0x8f, 0x92, 0x6e, 0xa6, 0x33, 0x92, 0x36, 0xd2, 0x4b, 0x92, 0x36, + 0xd1, 0xaf, 0x25, 0x1d, 0xa3, 0xf3, 0x92, 0x8e, 0x50, 0xae, 0xb4, 0xeb, + 0x4d, 0x54, 0x28, 0xed, 0xb7, 0x57, 0xb6, 0x57, 0xa9, 0xf5, 0x62, 0xfa, + 0x61, 0x49, 0xd5, 0xfc, 0x54, 0x22, 0x2a, 0xf8, 0x37, 0x49, 0xb7, 0xd1, + 0x37, 0x74, 0xf9, 0x59, 0x49, 0xb7, 0xd2, 0xcb, 0x92, 0x8e, 0x52, 0x86, + 0x50, 0xfc, 0x6c, 0x4d, 0xf3, 0x04, 0xdb, 0x77, 0x8f, 0x6c, 0xb7, 0x4a, + 0xb7, 0x5b, 0xa5, 0xdb, 0xad, 0xd2, 0xed, 0x56, 0xe9, 0xf6, 0xaa, 0x74, + 0xfd, 0x2a, 0x5d, 0xbf, 0x4a, 0xd7, 0xaf, 0xd6, 0xf5, 0xaa, 0xb5, 0x7c, + 0xb5, 0x96, 0xaf, 0xd6, 0xf2, 0xd5, 0x5a, 0xbe, 0x5a, 0xcb, 0xaf, 0x44, + 0xd4, 0x91, 0x21, 0xf7, 0xd1, 0x1a, 0xfa, 0xa1, 0xa4, 0x1d, 0xf4, 0x23, + 0x4d, 0x7f, 0x2c, 0x69, 0x3b, 0xfd, 0x44, 0xd2, 0xb5, 0xf4, 0x53, 0x4d, + 0xff, 0x43, 0xf3, 0x7f, 0xa9, 0xe9, 0x7f, 0x4a, 0xba, 0x9a, 0x7e, 0xa5, + 0xe9, 0x6f, 0xe4, 0xbe, 0xeb, 0x97, 0xed, 0xae, 0x42, 0xff, 0xef, 0x93, + 0xb4, 0x8a, 0x3e, 0x26, 0xa9, 0x4b, 0xde, 0xf5, 0xf8, 0x6c, 0xfc, 0x8c, + 0xa4, 0x88, 0xa6, 0x84, 0xda, 0x6f, 0x19, 0x72, 0xdf, 0xa9, 0xf1, 0xd6, + 0xc0, 0x52, 0xfe, 0x4e, 0xd2, 0x12, 0xba, 0x4f, 0xd2, 0x1a, 0x7a, 0x58, + 0x52, 0xb5, 0x7e, 0x35, 0xb0, 0x9b, 0x27, 0x24, 0xbd, 0x92, 0x9e, 0x92, + 0x74, 0x17, 0x7d, 0x5e, 0xd3, 0x7f, 0x90, 0xb4, 0x90, 0x9e, 0x96, 0x74, + 0x25, 0xfd, 0xb3, 0xa4, 0xa5, 0xf4, 0x8c, 0xa4, 0xeb, 0xe9, 0x67, 0x92, + 0xae, 0xa3, 0x17, 0x34, 0xfd, 0xb9, 0xe6, 0xbf, 0x28, 0x69, 0x37, 0xfd, + 0x42, 0xfb, 0x85, 0xdf, 0x4b, 0x5a, 0x44, 0xe7, 0x24, 0x5d, 0x46, 0x7f, + 0x90, 0x74, 0x07, 0xfd, 0x51, 0xd2, 0x56, 0xfa, 0x5f, 0xed, 0x47, 0xfe, + 0x22, 0xe9, 0x26, 0x2a, 0x10, 0xec, 0x1f, 0x9a, 0xe5, 0x38, 0x6a, 0x11, + 0x91, 0x9d, 0xd6, 0xfe, 0xe2, 0x2b, 0xd2, 0x4f, 0x34, 0x60, 0x47, 0x2a, + 0x9a, 0xa1, 0xe9, 0x6d, 0x92, 0x2e, 0xa5, 0x47, 0x24, 0x5d, 0x4e, 0x8f, + 0x4a, 0x6a, 0xd2, 0xa7, 0x74, 0xf9, 0x97, 0x89, 0x63, 0x82, 0x46, 0x29, + 0xdf, 0xa6, 0xdb, 0x69, 0xc3, 0xca, 0xf9, 0x04, 0xd3, 0x32, 0x2a, 0x12, + 0x1c, 0x03, 0xa8, 0xf6, 0x56, 0xeb, 0x79, 0x5b, 0x8d, 0x28, 0xe4, 0x13, + 0xc4, 0x67, 0xbd, 0xea, 0xbf, 0x1d, 0xf3, 0xff, 0x35, 0xe2, 0x58, 0x74, + 0x50, 0xca, 0x75, 0x60, 0x67, 0xf0, 0x3e, 0x59, 0xab, 0xeb, 0xad, 0x85, + 0xdc, 0x3b, 0x74, 0xfe, 0x0e, 0x9d, 0x3f, 0x25, 0x69, 0x2d, 0x7d, 0x53, + 0xe7, 0xff, 0x4c, 0x2a, 0x5e, 0x70, 0x0b, 0xa6, 0x3b, 0xc9, 0x2b, 0x38, + 0xa6, 0xad, 0xa3, 0x63, 0xc4, 0x71, 0xad, 0x6a, 0xa7, 0x53, 0xd7, 0xef, + 0x84, 0xfc, 0xdd, 0x92, 0xfa, 0x65, 0x3f, 0x9d, 0x88, 0x98, 0xbf, 0x2d, + 0x69, 0x05, 0xfd, 0x7f, 0xcd, 0xe7, 0xf6, 0xd6, 0xe9, 0x7a, 0xeb, 0x74, + 0xff, 0xeb, 0x74, 0x3f, 0xeb, 0x74, 0x3f, 0xeb, 0x74, 0x3f, 0xeb, 0xa1, + 0xff, 0x73, 0xc4, 0xb4, 0x9c, 0x7e, 0x40, 0x1c, 0x9f, 0x28, 0xbd, 0xba, + 0x35, 0xdd, 0xa0, 0xdb, 0xd9, 0x80, 0xe8, 0xd8, 0x10, 0x1c, 0x4f, 0xab, + 0xfc, 0x46, 0x6d, 0x77, 0x1c, 0xb3, 0x09, 0x6e, 0x93, 0xd4, 0xbf, 0x62, + 0xe0, 0x1a, 0x04, 0xd5, 0x5f, 0xc2, 0x21, 0x77, 0x6a, 0x48, 0xc5, 0x6b, + 0x22, 0x23, 0x1d, 0x6f, 0x71, 0xf9, 0x8d, 0x28, 0x3f, 0xaf, 0x0f, 0xc1, + 0x95, 0x9a, 0xef, 0xb4, 0x95, 0x9f, 0x40, 0x79, 0xe1, 0xa0, 0xca, 0xaf, + 0xd2, 0xfc, 0x8d, 0xb6, 0xf2, 0xd3, 0x28, 0x1f, 0xd1, 0xe5, 0x35, 0xba, + 0xff, 0xa5, 0x40, 0x4f, 0xa3, 0x2a, 0x7f, 0x0c, 0xe5, 0x71, 0x5d, 0x5e, + 0xab, 0xeb, 0xd9, 0xfb, 0x7f, 0x0d, 0xe5, 0x2f, 0xeb, 0xf2, 0x3a, 0x5d, + 0xdf, 0x5e, 0x9e, 0x83, 0x0b, 0x81, 0xa9, 0x0f, 0xe3, 0x4a, 0x5d, 0xce, + 0x67, 0xf2, 0x66, 0xdd, 0x7e, 0x29, 0xca, 0x9b, 0x75, 0x79, 0x95, 0xad, + 0xbe, 0x55, 0xbe, 0x06, 0xe5, 0xd7, 0xeb, 0x72, 0x07, 0xfc, 0x24, 0xc7, + 0xeb, 0xf7, 0xd5, 0xa9, 0x58, 0x37, 0xe0, 0x71, 0xd0, 0x01, 0xcf, 0x71, + 0xee, 0x85, 0x22, 0x7e, 0x03, 0xbc, 0x1c, 0x63, 0x9d, 0x91, 0x4d, 0x25, + 0x46, 0x21, 0xfa, 0xf8, 0x10, 0x1d, 0xf0, 0xaf, 0x86, 0xbc, 0xcf, 0xc8, + 0x37, 0x94, 0xe4, 0x31, 0x2d, 0xf9, 0x76, 0x48, 0xba, 0xc1, 0xb5, 0xda, + 0xfb, 0x58, 0x9d, 0x8a, 0xdf, 0xe7, 0x4b, 0xcd, 0x6a, 0xa9, 0x74, 0xbf, + 0x9f, 0xaa, 0x53, 0x31, 0xfc, 0x62, 0xfd, 0x46, 0x3c, 0x4e, 0xc8, 0xe4, + 0x18, 0x5e, 0x29, 0x2f, 0xa4, 0xfc, 0x67, 0x2c, 0x79, 0xbf, 0x93, 0x22, + 0x9e, 0x8f, 0x4a, 0x6b, 0xa9, 0xf2, 0x0e, 0xa1, 0xce, 0xc7, 0x70, 0x52, + 0xe5, 0xc0, 0x4a, 0x86, 0x70, 0x52, 0xa9, 0xf6, 0x79, 0xdc, 0x9f, 0xaf, + 0xe3, 0xb3, 0x10, 0xf1, 0x9b, 0x27, 0x0f, 0xf9, 0x4a, 0xd8, 0x55, 0xcc, + 0xc3, 0x7e, 0x64, 0x02, 0x6d, 0x4f, 0xf8, 0x1c, 0xf2, 0x2e, 0x61, 0xca, + 0x53, 0x9b, 0xe8, 0xcb, 0x75, 0x6a, 0x9d, 0xe2, 0x9e, 0x4f, 0x20, 0x9f, + 0xe3, 0x88, 0x7b, 0x3e, 0x0e, 0xea, 0x86, 0xcd, 0xe6, 0x82, 0xf7, 0x18, + 0xf3, 0xd0, 0x7e, 0x2e, 0xf9, 0xbc, 0x91, 0xd6, 0xf5, 0x38, 0xdf, 0x6a, + 0xcf, 0xe5, 0xe9, 0x51, 0xa8, 0x7f, 0xdc, 0x5f, 0x9e, 0xb4, 0x15, 0x87, + 0xe4, 0x7e, 0xab, 0x4e, 0xed, 0x1b, 0x9f, 0x67, 0xb5, 0xc3, 0x49, 0x3e, + 0x7f, 0xbb, 0xc3, 0x0b, 0x9d, 0x7d, 0xe8, 0x2f, 0x07, 0x6d, 0x66, 0x53, + 0xa0, 0x82, 0xc7, 0x60, 0xea, 0x31, 0x3f, 0x82, 0xfa, 0xbe, 0x9e, 0x76, + 0x47, 0x39, 0x95, 0x38, 0x78, 0xae, 0xc3, 0x72, 0xae, 0x1d, 0x56, 0x0d, + 0x47, 0xa7, 0xc3, 0x47, 0x81, 0x6a, 0x55, 0xc3, 0x21, 0x6b, 0x3c, 0x0a, + 0xbe, 0xce, 0x39, 0x22, 0xfe, 0x0d, 0x58, 0xe3, 0x3c, 0xc4, 0x0b, 0x86, + 0xbc, 0x4f, 0xfd, 0xb4, 0x4e, 0xdd, 0xff, 0x02, 0xd7, 0xa5, 0xe7, 0xb5, + 0x44, 0x14, 0x62, 0xfc, 0x99, 0x54, 0xe2, 0xca, 0x91, 0x6d, 0x1f, 0x80, + 0x7c, 0x44, 0x5e, 0x9a, 0x72, 0x34, 0x3f, 0x3b, 0xc5, 0xef, 0x74, 0x5d, + 0x46, 0x95, 0xc8, 0xc7, 0x3c, 0xf9, 0xf0, 0xd8, 0x25, 0xc2, 0x44, 0x2b, + 0x6d, 0xd0, 0x30, 0x47, 0x44, 0xfc, 0x5e, 0xf8, 0xc4, 0x4a, 0x91, 0x87, + 0xb2, 0x02, 0xd6, 0xd9, 0x17, 0xf1, 0x2f, 0xc1, 0x3e, 0xcb, 0x71, 0xf8, + 0xcc, 0x88, 0x7f, 0x29, 0xfc, 0x3e, 0x52, 0x2b, 0x39, 0x35, 0x4e, 0x55, + 0x95, 0x7d, 0xe8, 0xc1, 0x83, 0x16, 0x72, 0x5c, 0x5b, 0x5d, 0x86, 0x79, + 0xc0, 0xf3, 0x61, 0x5e, 0x51, 0x57, 0xc4, 0x53, 0xa8, 0xda, 0xea, 0xc9, + 0xa1, 0x58, 0xb0, 0x16, 0xf5, 0x72, 0xe9, 0x3a, 0x39, 0x77, 0x96, 0x5d, + 0xfc, 0xbe, 0x4e, 0xed, 0xd9, 0xf9, 0xf6, 0x73, 0x04, 0x76, 0x91, 0xa7, + 0x57, 0x56, 0xfd, 0x33, 0xe4, 0xfc, 0xe6, 0xa7, 0xec, 0xe3, 0x7f, 0xea, + 0xd4, 0x1d, 0x32, 0xe0, 0x77, 0x63, 0x7e, 0xb3, 0x51, 0x27, 0x21, 0xed, + 0x82, 0x6d, 0x22, 0x03, 0xff, 0xb9, 0xe6, 0xab, 0xda, 0x86, 0x62, 0x1e, + 0xbe, 0xb9, 0x4f, 0x08, 0x37, 0x4d, 0x18, 0x2e, 0x9a, 0x70, 0x64, 0xd3, + 0x6e, 0x33, 0x0b, 0xde, 0xf5, 0x1a, 0x91, 0xa9, 0x75, 0x11, 0xb2, 0xaf, + 0xcc, 0x7a, 0x15, 0x0b, 0x07, 0xfc, 0x2e, 0x69, 0x0b, 0x11, 0x0f, 0xdf, + 0xfe, 0x6b, 0x33, 0x4b, 0x70, 0xc6, 0x94, 0x08, 0xaf, 0x9c, 0x33, 0x8f, + 0xec, 0xb1, 0x13, 0x23, 0x55, 0xbd, 0xde, 0x0c, 0x8e, 0x8f, 0x26, 0xc0, + 0x9b, 0x40, 0xad, 0x3c, 0xb9, 0x26, 0xdc, 0x9e, 0x10, 0x2d, 0x08, 0xbb, + 0x84, 0xd4, 0xa3, 0x00, 0xed, 0xba, 0x40, 0x23, 0x1e, 0x8e, 0xe2, 0xa3, + 0x9e, 0x93, 0xda, 0x7e, 0x84, 0x6d, 0x7c, 0x96, 0x4d, 0xe5, 0x41, 0xf7, + 0x4c, 0xd0, 0x65, 0xf5, 0xca, 0x9e, 0x37, 0x64, 0xe7, 0xd0, 0xf8, 0x2d, + 0x59, 0xe4, 0x3a, 0xe2, 0x7a, 0xbf, 0x78, 0x50, 0x7c, 0xc6, 0xfc, 0xf2, + 0xc1, 0xcc, 0x3e, 0x2d, 0x6b, 0xa6, 0x6e, 0xd7, 0xe9, 0xfa, 0xd6, 0xfc, + 0x54, 0xd6, 0xab, 0x98, 0x4c, 0x69, 0xeb, 0xd1, 0x63, 0xca, 0xa1, 0x9d, + 0x15, 0x99, 0xb4, 0x0e, 0xe3, 0x8e, 0xe0, 0x82, 0xe5, 0xc7, 0x8c, 0x5e, + 0xe3, 0xcf, 0x9c, 0x57, 0xaf, 0xee, 0x0d, 0xea, 0x75, 0xca, 0x7a, 0xcd, + 0x5c, 0x8f, 0xac, 0x7a, 0x17, 0xad, 0x11, 0xa5, 0xd7, 0xa8, 0xb5, 0xde, + 0x5a, 0xa3, 0x5c, 0xcc, 0x56, 0xde, 0xbc, 0x35, 0x62, 0xdd, 0xb9, 0x66, + 0x47, 0xbd, 0x5a, 0xff, 0x98, 0xe7, 0xbd, 0x72, 0x8d, 0x72, 0xb1, 0x46, + 0x39, 0x58, 0xa3, 0x3c, 0xb4, 0x6e, 0xad, 0x4b, 0x4f, 0x6a, 0x5d, 0x72, + 0xf4, 0xba, 0x54, 0x2f, 0xba, 0x2e, 0xb9, 0x7a, 0x5d, 0xf2, 0x6c, 0xeb, + 0x82, 0xf6, 0x50, 0x6b, 0xf1, 0x75, 0x19, 0x49, 0xad, 0xcb, 0x96, 0x79, + 0xeb, 0xe2, 0xd4, 0xda, 0x5d, 0x51, 0xaf, 0x9e, 0x35, 0x04, 0x3c, 0xba, + 0xdf, 0x9e, 0x95, 0xe4, 0xef, 0x47, 0xbf, 0xec, 0x23, 0x1d, 0x4e, 0xc1, + 0xfd, 0xae, 0x5e, 0xa4, 0xed, 0x85, 0x6b, 0xb2, 0x18, 0xcf, 0x21, 0x6b, + 0x60, 0xc4, 0xf5, 0x24, 0xd7, 0x7b, 0x42, 0x78, 0x30, 0x07, 0x3c, 0x13, + 0x13, 0x46, 0xbe, 0x1c, 0xbb, 0xe3, 0xa2, 0x3a, 0x8b, 0xad, 0xf7, 0xeb, + 0xf1, 0x78, 0xfe, 0xa7, 0xea, 0x49, 0xce, 0xb5, 0xaf, 0xb2, 0xbd, 0x2a, + 0x5f, 0xee, 0xdf, 0x2c, 0xec, 0xdf, 0x00, 0xda, 0x8f, 0x78, 0x32, 0xf5, + 0x1e, 0xbf, 0x09, 0xb3, 0xf4, 0xd7, 0xb6, 0xfd, 0x66, 0x78, 0x8b, 0xe9, + 0xbf, 0x18, 0xcf, 0xb2, 0x9f, 0xd9, 0x7a, 0xf5, 0xdc, 0x28, 0xe0, 0xf1, + 0x4a, 0x9d, 0x9d, 0x72, 0xd6, 0x1c, 0x14, 0xaf, 0x57, 0x67, 0x6f, 0x29, + 0x3e, 0x57, 0x60, 0xcf, 0x4e, 0xf4, 0x16, 0x60, 0xa5, 0x9e, 0x44, 0x8f, + 0x6e, 0x23, 0xd0, 0xef, 0xa5, 0x4e, 0x07, 0xfc, 0x85, 0xc7, 0x05, 0x49, + 0xce, 0x45, 0x3c, 0x19, 0x48, 0x4d, 0xf4, 0x7a, 0x91, 0xf3, 0xa1, 0xcc, + 0x05, 0xce, 0x32, 0xc9, 0xf1, 0xc1, 0x82, 0xf2, 0x8d, 0x5c, 0x51, 0x46, + 0x35, 0x82, 0xb5, 0x5d, 0x8a, 0xd6, 0x4b, 0xb5, 0x4e, 0xfc, 0xbc, 0x25, + 0x43, 0xda, 0x5a, 0xd5, 0xcd, 0x2d, 0xe5, 0x55, 0x52, 0x27, 0xd6, 0xea, + 0xd6, 0x7a, 0xeb, 0x6c, 0xf3, 0xa1, 0x1d, 0x3e, 0x79, 0xb9, 0x2f, 0x3f, + 0xb1, 0xc5, 0xe6, 0x6b, 0x1d, 0xd9, 0x8b, 0x1d, 0xad, 0x57, 0xcf, 0x08, + 0x95, 0x8e, 0x01, 0xf4, 0xd5, 0x29, 0x2a, 0x64, 0x0d, 0x39, 0xc7, 0x9e, + 0x2a, 0x50, 0xb7, 0xe1, 0x6b, 0x6f, 0x5f, 0xbd, 0x14, 0xdc, 0x4a, 0xc9, + 0x2d, 0x31, 0xde, 0x0d, 0x2b, 0x6d, 0x65, 0x7f, 0x2a, 0xca, 0x85, 0x43, + 0xed, 0x2d, 0x8f, 0x29, 0xcb, 0xca, 0x10, 0x11, 0x95, 0xc9, 0x93, 0xde, + 0x4b, 0x4a, 0x63, 0x35, 0x37, 0xd5, 0x28, 0x6d, 0xd0, 0xf6, 0x24, 0x10, + 0x6f, 0x39, 0xa5, 0x06, 0x44, 0x77, 0xd4, 0xab, 0xe7, 0x66, 0x13, 0xf0, + 0xfb, 0x31, 0xcf, 0x13, 0xd2, 0x86, 0x0a, 0xb0, 0x87, 0x60, 0xff, 0xa6, + 0x57, 0xda, 0xa7, 0xda, 0x47, 0x1f, 0xd6, 0x7b, 0x5b, 0xeb, 0xd9, 0x56, + 0x80, 0x5e, 0xb3, 0x28, 0xb0, 0x1a, 0xfa, 0x1a, 0x38, 0x6f, 0xfc, 0x37, + 0x40, 0x9b, 0x32, 0xbe, 0x41, 0xda, 0xfa, 0xcc, 0x97, 0x7d, 0xb1, 0x67, + 0x57, 0xbd, 0x3e, 0x5c, 0xaf, 0x9e, 0x2f, 0x95, 0x22, 0xe2, 0x41, 0x1b, + 0xc1, 0x65, 0xd0, 0xfa, 0x34, 0x8f, 0x0f, 0xa7, 0xf3, 0x00, 0xe2, 0x85, + 0xc0, 0x24, 0x73, 0xee, 0xb5, 0x9f, 0xab, 0x66, 0xa7, 0xb9, 0xd4, 0x3a, + 0x57, 0xcd, 0x72, 0xd3, 0x4f, 0x67, 0x9c, 0x86, 0x08, 0x0c, 0x08, 0x2a, + 0x37, 0xbd, 0x72, 0x96, 0x70, 0xea, 0x99, 0x5b, 0x4d, 0x61, 0x88, 0xb1, + 0xda, 0x5f, 0xf1, 0xd8, 0xb9, 0xff, 0x5a, 0xa3, 0x46, 0xd4, 0x5e, 0x50, + 0x3a, 0x34, 0xc9, 0x9e, 0x9b, 0xa1, 0x83, 0x3a, 0x33, 0x9e, 0xac, 0x57, + 0xcf, 0xac, 0x02, 0x3b, 0x54, 0x5f, 0x3c, 0x7a, 0xee, 0x8b, 0x63, 0x84, + 0x4e, 0xd1, 0x2a, 0xfb, 0x22, 0x39, 0xaf, 0x7e, 0x0a, 0x20, 0x88, 0x2e, + 0x37, 0x54, 0x3f, 0x86, 0x8c, 0x35, 0x78, 0x7d, 0xdd, 0x0e, 0xdf, 0x9a, + 0xf6, 0xfe, 0x5f, 0x5d, 0xe0, 0xd5, 0x60, 0x6e, 0x89, 0x43, 0xad, 0xc6, + 0x6a, 0xa4, 0xcb, 0x11, 0xdb, 0x74, 0x1a, 0x3f, 0xbc, 0xc0, 0xab, 0x21, + 0x6b, 0xf8, 0xef, 0xa0, 0x3d, 0x58, 0xbf, 0x4e, 0xe3, 0x5b, 0x17, 0xbc, + 0xc2, 0x97, 0xe1, 0xcd, 0xc8, 0xd0, 0x16, 0xf2, 0xcf, 0xa9, 0x75, 0x97, + 0x73, 0xd1, 0xab, 0xb4, 0xe1, 0x15, 0x64, 0x6d, 0x84, 0xac, 0x53, 0x2c, + 0xb5, 0x11, 0xb2, 0x5d, 0x68, 0x53, 0x05, 0x6d, 0x1c, 0x4a, 0x1b, 0x79, + 0x9a, 0xc3, 0x9a, 0x30, 0x43, 0x8e, 0xf6, 0xf1, 0x97, 0x2e, 0x60, 0xe4, + 0x46, 0x19, 0xf9, 0x9c, 0x5e, 0x67, 0xae, 0x53, 0x8e, 0xdf, 0x69, 0x8d, + 0xbf, 0x46, 0xf6, 0x56, 0x4b, 0x19, 0xf2, 0xcc, 0x17, 0xf4, 0xd5, 0x7a, + 0xf5, 0xbc, 0x86, 0x35, 0x74, 0x4a, 0x9b, 0x7c, 0xbf, 0x1c, 0xbb, 0xcf, + 0xe8, 0x84, 0x25, 0xe5, 0x1b, 0xa5, 0x02, 0xfa, 0x08, 0x8e, 0xc2, 0x4c, + 0x19, 0xd5, 0x98, 0x54, 0x26, 0x10, 0xc7, 0xf5, 0x2c, 0xb5, 0x6a, 0x18, + 0x3e, 0x47, 0xa4, 0xf5, 0x41, 0xf2, 0x3b, 0x02, 0x3d, 0x4b, 0xc0, 0x2b, + 0x92, 0x33, 0x58, 0x69, 0xac, 0xa4, 0x58, 0xeb, 0x95, 0xd4, 0x67, 0xfa, + 0x0a, 0x22, 0x3d, 0x0e, 0x72, 0x56, 0xe5, 0x48, 0xcf, 0x1f, 0xe8, 0x4b, + 0xd5, 0x73, 0x72, 0xad, 0x31, 0xe2, 0x73, 0xfc, 0x26, 0xdc, 0xcb, 0xd0, + 0xaa, 0x03, 0xba, 0x8a, 0x1a, 0xa7, 0x3a, 0x67, 0x3b, 0xa4, 0x9e, 0x7d, + 0xd2, 0x7f, 0x72, 0x1c, 0xfd, 0xe3, 0x7a, 0x92, 0x31, 0xba, 0xcf, 0x13, + 0xdb, 0x71, 0x23, 0x55, 0xf4, 0x73, 0x84, 0xc7, 0x91, 0x1e, 0x97, 0xbd, + 0xa8, 0xfd, 0x1e, 0xc7, 0x61, 0x3e, 0x23, 0x36, 0x76, 0x23, 0xf5, 0x7b, + 0x72, 0x4c, 0xaf, 0xc9, 0xcf, 0x33, 0x78, 0x2f, 0xbe, 0x84, 0xf2, 0xb7, + 0xa4, 0xe6, 0xb6, 0x33, 0xc7, 0x44, 0x34, 0x56, 0x6b, 0xf8, 0x2a, 0x22, + 0xad, 0x49, 0x2a, 0xce, 0xca, 0xc9, 0xf2, 0x89, 0xce, 0xac, 0x11, 0x0a, + 0xdc, 0x5a, 0x82, 0x75, 0xfb, 0x08, 0x6e, 0x24, 0x3c, 0xd7, 0x18, 0x27, + 0xac, 0x67, 0xec, 0x8e, 0x52, 0x8a, 0xf9, 0xe3, 0x98, 0xaf, 0x1c, 0xf0, + 0xd6, 0x51, 0xa0, 0x52, 0x59, 0x40, 0xa7, 0xd1, 0x8e, 0x76, 0x0a, 0x69, + 0xec, 0x74, 0x19, 0xea, 0x94, 0xd2, 0x97, 0x60, 0x75, 0x9d, 0x66, 0x09, + 0x55, 0xe6, 0x54, 0x92, 0xeb, 0x4b, 0xae, 0xdb, 0x5c, 0x77, 0x99, 0x0f, + 0x1f, 0xcc, 0xd8, 0x08, 0xfd, 0x6a, 0x3d, 0x63, 0xf7, 0xb2, 0xcc, 0x72, + 0xba, 0x9f, 0x72, 0xdc, 0x9d, 0xee, 0x4c, 0xc8, 0x54, 0x51, 0xac, 0x67, + 0x98, 0x4e, 0xdc, 0x5b, 0x6b, 0xb8, 0x4a, 0x3b, 0x73, 0xf2, 0x28, 0xf0, + 0x4e, 0xd4, 0xcc, 0xee, 0x40, 0x4f, 0x77, 0xe2, 0xde, 0xc5, 0xf3, 0x72, + 0x6f, 0x36, 0x7a, 0xcf, 0x91, 0xf6, 0x9b, 0x85, 0xfd, 0x93, 0xa5, 0xc6, + 0x17, 0x90, 0x73, 0xb2, 0x9b, 0x9c, 0xda, 0x76, 0x5f, 0xab, 0x57, 0xef, + 0x15, 0x02, 0xad, 0xcb, 0x31, 0xab, 0x0f, 0x68, 0xdb, 0xfd, 0xe4, 0x02, + 0x1b, 0x5e, 0x6e, 0xb3, 0xe1, 0x36, 0xec, 0x50, 0xc8, 0xfa, 0xef, 0x87, + 0xa7, 0xe6, 0xfc, 0x2a, 0xd4, 0x9b, 0x92, 0x16, 0xc5, 0x96, 0xd9, 0x27, + 0x47, 0x7e, 0x96, 0x2d, 0x13, 0xb3, 0x97, 0x8e, 0x49, 0x33, 0x1a, 0xd4, + 0x73, 0xea, 0x88, 0x7f, 0x86, 0xad, 0xda, 0xb1, 0x60, 0x4f, 0x62, 0x65, + 0xf3, 0x6d, 0xb1, 0x6e, 0x2d, 0xda, 0xbc, 0x4d, 0xf6, 0xdd, 0xde, 0x7b, + 0xee, 0x82, 0x97, 0x7c, 0x0e, 0xaf, 0x83, 0xb4, 0xce, 0xd8, 0xfd, 0x0d, + 0x4a, 0x67, 0xb5, 0x16, 0x6c, 0x6d, 0xb0, 0x2b, 0xb1, 0x0e, 0xbb, 0x34, + 0xe6, 0xbf, 0x9e, 0xe3, 0x40, 0x68, 0x8c, 0xb8, 0xb7, 0x10, 0x1e, 0xd6, + 0x0c, 0xb4, 0x2d, 0x95, 0x2b, 0xd2, 0xcb, 0xf6, 0x58, 0xd9, 0x29, 0x4c, + 0xe9, 0x77, 0x63, 0xfe, 0xfd, 0x2c, 0x87, 0xf9, 0x56, 0x79, 0xd8, 0xb9, + 0x99, 0x6f, 0xe6, 0x9a, 0x98, 0x27, 0x73, 0xbe, 0x8d, 0xe7, 0xcb, 0x3e, + 0x0d, 0x2a, 0x6b, 0x50, 0xef, 0x33, 0x76, 0xbe, 0xb0, 0x42, 0x5a, 0xb0, + 0xcf, 0x83, 0xd5, 0xf7, 0x2b, 0xcb, 0x0e, 0x7c, 0xb7, 0x88, 0x2a, 0xaa, + 0x7c, 0xa6, 0xcf, 0xd9, 0xd1, 0xd1, 0x47, 0x43, 0x19, 0x86, 0x93, 0xf7, + 0x51, 0x06, 0xb9, 0x5d, 0x63, 0x2f, 0x95, 0x52, 0xfb, 0xd1, 0x0e, 0xe8, + 0x58, 0x81, 0x7c, 0x8e, 0xab, 0xe2, 0x90, 0x2f, 0xab, 0xe3, 0x78, 0x13, + 0x0d, 0xb9, 0x5d, 0x59, 0x11, 0x4f, 0x39, 0xc6, 0xed, 0xce, 0x6e, 0xcf, + 0xae, 0x44, 0x79, 0x99, 0x4c, 0x8f, 0xbd, 0x52, 0x46, 0xed, 0x5f, 0x83, + 0x0d, 0x79, 0x56, 0x20, 0x9f, 0x93, 0xc7, 0x63, 0xcb, 0x93, 0xb3, 0x93, + 0x27, 0x3d, 0x35, 0xda, 0xc8, 0x2b, 0xa1, 0xef, 0x4b, 0xdf, 0x90, 0x87, + 0x74, 0x79, 0x5e, 0x3b, 0xac, 0xde, 0x9b, 0x77, 0x26, 0x2b, 0x4b, 0xd4, + 0x3e, 0x7f, 0xc6, 0xe9, 0x14, 0xb5, 0x5f, 0x28, 0x13, 0x25, 0x38, 0xc8, + 0xbc, 0x79, 0xb9, 0x79, 0x65, 0x02, 0xbb, 0x36, 0xaf, 0xf6, 0x02, 0x9f, + 0xe2, 0x9b, 0x31, 0x9a, 0x5d, 0x29, 0x5f, 0xbd, 0x53, 0xcf, 0xa5, 0x41, + 0xad, 0x0d, 0xea, 0x3d, 0x8f, 0x9a, 0xcb, 0x98, 0x27, 0xc2, 0x2b, 0x20, + 0x26, 0xda, 0x8a, 0x30, 0x2f, 0x95, 0xb8, 0x45, 0xc4, 0x3c, 0xa7, 0xf4, + 0xaa, 0xf1, 0x7c, 0xf1, 0xaa, 0xb1, 0x77, 0xe4, 0x55, 0x33, 0x6d, 0x96, + 0x61, 0x4a, 0x4b, 0xa8, 0x95, 0x11, 0x55, 0x81, 0xb4, 0x84, 0xbb, 0x11, + 0x95, 0xf1, 0x1a, 0xb2, 0x27, 0x3e, 0xe0, 0x79, 0xb7, 0x3e, 0xdd, 0xef, + 0x86, 0xe7, 0xae, 0x7d, 0x91, 0x3d, 0x34, 0xd6, 0xd6, 0xac, 0x1a, 0xe0, + 0xfb, 0xd3, 0x87, 0xa8, 0x47, 0xfa, 0x61, 0xdc, 0x9f, 0xe4, 0x0a, 0x40, + 0x67, 0xb3, 0xf6, 0x02, 0xaf, 0x01, 0xfb, 0xf8, 0x81, 0x94, 0xce, 0xfd, + 0x72, 0xed, 0xd9, 0x96, 0xfa, 0x1b, 0x52, 0xfb, 0xd8, 0x1f, 0xe5, 0x96, + 0x71, 0x2e, 0x59, 0x65, 0x9b, 0xad, 0x32, 0x7f, 0xba, 0x2c, 0x5f, 0xdf, + 0x4d, 0xb6, 0x36, 0xa8, 0x77, 0x0e, 0xe9, 0x71, 0x05, 0xbe, 0x83, 0x95, + 0xf3, 0xf9, 0x70, 0x83, 0xe8, 0xa8, 0x6e, 0xa1, 0x21, 0xa7, 0x30, 0x79, + 0xa5, 0xe0, 0x59, 0x32, 0x2a, 0xf6, 0xf9, 0x32, 0x3b, 0x0e, 0x55, 0xd2, + 0x50, 0x56, 0x46, 0x26, 0xaf, 0x54, 0x16, 0xb9, 0xdd, 0xed, 0x2f, 0xe3, + 0xfe, 0xe1, 0xae, 0x95, 0x67, 0xae, 0x13, 0xab, 0xe5, 0x2b, 0x6d, 0xff, + 0xa6, 0x03, 0xfa, 0xfa, 0x72, 0x78, 0xfd, 0x20, 0x91, 0x15, 0xeb, 0xb9, + 0x85, 0xfe, 0xe1, 0x34, 0x8f, 0xf3, 0x3e, 0x3a, 0x93, 0x99, 0x29, 0x6a, + 0x7f, 0x76, 0xc6, 0x34, 0x45, 0xed, 0x77, 0xbd, 0x72, 0xbe, 0x79, 0x4c, + 0x57, 0x37, 0xa8, 0xf7, 0x68, 0x31, 0xcf, 0x2a, 0xe4, 0x2b, 0xb1, 0xb2, + 0x31, 0x0f, 0x3f, 0x6f, 0x9a, 0x68, 0x5d, 0x3a, 0x2f, 0xb7, 0xdc, 0xa6, + 0xe5, 0x44, 0xeb, 0xb2, 0x79, 0x65, 0x25, 0x34, 0xb1, 0x66, 0x09, 0xce, + 0xe3, 0xef, 0x62, 0xf6, 0x8a, 0xe5, 0x7a, 0x94, 0x9b, 0xc5, 0xe0, 0x15, + 0xd3, 0x3a, 0xd3, 0x4d, 0x25, 0x26, 0xdf, 0xe2, 0x42, 0x32, 0x0a, 0x35, + 0xa5, 0xdd, 0xd4, 0x48, 0x99, 0x8a, 0x1e, 0x9f, 0xe8, 0xc0, 0x9d, 0x63, + 0xc8, 0x30, 0xb1, 0x12, 0x73, 0xb8, 0xa1, 0x9f, 0x11, 0x42, 0xd4, 0xfe, + 0x6f, 0x00, 0xf5, 0x10, 0x4f, 0x20, 0x38, 0x5e, 0x03, 0x69, 0x2b, 0x86, + 0x88, 0x41, 0x4f, 0x7e, 0x9e, 0x12, 0xe8, 0x29, 0x46, 0x2f, 0x0d, 0x58, + 0x23, 0xeb, 0x54, 0x61, 0xef, 0x7b, 0x1f, 0xa4, 0x02, 0xbd, 0xca, 0x63, + 0xa8, 0xf3, 0xe5, 0x93, 0x0b, 0xce, 0x99, 0x42, 0xdb, 0x39, 0x03, 0x8f, + 0xd1, 0xaf, 0x3c, 0x46, 0x95, 0xcc, 0xb3, 0xc7, 0x98, 0x64, 0xbf, 0xf6, + 0x6b, 0x8e, 0x9f, 0x96, 0xc3, 0xd2, 0x02, 0x3d, 0x25, 0xaf, 0xe7, 0x7d, + 0xd0, 0x56, 0x89, 0xe5, 0x7d, 0x50, 0xb7, 0x16, 0x6d, 0x95, 0xd8, 0xda, + 0xe2, 0xbd, 0x75, 0x97, 0x3c, 0x17, 0xcb, 0x8d, 0x6a, 0xc8, 0x5d, 0xc1, + 0xed, 0xfe, 0x62, 0xa2, 0xb7, 0x04, 0x6d, 0x2e, 0x76, 0x1a, 0x57, 0x2e, + 0x38, 0x8d, 0x0d, 0xf8, 0x61, 0x8f, 0xa4, 0xe5, 0x86, 0x29, 0x23, 0x37, + 0xc3, 0x96, 0xe3, 0x13, 0x2e, 0xe0, 0x85, 0xbf, 0x16, 0x5e, 0x19, 0xb9, + 0xc1, 0x23, 0xfc, 0x58, 0xb5, 0xcb, 0xcf, 0x78, 0x39, 0x42, 0x37, 0x75, + 0x7c, 0x62, 0xc5, 0x07, 0xec, 0x63, 0x1b, 0x20, 0xf7, 0xfe, 0x94, 0xdd, + 0xde, 0x21, 0x4c, 0x6d, 0x7f, 0x27, 0x1b, 0xd4, 0xb9, 0xc4, 0x67, 0x3e, + 0xfb, 0x3c, 0x5f, 0x5b, 0xbb, 0x87, 0x9f, 0x04, 0x04, 0xb0, 0x8a, 0x3e, + 0xdc, 0x49, 0xeb, 0xa8, 0xd5, 0xc7, 0x31, 0x68, 0x96, 0x3c, 0x93, 0x1c, + 0x74, 0x37, 0xe4, 0x8f, 0xd9, 0xfc, 0x5c, 0x09, 0x5a, 0xe7, 0xf8, 0xcd, + 0xaf, 0xe2, 0x37, 0x58, 0x6d, 0x60, 0x6e, 0x39, 0x6e, 0xa9, 0xef, 0xe1, + 0xf1, 0x67, 0xb0, 0x97, 0x0b, 0x91, 0xdb, 0xb9, 0xce, 0x39, 0x43, 0x3a, + 0xc6, 0x73, 0xfa, 0xd6, 0xb6, 0x87, 0x36, 0xc1, 0x13, 0xa6, 0xa2, 0x3c, + 0xa7, 0x8a, 0x2b, 0xae, 0x48, 0x45, 0x79, 0x9d, 0x56, 0x94, 0xe7, 0x08, + 0xcc, 0x29, 0x4f, 0xd9, 0x81, 0x7a, 0x9d, 0x4e, 0x44, 0xac, 0x07, 0x96, + 0xca, 0x79, 0x6e, 0x93, 0xb2, 0x26, 0xa9, 0xf2, 0x87, 0x50, 0xee, 0x2a, + 0xa8, 0x2d, 0xb5, 0x62, 0x43, 0xf6, 0xb8, 0x45, 0xd2, 0xe3, 0x62, 0x1c, + 0x5e, 0xcc, 0x1b, 0x24, 0x55, 0xec, 0xc8, 0xbb, 0x97, 0x67, 0x50, 0xc8, + 0x99, 0xcb, 0x94, 0x91, 0x5c, 0x25, 0x4e, 0x8b, 0xd8, 0xf8, 0x1e, 0x3a, + 0x70, 0x34, 0x70, 0x28, 0xa5, 0xb9, 0xc1, 0xa7, 0x55, 0xad, 0xa8, 0xcc, + 0xdc, 0x00, 0x0b, 0xff, 0x14, 0x24, 0x3b, 0x4d, 0x27, 0x15, 0x18, 0xdf, + 0x76, 0xd5, 0x3a, 0x0a, 0x8c, 0x29, 0xba, 0xa5, 0x32, 0xd2, 0xf3, 0x38, + 0x15, 0xaf, 0x96, 0x91, 0x60, 0x26, 0x3c, 0x74, 0x26, 0xef, 0xa3, 0x41, + 0xb4, 0xcb, 0xb7, 0xa4, 0x65, 0x98, 0xd9, 0x49, 0x1d, 0x8b, 0x1a, 0xf4, + 0x0e, 0x71, 0x73, 0xcb, 0xe4, 0x3b, 0x84, 0x8c, 0x9f, 0x0d, 0x19, 0x4b, + 0x3f, 0xd9, 0xa0, 0xde, 0x63, 0xa5, 0xe7, 0xd0, 0x99, 0x9e, 0x43, 0x11, + 0xe8, 0x53, 0x5a, 0x08, 0xf9, 0x24, 0xe3, 0x23, 0x38, 0x99, 0xd8, 0xde, + 0x60, 0xaf, 0x7d, 0x58, 0x63, 0xff, 0x07, 0x10, 0x5b, 0xb8, 0x8d, 0x75, + 0xc6, 0x95, 0x34, 0x5f, 0xee, 0x7e, 0x1d, 0x97, 0xb1, 0x1d, 0x87, 0xe4, + 0x08, 0xd8, 0xbe, 0x75, 0xb9, 0xe0, 0x39, 0x2a, 0x90, 0xd1, 0x57, 0xa5, + 0xc3, 0x8f, 0x08, 0xa6, 0x9d, 0xc6, 0xa5, 0x3f, 0x6c, 0xa3, 0x03, 0xf2, + 0x8d, 0x52, 0x6d, 0x4b, 0x5a, 0x8b, 0xd7, 0x8b, 0xbd, 0x97, 0xeb, 0x55, + 0xb1, 0xcf, 0x72, 0xe1, 0x9b, 0x98, 0x65, 0xa7, 0x8a, 0x97, 0x11, 0xaf, + 0x71, 0x0c, 0xc4, 0xf3, 0x14, 0x41, 0xc9, 0x01, 0x7d, 0xaf, 0xe0, 0x77, + 0x81, 0x2a, 0xf6, 0x3e, 0x78, 0x73, 0x4b, 0xf2, 0x20, 0xee, 0x12, 0xea, + 0x0c, 0x78, 0xae, 0x41, 0xbd, 0x9b, 0xb7, 0xe6, 0xc8, 0xcf, 0x67, 0x91, + 0xe0, 0x98, 0x65, 0x99, 0xec, 0x73, 0x34, 0x15, 0xb5, 0x5a, 0x3b, 0xc3, + 0x57, 0xe0, 0x2b, 0x6c, 0x5f, 0xd3, 0x8e, 0x53, 0x33, 0x70, 0x97, 0xda, + 0xb9, 0x1c, 0x8d, 0xf1, 0xce, 0x55, 0xf4, 0xe3, 0xec, 0x1f, 0x33, 0x3a, + 0x33, 0x7e, 0x7f, 0x81, 0x77, 0x1b, 0xfb, 0xd3, 0xf2, 0x8c, 0x5a, 0x1a, + 0xdb, 0x57, 0x6a, 0xb5, 0x9e, 0xd9, 0x7e, 0xf4, 0x77, 0x17, 0x02, 0x77, + 0xaa, 0x9d, 0x3c, 0x25, 0x3d, 0x98, 0xda, 0xc9, 0xca, 0x9b, 0xa9, 0x9d, + 0x6c, 0x52, 0xed, 0x37, 0x3a, 0x8d, 0x4c, 0xbd, 0x2b, 0xf5, 0x6e, 0xbc, + 0x97, 0x57, 0xe6, 0x83, 0xf0, 0x70, 0x65, 0x7a, 0x3e, 0x31, 0x5e, 0xb7, + 0xdc, 0x7f, 0x6e, 0x2b, 0x3e, 0xdd, 0x89, 0x31, 0xbe, 0x25, 0xb5, 0xff, + 0xae, 0x59, 0xf4, 0x59, 0x99, 0xb5, 0x27, 0xff, 0xa3, 0x41, 0xdd, 0xb9, + 0xad, 0x3d, 0x58, 0xab, 0xf7, 0xa0, 0xf5, 0x3c, 0xe8, 0xac, 0x3e, 0x4f, + 0x02, 0x9e, 0x12, 0x69, 0xfd, 0x7e, 0xe9, 0x23, 0x0d, 0x69, 0x5d, 0x2f, + 0x37, 0xa8, 0xef, 0x36, 0xe8, 0x08, 0x04, 0x1e, 0x9a, 0x77, 0xb3, 0xf6, + 0x93, 0xb6, 0xb8, 0xa3, 0x53, 0x14, 0xe9, 0xfc, 0xfd, 0xc8, 0xab, 0xdd, + 0xb4, 0x70, 0xf5, 0x54, 0xf9, 0x43, 0x28, 0xd7, 0xb1, 0x09, 0x6a, 0xf1, + 0x2d, 0x6f, 0xaf, 0xdc, 0xeb, 0xec, 0x2f, 0x59, 0xc6, 0xb6, 0x67, 0x20, + 0x5b, 0x61, 0xc5, 0x3b, 0x88, 0x63, 0x8a, 0x69, 0xc1, 0x0d, 0x06, 0x76, + 0x78, 0x08, 0x76, 0xc8, 0x56, 0x61, 0xf2, 0xb3, 0x09, 0x3e, 0x15, 0xd0, + 0x22, 0x9f, 0x0a, 0x85, 0xca, 0x4a, 0x64, 0xb4, 0xc3, 0xb1, 0xc1, 0x00, + 0xda, 0xde, 0xa6, 0x6d, 0x84, 0xbf, 0xcb, 0x91, 0x2d, 0x6d, 0x64, 0xe2, + 0xe6, 0x96, 0xb1, 0x09, 0x39, 0x56, 0x79, 0x23, 0x6e, 0x54, 0xcf, 0xa4, + 0x7d, 0x38, 0x63, 0x10, 0xd3, 0xa3, 0xdd, 0xf7, 0xc9, 0x48, 0x81, 0x29, + 0x7a, 0x33, 0x56, 0x57, 0x30, 0xb7, 0xdc, 0xc4, 0x2a, 0xb7, 0x95, 0xd1, + 0x58, 0x1f, 0xe2, 0x98, 0x8a, 0x7c, 0xda, 0xd9, 0xb6, 0x82, 0x76, 0xf6, + 0xad, 0x40, 0x3a, 0x0b, 0xfc, 0x52, 0x1a, 0x1b, 0x40, 0x3c, 0xd4, 0xeb, + 0x90, 0x4f, 0xce, 0xac, 0xfb, 0x2a, 0x7c, 0x66, 0xa3, 0xf5, 0x1d, 0x98, + 0x36, 0x1a, 0xeb, 0x2d, 0xc5, 0xde, 0x3f, 0x42, 0xdf, 0xf5, 0x1e, 0xa1, + 0xb1, 0xfe, 0x32, 0xea, 0xa8, 0xc2, 0x09, 0xeb, 0x28, 0x70, 0xdc, 0x4c, + 0x8f, 0xb7, 0xc5, 0xfc, 0xef, 0x42, 0xfc, 0x10, 0xf1, 0x9c, 0x90, 0x37, + 0xde, 0x9d, 0xbd, 0x88, 0xc4, 0x30, 0x93, 0xbe, 0x3f, 0xe0, 0x04, 0xf6, + 0xde, 0x81, 0xa5, 0xcd, 0xa7, 0xf4, 0x73, 0x1c, 0x7e, 0x54, 0x96, 0x7e, + 0x8e, 0x73, 0xb5, 0x28, 0xa5, 0x6b, 0x8c, 0x15, 0x74, 0xb5, 0xa3, 0x2c, + 0xf5, 0x1c, 0x87, 0x68, 0xb9, 0x7e, 0x2e, 0x7d, 0x1d, 0x50, 0x80, 0xd3, + 0xa0, 0x03, 0xeb, 0x71, 0x40, 0xd6, 0xe6, 0x9b, 0x41, 0x09, 0x1d, 0x97, + 0xe7, 0xab, 0x3a, 0x5b, 0x78, 0xb5, 0xb2, 0xf5, 0x53, 0x61, 0x87, 0x3e, + 0x23, 0x2b, 0x1b, 0xd5, 0x73, 0x7c, 0x7e, 0xce, 0x89, 0x12, 0xd8, 0xcf, + 0x3a, 0xb4, 0xed, 0x15, 0xe9, 0x67, 0x9b, 0x9c, 0x2b, 0xa5, 0x3a, 0xd8, + 0xc3, 0x1e, 0x51, 0x4e, 0xeb, 0x70, 0xbb, 0xad, 0x14, 0xbc, 0x6a, 0x6b, + 0x30, 0xde, 0x30, 0x38, 0x65, 0xb4, 0xc7, 0x28, 0xc7, 0x3d, 0x2b, 0x17, + 0x11, 0x68, 0x8d, 0xe1, 0x93, 0xb5, 0x84, 0x7e, 0xb6, 0xce, 0xff, 0x2b, + 0xc8, 0xea, 0xab, 0x45, 0x7f, 0x0f, 0xc3, 0x3a, 0xf5, 0x0d, 0xd9, 0x3e, + 0x46, 0x0f, 0x7d, 0xac, 0x1e, 0xfc, 0xba, 0x87, 0x1a, 0xf4, 0x30, 0x2d, + 0x7b, 0xf0, 0xcb, 0x1e, 0xfc, 0xa9, 0x1e, 0xd4, 0x33, 0x3c, 0xee, 0x63, + 0x45, 0xaa, 0x0f, 0xeb, 0xdb, 0x28, 0xf3, 0xf7, 0x87, 0xf5, 0x4c, 0xaa, + 0xab, 0x51, 0x7d, 0x4f, 0x46, 0xcd, 0x63, 0xfa, 0x5b, 0x39, 0x16, 0xff, + 0x80, 0x7c, 0xcb, 0x9e, 0x47, 0xf7, 0x0a, 0x41, 0x79, 0xc2, 0xe3, 0x7b, + 0x0b, 0xc5, 0x90, 0xa0, 0xeb, 0xf1, 0xf1, 0x10, 0x8e, 0xa3, 0x3c, 0xba, + 0x16, 0x29, 0xe3, 0x1c, 0x75, 0x19, 0xef, 0xbb, 0xf9, 0x06, 0x7a, 0x4e, + 0x4a, 0x79, 0xf3, 0xe9, 0xef, 0x05, 0x74, 0x99, 0xde, 0x2f, 0x3c, 0x05, + 0xdd, 0x33, 0xa7, 0x68, 0x0e, 0xdc, 0x2f, 0x6f, 0x7b, 0x67, 0xe4, 0xd0, + 0xe1, 0xf0, 0xee, 0xdd, 0x13, 0x0f, 0x0d, 0x6f, 0xa7, 0x47, 0x58, 0x90, + 0x3e, 0x6a, 0xe0, 0xe3, 0x8c, 0x7c, 0x3e, 0x42, 0x79, 0xdd, 0x4d, 0x4d, + 0x4d, 0xdd, 0x74, 0x3b, 0x58, 0xdb, 0x8e, 0x5f, 0x3e, 0x72, 0x7d, 0x13, + 0xfd, 0x02, 0x22, 0xdd, 0x74, 0xaf, 0x61, 0x2a, 0xf3, 0x3c, 0x87, 0xec, + 0xb3, 0x23, 0xf4, 0xaa, 0x26, 0x5c, 0xf5, 0xb3, 0x86, 0x43, 0xd7, 0xa4, + 0x5f, 0xa6, 0xeb, 0x7d, 0xc1, 0xe0, 0x7a, 0xdf, 0x57, 0x65, 0xdb, 0x8e, + 0xd3, 0xc7, 0x1d, 0xd0, 0x25, 0x0f, 0x6d, 0x7f, 0xda, 0xc1, 0xac, 0x2d, + 0xdd, 0xf4, 0x2e, 0x3e, 0xd5, 0x7f, 0x8c, 0xcd, 0x3c, 0xda, 0x34, 0x3a, + 0xda, 0x3d, 0xd1, 0xb2, 0xad, 0xa7, 0xa5, 0x9b, 0xde, 0xcb, 0xcc, 0x57, + 0xc1, 0xdc, 0x30, 0x3a, 0x72, 0xf8, 0xc5, 0xfd, 0xf4, 0x5d, 0x87, 0xd2, + 0x6b, 0x37, 0x5a, 0xbf, 0x0b, 0x65, 0x1b, 0x8e, 0x76, 0xd3, 0x7b, 0x32, + 0x41, 0xef, 0x11, 0x85, 0xf9, 0xcf, 0x76, 0xd3, 0x5d, 0x19, 0x3c, 0x56, + 0x9f, 0xe7, 0xe8, 0xe1, 0x9f, 0xd3, 0xe9, 0x4c, 0xa4, 0x37, 0x08, 0x5f, + 0xfe, 0xcf, 0x9b, 0xe8, 0x2b, 0x4e, 0xa4, 0x47, 0x8e, 0x6f, 0x08, 0xb7, + 0x3c, 0x24, 0x7c, 0xbe, 0x47, 0x36, 0xd0, 0xc7, 0x9c, 0x06, 0xdf, 0x8d, + 0x3e, 0x05, 0x7e, 0x17, 0x9d, 0x37, 0xa5, 0x5a, 0xc7, 0x6f, 0x3c, 0xda, + 0xfc, 0xce, 0x77, 0x1f, 0x7f, 0xe4, 0xf8, 0xbd, 0x0f, 0xb7, 0xd1, 0x43, + 0xb2, 0xa5, 0xa5, 0x9e, 0xa3, 0xf4, 0x8e, 0x4c, 0x56, 0x15, 0xed, 0xd3, + 0x67, 0xb8, 0x95, 0x0d, 0xd7, 0x1f, 0x6a, 0x3e, 0xd5, 0x1c, 0x6e, 0xa6, + 0x1f, 0xb8, 0x90, 0x3b, 0xbc, 0xe1, 0xee, 0x63, 0x0f, 0xef, 0x1f, 0x19, + 0x1d, 0x09, 0x3f, 0x7b, 0x82, 0x7e, 0x69, 0x72, 0x79, 0xb8, 0x7c, 0x42, + 0x14, 0x7a, 0x0e, 0xfd, 0x6b, 0xd8, 0x98, 0xfb, 0x5b, 0xfa, 0x99, 0x89, + 0x5e, 0x7e, 0xc4, 0x1f, 0xe7, 0x59, 0x7c, 0xe2, 0xd4, 0x43, 0xe1, 0x4f, + 0x1f, 0xa4, 0x07, 0x58, 0xd0, 0xb8, 0xdd, 0xec, 0x3a, 0x74, 0xe8, 0xb0, + 0xf1, 0xa7, 0xb7, 0xdd, 0x30, 0x72, 0x76, 0xdb, 0x68, 0xf8, 0x7a, 0xfa, + 0x1c, 0x46, 0x34, 0xb1, 0x61, 0x42, 0x2c, 0xcd, 0xff, 0x5e, 0x53, 0x39, + 0x3e, 0x31, 0x90, 0x66, 0x60, 0xf4, 0xd0, 0x5b, 0x8f, 0x4f, 0x18, 0x33, + 0x57, 0xd3, 0x53, 0xac, 0xd3, 0x71, 0x3a, 0xc7, 0x64, 0xc3, 0xc8, 0xcc, + 0xb3, 0xc7, 0x7f, 0x31, 0x72, 0xec, 0xe8, 0xdb, 0x1f, 0x99, 0xe9, 0xbe, + 0xbc, 0xa7, 0x6d, 0xf7, 0xdd, 0xc2, 0xe3, 0xa1, 0x8f, 0x72, 0x27, 0x1b, + 0x8e, 0x3d, 0x7b, 0xec, 0xc2, 0xa9, 0x87, 0xb6, 0x8f, 0xfc, 0xa2, 0x1b, + 0x65, 0x7d, 0x3d, 0xf4, 0x45, 0x59, 0xe1, 0xd1, 0x91, 0x0f, 0x61, 0x3c, + 0xc7, 0x44, 0x61, 0x51, 0xf7, 0xc6, 0x89, 0xf2, 0x2b, 0xe9, 0x2c, 0x8f, + 0x86, 0x9e, 0xe0, 0x32, 0xfa, 0x35, 0xa7, 0xdf, 0xba, 0xe1, 0xd8, 0x23, + 0xdd, 0x1b, 0xaf, 0xd9, 0x3f, 0xd2, 0x7d, 0xcf, 0xfe, 0x91, 0xb7, 0x1d, + 0xdf, 0x48, 0xa7, 0x1d, 0x38, 0xef, 0x3f, 0xdb, 0x44, 0x77, 0x60, 0x01, + 0x44, 0x41, 0x3e, 0xbd, 0xc3, 0x91, 0x5a, 0xda, 0x9d, 0x90, 0x0f, 0x1f, + 0xa6, 0x2f, 0xf0, 0x1c, 0xbf, 0xeb, 0xad, 0x1b, 0x46, 0x0e, 0x95, 0x6f, + 0xa6, 0x27, 0x90, 0x69, 0x3c, 0xae, 0xd2, 0x97, 0xb3, 0xd9, 0xb2, 0x2d, + 0x17, 0x69, 0xfb, 0xae, 0xd6, 0x94, 0x9f, 0x1b, 0x19, 0x92, 0xb6, 0x2b, + 0x9f, 0x41, 0xea, 0xfc, 0xf0, 0x20, 0xda, 0x75, 0x6a, 0x99, 0x32, 0x4d, + 0x89, 0xac, 0xef, 0x9a, 0x09, 0xfd, 0xd4, 0x50, 0xc8, 0xef, 0xb1, 0x58, + 0x27, 0x8b, 0xf5, 0xae, 0xcb, 0x90, 0x74, 0xb5, 0xcc, 0xd7, 0x6a, 0xfe, + 0x60, 0x4a, 0x2e, 0x57, 0xd7, 0xed, 0x91, 0x9f, 0xaa, 0x8f, 0xde, 0x54, + 0x7d, 0xa1, 0xfb, 0x57, 0x28, 0x92, 0x7b, 0xd4, 0x20, 0xd2, 0xcf, 0x73, + 0xd3, 0xdf, 0x5d, 0x53, 0xbc, 0x0c, 0xcd, 0xcb, 0x90, 0x3c, 0x95, 0x76, + 0xa5, 0xda, 0x72, 0x6b, 0xea, 0xd5, 0xb4, 0x40, 0xcb, 0x14, 0xe8, 0x76, + 0x99, 0x57, 0x48, 0xe9, 0x77, 0x84, 0x86, 0xa4, 0x2b, 0xc8, 0x7a, 0xa7, + 0xa7, 0xee, 0xc0, 0x4b, 0xe4, 0x18, 0x4c, 0x52, 0xef, 0xa1, 0x6b, 0xb5, + 0xdf, 0xe4, 0x77, 0xe2, 0xa6, 0xa6, 0x5e, 0xed, 0x6f, 0xbb, 0x74, 0x9d, + 0x2e, 0x9c, 0x02, 0x6e, 0xdd, 0xde, 0x46, 0xed, 0x43, 0x7a, 0x74, 0x59, + 0xaf, 0xd6, 0xdf, 0x4c, 0xa5, 0xe5, 0xa8, 0x6b, 0xc9, 0x51, 0x3b, 0x5c, + 0x47, 0xa2, 0x8e, 0xaa, 0x5b, 0xdb, 0xfb, 0x3a, 0x5b, 0x07, 0x3b, 0x7a, + 0x9b, 0x06, 0x07, 0x06, 0x3b, 0x9b, 0xd6, 0xf4, 0xb5, 0xb7, 0x37, 0xf5, + 0x5e, 0xd6, 0xd1, 0xd6, 0xb4, 0xb6, 0x7f, 0xb0, 0x7d, 0xcd, 0x60, 0xff, + 0x9a, 0xfe, 0xcb, 0x5a, 0x5b, 0x29, 0xb3, 0x7b, 0x72, 0x26, 0x1c, 0x09, + 0x27, 0x37, 0x52, 0x46, 0xb7, 0xa2, 0xc6, 0xc6, 0x2e, 0x32, 0x37, 0x76, + 0xd5, 0xed, 0xe2, 0x4f, 0xa4, 0x0b, 0xfb, 0x66, 0xe6, 0x42, 0xc9, 0x68, + 0x34, 0x39, 0xbd, 0x35, 0x3c, 0x15, 0xde, 0x1a, 0x8c, 0x04, 0xf7, 0x85, + 0xe2, 0xb4, 0x71, 0x31, 0xae, 0x3f, 0x14, 0x8f, 0x47, 0xe3, 0xeb, 0xfd, + 0x93, 0xd1, 0xb9, 0x99, 0x29, 0x7f, 0x24, 0x9a, 0xf4, 0xef, 0x0b, 0x25, + 0xfd, 0x29, 0x49, 0xff, 0xe8, 0xa0, 0x3f, 0x31, 0x19, 0x8c, 0x44, 0x50, + 0xbf, 0xff, 0xcd, 0xd7, 0x9f, 0x0a, 0xed, 0x0d, 0xce, 0xcd, 0xd8, 0xdb, + 0x09, 0x4e, 0x05, 0x63, 0x49, 0x34, 0x52, 0x32, 0x30, 0x37, 0x3b, 0x7b, + 0x38, 0xc5, 0xdf, 0x14, 0x4c, 0x26, 0xfb, 0x83, 0x33, 0x33, 0x7b, 0x82, + 0x93, 0xfb, 0x49, 0x0c, 0x93, 0x31, 0x3c, 0x4a, 0x8e, 0xe1, 0xd1, 0x51, + 0x2a, 0x1f, 0xde, 0xee, 0x1f, 0x3c, 0x34, 0x19, 0x8a, 0x25, 0xc3, 0xd1, + 0x88, 0xff, 0x86, 0xe9, 0xf0, 0x4c, 0xc8, 0x3f, 0x39, 0x13, 0x4d, 0x84, + 0x23, 0xfb, 0xfc, 0xb1, 0x68, 0x3c, 0x49, 0x2b, 0x87, 0xb7, 0xbf, 0x5e, + 0xf9, 0x2c, 0xd4, 0x83, 0x0a, 0x07, 0xc3, 0x93, 0x21, 0x12, 0x5b, 0xc8, + 0xdc, 0xb2, 0xb3, 0x7f, 0x90, 0xbc, 0x5b, 0xe6, 0x26, 0x43, 0xac, 0xf8, + 0x70, 0x24, 0x36, 0x97, 0xdc, 0xc1, 0x4d, 0xf8, 0x2c, 0xd6, 0xf6, 0xb9, + 0xa4, 0xc5, 0xcb, 0xb1, 0x78, 0x32, 0x57, 0x68, 0xe5, 0xc6, 0xe7, 0x62, + 0xdc, 0x6b, 0xf3, 0xf5, 0xc1, 0x83, 0x41, 0x42, 0x40, 0x68, 0x8c, 0x0e, + 0x93, 0x63, 0x74, 0x58, 0x7e, 0xa0, 0x07, 0x7c, 0xec, 0x06, 0x0f, 0xba, + 0x8f, 0xe2, 0xc3, 0x1c, 0x1d, 0xdd, 0x3d, 0x4a, 0xd5, 0xa3, 0xc1, 0xc8, + 0x54, 0x3c, 0x1a, 0x9e, 0x6a, 0xd9, 0x63, 0x8d, 0xb6, 0x25, 0x35, 0xee, + 0x5e, 0x35, 0x1d, 0x5d, 0x54, 0xf5, 0x46, 0x52, 0x03, 0x72, 0x0c, 0x5d, + 0x54, 0xf1, 0x46, 0x42, 0x3c, 0x85, 0x5d, 0x54, 0x77, 0x29, 0x11, 0x6b, + 0x96, 0xbb, 0xa8, 0xe5, 0x92, 0xa2, 0xd3, 0xc1, 0x78, 0x70, 0x12, 0xea, + 0x85, 0x13, 0xc9, 0xf0, 0x64, 0x17, 0x35, 0x5c, 0xaa, 0xc2, 0x40, 0x28, + 0x31, 0x19, 0x0f, 0xc7, 0x92, 0x51, 0x0c, 0xe8, 0x0d, 0x87, 0xad, 0x8d, + 0x66, 0x71, 0x75, 0x67, 0x42, 0x69, 0xc1, 0xd1, 0xd0, 0xb8, 0xb2, 0xba, + 0xc5, 0x67, 0x08, 0xa2, 0x5c, 0x9e, 0x1e, 0xd3, 0xeb, 0xb4, 0xc7, 0x42, + 0x43, 0xe1, 0x19, 0x0c, 0xa5, 0xba, 0x6f, 0x2e, 0x3c, 0x33, 0xc5, 0xed, + 0x2d, 0x36, 0x99, 0xf3, 0x44, 0xdf, 0x50, 0x64, 0x2c, 0x94, 0x80, 0x61, + 0x2f, 0x3e, 0x27, 0x5a, 0x64, 0x3c, 0x94, 0x4c, 0xc2, 0x0c, 0x13, 0xe9, + 0x2e, 0xdf, 0x60, 0x08, 0x96, 0x70, 0x17, 0x2d, 0x4b, 0x09, 0x4d, 0x46, + 0x23, 0xc9, 0x50, 0x24, 0xd9, 0xd2, 0xcf, 0xf4, 0x10, 0x3a, 0x2b, 0x4f, + 0x15, 0xcd, 0x86, 0xa6, 0xc2, 0xc1, 0x16, 0x36, 0xf0, 0x16, 0x36, 0x4b, + 0xcb, 0x40, 0x1a, 0xdf, 0x58, 0x60, 0x38, 0xb2, 0x37, 0x5a, 0xcd, 0x06, + 0xcd, 0x09, 0xbb, 0x3a, 0xaf, 0x2b, 0xdd, 0x45, 0x2b, 0xdf, 0x58, 0x68, + 0x3c, 0x19, 0x4c, 0xce, 0x41, 0xeb, 0xca, 0xd7, 0x13, 0x4b, 0x6d, 0x33, + 0xbb, 0xc1, 0x2d, 0x90, 0xd1, 0xe6, 0x50, 0xad, 0x9a, 0x4c, 0xaf, 0xe6, + 0x65, 0x97, 0xaa, 0xb0, 0x3d, 0xa2, 0xaa, 0x6c, 0x8f, 0x85, 0x22, 0xa1, + 0xa9, 0x51, 0xd8, 0x69, 0x48, 0xda, 0x8a, 0xff, 0x12, 0x15, 0xdf, 0x60, + 0xec, 0x69, 0x1f, 0x60, 0x5f, 0xff, 0x05, 0x42, 0x63, 0xa1, 0xc9, 0x50, + 0xf8, 0x20, 0xb7, 0x53, 0x92, 0x12, 0x89, 0x26, 0x5a, 0xe4, 0x42, 0x57, + 0xef, 0x1a, 0x1c, 0x1b, 0x1f, 0xde, 0xbe, 0xad, 0x8b, 0x0a, 0xe6, 0x97, + 0x45, 0xa6, 0x66, 0xb0, 0x44, 0x85, 0x76, 0xe6, 0xe6, 0x20, 0x33, 0xd1, + 0x4c, 0x91, 0x9d, 0xbb, 0x23, 0x18, 0x9f, 0x0c, 0xcd, 0xec, 0x9c, 0x0b, + 0x4f, 0x75, 0x91, 0x2f, 0x55, 0x30, 0x97, 0x0c, 0xcf, 0xb4, 0x8c, 0x46, + 0xf7, 0xd9, 0xdb, 0x95, 0xbc, 0x1d, 0xc1, 0x70, 0x7c, 0x51, 0x66, 0x37, + 0xad, 0x19, 0x9d, 0x8c, 0xce, 0xb6, 0xc4, 0x67, 0x13, 0x33, 0x2d, 0xd7, + 0xc3, 0x83, 0xb5, 0x2c, 0x70, 0x63, 0xd5, 0x8b, 0x79, 0xf2, 0x2e, 0x6a, + 0xbb, 0x44, 0xad, 0x8b, 0x3c, 0x68, 0x17, 0xad, 0x7e, 0x93, 0x55, 0xec, + 0xb3, 0xdb, 0xf8, 0x26, 0xeb, 0x28, 0xe9, 0xd1, 0x4b, 0x48, 0xa7, 0x4d, + 0x32, 0x65, 0x4d, 0xaf, 0x7b, 0xc2, 0x74, 0xd1, 0xc0, 0x5f, 0xdd, 0x5a, + 0x9a, 0xc3, 0xc6, 0x16, 0x08, 0x26, 0xf6, 0x5f, 0x7a, 0xa2, 0x2e, 0x6a, + 0xe5, 0xd2, 0x83, 0xb6, 0x06, 0xbc, 0x23, 0x98, 0x9c, 0xe6, 0x0d, 0xff, + 0x86, 0xd2, 0xbc, 0xed, 0xa6, 0x82, 0x33, 0x07, 0xc3, 0xfb, 0x5b, 0xe0, + 0x24, 0xa3, 0xd8, 0x8a, 0x38, 0x04, 0x5b, 0x06, 0x23, 0xfa, 0x00, 0xec, + 0x9f, 0x09, 0x26, 0xb0, 0x35, 0xcb, 0x16, 0x91, 0x19, 0x66, 0x9f, 0xaa, + 0xcb, 0x2b, 0x16, 0x29, 0xdf, 0x1a, 0x9a, 0xdd, 0xa3, 0x05, 0x42, 0x10, + 0x59, 0xb1, 0x88, 0xc8, 0x78, 0x78, 0x5f, 0x04, 0x7b, 0x3f, 0x1e, 0xe2, + 0x4d, 0x70, 0x71, 0x71, 0x60, 0x3a, 0x1e, 0xbd, 0x01, 0x55, 0x97, 0x8c, + 0xf2, 0x59, 0xd9, 0x12, 0x8e, 0xb6, 0xd8, 0x0e, 0xea, 0x2e, 0xf2, 0x2a, + 0xf6, 0x4c, 0x30, 0xb2, 0xaf, 0x45, 0xeb, 0x51, 0x60, 0x63, 0x0d, 0xc3, + 0xe3, 0xc9, 0xf9, 0xf2, 0xd9, 0x98, 0xdb, 0xf7, 0x5c, 0x1f, 0x9a, 0x4c, + 0xce, 0xe7, 0x8d, 0x27, 0xe3, 0x18, 0x69, 0xaa, 0x1b, 0xc9, 0x93, 0x5d, + 0x07, 0xf7, 0xf0, 0x6e, 0x5b, 0x61, 0x63, 0xc7, 0x43, 0x7b, 0x5b, 0xae, + 0x0c, 0x05, 0xf7, 0x8f, 0x85, 0xf6, 0x86, 0xe2, 0xa1, 0xc8, 0xe4, 0xa5, + 0x8a, 0xbb, 0xad, 0x46, 0xe5, 0x86, 0xea, 0x8d, 0xc7, 0x83, 0x87, 0xd9, + 0xc3, 0x74, 0x2d, 0xce, 0xee, 0xb6, 0xd4, 0x4a, 0xb3, 0xd3, 0x63, 0x92, + 0xbc, 0xcd, 0xc1, 0x04, 0x0e, 0xbe, 0xd8, 0xa2, 0xcc, 0xee, 0x8b, 0x98, + 0x38, 0x10, 0x2e, 0x96, 0x04, 0xb3, 0x1b, 0x1e, 0x24, 0xcd, 0x1c, 0xc6, + 0x39, 0x15, 0x94, 0xe7, 0xad, 0xc7, 0xc6, 0x55, 0x6a, 0x2e, 0xe4, 0x74, + 0x53, 0xbe, 0x8d, 0x23, 0xdb, 0xf7, 0xda, 0x18, 0x81, 0xf0, 0x2c, 0x4f, + 0xf8, 0x92, 0x85, 0x2c, 0x65, 0xea, 0xde, 0x8b, 0x6c, 0x99, 0x7a, 0x2f, + 0x62, 0x2d, 0x1e, 0x04, 0xda, 0xa3, 0xc4, 0xc4, 0x61, 0xb8, 0xe8, 0x59, + 0x7f, 0x22, 0x14, 0x97, 0x51, 0x99, 0xef, 0xe2, 0x5d, 0x45, 0x39, 0xf6, + 0x2d, 0x40, 0xae, 0xf1, 0x81, 0x91, 0x6b, 0x87, 0xb7, 0x05, 0x68, 0xa5, + 0xfd, 0x94, 0x6c, 0xee, 0xef, 0x1d, 0x1d, 0xed, 0xeb, 0xed, 0x1f, 0xb9, + 0x36, 0x70, 0xf5, 0x8e, 0xc1, 0x6b, 0xb7, 0xf6, 0x06, 0xfa, 0x37, 0x5f, + 0x3b, 0xba, 0x7d, 0x3c, 0x40, 0x62, 0x17, 0x19, 0xbb, 0x10, 0x8e, 0xed, + 0x42, 0x00, 0x69, 0xee, 0x1a, 0xde, 0x3d, 0x4c, 0x19, 0xbb, 0xb6, 0x20, + 0x40, 0xdb, 0x02, 0x36, 0xc2, 0xb2, 0x5d, 0x88, 0xd7, 0xcc, 0x5d, 0x1c, + 0xb0, 0x39, 0x77, 0x49, 0x2e, 0x38, 0xf2, 0x83, 0xa5, 0x47, 0x55, 0x21, + 0xd2, 0x4e, 0xfe, 0xdc, 0xa2, 0x08, 0x82, 0xbc, 0x5d, 0xbb, 0x49, 0x20, + 0xae, 0x43, 0x63, 0x06, 0x02, 0x3a, 0x63, 0xa2, 0x8f, 0x2a, 0x27, 0x2e, + 0x1d, 0x3d, 0x34, 0x4d, 0xfc, 0x55, 0xa7, 0x71, 0xf5, 0x9b, 0x10, 0x87, + 0x45, 0x4c, 0x2c, 0xb2, 0x21, 0xe6, 0x31, 0xad, 0x1d, 0xe1, 0x0e, 0x4e, + 0x4e, 0x86, 0x12, 0x89, 0xea, 0x56, 0x5c, 0x15, 0xb2, 0x55, 0x7a, 0x68, + 0x26, 0xb8, 0x2f, 0x41, 0x8e, 0xe0, 0xd4, 0x14, 0x38, 0xaa, 0x2f, 0x19, + 0xde, 0xba, 0x83, 0xb1, 0x98, 0x0e, 0x32, 0x28, 0x23, 0x98, 0x60, 0x63, + 0xa1, 0xac, 0xd4, 0xb8, 0xa8, 0x24, 0x95, 0x1c, 0x1d, 0x94, 0xde, 0x47, + 0xad, 0xde, 0xce, 0x9d, 0xc3, 0x03, 0xe4, 0xd9, 0xb3, 0x20, 0xa6, 0xa3, + 0xc2, 0x3d, 0xf6, 0x43, 0x45, 0xe9, 0x9e, 0xb0, 0xc9, 0x5d, 0xab, 0x23, + 0x72, 0xcf, 0x9e, 0xa4, 0x2e, 0xe4, 0xb3, 0x0a, 0x2a, 0x53, 0xc6, 0x9e, + 0x24, 0x7b, 0x69, 0x72, 0xee, 0xe1, 0x73, 0x94, 0x32, 0x30, 0x97, 0x38, + 0x07, 0xc9, 0x39, 0x39, 0x13, 0x0a, 0xc6, 0x99, 0x44, 0x13, 0x21, 0x72, + 0x21, 0x2a, 0x8a, 0x60, 0xd4, 0x94, 0xad, 0x13, 0xb2, 0x4a, 0x26, 0xc7, + 0x4a, 0xc1, 0x70, 0x24, 0x21, 0xd9, 0x32, 0x35, 0x12, 0x3a, 0x4c, 0x62, + 0x8a, 0x32, 0x55, 0x77, 0xc3, 0x18, 0xf2, 0x54, 0x6a, 0x1e, 0x13, 0xe4, + 0x9e, 0x0a, 0x27, 0xac, 0x96, 0x32, 0x42, 0x07, 0xe6, 0x82, 0x33, 0x09, + 0x6a, 0xde, 0x1b, 0xc4, 0xf5, 0x61, 0xca, 0x9f, 0x8c, 0xfa, 0x27, 0xe3, + 0xa1, 0x60, 0x32, 0xe4, 0xdf, 0x33, 0x37, 0xa3, 0xef, 0x2d, 0xaa, 0xae, + 0x7f, 0x6f, 0x3c, 0x3a, 0x8b, 0x3b, 0xcc, 0x54, 0x1c, 0xb3, 0x49, 0x99, + 0x7b, 0xc3, 0x91, 0xe0, 0x4c, 0xf8, 0xad, 0x21, 0xaa, 0x40, 0x6a, 0x2a, + 0x3d, 0xdc, 0xa1, 0x68, 0xdc, 0x16, 0xe1, 0x2b, 0xe1, 0x72, 0x16, 0xb1, + 0x8c, 0x7c, 0x31, 0x01, 0xe7, 0xde, 0x70, 0x1c, 0xf3, 0xee, 0xe6, 0x2e, + 0xd4, 0x1a, 0x92, 0x03, 0xdb, 0x87, 0xdc, 0xf8, 0xd0, 0xd7, 0x04, 0x9d, + 0x56, 0xf2, 0xd9, 0x9c, 0x9e, 0x99, 0xe1, 0x05, 0x4c, 0x50, 0x09, 0x67, + 0xd4, 0x8a, 0x2e, 0x0c, 0xb2, 0x69, 0x79, 0xba, 0xec, 0xe2, 0x4d, 0xbc, + 0x84, 0x0b, 0x63, 0xb1, 0x99, 0xf0, 0xa4, 0x74, 0xdb, 0x96, 0x15, 0x14, + 0x80, 0x7d, 0x91, 0x86, 0xc5, 0x76, 0xa6, 0x3d, 0xfc, 0x93, 0xad, 0x5c, + 0x1c, 0xb3, 0x53, 0x26, 0xd8, 0xd2, 0xb9, 0x93, 0x17, 0xa9, 0x01, 0x75, + 0x19, 0xb4, 0xc6, 0x52, 0x92, 0x66, 0x2d, 0xbc, 0x0e, 0x51, 0x96, 0x2c, + 0x93, 0x66, 0x92, 0x97, 0x4a, 0xea, 0x85, 0x4b, 0xe5, 0x13, 0xe4, 0x42, + 0x5a, 0x2e, 0x7f, 0x1d, 0x12, 0x9b, 0xe7, 0x66, 0x39, 0x2c, 0xc7, 0x05, + 0x13, 0x9e, 0x5f, 0x4d, 0xe0, 0xa2, 0xd3, 0x0c, 0x51, 0xd8, 0xad, 0x24, + 0x53, 0xb2, 0x05, 0x6e, 0x97, 0x2a, 0x91, 0xe0, 0xd3, 0xf5, 0xa2, 0x89, + 0xda, 0x16, 0x9c, 0x65, 0xe6, 0xf0, 0x40, 0x82, 0x6a, 0x2e, 0x96, 0x91, + 0x21, 0xd0, 0x45, 0x82, 0xb5, 0x17, 0x0b, 0xaa, 0xc0, 0xe7, 0x22, 0xc9, + 0x65, 0x90, 0xe4, 0xe2, 0x85, 0x6a, 0x62, 0x70, 0x4b, 0x75, 0x91, 0xaa, + 0xc3, 0x7b, 0x04, 0xc3, 0xd1, 0x2a, 0x73, 0x0b, 0xd2, 0x00, 0x78, 0xf5, + 0x65, 0x26, 0xd7, 0xca, 0xcc, 0xf1, 0xc1, 0x4d, 0x1e, 0x9d, 0x65, 0x1f, + 0xca, 0xd5, 0x06, 0xe4, 0x5a, 0x28, 0x5b, 0x91, 0xa2, 0xf1, 0x68, 0x2c, + 0x14, 0x4f, 0x86, 0xd1, 0x4f, 0x3e, 0xb2, 0x63, 0xa1, 0xd9, 0x68, 0x32, + 0xa4, 0x67, 0x9c, 0xeb, 0x8e, 0x4b, 0x3f, 0xad, 0x37, 0xba, 0xec, 0x32, + 0x70, 0x38, 0x16, 0xa2, 0xc2, 0x69, 0x19, 0xb0, 0xea, 0xf9, 0xc7, 0xfd, + 0x30, 0xb2, 0x2f, 0x34, 0x45, 0xb9, 0x8a, 0xab, 0x83, 0x62, 0x72, 0x4d, + 0x07, 0x13, 0xdb, 0xd8, 0x88, 0x32, 0x91, 0x98, 0xee, 0x8f, 0x4e, 0x41, + 0xd5, 0x70, 0xa2, 0x5f, 0x6d, 0x36, 0x88, 0xbb, 0xc2, 0x89, 0xc1, 0xd9, + 0x58, 0xf2, 0x30, 0x27, 0xe4, 0xfc, 0x71, 0x71, 0xfa, 0x36, 0x9e, 0x19, + 0xd6, 0x67, 0x1a, 0x65, 0x72, 0xcc, 0xb3, 0x39, 0x8a, 0x4d, 0x91, 0xb1, + 0x3f, 0x74, 0x18, 0xbe, 0x9f, 0x5c, 0xb3, 0xda, 0x6c, 0x4d, 0x76, 0x8e, + 0xe4, 0x9e, 0x4d, 0xcd, 0x0f, 0x79, 0x67, 0x2f, 0xb2, 0xed, 0xec, 0x59, + 0x9b, 0x03, 0x32, 0x23, 0x3c, 0x4d, 0x66, 0x84, 0x15, 0xf3, 0x45, 0x23, + 0x7d, 0xc1, 0xe4, 0xe4, 0x74, 0xfa, 0x22, 0x97, 0xa0, 0x22, 0x18, 0xff, + 0xbc, 0xfb, 0xae, 0x35, 0xba, 0xc2, 0x85, 0x05, 0x6c, 0x63, 0xb4, 0x64, + 0x21, 0xf7, 0xca, 0x38, 0xf4, 0x96, 0xad, 0xa8, 0x81, 0x62, 0x33, 0xf1, + 0xe6, 0x08, 0xa9, 0x66, 0xc8, 0x13, 0x8d, 0xa4, 0x6f, 0xc7, 0xb2, 0x05, + 0xaf, 0x9d, 0xa3, 0x6a, 0xe7, 0x46, 0xf5, 0x7d, 0x06, 0x56, 0x80, 0x9e, + 0xf3, 0xa2, 0xf3, 0xae, 0x37, 0xdc, 0xa7, 0x3d, 0x3f, 0x10, 0x9a, 0x09, + 0x1e, 0x06, 0x3b, 0xdf, 0x62, 0xf3, 0x2a, 0x1e, 0xb4, 0xcb, 0xa9, 0xdd, + 0x69, 0x0d, 0xc4, 0x15, 0x8d, 0x0c, 0xcd, 0xcc, 0x25, 0xa6, 0x29, 0x27, + 0x1a, 0xd9, 0x9a, 0x9c, 0xb3, 0xd8, 0xd0, 0x8c, 0xf5, 0x51, 0x26, 0x30, + 0x96, 0x48, 0x84, 0xa9, 0x98, 0x39, 0x33, 0x61, 0xde, 0x47, 0x52, 0xaf, + 0xfe, 0xe8, 0x6c, 0x0c, 0x7e, 0x10, 0xb2, 0xa8, 0x29, 0x4f, 0x38, 0xe9, + 0x27, 0xad, 0x9c, 0x9a, 0x41, 0xca, 0x40, 0x2e, 0x14, 0x91, 0xf3, 0xa5, + 0xed, 0x26, 0x31, 0xc0, 0x3e, 0x16, 0xd7, 0x24, 0xc8, 0x16, 0xc0, 0xde, + 0x22, 0x0b, 0x9c, 0x07, 0xb9, 0x99, 0xa9, 0xd3, 0xb9, 0x9c, 0x4e, 0x5b, + 0x41, 0x11, 0x67, 0xe7, 0x5d, 0x32, 0xae, 0x0c, 0x27, 0xa7, 0x61, 0xc7, + 0xc5, 0x56, 0x41, 0xfa, 0x2a, 0xa1, 0x4b, 0x7c, 0x56, 0x89, 0x8d, 0x97, + 0xc7, 0x3c, 0xdb, 0x63, 0x9d, 0x2c, 0xce, 0xab, 0x6d, 0x20, 0x93, 0xec, + 0x8c, 0xe1, 0x13, 0xa2, 0x37, 0xb0, 0xbb, 0x2a, 0x88, 0x61, 0x93, 0x2d, + 0xd4, 0xb1, 0x64, 0x11, 0xe6, 0x78, 0x32, 0x14, 0x0b, 0xdc, 0x10, 0xa5, + 0xa2, 0x79, 0x65, 0xe9, 0xcd, 0x4a, 0x59, 0x31, 0x79, 0xac, 0x4f, 0x85, + 0x0e, 0x51, 0x66, 0xcc, 0x0a, 0x65, 0x1c, 0x6c, 0xea, 0x4b, 0xe3, 0xa1, + 0x7d, 0x7c, 0x4d, 0x8d, 0xcf, 0xbf, 0xeb, 0x52, 0x46, 0x5c, 0x2e, 0x1e, + 0xb9, 0x15, 0x95, 0xca, 0x2e, 0x8b, 0xe3, 0x60, 0x0a, 0x25, 0x92, 0x69, + 0x8b, 0xda, 0x11, 0x0f, 0x47, 0xb1, 0x22, 0x87, 0xc9, 0x11, 0x9f, 0x8b, + 0x90, 0xcb, 0x7a, 0x22, 0x97, 0x99, 0x98, 0x9c, 0x0e, 0x4d, 0xe1, 0xac, + 0xa2, 0x8c, 0x44, 0x08, 0xa7, 0xda, 0x14, 0x99, 0x09, 0x5e, 0x8a, 0x12, + 0xfe, 0x54, 0x8f, 0xc1, 0xa6, 0x83, 0x53, 0xfe, 0xe1, 0xed, 0xfe, 0x90, + 0x15, 0x81, 0xa3, 0x4e, 0x48, 0x1d, 0x59, 0x94, 0x9f, 0x08, 0xa5, 0x6e, + 0x46, 0x72, 0x97, 0x67, 0x83, 0xc1, 0x0b, 0xbb, 0x95, 0xb7, 0x6e, 0x1e, + 0x67, 0xf4, 0x81, 0x8f, 0x1b, 0x29, 0x5a, 0xe6, 0x03, 0xcf, 0x99, 0x48, + 0x06, 0x79, 0x3a, 0x25, 0x61, 0x59, 0xca, 0x55, 0xc9, 0x64, 0x34, 0x26, + 0xb3, 0x66, 0x02, 0x29, 0x74, 0x62, 0xe5, 0x33, 0x92, 0xd3, 0x61, 0xc4, + 0x22, 0xe4, 0x4a, 0x46, 0x65, 0x6c, 0x4c, 0x99, 0xc9, 0xa8, 0x3e, 0xe5, + 0x96, 0xcc, 0x45, 0x16, 0x9b, 0xf8, 0x65, 0x0b, 0xd8, 0xb6, 0xe9, 0x2d, + 0x9e, 0x8b, 0xbc, 0xce, 0x34, 0x3a, 0x0f, 0x06, 0x21, 0x4f, 0x2e, 0x49, + 0xb6, 0xef, 0xa5, 0xf8, 0x4d, 0x37, 0x0d, 0x74, 0xbe, 0xad, 0x92, 0xcb, + 0x30, 0xdc, 0xca, 0xf5, 0x95, 0x58, 0x92, 0xca, 0xc6, 0x4a, 0xdc, 0xaa, + 0x62, 0xe1, 0x19, 0x79, 0xe2, 0x35, 0xcd, 0x62, 0x94, 0x28, 0x88, 0x87, + 0x10, 0x65, 0x24, 0x42, 0x28, 0x84, 0xd7, 0x6a, 0xc2, 0x7c, 0x4e, 0xee, + 0x4f, 0xcc, 0xcd, 0x26, 0x2a, 0xd7, 0xef, 0x45, 0x68, 0x10, 0x6a, 0xac, + 0x9c, 0x0d, 0x47, 0x9a, 0x82, 0xb1, 0x70, 0xe5, 0xfa, 0xb6, 0xb5, 0x8d, + 0x95, 0xb0, 0xe9, 0x04, 0xea, 0xa2, 0x5a, 0x7b, 0x73, 0x7b, 0xf3, 0xea, + 0xd6, 0x26, 0x84, 0x07, 0x0d, 0xc1, 0x68, 0x22, 0xd6, 0x51, 0xf9, 0x76, + 0x32, 0x9a, 0xc4, 0x29, 0xa3, 0xd4, 0x2c, 0x12, 0x45, 0xd7, 0x15, 0x35, + 0x16, 0x65, 0xaa, 0xac, 0xa3, 0xe8, 0x2d, 0x45, 0xe3, 0x45, 0x2e, 0xa3, + 0x1e, 0x99, 0xe2, 0x3a, 0xa3, 0xc1, 0xb8, 0x5d, 0x98, 0x59, 0xdf, 0x17, + 0x45, 0x6e, 0x99, 0xac, 0xce, 0xca, 0x40, 0xba, 0x48, 0x95, 0xd6, 0xa8, + 0x52, 0x03, 0x9c, 0xdc, 0x74, 0x72, 0xaf, 0x6a, 0xc7, 0x85, 0x66, 0xc7, + 0x8b, 0x1c, 0x45, 0x3d, 0x45, 0xad, 0x45, 0x55, 0x68, 0x4f, 0x32, 0x9d, + 0x45, 0x46, 0x8a, 0xd1, 0xcc, 0x0c, 0x51, 0xbc, 0xc6, 0xd2, 0xc2, 0x28, + 0xba, 0xaa, 0x68, 0xb3, 0x25, 0x68, 0x16, 0x4d, 0xa0, 0x76, 0x95, 0x3d, + 0x7b, 0x45, 0xd1, 0x50, 0xba, 0x99, 0xab, 0x74, 0x33, 0x59, 0x16, 0x63, + 0x02, 0x75, 0x77, 0x15, 0x0d, 0x80, 0x91, 0xd2, 0x78, 0xca, 0x68, 0xe4, + 0x32, 0xa3, 0x78, 0x55, 0xf1, 0x4a, 0xc5, 0x75, 0x83, 0xbb, 0x4f, 0x71, + 0x33, 0x8a, 0x6b, 0x8a, 0x2b, 0x8a, 0x6b, 0x8b, 0xab, 0x8a, 0x2b, 0x8b, + 0xab, 0xd3, 0x75, 0x96, 0xa4, 0x93, 0x4b, 0x85, 0x43, 0x64, 0x99, 0x25, + 0x0e, 0xc3, 0x30, 0x84, 0xb1, 0xe6, 0xc8, 0x11, 0xf3, 0xd1, 0x95, 0x1d, + 0xe2, 0xbe, 0x6a, 0x21, 0x9e, 0x03, 0xce, 0x03, 0xcf, 0xaf, 0x14, 0xe2, + 0xe4, 0x2a, 0x21, 0x1e, 0x04, 0xbe, 0x5d, 0x25, 0xc4, 0x7d, 0x35, 0x42, + 0xbc, 0xc0, 0x8f, 0xdf, 0x33, 0xae, 0xb8, 0x25, 0x93, 0xc4, 0x22, 0x20, + 0x43, 0xb8, 0xf3, 0x0d, 0x71, 0xd2, 0x7f, 0xe5, 0x2d, 0x47, 0xcc, 0x17, + 0x9a, 0xaf, 0x12, 0x47, 0x5a, 0x84, 0xb8, 0x13, 0x78, 0x14, 0x78, 0x1a, + 0x38, 0x07, 0xdc, 0xde, 0x2a, 0xc4, 0x3d, 0xc0, 0x63, 0xc0, 0x33, 0xc0, + 0xf3, 0xad, 0x64, 0x0a, 0xa7, 0x17, 0x4a, 0x08, 0xae, 0xba, 0x07, 0x55, + 0x1f, 0x6c, 0x9f, 0x14, 0x47, 0xda, 0xd0, 0xf3, 0x6a, 0x21, 0x5e, 0x82, + 0xc8, 0x6b, 0x48, 0x7f, 0xbd, 0x9d, 0x5c, 0x2e, 0xdf, 0x12, 0x25, 0xa6, + 0xff, 0x4f, 0x43, 0xf6, 0x99, 0x5e, 0xc3, 0xb8, 0xb3, 0x43, 0x18, 0xdf, + 0x5e, 0xef, 0x30, 0x4e, 0xae, 0x01, 0xdd, 0xe8, 0x30, 0x4e, 0xaf, 0x75, + 0x1b, 0xe7, 0x3b, 0xc3, 0xe6, 0x4b, 0x7d, 0x0e, 0xf1, 0x74, 0x0f, 0xba, + 0xec, 0x76, 0x88, 0xdb, 0x41, 0xef, 0xeb, 0x31, 0xc4, 0xf9, 0x6e, 0x21, + 0x9e, 0xea, 0x82, 0x3a, 0x83, 0x42, 0xbc, 0x02, 0x3c, 0xbe, 0x19, 0x2a, + 0x6c, 0x41, 0x7e, 0x14, 0xe8, 0x14, 0xe2, 0x4c, 0xa7, 0x21, 0xee, 0xbc, + 0x0c, 0x23, 0x46, 0xfe, 0x1c, 0x70, 0x62, 0x2b, 0x39, 0x04, 0x16, 0x92, + 0xff, 0xdd, 0x22, 0xd0, 0xe1, 0xa3, 0x3b, 0x6e, 0xc5, 0xfc, 0x6c, 0x43, + 0xad, 0xed, 0x06, 0xb9, 0xa8, 0xdc, 0x2d, 0xdc, 0xb7, 0x8b, 0x63, 0x47, + 0xcc, 0x9f, 0x8c, 0x71, 0xe9, 0xb9, 0x31, 0x71, 0xcc, 0x7f, 0x6c, 0x5c, + 0x64, 0x9d, 0xb8, 0x42, 0x64, 0x9d, 0xbf, 0x42, 0x64, 0x7e, 0x7d, 0x87, + 0x78, 0xa7, 0x41, 0xe4, 0x34, 0xb2, 0xac, 0x6f, 0x08, 0x0b, 0xda, 0x08, + 0xc1, 0xa7, 0xeb, 0xcc, 0x5b, 0x0d, 0xba, 0x5c, 0xbc, 0x52, 0x27, 0xcc, + 0x67, 0xeb, 0x31, 0x25, 0x75, 0x86, 0xb8, 0xbd, 0x4e, 0x88, 0xb3, 0x48, + 0x9f, 0x07, 0x1e, 0x6c, 0x80, 0x9e, 0xc0, 0xb9, 0x06, 0xf4, 0xef, 0xca, + 0x91, 0xf5, 0x86, 0x79, 0x5a, 0x1b, 0xb7, 0x88, 0xdb, 0x9b, 0x84, 0xf9, + 0x93, 0x26, 0xe8, 0xdb, 0x88, 0xa9, 0x05, 0x5e, 0x43, 0xfa, 0xa9, 0x66, + 0xcc, 0x51, 0xb3, 0x28, 0xb2, 0xde, 0xc9, 0xf0, 0x9b, 0x8c, 0x07, 0xfa, + 0x15, 0x7d, 0xb2, 0x5f, 0xbd, 0xff, 0xf8, 0x02, 0xe8, 0x97, 0x6d, 0xe9, + 0xef, 0xe8, 0xf4, 0x4f, 0x41, 0xcf, 0xda, 0xd2, 0xbf, 0xd7, 0xf5, 0x5e, + 0xd5, 0x34, 0x7f, 0x40, 0x51, 0xbf, 0xa6, 0x75, 0x9a, 0x76, 0x6a, 0xba, + 0x49, 0xd3, 0x5d, 0x9a, 0xee, 0x1b, 0x50, 0xef, 0x57, 0xb8, 0x8f, 0x43, + 0x48, 0xdf, 0x36, 0x90, 0xee, 0xf3, 0x3d, 0x5a, 0xe6, 0x03, 0x36, 0xde, + 0x63, 0xb6, 0xf4, 0xe7, 0x90, 0x7e, 0x7c, 0x28, 0xfd, 0xfe, 0xc9, 0x7a, + 0x2f, 0xf5, 0xe8, 0x90, 0xfa, 0xdb, 0x11, 0xf7, 0x81, 0x3e, 0x6d, 0xfd, + 0x00, 0x5b, 0xff, 0x7b, 0x6e, 0x41, 0xfe, 0xf9, 0x05, 0x79, 0xff, 0x26, + 0xf5, 0x8e, 0xc7, 0x9a, 0x1b, 0x7e, 0xbf, 0xc4, 0x7f, 0x50, 0x42, 0xfe, + 0xad, 0x84, 0x4d, 0xea, 0xfd, 0x52, 0xf1, 0x26, 0xf5, 0x1b, 0xee, 0x4c, + 0xd0, 0x30, 0xe8, 0xb9, 0x21, 0xf5, 0x7b, 0xff, 0x17, 0x86, 0xd4, 0xef, + 0xfb, 0xcf, 0x0f, 0xa9, 0xdf, 0x99, 0xbf, 0x04, 0xda, 0xba, 0x69, 0x7e, + 0xfb, 0xdd, 0x0b, 0xf2, 0x03, 0x9b, 0xd2, 0x6b, 0xc0, 0xff, 0x7a, 0x74, + 0x7b, 0x3b, 0x16, 0xf0, 0x47, 0x34, 0xdf, 0x4b, 0xf3, 0xf9, 0x4c, 0xad, + 0xbf, 0x13, 0x64, 0x50, 0xfa, 0x6f, 0x05, 0xf1, 0x9c, 0x5a, 0x7f, 0x2f, + 0x88, 0xc7, 0xc2, 0xdf, 0x51, 0xe0, 0x9f, 0x44, 0xf0, 0xfc, 0x58, 0x7f, + 0x37, 0x88, 0xdf, 0xbe, 0x59, 0x7f, 0x3b, 0x48, 0xf8, 0xd5, 0xdf, 0xc5, + 0xe0, 0xbf, 0x1f, 0xe4, 0xf0, 0xab, 0xef, 0x84, 0xf3, 0xef, 0xdb, 0x84, + 0x47, 0x7d, 0x5f, 0x95, 0x7f, 0x87, 0x67, 0xf8, 0x55, 0x5f, 0xfc, 0xf7, + 0x85, 0x4c, 0xbf, 0x9a, 0x1b, 0xb6, 0x1b, 0xfe, 0x11, 0x1c, 0xb7, 0xc3, + 0xbf, 0x0f, 0x74, 0xfa, 0x95, 0x4e, 0xfc, 0x3b, 0x41, 0x87, 0x47, 0xbd, + 0xa7, 0x3b, 0x8d, 0x74, 0x86, 0x96, 0xe1, 0xdf, 0x11, 0xf2, 0xcb, 0x4a, + 0x96, 0xe1, 0xbf, 0x71, 0xf4, 0x7f, 0x27, 0xec, 0x58, 0xd2, 0x1c, 0x49, + 0x00, 0x00 +}; + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (getJuceAndroidMidiInputDeviceNameAndIDs, "getJuceAndroidMidiInputDeviceNameAndIDs", "()[Ljava/lang/String;") \ + METHOD (getJuceAndroidMidiOutputDeviceNameAndIDs, "getJuceAndroidMidiOutputDeviceNameAndIDs", "()[Ljava/lang/String;") \ + METHOD (openMidiInputPortWithID, "openMidiInputPortWithID", "(IJ)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") \ + METHOD (openMidiOutputPortWithID, "openMidiOutputPortWithID", "(I)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") + +DECLARE_JNI_CLASS_WITH_MIN_SDK (MidiDeviceManager, "com/rmsl/juce/JuceMidiSupport$MidiDeviceManager", 23) +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (start, "start", "()V") \ + METHOD (stop, "stop", "()V") \ + METHOD (close, "close", "()V") \ + METHOD (sendMidi, "sendMidi", "([BII)V") \ + METHOD (getName, "getName", "()Ljava/lang/String;") + +DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiPort", 23) +#undef JNI_CLASS_MEMBERS + +//============================================================================== +class MidiInput::Pimpl +{ +public: + Pimpl (MidiInput* midiInput, int deviceID, juce::MidiInputCallback* midiInputCallback, jobject deviceManager) + : juceMidiInput (midiInput), + callback (midiInputCallback), + midiConcatenator (2048), + javaMidiDevice (LocalRef (getEnv()->CallObjectMethod (deviceManager, + MidiDeviceManager.openMidiInputPortWithID, + (jint) deviceID, + (jlong) this))) + { + } + + ~Pimpl() + { + if (jobject d = javaMidiDevice.get()) + { + getEnv()->CallVoidMethod (d, JuceMidiPort.close); + javaMidiDevice.clear(); + } + } + + bool isOpen() const noexcept + { + return javaMidiDevice != nullptr; + } + + void start() + { + if (jobject d = javaMidiDevice.get()) + getEnv()->CallVoidMethod (d, JuceMidiPort.start); + } + + void stop() + { + if (jobject d = javaMidiDevice.get()) + getEnv()->CallVoidMethod (d, JuceMidiPort.stop); + + callback = nullptr; + } + + String getName() const noexcept + { + if (jobject d = javaMidiDevice.get()) + return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); + + return {}; + } + + static void handleReceive (JNIEnv* env, Pimpl& myself, jbyteArray byteArray, jint offset, jint len, jlong timestamp) + { + jassert (byteArray != nullptr); + auto* data = env->GetByteArrayElements (byteArray, nullptr); + + std::vector buffer (static_cast (len)); + std::memcpy (buffer.data(), data + offset, static_cast (len)); + + myself.midiConcatenator.pushMidiData (buffer.data(), + len, + static_cast (timestamp) * 1.0e-9, + myself.juceMidiInput, + *myself.callback); + + env->ReleaseByteArrayElements (byteArray, data, 0); + } + +private: + MidiInput* juceMidiInput; + MidiInputCallback* callback; + MidiDataConcatenator midiConcatenator; + GlobalRef javaMidiDevice; +}; + +//============================================================================== +class MidiOutput::Pimpl +{ +public: + Pimpl (const LocalRef& midiDevice) + : javaMidiDevice (midiDevice) + { + } + + ~Pimpl() + { + if (jobject d = javaMidiDevice.get()) + { + getEnv()->CallVoidMethod (d, JuceMidiPort.close); + javaMidiDevice.clear(); + } + } + + void send (jbyteArray byteArray, jint offset, jint len) + { + if (jobject d = javaMidiDevice.get()) + getEnv()->CallVoidMethod (d, + JuceMidiPort.sendMidi, + byteArray, offset, len); + } + + String getName() const noexcept + { + if (jobject d = javaMidiDevice.get()) + return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); + + return {}; + } + +private: + GlobalRef javaMidiDevice; +}; + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + CALLBACK (generatedCallback<&MidiInput::Pimpl::handleReceive>, "handleReceive", "(J[BIIJ)V" ) + +DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiInputPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiInputPort", 23) +#undef JNI_CLASS_MEMBERS + +//============================================================================== +class AndroidMidiDeviceManager +{ +public: + AndroidMidiDeviceManager() = default; + + Array getDevices (bool input) + { + if (jobject dm = deviceManager.get()) + { + jobjectArray jDeviceNameAndIDs + = (jobjectArray) getEnv()->CallObjectMethod (dm, input ? MidiDeviceManager.getJuceAndroidMidiInputDeviceNameAndIDs + : MidiDeviceManager.getJuceAndroidMidiOutputDeviceNameAndIDs); + + // Create a local reference as converting this to a JUCE string will call into JNI + LocalRef localDeviceNameAndIDs (jDeviceNameAndIDs); + + auto deviceNameAndIDs = javaStringArrayToJuce (localDeviceNameAndIDs); + deviceNameAndIDs.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); + + Array devices; + + for (int i = 0; i < deviceNameAndIDs.size(); i += 2) + devices.add ({ deviceNameAndIDs[i], deviceNameAndIDs[i + 1] }); + + return devices; + } + + return {}; + } + + MidiInput::Pimpl* openMidiInputPortWithID (int deviceID, MidiInput* juceMidiInput, juce::MidiInputCallback* callback) + { + if (auto dm = deviceManager.get()) + { + auto androidMidiInput = std::make_unique (juceMidiInput, deviceID, callback, dm); + + if (androidMidiInput->isOpen()) + return androidMidiInput.release(); + + // Perhaps the device is already open + jassertfalse; + } + + return nullptr; + } + + MidiOutput::Pimpl* openMidiOutputPortWithID (int deviceID) + { + if (auto dm = deviceManager.get()) + { + if (auto javaMidiPort = getEnv()->CallObjectMethod (dm, MidiDeviceManager.openMidiOutputPortWithID, (jint) deviceID)) + return new MidiOutput::Pimpl (LocalRef(javaMidiPort)); + + // Perhaps the port is already open + jassertfalse; + } + + return nullptr; + } + +private: + static void handleDevicesChanged (JNIEnv*, jclass) + { + MidiDeviceListConnectionBroadcaster::get().notify(); + } + + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + CALLBACK (handleDevicesChanged, "handleDevicesChanged", "()V" ) \ + STATICMETHOD (getAndroidMidiDeviceManager, "getAndroidMidiDeviceManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$MidiDeviceManager;") \ + STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothMidiManager;") + + DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23, javaMidiByteCode) + #undef JNI_CLASS_MEMBERS + + GlobalRef deviceManager { LocalRef (getEnv()->CallStaticObjectMethod (JuceMidiSupport, + JuceMidiSupport.getAndroidMidiDeviceManager, + getAppContext().get())) }; +}; + +//============================================================================== +Array MidiInput::getAvailableDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + AndroidMidiDeviceManager manager; + return manager.getDevices (true); +} + +MidiDeviceInfo MidiInput::getDefaultDevice() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + return getAvailableDevices().getFirst(); +} + +std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) +{ + if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) + return {}; + + AndroidMidiDeviceManager manager; + + std::unique_ptr midiInput (new MidiInput ({}, deviceIdentifier)); + + if (auto* port = manager.openMidiInputPortWithID (deviceIdentifier.getIntValue(), midiInput.get(), callback)) + { + midiInput->internal.reset (port); + midiInput->setName (port->getName()); + + return midiInput; + } + + return {}; +} + +StringArray MidiInput::getDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiInput::getDefaultDeviceIndex() +{ + return (getAndroidSDKVersion() < 23 ? -1 : 0); +} + +std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) +{ + return openDevice (getAvailableDevices()[index].identifier, callback); +} + +MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) + : deviceInfo (deviceName, deviceIdentifier) +{ +} + +MidiInput::~MidiInput() = default; + +void MidiInput::start() +{ + if (auto* mi = internal.get()) + mi->start(); +} + +void MidiInput::stop() +{ + if (auto* mi = internal.get()) + mi->stop(); +} + +//============================================================================== +Array MidiOutput::getAvailableDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + AndroidMidiDeviceManager manager; + return manager.getDevices (false); +} + +MidiDeviceInfo MidiOutput::getDefaultDevice() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + return getAvailableDevices().getFirst(); +} + +std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) +{ + if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) + return {}; + + AndroidMidiDeviceManager manager; + + if (auto* port = manager.openMidiOutputPortWithID (deviceIdentifier.getIntValue())) + { + std::unique_ptr midiOutput (new MidiOutput ({}, deviceIdentifier)); + midiOutput->internal.reset (port); + midiOutput->setName (port->getName()); + + return midiOutput; + } + + return {}; +} + +StringArray MidiOutput::getDevices() +{ + if (getAndroidSDKVersion() < 23) + return {}; + + StringArray deviceNames; + + for (auto& d : getAvailableDevices()) + deviceNames.add (d.name); + + return deviceNames; +} + +int MidiOutput::getDefaultDeviceIndex() +{ + return (getAndroidSDKVersion() < 23 ? -1 : 0); +} + +std::unique_ptr MidiOutput::openDevice (int index) +{ + return openDevice (getAvailableDevices()[index].identifier); +} + +MidiOutput::~MidiOutput() +{ + stopBackgroundThread(); +} + +void MidiOutput::sendMessageNow (const MidiMessage& message) +{ + if (auto* androidMidi = internal.get()) + { + auto* env = getEnv(); + auto messageSize = message.getRawDataSize(); + + LocalRef messageContent (env->NewByteArray (messageSize)); + auto content = messageContent.get(); + + auto* rawBytes = env->GetByteArrayElements (content, nullptr); + std::memcpy (rawBytes, message.getRawData(), static_cast (messageSize)); + env->ReleaseByteArrayElements (content, rawBytes, 0); + + androidMidi->send (content, (jint) 0, (jint) messageSize); + } +} + +MidiDeviceListConnection MidiDeviceListConnection::make (std::function callback) +{ + auto& broadcaster = MidiDeviceListConnectionBroadcaster::get(); + return { &broadcaster, broadcaster.add (std::move (callback)) }; +} + +} // namespace juce diff --git a/modules/juce_audio_devices/native/juce_linux_Midi.cpp b/modules/juce_audio_devices/native/juce_Midi_linux.cpp similarity index 67% rename from modules/juce_audio_devices/native/juce_linux_Midi.cpp rename to modules/juce_audio_devices/native/juce_Midi_linux.cpp index 3f87c27d0cd1..97ba3b8fe768 100644 --- a/modules/juce_audio_devices/native/juce_linux_Midi.cpp +++ b/modules/juce_audio_devices/native/juce_Midi_linux.cpp @@ -26,38 +26,32 @@ namespace juce #if JUCE_ALSA //============================================================================== -class AlsaClient : public ReferenceCountedObject +class AlsaClient { -public: - AlsaClient() + auto lowerBound (int portId) const { - jassert (instance == nullptr); - - snd_seq_open (&handle, "default", SND_SEQ_OPEN_DUPLEX, 0); - - if (handle != nullptr) - { - snd_seq_nonblock (handle, SND_SEQ_NONBLOCK); - snd_seq_set_client_name (handle, getAlsaMidiName().toRawUTF8()); - clientId = snd_seq_client_id (handle); + const auto comparator = [] (const auto& port, const auto& id) { return port->getPortId() < id; }; + return std::lower_bound (ports.begin(), ports.end(), portId, comparator); + } - // It's good idea to pre-allocate a good number of elements - ports.ensureStorageAllocated (32); - } + auto findPortIterator (int portId) const + { + const auto iter = lowerBound (portId); + return (iter == ports.end() || (*iter)->getPortId() != portId) ? ports.end() : iter; } +public: ~AlsaClient() { - jassert (instance != nullptr); - instance = nullptr; + inputThread.reset(); jassert (activeCallbacks.get() == 0); - if (inputThread) - inputThread->stopThread (3000); - if (handle != nullptr) + { + snd_seq_delete_simple_port (handle, announcementsIn); snd_seq_close (handle); + } } static String getAlsaMidiName() @@ -72,15 +66,12 @@ class AlsaClient : public ReferenceCountedObject #endif } - using Ptr = ReferenceCountedObjectPtr; - //============================================================================== // represents an input or output port of the supplied AlsaClient struct Port { - Port (AlsaClient& c, bool forInput) noexcept - : client (c), isInput (forInput) - {} + explicit Port (bool forInput) noexcept + : isInput (forInput) {} ~Port() { @@ -91,21 +82,21 @@ class AlsaClient : public ReferenceCountedObject else snd_midi_event_free (midiParser); - snd_seq_delete_simple_port (client.get(), portId); + snd_seq_delete_simple_port (client->get(), portId); } } void connectWith (int sourceClient, int sourcePort) const noexcept { if (isInput) - snd_seq_connect_from (client.get(), portId, sourceClient, sourcePort); + snd_seq_connect_from (client->get(), portId, sourceClient, sourcePort); else - snd_seq_connect_to (client.get(), portId, sourceClient, sourcePort); + snd_seq_connect_to (client->get(), portId, sourceClient, sourcePort); } bool isValid() const noexcept { - return client.get() != nullptr && portId >= 0; + return client->get() != nullptr && portId >= 0; } void setupInput (MidiInput* input, MidiInputCallback* cb) @@ -123,15 +114,7 @@ class AlsaClient : public ReferenceCountedObject void enableCallback (bool enable) { - const auto oldValue = callbackEnabled.exchange (enable); - - if (oldValue != enable) - { - if (enable) - client.registerCallback(); - else - client.unregisterCallback(); - } + callbackEnabled = enable; } bool sendMessageNow (const MidiMessage& message) @@ -149,7 +132,7 @@ class AlsaClient : public ReferenceCountedObject auto numBytes = (long) message.getRawDataSize(); auto* data = message.getRawData(); - auto seqHandle = client.get(); + auto seqHandle = client->get(); bool success = true; while (numBytes > 0) @@ -188,7 +171,7 @@ class AlsaClient : public ReferenceCountedObject void createPort (const String& name, bool enableSubscription) { - if (auto seqHandle = client.get()) + if (auto seqHandle = client->get()) { const unsigned int caps = isInput ? (SND_SEQ_PORT_CAP_WRITE | (enableSubscription ? SND_SEQ_PORT_CAP_SUBS_WRITE : 0)) @@ -217,7 +200,7 @@ class AlsaClient : public ReferenceCountedObject const String& getPortName() const { return portName; } private: - AlsaClient& client; + const std::shared_ptr client = AlsaClient::getInstance(); MidiInputCallback* callback = nullptr; snd_midi_event_t* midiParser = nullptr; @@ -230,36 +213,23 @@ class AlsaClient : public ReferenceCountedObject bool isInput = false; }; - static Ptr getInstance() - { - if (instance == nullptr) - instance = new AlsaClient(); - - return instance; - } - - void registerCallback() + static std::shared_ptr getInstance() { - if (inputThread == nullptr) - inputThread.reset (new MidiInputThread (*this)); - - if (++activeCallbacks == 1) - inputThread->startThread(); - } + static std::weak_ptr ptr; - void unregisterCallback() - { - jassert (activeCallbacks.get() > 0); + if (auto locked = ptr.lock()) + return locked; - if (--activeCallbacks == 0 && inputThread->isThreadRunning()) - inputThread->signalThreadShouldExit(); + std::shared_ptr result (new AlsaClient()); + ptr = result; + return result; } void handleIncomingMidiMessage (snd_seq_event* event, const MidiMessage& message) { const ScopedLock sl (callbackLock); - if (auto* port = ports[event->dest.port]) + if (auto* port = findPort (event->dest.port)) port->handleIncomingMidiMessage (message); } @@ -267,7 +237,7 @@ class AlsaClient : public ReferenceCountedObject { const ScopedLock sl (callbackLock); - if (auto* port = ports[event->dest.port]) + if (auto* port = findPort (event->dest.port)) port->handlePartialSysexMessage (messageData, numBytesSoFar, timeStamp); } @@ -278,10 +248,13 @@ class AlsaClient : public ReferenceCountedObject { const ScopedLock sl (callbackLock); - auto port = new Port (*this, forInput); + auto port = new Port (forInput); port->createPort (name, enableSubscription); - ports.set (port->getPortId(), port); - incReferenceCount(); + + const auto iter = lowerBound (port->getPortId()); + jassert (iter == ports.end() || port->getPortId() < (*iter)->getPortId()); + ports.insert (iter, rawToUniquePtr (port)); + return port; } @@ -289,31 +262,96 @@ class AlsaClient : public ReferenceCountedObject { const ScopedLock sl (callbackLock); - ports.set (port->getPortId(), nullptr); - decReferenceCount(); + if (const auto iter = findPortIterator (port->getPortId()); iter != ports.end()) + ports.erase (iter); } private: + AlsaClient() + { + snd_seq_open (&handle, "default", SND_SEQ_OPEN_DUPLEX, 0); + + if (handle != nullptr) + { + snd_seq_nonblock (handle, SND_SEQ_NONBLOCK); + snd_seq_set_client_name (handle, getAlsaMidiName().toRawUTF8()); + clientId = snd_seq_client_id (handle); + + // It's good idea to pre-allocate a good number of elements + ports.reserve (32); + + announcementsIn = snd_seq_create_simple_port (handle, + TRANS ("announcements").toRawUTF8(), + SND_SEQ_PORT_CAP_WRITE, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_connect_from (handle, announcementsIn, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE); + + inputThread.emplace (*this); + } + } + + Port* findPort (int portId) + { + if (const auto iter = findPortIterator (portId); iter != ports.end()) + return iter->get(); + + return nullptr; + } + snd_seq_t* handle = nullptr; int clientId = 0; - OwnedArray ports; + int announcementsIn = 0; + std::vector> ports; Atomic activeCallbacks; CriticalSection callbackLock; - static AlsaClient* instance; - //============================================================================== - class MidiInputThread : public Thread + class SequencerThread { public: - MidiInputThread (AlsaClient& c) - : Thread ("JUCE MIDI Input"), client (c) + explicit SequencerThread (AlsaClient& c) + : client (c) + { + } + + ~SequencerThread() noexcept { - jassert (client.get() != nullptr); + shouldStop = true; + thread.join(); } - void run() override + private: + // If we directly call MidiDeviceListConnectionBroadcaster::get() from the background thread, + // there's a possibility that we'll deadlock in the following scenario: + // - The main thread calls MidiDeviceListConnectionBroadcaster::get() for the first time + // (e.g. to register a listener). The static MidiDeviceListConnectionBroadcaster singleton + // begins construction. During the constructor, an AlsaClient is created to iterate midi + // ins/outs. + // - The AlsaClient starts a new SequencerThread. If connections are updated, the + // SequencerThread may call MidiDeviceListConnectionBroadcaster::get().notify() + // while the MidiDeviceListConnectionBroadcaster singleton is still being created. + // - The SequencerThread blocks until the MidiDeviceListConnectionBroadcaster has been + // created on the main thread, but the MidiDeviceListConnectionBroadcaster's constructor + // can't complete until the AlsaClient's destructor has run, which in turn requires the + // SequencerThread to join. + class UpdateNotifier : private AsyncUpdater { + public: + ~UpdateNotifier() override { cancelPendingUpdate(); } + using AsyncUpdater::triggerAsyncUpdate; + + private: + void handleAsyncUpdate() override { MidiDeviceListConnectionBroadcaster::get().notify(); } + }; + + AlsaClient& client; + MidiDataConcatenator concatenator { 2048 }; + std::atomic shouldStop { false }; + UpdateNotifier notifier; + std::thread thread { [this] + { + Thread::setCurrentThreadName ("JUCE MIDI Input"); + auto seqHandle = client.get(); const int maxEventSize = 16 * 1024; @@ -321,17 +359,20 @@ class AlsaClient : public ReferenceCountedObject if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) { - auto numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); - HeapBlock pfd (numPfds); - snd_seq_poll_descriptors (seqHandle, pfd, (unsigned int) numPfds, POLLIN); + const ScopeGuard freeMidiEvent { [&] { snd_midi_event_free (midiParser); } }; - HeapBlock buffer (maxEventSize); + const auto numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); + std::vector pfd (static_cast (numPfds)); + snd_seq_poll_descriptors (seqHandle, pfd.data(), (unsigned int) numPfds, POLLIN); - while (! threadShouldExit()) + std::vector buffer (maxEventSize); + + while (! shouldStop) { - if (poll (pfd, (nfds_t) numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call + // This timeout shouldn't be too long, so that the program can exit in a timely manner + if (poll (pfd.data(), (nfds_t) numPfds, 100) > 0) { - if (threadShouldExit()) + if (shouldStop) break; do @@ -340,44 +381,60 @@ class AlsaClient : public ReferenceCountedObject if (snd_seq_event_input (seqHandle, &inputEvent) >= 0) { + const ScopeGuard freeInputEvent { [&] { snd_seq_free_event (inputEvent); } }; + + constexpr int systemEvents[] + { + SND_SEQ_EVENT_CLIENT_CHANGE, + SND_SEQ_EVENT_CLIENT_START, + SND_SEQ_EVENT_CLIENT_EXIT, + SND_SEQ_EVENT_PORT_CHANGE, + SND_SEQ_EVENT_PORT_START, + SND_SEQ_EVENT_PORT_EXIT, + SND_SEQ_EVENT_PORT_SUBSCRIBED, + SND_SEQ_EVENT_PORT_UNSUBSCRIBED, + }; + + const auto foundEvent = std::find (std::begin (systemEvents), + std::end (systemEvents), + inputEvent->type); + + if (foundEvent != std::end (systemEvents)) + { + notifier.triggerAsyncUpdate(); + continue; + } + // xxx what about SYSEXes that are too big for the buffer? - auto numBytes = snd_midi_event_decode (midiParser, buffer, - maxEventSize, inputEvent); + const auto numBytes = snd_midi_event_decode (midiParser, + buffer.data(), + maxEventSize, + inputEvent); snd_midi_event_reset_decode (midiParser); - concatenator.pushMidiData (buffer, (int) numBytes, + concatenator.pushMidiData (buffer.data(), (int) numBytes, Time::getMillisecondCounter() * 0.001, inputEvent, client); - - snd_seq_free_event (inputEvent); } } while (snd_seq_event_input_pending (seqHandle, 0) > 0); } } - - snd_midi_event_free (midiParser); } - } - - private: - AlsaClient& client; - MidiDataConcatenator concatenator { 2048 }; + } }; }; - std::unique_ptr inputThread; + std::optional inputThread; }; -AlsaClient* AlsaClient::instance = nullptr; - //============================================================================== static String getFormattedPortIdentifier (int clientId, int portId) { return String (clientId) + "-" + String (portId); } -static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, +static AlsaClient::Port* iterateMidiClient (AlsaClient& client, snd_seq_client_info_t* clientInfo, bool forInput, Array& devices, @@ -385,7 +442,7 @@ static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, { AlsaClient::Port* port = nullptr; - auto seqHandle = client->get(); + auto seqHandle = client.get(); snd_seq_port_info_t* portInfo = nullptr; snd_seq_port_info_alloca (&portInfo); @@ -412,7 +469,7 @@ static AlsaClient::Port* iterateMidiClient (const AlsaClient::Ptr& client, { if (portID != -1) { - port = client->createPort (portName, forInput, false); + port = client.createPort (portName, forInput, false); jassert (port->isValid()); port->connectWith (sourceClient, portID); break; @@ -450,8 +507,11 @@ static AlsaClient::Port* iterateMidiDevices (bool forInput, { if (snd_seq_query_next_client (seqHandle, clientInfo) == 0) { - port = iterateMidiClient (client, clientInfo, forInput, - devices, deviceIdentifierToOpen); + port = iterateMidiClient (*client, + clientInfo, + forInput, + devices, + deviceIdentifierToOpen); if (port != nullptr) break; @@ -659,6 +719,18 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) internal->ptr->sendMessageNow (message); } +MidiDeviceListConnection MidiDeviceListConnection::make (std::function cb) +{ + auto& broadcaster = MidiDeviceListConnectionBroadcaster::get(); + // We capture the AlsaClient instance here to ensure that it remains alive for at least as long + // as the MidiDeviceListConnection. This is necessary because system change messages will only + // be processed when the AlsaClient's SequencerThread is running. + return { &broadcaster, broadcaster.add ([fn = std::move (cb), client = AlsaClient::getInstance()] + { + NullCheckedInvocation::invoke (fn); + }) }; +} + //============================================================================== #else @@ -693,6 +765,12 @@ StringArray MidiOutput::getDevices() int MidiOutput::getDefaultDeviceIndex() { return 0;} std::unique_ptr MidiOutput::openDevice (int) { return {}; } +MidiDeviceListConnection MidiDeviceListConnection::make (std::function cb) +{ + auto& broadcaster = MidiDeviceListConnectionBroadcaster::get(); + return { &broadcaster, broadcaster.add (std::move (cb)) }; +} + #endif } // namespace juce diff --git a/modules/juce_audio_devices/native/juce_win32_Midi.cpp b/modules/juce_audio_devices/native/juce_Midi_windows.cpp similarity index 96% rename from modules/juce_audio_devices/native/juce_win32_Midi.cpp rename to modules/juce_audio_devices/native/juce_Midi_windows.cpp index c2b13f70983a..05ee23d6c176 100644 --- a/modules/juce_audio_devices/native/juce_win32_Midi.cpp +++ b/modules/juce_audio_devices/native/juce_Midi_windows.cpp @@ -103,7 +103,7 @@ struct MidiServiceType struct Win32MidiService : public MidiServiceType, private Timer { - Win32MidiService() {} + Win32MidiService() = default; Array getAvailableDevices (bool isInput) override { @@ -1871,6 +1871,10 @@ struct MidiService : public DeletedAtShutdown private: std::unique_ptr internal; + DeviceChangeDetector detector { L"JuceMidiDeviceDetector_", [] + { + MidiDeviceListConnectionBroadcaster::get().notify(); + } }; }; JUCE_IMPLEMENT_SINGLETON (MidiService) @@ -2013,4 +2017,10 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) internal->sendMessageNow (message); } +MidiDeviceListConnection MidiDeviceListConnection::make (std::function cb) +{ + auto& broadcaster = MidiDeviceListConnectionBroadcaster::get(); + return { &broadcaster, broadcaster.add (std::move (cb)) }; +} + } // namespace juce diff --git a/modules/juce_audio_devices/native/juce_android_Oboe.cpp b/modules/juce_audio_devices/native/juce_Oboe_android.cpp similarity index 95% rename from modules/juce_audio_devices/native/juce_android_Oboe.cpp rename to modules/juce_audio_devices/native/juce_Oboe_android.cpp index 42a9efc9154e..95d00d3cb3c5 100644 --- a/modules/juce_audio_devices/native/juce_android_Oboe.cpp +++ b/modules/juce_audio_devices/native/juce_Oboe_android.cpp @@ -478,7 +478,7 @@ class OboeAudioIODevice : public AudioIODevice auto nextState = oboe::StreamState::Started; int64 timeoutNanos = 1000 * oboe::kNanosPerMillisecond; - auto startResult = stream->requestStart(); + [[maybe_unused]] auto startResult = stream->requestStart(); JUCE_OBOE_LOG ("Requested Oboe stream start with result: " + getOboeString (startResult)); startResult = stream->waitForStateChange (expectedState, &nextState, timeoutNanos); @@ -751,8 +751,6 @@ class OboeAudioIODevice : public AudioIODevice void start() override { - audioCallbackGuard.set (0); - if (inputStream != nullptr) inputStream->start(); @@ -764,13 +762,10 @@ class OboeAudioIODevice : public AudioIODevice void stop() override { - while (! audioCallbackGuard.compareAndSetBool (1, 0)) - Thread::sleep (1); + const SpinLock::ScopedLockType lock { audioCallbackMutex }; inputStream = nullptr; outputStream = nullptr; - - audioCallbackGuard.set (0); } int getOutputLatencyInSamples() override { return outputLatency; } @@ -788,7 +783,9 @@ class OboeAudioIODevice : public AudioIODevice oboe::DataCallbackResult onAudioReady (oboe::AudioStream* stream, void* audioData, int32_t numFrames) override { - if (audioCallbackGuard.compareAndSetBool (1, 0)) + const SpinLock::ScopedTryLockType lock { audioCallbackMutex }; + + if (lock.isLocked()) { if (stream == nullptr) return oboe::DataCallbackResult::Stop; @@ -797,8 +794,9 @@ class OboeAudioIODevice : public AudioIODevice jassert (stream->getDirection() == oboe::Direction::Output && stream == outputStream->getNativeStream()); // Read input from Oboe - inputStreamSampleBuffer.clear(); - inputStreamNativeBuffer.calloc (static_cast (numInputChannels * bufferSize)); + const auto expandedBufferSize = jmax (inputStreamNativeBuffer.size(), + static_cast (numInputChannels * jmax (bufferSize, numFrames))); + inputStreamNativeBuffer.resize (expandedBufferSize); if (inputStream != nullptr) { @@ -811,17 +809,17 @@ class OboeAudioIODevice : public AudioIODevice return oboe::DataCallbackResult::Continue; } - auto result = inputStream->getNativeStream()->read (inputStreamNativeBuffer.getData(), numFrames, 0); + auto result = inputStream->getNativeStream()->read (inputStreamNativeBuffer.data(), numFrames, 0); if (result) { auto referringDirectlyToOboeData = OboeAudioIODeviceBufferHelpers - ::referAudioBufferDirectlyToOboeIfPossible (inputStreamNativeBuffer.get(), + ::referAudioBufferDirectlyToOboeIfPossible (inputStreamNativeBuffer.data(), inputStreamSampleBuffer, result.value()); if (! referringDirectlyToOboeData) - OboeAudioIODeviceBufferHelpers::convertFromOboe (inputStreamNativeBuffer.get(), inputStreamSampleBuffer, result.value()); + OboeAudioIODeviceBufferHelpers::convertFromOboe (inputStreamNativeBuffer.data(), inputStreamSampleBuffer, result.value()); } else { @@ -853,8 +851,6 @@ class OboeAudioIODevice : public AudioIODevice if (isOutputLatencyDetectionSupported) outputLatency = getLatencyFor (*outputStream); - - audioCallbackGuard.set (0); } return oboe::DataCallbackResult::Continue; @@ -944,13 +940,14 @@ class OboeAudioIODevice : public AudioIODevice if (error == oboe::Result::ErrorDisconnected) { - if (streamRestartGuard.compareAndSetBool (1, 0)) + const SpinLock::ScopedTryLockType streamRestartLock { streamRestartMutex }; + + if (streamRestartLock.isLocked()) { // Close, recreate, and start the stream, not much use in current one. // Use default device id, to let the OS pick the best ID (since our was disconnected). - while (! audioCallbackGuard.compareAndSetBool (1, 0)) - Thread::sleep (1); + const SpinLock::ScopedLockType audioCallbackLock { audioCallbackMutex }; outputStream = nullptr; outputStream.reset (new OboeStream (oboe::kUnspecified, @@ -963,18 +960,14 @@ class OboeAudioIODevice : public AudioIODevice this)); outputStream->start(); - - audioCallbackGuard.set (0); - streamRestartGuard.set (0); } } } - HeapBlock inputStreamNativeBuffer; + std::vector inputStreamNativeBuffer; AudioBuffer inputStreamSampleBuffer, outputStreamSampleBuffer; - Atomic audioCallbackGuard { 0 }, - streamRestartGuard { 0 }; + SpinLock audioCallbackMutex, streamRestartMutex; bool isInputLatencyDetectionSupported = false; int inputLatency = -1; diff --git a/modules/juce_audio_devices/native/juce_android_OpenSL.cpp b/modules/juce_audio_devices/native/juce_OpenSL_android.cpp similarity index 100% rename from modules/juce_audio_devices/native/juce_android_OpenSL.cpp rename to modules/juce_audio_devices/native/juce_OpenSL_android.cpp diff --git a/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp b/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp similarity index 94% rename from modules/juce_audio_devices/native/juce_win32_WASAPI.cpp rename to modules/juce_audio_devices/native/juce_WASAPI_windows.cpp index b516cdbba9b0..92122988b2b7 100644 --- a/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp +++ b/modules/juce_audio_devices/native/juce_WASAPI_windows.cpp @@ -1694,13 +1694,11 @@ class WASAPIAudioIODevice : public AudioIODevice, //============================================================================== -class WASAPIAudioIODeviceType : public AudioIODeviceType, - private DeviceChangeDetector +class WASAPIAudioIODeviceType : public AudioIODeviceType { public: - WASAPIAudioIODeviceType (WASAPIDeviceMode mode) + explicit WASAPIAudioIODeviceType (WASAPIDeviceMode mode) : AudioIODeviceType (getDeviceTypename (mode)), - DeviceChangeDetector (L"Windows Audio"), deviceMode (mode) { } @@ -1715,22 +1713,15 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, void scanForDevices() override { hasScanned = true; - - outputDeviceNames.clear(); - inputDeviceNames.clear(); - outputDeviceIds.clear(); - inputDeviceIds.clear(); - - scan (outputDeviceNames, inputDeviceNames, - outputDeviceIds, inputDeviceIds); + devices = scan(); } StringArray getDeviceNames (bool wantInputNames) const override { jassert (hasScanned); // need to call scanForDevices() before doing this - return wantInputNames ? inputDeviceNames - : outputDeviceNames; + return wantInputNames ? devices.inputDeviceNames + : devices.outputDeviceNames; } int getDefaultDeviceIndex (bool /*forInput*/) const override @@ -1744,8 +1735,8 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, jassert (hasScanned); // need to call scanForDevices() before doing this if (auto d = dynamic_cast (device)) - return asInput ? inputDeviceIds.indexOf (d->inputDeviceId) - : outputDeviceIds.indexOf (d->outputDeviceId); + return asInput ? devices.inputDeviceIds .indexOf (d->inputDeviceId) + : devices.outputDeviceIds.indexOf (d->outputDeviceId); return -1; } @@ -1759,16 +1750,16 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, std::unique_ptr device; - auto outputIndex = outputDeviceNames.indexOf (outputDeviceName); - auto inputIndex = inputDeviceNames.indexOf (inputDeviceName); + auto outputIndex = devices.outputDeviceNames.indexOf (outputDeviceName); + auto inputIndex = devices.inputDeviceNames .indexOf (inputDeviceName); if (outputIndex >= 0 || inputIndex >= 0) { device.reset (new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName : inputDeviceName, getTypeName(), - outputDeviceIds [outputIndex], - inputDeviceIds [inputIndex], + devices.outputDeviceIds[outputIndex], + devices.inputDeviceIds [inputIndex], deviceMode)); if (! device->initialise()) @@ -1779,10 +1770,24 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, } //============================================================================== - StringArray outputDeviceNames, outputDeviceIds; - StringArray inputDeviceNames, inputDeviceIds; + struct Devices + { + StringArray outputDeviceNames, outputDeviceIds; + StringArray inputDeviceNames, inputDeviceIds; + + auto tie() const + { + return std::tie (outputDeviceNames, outputDeviceIds, inputDeviceNames, inputDeviceIds); + } + + bool operator== (const Devices& other) const { return tie() == other.tie(); } + bool operator!= (const Devices& other) const { return tie() != other.tie(); } + }; + + Devices devices; private: + DeviceChangeDetector deviceChangeDetector { L"Windows Audio", [this] { systemDeviceChanged(); } }; WASAPIDeviceMode deviceMode; bool hasScanned = false; ComSmartPtr enumerator; @@ -1791,7 +1796,7 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, class ChangeNotificationClient : public ComBaseClassHelper { public: - ChangeNotificationClient (WASAPIAudioIODeviceType* d) + explicit ChangeNotificationClient (WASAPIAudioIODeviceType* d) : ComBaseClassHelper (0), device (d) {} JUCE_COMRESULT OnDeviceAdded (LPCWSTR) { return notify(); } @@ -1806,7 +1811,7 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, HRESULT notify() { if (device != nullptr) - device->triggerAsyncDeviceChangeCallback(); + device->deviceChangeDetector.triggerAsyncDeviceChangeCallback(); return S_OK; } @@ -1840,15 +1845,12 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, } //============================================================================== - void scan (StringArray& outDeviceNames, - StringArray& inDeviceNames, - StringArray& outDeviceIds, - StringArray& inDeviceIds) + Devices scan() { if (enumerator == nullptr) { if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator)))) - return; + return {}; notifyClient = new ChangeNotificationClient (this); enumerator->RegisterEndpointNotificationCallback (notifyClient); @@ -1862,7 +1864,9 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, if (! (check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, deviceCollection.resetAndGetPointerAddress())) && check (deviceCollection->GetCount (&numDevices)))) - return; + return {}; + + Devices result; for (UINT32 i = 0; i < numDevices; ++i) { @@ -1902,40 +1906,33 @@ class WASAPIAudioIODeviceType : public AudioIODeviceType, if (flow == eRender) { const int index = (deviceId == defaultRenderer) ? 0 : -1; - outDeviceIds.insert (index, deviceId); - outDeviceNames.insert (index, name); + result.outputDeviceIds.insert (index, deviceId); + result.outputDeviceNames.insert (index, name); } else if (flow == eCapture) { const int index = (deviceId == defaultCapture) ? 0 : -1; - inDeviceIds.insert (index, deviceId); - inDeviceNames.insert (index, name); + result.inputDeviceIds.insert (index, deviceId); + result.inputDeviceNames.insert (index, name); } } - inDeviceNames.appendNumbersToDuplicates (false, false); - outDeviceNames.appendNumbersToDuplicates (false, false); + result.inputDeviceNames .appendNumbersToDuplicates (false, false); + result.outputDeviceNames.appendNumbersToDuplicates (false, false); + + return result; } //============================================================================== - void systemDeviceChanged() override + void systemDeviceChanged() { - StringArray newOutNames, newInNames, newOutIds, newInIds; - scan (newOutNames, newInNames, newOutIds, newInIds); + const auto newDevices = scan(); - if (newOutNames != outputDeviceNames - || newInNames != inputDeviceNames - || newOutIds != outputDeviceIds - || newInIds != inputDeviceIds) + if (std::exchange (devices, newDevices) != newDevices) { hasScanned = true; - outputDeviceNames = newOutNames; - inputDeviceNames = newInNames; - outputDeviceIds = newOutIds; - inputDeviceIds = newInIds; + callDeviceChangeListeners(); } - - callDeviceChangeListeners(); } //============================================================================== diff --git a/modules/juce_audio_devices/native/juce_android_Midi.cpp b/modules/juce_audio_devices/native/juce_android_Midi.cpp deleted file mode 100644 index 08825325c8e2..000000000000 --- a/modules/juce_audio_devices/native/juce_android_Midi.cpp +++ /dev/null @@ -1,701 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - JUCE is an open source library subject to commercial or open-source - licensing. - - The code included in this file is provided under the terms of the ISC license - http://www.isc.org/downloads/software-support-policy/isc-license. Permission - To use, copy, modify, and/or distribute this software for any purpose with or - without fee is hereby granted provided that the above copyright notice and - this permission notice appear in all copies. - - JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER - EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE - DISCLAIMED. - - ============================================================================== -*/ - -namespace juce -{ - -//============================================================================== -// This byte-code is generated from native/java/com/rmsl/juce/JuceMidiSupport.java with min sdk version 23 -// See juce_core/native/java/README.txt on how to generate this byte-code. -static const uint8 javaMidiByteCode[] = -{31,139,8,8,43,113,161,94,0,3,106,97,118,97,77,105,100,105,66,121,116,101,67,111,100,101,46,100,101,120,0,149,124,11,124,220, -69,181,255,153,223,99,119,179,217,36,155,77,218,164,105,178,217,164,73,179,165,205,171,233,35,109,146,182,121,180,77,218,164,45, -201,182,72,195,5,183,201,182,217,146,236,134,236,166,180,114,189,20,244,210,162,168,40,80,65,177,162,2,242,18,81,65,80,17,81, -80,81,81,122,149,63,214,39,138,112,69,69,64,20,17,229,218,255,247,204,204,110,126,109,3,213,246,243,221,51,191,51,103,206,204, -156,57,115,230,204,111,183,29,141,237,247,54,181,44,167,234,195,55,252,236,231,159,31,184,160,244,71,71,143,188,248,212,248, -199,142,188,62,189,243,225,179,11,151,53,157,77,52,73,68,251,119,44,11,144,254,243,246,109,68,231,10,197,95,15,60,105,19,157,3, -250,188,139,40,4,250,134,151,232,179,76,115,137,114,64,211,133,68,55,174,33,186,22,26,254,86,79,244,119,224,255,0,163,129,200, -6,22,3,13,64,43,176,14,232,1,54,1,219,128,93,192,81,224,105,224,31,192,63,1,163,145,200,13,132,129,173,192,32,240,54,224,66, -224,82,224,125,192,167,128,91,129,59,128,207,2,247,2,95,6,30,2,30,1,190,3,188,4,20,55,17,173,4,118,1,215,0,15,3,127,0,252,205, -68,109,192,249,192,101,192,221,192,143,128,23,129,130,165,68,29,192,46,224,74,224,51,192,47,129,146,22,162,85,192,249,192,101, -192,17,224,46,224,155,192,79,128,63,2,198,50,216,14,120,47,240,16,240,10,16,90,78,148,0,238,5,126,11,204,89,65,180,2,216,9,188, -3,248,24,240,32,112,28,120,9,48,86,162,47,96,49,176,22,216,1,164,129,107,128,219,129,135,1,187,149,168,9,232,1,222,6,76,0,151, -1,71,128,187,128,175,2,79,0,214,42,244,7,132,129,181,192,32,112,29,112,59,112,63,240,75,224,215,192,115,192,239,129,151,129,191, -1,111,0,98,53,214,1,200,7,138,128,82,32,8,212,0,139,129,165,192,10,96,21,208,1,116,2,235,129,56,112,61,240,16,240,35,224,121, -224,85,64,180,17,121,129,2,160,20,88,8,180,0,107,129,141,192,185,192,52,112,37,240,81,224,115,192,35,192,15,128,227,192,239, -129,87,128,215,1,119,59,244,0,149,192,66,160,30,88,1,116,3,3,192,78,96,4,184,8,216,15,92,2,28,2,62,0,220,0,124,10,248,60,240,53, -224,7,192,79,129,231,128,63,1,175,3,86,7,244,3,107,129,62,96,28,120,31,112,45,240,73,224,110,224,94,224,107,192,163,192,49,224, -23,192,235,192,92,236,133,122,160,11,56,15,72,1,239,4,174,6,62,10,220,9,220,15,60,12,252,1,120,5,120,29,48,214,98,46,192,86, -224,0,112,45,112,23,112,31,240,13,224,127,128,223,0,127,4,222,0,242,214,97,254,64,24,88,9,172,3,54,1,219,128,97,224,124,96,4, -136,3,147,192,37,192,97,224,58,224,40,240,105,224,94,224,33,224,49,224,41,224,103,192,111,128,151,128,191,1,255,4,188,157,68, -21,64,61,176,26,88,3,116,3,189,192,22,96,59,112,1,16,3,246,2,83,192,21,192,199,129,251,128,199,129,231,128,215,0,111,23,209,60, -96,17,176,14,56,27,24,3,46,2,46,5,62,8,220,9,124,9,248,54,240,4,240,28,240,119,192,213,13,95,6,26,128,94,224,60,96,28,184,24, -184,12,184,10,184,6,248,56,112,43,240,21,224,199,192,203,192,95,129,55,0,119,15,81,33,48,31,88,12,44,7,122,128,45,192,249,64, -12,216,11,92,14,188,7,56,2,124,10,120,8,248,22,240,4,240,99,224,23,192,51,192,171,128,23,65,178,8,168,0,106,129,197,192,70,224, -108,96,23,144,4,46,5,174,2,62,4,220,0,220,12,124,1,248,10,240,117,224,123,192,83,192,207,129,103,129,151,128,191,1,198,6,216, -11,88,6,108,1,182,3,5,136,185,197,64,53,176,0,168,1,106,129,133,64,29,16,6,22,1,103,1,139,129,37,0,194,49,33,180,18,66,34,33, -252,17,194,28,33,164,17,66,22,33,68,17,194,18,33,244,16,66,11,33,108,16,182,63,97,203,18,182,26,97,59,16,220,154,224,114,132, -37,36,44,5,193,148,212,163,207,7,12,137,54,2,189,64,31,176,9,216,12,244,3,3,192,22,96,43,128,99,133,112,220,208,32,48,4,68,128, -29,192,219,128,97,224,63,128,11,248,252,1,118,1,163,64,12,216,13,140,3,255,9,92,10,28,4,46,3,46,7,222,5,188,155,148,77,50,127, -252,154,78,98,226,133,186,188,31,229,50,80,67,63,115,217,212,229,74,93,158,212,50,150,230,87,233,242,65,205,247,56,228,113,4, -210,85,154,159,171,249,243,129,60,224,90,205,207,119,244,85,224,40,7,28,242,197,90,158,203,165,142,182,101,142,190,202,245,216, -88,38,168,101,42,117,121,82,151,25,55,106,153,106,45,83,161,203,55,47,81,178,92,190,75,203,215,56,218,214,234,182,220,15,251, -208,3,122,12,13,142,113,54,58,198,214,228,24,27,151,31,94,162,242,2,46,63,182,100,134,159,177,103,179,67,79,179,99,252,92,62, -230,40,103,230,184,204,209,87,171,163,47,246,201,227,154,191,90,243,217,47,58,116,121,66,151,185,109,66,151,127,133,114,82,151, -159,95,162,114,26,46,255,5,229,139,116,217,194,230,216,175,203,62,148,167,116,185,20,229,148,46,135,80,222,167,203,75,80,190, -88,151,151,57,202,235,234,103,116,246,59,202,55,58,250,138,56,248,231,57,250,29,117,240,39,29,229,253,142,126,15,58,248,135,29, -109,175,70,249,64,166,47,135,252,109,40,191,67,151,239,113,180,61,230,24,15,175,93,70,254,49,7,127,210,81,126,208,209,215,163, -40,79,103,244,160,124,137,46,31,119,216,234,87,40,167,117,249,133,122,181,111,215,232,53,122,167,46,243,26,253,151,46,179,253, -51,229,135,29,252,140,255,116,234,182,92,238,114,248,67,183,195,31,122,52,127,190,46,95,43,125,190,137,238,39,69,215,10,110, -83,64,87,201,182,205,244,1,73,87,210,135,36,245,80,135,96,31,46,165,247,242,90,163,247,231,37,21,244,71,73,107,169,74,214,47,164, -197,130,227,66,177,148,171,210,252,42,205,95,160,159,153,110,19,188,199,44,250,48,49,245,211,95,36,85,245,53,186,190,86,143,167, -22,145,247,136,164,93,116,167,164,37,244,138,164,203,232,53,93,95,46,20,13,10,181,71,111,39,166,107,232,247,164,227,190,224, -216,95,73,31,228,50,36,95,37,142,117,30,122,84,82,147,190,37,169,77,63,37,142,117,110,250,184,164,213,244,85,77,159,228,117, -192,137,241,49,77,63,43,169,69,223,150,116,11,45,135,126,27,124,55,113,28,236,165,62,193,116,5,13,8,190,3,40,190,55,75,189,116, -189,164,57,180,30,245,62,173,39,79,215,231,129,115,189,164,185,212,45,20,237,17,28,35,243,232,235,196,180,138,126,70,28,199, -213,120,252,136,164,63,144,180,128,74,4,83,63,205,23,28,219,213,184,57,198,63,165,233,207,73,197,215,239,75,58,72,199,37,45,164, -159,104,62,215,23,107,189,197,56,165,214,65,207,28,61,174,18,156,74,223,145,180,137,230,8,166,171,105,174,164,29,212,44,105, -59,237,16,28,167,85,251,82,216,255,168,166,108,175,121,90,79,25,198,255,32,113,60,13,208,151,136,227,176,65,183,72,63,92,47,235, -217,239,20,21,244,136,164,181,244,61,73,183,211,15,37,221,72,66,250,235,98,42,148,116,9,5,36,61,155,106,36,221,68,155,36,221, -64,219,165,95,174,147,250,66,122,92,76,239,149,84,217,39,132,72,254,11,73,7,232,15,186,62,79,182,235,167,34,73,55,83,151,80,252, -94,77,251,165,95,175,149,122,171,180,222,42,173,183,74,235,173,210,250,170,116,251,42,221,190,74,183,175,214,237,170,181,124, -181,150,175,214,242,213,90,190,90,203,47,192,78,231,254,22,32,43,49,228,243,50,50,53,181,36,93,74,182,164,203,201,165,169,91, -243,243,53,45,144,180,153,252,154,22,203,253,214,37,245,214,160,255,143,72,90,77,223,144,212,69,223,37,117,22,62,46,233,89, -180,90,238,51,181,62,181,122,190,181,240,148,251,36,157,71,95,148,116,33,61,36,169,90,191,90,248,205,99,146,238,160,39,36,221,78, -199,52,253,31,73,139,232,71,146,214,208,255,147,116,62,253,88,210,85,228,145,253,181,82,142,166,94,161,248,185,146,182,145,79, -168,120,80,42,233,92,154,39,105,41,149,73,186,149,170,37,109,164,5,146,118,83,139,164,27,40,34,227,68,189,156,199,66,100,94, -247,232,56,241,180,140,15,103,97,230,138,186,37,157,67,95,147,180,140,30,38,62,235,23,75,126,163,150,135,118,26,18,76,43,232, -109,130,207,118,213,174,73,219,167,9,158,254,77,226,51,92,245,211,12,59,255,142,56,183,236,145,114,45,240,124,222,15,203,116, -187,101,144,59,172,159,111,212,207,55,73,90,71,47,232,231,165,66,229,1,27,37,141,208,160,224,28,53,76,239,35,206,83,149,158, -21,186,253,10,200,127,66,210,74,217,207,10,100,191,47,75,26,162,38,161,248,172,111,165,110,183,82,247,191,82,247,179,82,247,179, -82,247,211,138,241,255,146,152,6,233,159,196,121,135,26,215,106,77,219,180,158,54,100,187,107,4,231,199,234,185,93,251,23,159, -77,96,203,119,35,36,227,2,206,50,36,226,55,32,17,62,178,69,229,97,194,53,147,71,113,253,213,168,127,98,139,122,14,233,246,204, -127,251,18,69,111,66,253,31,116,125,149,174,111,114,212,63,128,250,186,173,170,126,129,214,107,59,244,31,67,253,144,174,175,209, -252,118,71,253,175,80,255,30,93,95,171,245,207,1,198,180,254,151,81,255,57,93,191,80,183,115,142,127,29,228,22,109,83,207, -117,142,241,101,234,183,161,190,91,215,115,14,30,197,197,96,108,64,201,165,52,189,124,96,166,238,26,71,249,227,186,254,14,7, -239,11,186,252,16,232,55,29,229,99,3,42,151,103,153,159,1,255,171,219,254,73,83,99,139,162,69,154,134,53,237,208,52,162,105,108, -203,76,95,251,53,239,93,91,88,183,33,203,231,111,80,247,140,73,127,30,158,171,225,59,147,254,79,226,121,216,111,33,234,15,251, -13,26,14,24,56,183,88,158,245,36,55,168,123,66,4,53,23,249,175,32,62,21,19,161,113,172,181,87,222,13,44,45,183,111,131,186,67, -92,36,123,241,137,68,200,192,126,130,172,223,150,207,124,30,152,168,99,217,119,109,80,103,94,36,100,81,164,202,130,204,45,168, -241,138,5,184,224,38,66,183,98,124,62,248,98,143,148,177,101,22,128,188,17,109,230,130,78,249,111,71,159,62,49,229,255,52,183, -49,90,141,60,240,110,67,153,219,248,40,16,72,52,173,130,39,133,95,206,215,35,35,58,186,65,217,129,239,53,46,57,51,220,179,55, -168,123,99,160,112,105,177,77,129,170,150,226,66,140,163,16,253,249,176,127,114,41,210,204,227,226,91,148,207,72,132,62,5,223, -13,116,182,20,87,34,126,205,161,50,227,66,186,40,212,12,222,76,139,192,41,45,110,150,181,150,182,69,59,34,105,190,156,11,247, -253,205,13,234,94,227,180,85,39,180,32,122,106,253,95,208,250,3,162,64,68,154,149,229,133,148,252,79,105,169,240,171,94,104,98, -237,79,109,80,239,56,3,37,1,151,214,7,61,94,42,179,160,199,206,147,122,34,232,59,33,47,151,62,177,74,100,234,124,186,46,252, -74,107,206,114,170,54,188,240,4,182,89,153,101,161,191,38,182,178,149,8,249,113,6,85,155,121,168,11,192,114,137,80,49,178,101, -230,207,193,45,215,103,5,106,185,20,161,5,233,117,232,161,0,173,125,246,128,109,185,46,242,127,68,181,247,23,161,149,207,78, -172,203,165,206,255,14,127,53,17,242,225,6,28,254,18,101,253,203,187,81,221,73,79,246,175,75,225,95,249,200,211,92,202,231,55, -170,123,232,164,191,1,109,134,23,228,208,112,141,139,134,107,189,180,115,161,7,150,63,47,228,150,107,107,75,255,18,84,183,81, -197,146,128,25,233,116,81,171,112,19,211,132,127,49,234,34,157,57,224,228,72,26,233,242,162,175,255,130,157,135,187,161,179,219, -5,45,121,122,5,2,122,5,194,207,171,120,196,186,133,168,199,241,37,228,152,218,209,7,199,206,132,159,51,254,164,255,42,237,95, -25,31,239,217,168,226,104,36,132,126,170,184,159,41,233,215,133,50,142,8,233,151,155,54,170,189,26,128,229,132,230,109,219,56, -227,171,249,152,63,223,221,119,108,84,123,171,35,215,71,67,151,121,200,125,208,125,141,184,89,220,103,125,107,159,167,83,203, -90,250,246,191,219,209,222,208,99,153,218,168,98,98,196,159,163,60,213,15,171,64,98,187,223,45,125,133,159,19,161,37,24,95,192, -127,158,223,125,82,219,75,222,162,109,107,182,109,61,183,165,76,91,30,11,143,225,221,122,109,39,253,124,235,24,22,62,26,54,114, -105,24,222,148,159,93,171,107,29,107,149,171,215,42,23,86,93,32,215,202,167,215,202,135,181,202,203,174,21,244,116,231,254, -27,107,117,123,118,173,250,102,93,171,207,101,215,10,253,84,229,205,186,86,247,103,214,10,158,232,214,51,252,42,120,69,220, -174,89,143,28,52,177,174,134,58,99,51,99,235,20,122,108,175,169,119,50,122,108,222,204,122,63,233,88,175,12,239,167,14,158,41,71, -137,115,110,163,122,143,51,44,10,96,79,182,234,176,145,47,227,180,122,27,244,130,163,77,198,23,254,58,11,207,232,117,198,66, -75,206,41,191,87,197,227,64,168,197,46,128,15,36,224,179,38,172,193,81,195,195,251,23,113,231,157,242,54,51,163,167,162,247,116, -221,139,102,225,45,159,133,215,217,123,242,252,248,207,192,44,188,115,28,60,91,90,14,231,90,47,71,8,182,67,17,236,240,25,105, -7,156,91,102,33,13,91,60,66,75,90,209,164,169,94,245,30,168,220,168,161,10,35,32,134,155,3,88,249,187,81,3,159,109,246,99,189, -10,36,77,192,103,133,46,113,180,97,73,63,158,11,33,225,149,52,225,47,213,252,66,10,26,184,235,137,160,81,39,242,68,248,53,158, -205,60,212,85,202,241,153,50,255,112,73,159,90,116,105,253,146,69,186,108,208,7,122,85,78,90,110,98,44,102,100,16,186,141,5, -196,52,225,159,199,49,83,36,252,213,242,52,11,44,107,233,154,11,110,21,71,123,163,204,186,6,190,216,136,8,204,103,155,137,253, -230,201,158,48,65,179,16,40,195,242,133,223,200,67,169,206,80,249,195,66,180,172,215,190,36,112,255,202,248,239,103,122,85,125, -196,239,207,250,53,215,124,161,55,115,190,171,209,200,248,235,87,111,10,213,249,174,246,233,151,122,249,30,137,57,8,204,65,68, -154,2,24,77,30,69,154,10,249,14,64,252,28,89,10,13,161,125,136,220,65,193,254,31,20,117,164,250,44,146,125,21,99,223,168,179, -252,209,94,245,14,53,96,77,250,107,97,185,225,72,49,13,239,40,134,69,138,169,204,252,51,180,148,224,70,228,51,42,141,18,26,30, -44,1,191,132,86,225,124,42,51,176,163,204,49,185,219,113,115,194,153,181,2,62,240,81,62,19,6,231,225,105,25,158,62,36,159,74, -79,170,43,59,233,105,142,212,151,240,47,100,203,83,149,25,48,150,47,245,210,6,76,51,17,74,35,214,29,55,12,172,173,148,105,90, -68,131,86,248,113,143,62,171,254,212,171,114,207,200,72,41,218,31,225,157,97,113,30,98,145,215,108,53,155,100,30,98,201,113,7, -41,130,160,86,105,250,165,77,205,153,21,54,3,203,91,134,126,123,66,175,176,89,102,171,21,30,202,174,240,79,78,232,21,54,19,161, -247,227,172,101,205,79,156,40,52,2,70,248,159,46,61,142,185,125,234,253,120,164,171,12,250,63,206,243,48,166,252,119,104,250, -105,80,110,53,95,142,199,144,154,27,41,210,13,217,208,81,57,150,74,172,97,194,63,34,71,192,189,12,73,249,103,79,20,138,128,8, -255,147,227,140,242,158,230,62,245,174,189,220,174,165,10,59,146,230,89,95,207,179,181,22,116,117,241,89,144,86,118,192,156,93, -66,102,100,46,212,181,90,115,101,207,46,104,175,52,131,116,28,241,46,130,43,81,165,165,172,193,121,193,128,101,8,33,194,191,13, -218,133,70,158,21,180,235,44,246,139,6,217,107,163,244,19,254,59,214,167,222,209,151,91,232,31,190,50,193,185,150,57,60,52, -151,130,214,204,106,39,66,23,82,140,103,162,86,196,228,113,152,114,28,65,57,14,53,227,133,50,170,207,145,185,203,53,216,81,9, -255,229,188,30,214,69,254,43,117,166,195,220,240,51,121,102,208,170,51,121,158,108,197,5,77,156,145,222,192,86,196,92,144,145, -154,60,78,142,24,43,179,123,108,5,185,244,110,186,70,175,75,185,129,241,26,145,78,101,29,49,51,38,209,42,74,51,99,194,170,4, -229,109,183,82,40,187,200,252,206,95,41,243,187,150,179,159,63,17,52,56,222,4,40,252,127,42,226,168,189,84,39,123,10,19,231,157, -220,239,93,125,234,59,136,114,47,250,244,182,250,139,41,48,47,209,148,162,27,243,124,88,211,45,20,249,250,60,204,224,99,200, -197,185,119,55,86,45,232,45,164,192,162,240,139,131,205,243,105,50,116,17,238,192,62,119,171,123,21,69,246,97,44,46,68,70,87,11, -164,90,225,175,131,205,21,104,59,31,121,183,15,121,118,14,110,11,33,114,127,221,122,118,159,139,223,144,182,98,6,172,189,218, -106,129,158,171,97,197,68,211,77,212,108,5,189,225,99,24,177,183,78,168,246,101,220,222,211,234,249,221,137,106,156,131,147,235, -122,233,225,214,240,51,65,47,102,246,32,201,251,124,55,102,196,223,189,168,44,104,163,244,63,94,255,122,48,249,253,98,192,21, -73,97,55,134,206,194,126,80,190,16,73,205,129,205,110,228,83,42,165,246,128,90,249,59,100,182,201,214,182,165,79,151,72,107,219, -210,3,26,149,44,246,64,145,92,77,222,3,187,32,31,254,157,90,243,128,57,140,250,32,116,207,59,85,163,99,151,151,57,118,249,66, -146,178,208,184,64,106,108,65,187,15,202,118,149,102,53,228,182,177,246,223,12,239,155,7,185,217,34,70,117,70,151,242,5,83,80, -43,34,6,211,74,211,146,39,147,233,120,114,201,167,76,84,41,101,221,63,83,122,175,69,153,179,26,206,190,56,143,89,4,251,45,211, -249,141,192,109,182,64,223,21,70,54,169,247,211,51,123,39,242,212,92,170,218,19,48,197,242,229,211,45,216,107,46,59,225,15,113, -244,241,84,93,9,238,178,229,215,214,32,50,122,144,199,7,101,244,106,249,205,92,170,246,46,204,156,16,185,129,162,150,53,240, -166,162,132,191,130,235,125,147,235,14,210,151,31,225,189,244,73,58,110,90,66,44,11,63,29,48,195,127,58,110,218,66,44,15,255,160, -208,176,245,222,190,114,147,218,43,129,80,185,192,138,194,243,63,192,86,49,86,25,33,120,83,28,62,193,62,135,155,153,63,200,39, -245,210,57,210,139,187,228,141,207,141,179,37,252,87,117,194,76,134,246,106,89,139,185,127,8,138,128,204,3,121,190,243,49,38, -158,77,142,180,67,69,54,167,61,186,73,249,93,192,63,25,74,200,155,99,97,182,238,230,76,93,104,166,46,160,199,124,199,38,245,253, -158,7,188,237,158,114,106,245,108,193,189,75,237,60,15,242,163,72,46,172,249,96,192,35,174,92,254,157,77,176,91,110,78,192, -208,59,218,195,109,6,243,230,83,203,241,85,196,54,134,230,188,170,95,6,60,203,159,111,166,13,86,158,135,45,140,249,187,90,246, -177,117,43,164,135,200,54,5,21,212,242,231,114,240,202,217,83,108,182,19,124,27,251,41,63,147,39,120,202,114,254,33,79,145,235, -81,95,105,55,243,14,183,3,117,225,123,143,123,60,34,124,236,184,39,71,136,43,195,247,7,189,101,72,142,195,127,206,243,96,111, -122,56,131,28,68,235,183,103,227,216,5,217,187,241,156,205,234,59,56,142,172,221,50,42,201,40,230,184,115,23,56,238,220,11,101, -44,133,55,24,45,131,47,159,96,107,241,25,98,105,159,59,107,179,186,187,241,249,199,185,87,160,185,197,111,194,79,35,56,227,3, -34,177,46,76,77,129,240,235,252,78,219,144,57,212,50,200,223,196,241,44,15,86,205,75,139,121,188,91,61,108,69,15,172,19,112,7, -114,248,198,23,241,149,225,182,248,30,62,99,242,217,47,94,128,239,173,242,157,47,123,129,156,47,176,166,229,133,38,142,132,176, -144,135,124,190,178,124,117,206,190,32,45,132,115,214,86,183,115,68,6,75,233,83,254,213,143,182,173,190,118,154,225,29,5,207, -231,174,116,91,14,222,39,192,171,206,173,145,28,15,252,205,99,32,23,61,39,74,185,85,167,141,13,17,241,133,220,234,252,54,236, -183,59,49,235,214,156,38,42,242,29,115,95,246,176,237,231,156,17,59,121,221,93,244,144,63,152,151,159,25,143,143,117,240,14,120, -152,124,222,86,47,188,234,46,65,238,135,43,97,77,55,226,180,71,198,5,183,140,7,110,74,227,60,41,162,96,94,248,215,121,190,96, -94,157,175,200,55,74,225,31,230,249,194,175,241,89,49,141,21,226,239,215,216,155,142,100,115,185,235,197,165,245,71,197,245,130, -243,62,67,230,218,15,108,86,223,195,149,187,97,115,55,159,69,94,156,232,108,115,156,231,70,228,136,154,143,193,235,0,27,93,129, -117,104,117,33,154,30,65,236,9,93,71,183,226,121,149,171,150,78,150,59,10,57,159,171,210,197,81,118,84,230,2,39,215,127,2,245, -172,161,218,19,164,201,166,165,116,155,201,81,227,10,10,186,243,73,143,192,226,213,227,220,162,204,163,86,239,10,25,199,177,122, -162,92,90,75,200,92,85,82,23,91,44,142,213,109,181,225,91,67,42,102,182,154,30,29,69,85,244,228,168,233,165,240,19,121,174, -240,247,243,92,65,119,157,75,157,169,156,87,76,234,120,121,177,220,15,136,82,151,214,167,247,209,62,105,35,142,13,158,126,245, -61,127,57,102,90,33,109,227,37,175,205,231,231,185,242,253,207,64,54,54,71,4,122,23,22,5,138,3,115,90,144,248,4,172,200,117, -234,68,177,229,217,116,135,166,242,140,194,138,190,120,66,159,81,242,68,25,172,155,79,90,187,167,229,208,139,39,100,91,88,179, -86,122,174,58,97,108,89,86,39,12,34,100,113,248,241,86,225,209,55,25,117,139,137,92,199,107,243,97,212,6,93,200,197,237,160, -171,206,86,115,61,87,238,245,157,217,119,99,155,251,79,190,15,242,253,121,168,63,27,31,183,93,66,75,35,62,153,109,24,178,238, -63,250,213,61,148,223,197,5,140,201,193,75,168,219,207,245,57,114,191,27,20,235,87,191,169,8,20,113,236,227,93,195,107,196,223, -90,114,70,102,82,129,161,78,112,126,135,232,134,5,91,109,68,115,43,252,42,238,48,86,157,17,153,154,67,186,149,29,112,241,238, -25,116,69,166,138,193,155,43,179,219,192,156,106,215,2,248,203,14,218,231,78,172,195,9,24,243,33,171,193,138,59,218,201,86,34, -104,137,165,225,239,242,189,245,16,133,255,174,222,121,122,49,83,254,158,117,177,180,65,105,54,70,189,191,95,189,31,200,196, -164,58,196,36,117,15,85,86,250,176,182,71,196,63,79,238,126,126,55,165,252,194,162,155,250,213,111,63,120,142,94,185,51,56,186, -169,157,20,57,162,162,202,173,146,143,123,204,17,21,81,110,149,107,13,255,52,212,170,25,114,213,12,93,255,9,212,243,169,118, -187,244,230,0,234,98,236,41,50,91,177,179,187,140,178,187,136,61,31,178,176,46,124,175,251,164,91,135,43,17,186,24,187,66,101, -11,65,119,248,94,229,245,121,162,204,133,155,148,167,72,222,164,174,192,153,160,222,211,244,192,42,91,244,253,251,108,29,47, -206,209,249,174,65,67,151,214,239,24,202,190,219,249,75,191,243,221,206,185,98,62,157,103,148,211,185,102,133,124,107,165,110, -157,214,128,122,39,31,16,171,16,115,11,112,142,188,79,102,78,76,57,147,111,89,250,218,9,247,54,62,65,6,187,42,104,16,109,91, -150,190,120,98,123,87,57,109,55,203,81,126,254,196,96,215,124,240,113,106,46,125,230,68,160,48,252,116,230,29,31,206,168,1,245, -125,68,53,238,11,131,157,243,233,135,129,131,160,21,84,100,30,164,229,205,69,178,124,79,213,100,232,16,199,88,255,97,121,62, -109,239,196,153,141,157,18,248,211,231,171,10,68,145,184,148,194,47,65,235,223,213,13,25,121,211,128,246,123,216,172,18,8,98,46, -153,119,72,77,3,42,167,80,243,205,215,177,212,160,229,3,250,253,149,152,121,251,106,82,161,208,239,91,113,86,254,227,68,185, -81,135,251,192,46,17,164,85,2,89,180,168,196,154,181,32,35,143,131,19,148,252,240,243,153,28,191,80,234,16,250,187,18,33,51,24, -83,247,181,117,64,125,71,83,70,234,142,108,200,222,44,249,61,113,57,114,161,10,177,11,245,171,136,51,245,90,244,177,7,109,121, -38,65,201,15,191,152,185,147,231,233,62,42,178,125,148,203,223,192,10,34,202,216,130,231,122,83,64,125,199,116,27,232,61,217, -95,217,170,63,15,234,231,140,60,255,198,234,49,240,142,157,194,223,164,249,63,63,165,253,243,167,60,255,37,160,250,204,252,134, -137,223,57,90,69,234,183,69,197,69,234,187,152,242,34,245,155,9,31,232,152,214,27,7,173,193,243,133,160,75,138,212,111,63,150, -129,182,23,157,172,191,247,148,103,65,250,251,44,82,177,140,41,255,150,199,144,180,89,198,202,2,100,203,182,174,43,119,204,73, -144,202,105,12,253,100,106,186,134,102,126,167,149,249,30,201,144,180,73,62,47,212,252,238,172,156,79,183,85,191,50,81,125,173, -205,182,103,152,89,204,149,177,203,208,54,50,29,182,82,60,151,230,185,36,79,149,221,89,93,57,154,250,53,13,104,153,128,214,43, -223,179,211,204,247,103,114,143,201,12,90,217,158,101,249,251,228,133,186,95,254,46,119,161,222,139,181,248,107,105,234,215, -241,97,149,110,179,74,223,73,88,174,93,239,165,53,186,110,173,30,191,149,45,203,89,135,201,12,247,225,14,179,136,106,154,90,186, -90,155,214,47,239,172,95,223,179,190,181,126,89,87,75,75,125,231,202,229,205,245,43,186,215,183,44,91,223,189,172,123,101, -19,76,139,124,173,125,100,60,158,136,167,215,144,171,93,81,99,77,27,89,107,218,22,237,224,79,148,253,93,227,211,177,116,50,153, -30,27,136,38,162,123,98,83,180,250,84,78,40,54,53,149,156,90,29,26,73,78,143,143,134,18,201,116,104,79,44,29,202,74,133,250, -215,135,82,35,209,68,2,109,215,254,107,109,71,99,187,163,211,227,78,29,209,209,232,100,26,10,202,122,166,39,38,14,100,249,27, -163,233,116,119,116,124,124,87,116,228,66,18,125,100,244,245,147,217,215,223,79,149,125,91,67,235,247,143,196,38,211,241,36,130, -249,88,124,60,22,26,25,79,166,226,137,61,161,201,228,84,154,106,251,182,190,89,253,68,124,52,142,33,236,139,143,196,72,108,34, -107,211,246,238,245,84,184,105,122,36,54,128,154,190,196,228,116,122,27,171,8,100,88,91,167,211,25,158,47,195,147,79,197,153, -167,161,233,73,238,181,97,111,116,95,148,68,63,25,253,125,100,246,247,201,15,244,128,15,100,22,24,182,217,143,15,171,191,127, -103,63,213,244,71,19,163,83,201,248,104,227,174,204,108,27,179,243,238,84,230,104,163,5,111,37,213,35,231,208,70,85,111,37,196, -38,108,163,69,103,18,201,88,185,141,26,207,40,58,22,157,138,142,96,120,241,84,58,62,210,70,139,207,212,160,39,150,26,153,138, -79,166,147,83,179,15,100,60,54,35,223,31,27,82,190,52,251,220,33,202,245,51,163,125,19,125,44,180,33,62,142,65,214,116,77,199, -199,71,89,223,108,102,58,73,244,45,69,6,99,41,184,236,236,179,213,34,67,177,116,26,14,150,154,233,242,45,166,144,17,110,163, -121,89,161,145,100,34,29,75,164,27,187,153,238,71,103,149,217,170,137,216,104,60,218,200,174,219,200,14,151,89,250,37,111,45,208, -151,216,157,172,97,87,229,130,115,56,111,42,221,70,181,111,45,52,148,142,166,167,49,234,234,55,19,203,110,32,167,43,157,34,163, -163,67,141,82,57,179,154,43,207,212,96,107,66,53,217,58,25,75,196,70,251,225,129,49,233,43,161,51,52,124,139,185,207,236,110, -231,250,159,34,52,24,27,137,197,247,177,158,162,172,72,50,213,216,53,157,24,29,199,50,20,59,153,189,81,102,66,180,196,201,221, -22,157,26,137,141,111,159,142,143,182,81,32,91,49,157,142,143,55,246,39,247,156,198,219,22,141,79,57,250,202,242,218,104,251, -233,204,246,51,184,201,25,227,3,14,130,166,254,145,228,68,227,212,68,106,188,113,47,162,90,227,41,161,173,230,212,200,222,70, -205,103,104,113,90,68,109,163,165,255,98,19,231,154,44,249,23,219,40,233,254,51,72,207,88,37,235,131,111,122,226,180,81,207,191, -173,109,134,195,46,26,137,166,46,60,179,161,78,211,114,230,73,103,38,188,45,154,30,227,48,241,150,210,188,89,71,163,227,251, -226,23,54,34,180,38,177,129,113,40,54,174,79,232,3,177,123,60,154,194,134,14,206,34,211,199,145,88,215,87,205,82,63,16,155,216, -165,5,98,16,169,152,69,100,40,190,39,129,136,49,133,93,82,54,75,117,100,108,42,121,49,154,206,233,231,179,179,49,158,108,116, -28,220,109,84,168,216,227,209,196,158,70,61,142,34,7,171,15,113,82,218,43,224,96,110,221,181,55,54,146,62,153,55,148,158,194, -76,179,221,72,158,236,58,186,139,247,111,185,131,61,21,219,221,120,78,44,122,225,96,108,119,108,42,150,64,146,80,241,86,181, -188,249,101,181,220,141,157,83,83,209,3,28,150,50,61,157,204,109,163,238,217,216,237,255,206,106,175,225,67,111,86,37,167,77,119, -77,214,8,51,162,169,147,121,189,209,20,118,244,100,198,170,78,222,233,130,56,179,78,19,4,239,100,19,244,225,36,141,202,179,190, -192,193,149,54,241,159,194,104,163,150,83,56,237,103,60,128,215,156,172,87,118,95,232,96,68,226,19,236,16,115,78,101,169,173, -88,120,218,94,163,206,211,88,179,39,173,142,211,36,148,58,128,131,103,34,148,138,77,201,44,50,112,250,174,39,159,115,209,168, -214,121,228,55,116,119,246,247,119,117,118,111,190,32,114,238,182,245,23,12,116,70,186,123,47,232,223,58,20,33,177,131,140,29, -200,26,119,32,207,181,118,244,237,236,35,215,142,77,200,35,55,129,141,236,113,7,210,74,107,7,231,149,246,14,201,5,71,126,176, -116,191,170,68,217,230,207,77,138,32,23,221,177,147,4,210,79,40,51,144,119,26,195,93,84,61,124,230,84,168,126,248,223,74,45,106, -254,5,113,236,221,225,89,246,233,73,204,204,70,205,141,142,140,196,82,169,13,227,209,61,41,242,34,221,156,142,142,203,156,219, -157,185,42,152,209,209,81,126,26,157,130,28,249,116,239,125,137,209,216,126,180,86,79,178,133,55,58,57,169,51,42,114,69,83,202, -19,119,157,146,106,83,89,150,211,191,94,238,61,181,182,219,183,247,245,80,96,215,105,233,169,67,67,198,145,138,103,56,217,105, -167,28,114,23,232,59,71,206,174,116,167,30,181,103,87,90,201,65,76,151,82,124,160,195,4,228,218,149,230,195,136,236,93,156,77, -146,111,68,159,74,145,3,147,49,114,97,20,72,39,40,127,228,164,100,156,236,145,241,88,116,138,73,50,21,35,55,18,202,4,108,76, -185,186,32,21,122,56,205,140,198,19,41,201,150,165,205,177,3,82,88,218,200,167,11,145,228,118,232,176,177,11,18,105,18,163,228, -29,205,230,241,228,210,115,241,40,10,27,101,74,163,148,151,41,41,5,185,163,89,7,72,101,234,50,38,243,170,71,153,236,228,140,198, -167,48,68,132,125,176,227,169,204,208,93,177,139,176,244,41,202,145,155,178,59,57,10,3,198,50,7,4,53,236,142,226,106,55,26, -74,39,67,35,83,177,104,58,22,218,53,61,174,239,148,74,119,104,247,84,114,34,148,113,19,207,238,120,34,58,30,127,71,140,170,80, -26,157,89,168,13,201,41,199,237,75,9,87,178,72,102,67,207,38,96,239,142,79,193,153,124,187,97,162,209,204,130,123,185,67,229, -198,100,237,97,131,231,240,167,50,134,137,72,66,94,124,100,84,228,114,121,92,186,118,138,202,248,65,121,238,105,215,242,249, -51,117,167,199,176,57,92,57,57,57,30,31,145,167,106,198,219,139,192,62,109,208,165,78,166,51,167,151,90,78,191,136,145,7,108,121, -246,82,33,74,61,234,238,158,217,54,57,146,37,125,33,63,91,84,107,237,205,62,167,200,141,178,116,190,69,40,244,78,79,112,56,199, -70,198,225,171,44,53,171,117,33,10,199,146,100,84,106,96,189,84,141,2,31,144,167,25,99,75,116,130,153,125,61,41,170,59,93,70, -102,161,167,9,134,79,23,84,185,231,105,146,243,32,201,213,167,14,19,147,155,171,171,122,178,206,140,233,232,33,179,6,185,200, -188,194,242,33,47,243,48,205,185,19,249,245,35,31,19,220,172,71,218,91,249,131,20,157,74,78,198,166,210,113,244,83,128,199,193, -216,68,50,29,203,4,13,48,134,228,81,164,163,149,236,82,6,136,188,49,121,11,209,247,22,114,143,69,83,91,216,37,60,40,140,201, -93,100,141,37,225,187,57,252,169,124,83,196,201,140,143,238,39,43,206,102,182,227,114,17,115,226,217,247,33,185,241,84,118,242, -252,208,173,118,104,12,19,141,167,214,79,76,166,15,112,65,218,153,171,103,94,164,120,226,58,37,32,15,167,55,189,220,175,111,175, -243,69,138,121,33,2,144,11,31,156,97,120,199,147,136,117,42,144,187,39,180,135,91,124,158,144,119,34,107,102,42,156,56,109, -27,228,79,156,180,10,148,59,225,8,196,198,196,4,153,19,169,61,248,72,79,147,149,224,181,176,249,19,81,33,17,187,152,247,0,140, -146,96,35,153,201,93,123,201,149,220,189,59,133,225,4,146,137,174,104,122,100,108,38,7,73,81,9,246,216,73,129,23,79,137,61,176, -68,241,169,21,236,230,52,231,84,238,57,83,48,137,212,162,108,136,61,43,251,87,106,200,159,76,204,188,51,145,26,10,157,28,213, -58,47,169,239,194,112,68,244,156,159,60,233,106,204,125,58,159,123,98,227,209,3,96,23,100,216,236,72,251,156,114,42,8,100,38, -226,78,38,54,140,79,167,198,200,151,76,12,164,167,51,108,140,140,199,163,188,112,48,149,138,83,41,115,198,227,188,149,229,184, -186,147,19,147,136,192,144,69,75,153,80,200,8,157,121,82,22,132,113,145,13,37,164,189,180,235,166,122,56,230,227,138,13,217, -34,184,124,226,148,24,69,94,102,234,114,30,151,103,28,172,132,31,79,186,106,158,19,79,143,97,43,149,102,42,102,46,148,186,38, -144,169,113,240,242,153,231,120,217,151,195,207,106,39,122,146,153,188,46,39,83,66,128,194,224,248,16,75,206,52,177,147,23,115, -200,44,154,132,251,157,58,129,178,89,152,67,233,216,100,228,226,36,149,156,84,55,19,76,200,154,228,244,209,146,239,52,115,38, -101,186,197,251,194,51,169,51,47,85,146,129,37,63,83,210,17,75,214,200,236,51,47,83,82,27,93,86,200,40,145,159,41,69,146,27,112, -214,145,61,41,103,107,242,22,158,59,21,219,195,239,87,166,78,126,73,67,174,41,233,57,228,85,84,133,6,85,86,249,214,188,41,28, -217,177,84,122,198,183,183,77,197,147,240,141,3,220,86,46,191,123,74,111,36,48,210,251,162,227,100,77,177,47,153,83,211,9,42, -76,101,179,80,253,30,141,138,82,142,236,57,195,116,103,94,58,123,82,35,99,177,81,28,251,228,74,197,144,54,140,146,149,98,223, -42,227,79,245,182,119,44,58,26,234,219,26,154,201,27,60,92,199,102,166,2,236,241,110,103,106,149,11,6,123,234,0,7,201,124,126, -208,153,224,116,124,20,149,99,124,41,192,94,193,68,173,20,39,18,118,74,62,228,72,194,13,41,79,21,211,201,73,249,232,74,169,227, -213,74,129,131,158,51,252,28,120,79,102,149,211,99,113,24,131,63,107,154,80,129,11,11,26,77,76,146,59,157,148,183,54,242,164, -147,58,167,152,51,157,152,205,187,230,157,194,118,248,80,233,116,226,77,214,210,134,237,167,113,58,72,178,117,55,69,196,205, -194,157,111,188,76,109,251,141,171,47,109,171,167,152,120,15,24,116,129,36,135,76,58,34,44,218,73,224,124,85,8,178,172,7,140,213, -163,238,252,19,38,221,111,228,237,180,137,62,33,196,231,89,254,22,97,124,68,220,111,184,243,47,236,55,233,54,97,213,95,111,83, -199,254,126,23,53,28,121,7,196,62,32,164,190,195,82,95,195,254,16,237,21,223,54,220,75,32,251,1,97,54,24,21,23,27,123,42,250, -77,241,65,145,211,240,158,134,157,166,241,160,145,251,225,157,166,249,85,35,127,243,206,142,71,250,182,218,134,109,210,141,74, -201,17,250,190,176,94,23,135,196,103,140,103,240,216,94,143,63,237,244,186,32,119,197,150,183,111,62,80,95,111,76,87,84,154, -244,5,209,64,199,193,204,111,111,167,163,6,207,224,105,126,162,107,101,249,253,134,245,119,113,153,113,139,248,33,198,92,127, -11,221,96,152,234,25,117,207,177,220,163,59,59,232,165,76,225,78,195,84,29,170,238,232,167,198,44,157,221,107,168,206,94,146, -29,124,69,126,126,111,70,237,150,11,140,75,50,162,95,151,149,223,146,159,55,153,6,6,143,65,180,215,211,189,166,241,21,113,35, -143,225,30,211,228,210,227,232,145,62,239,40,127,154,203,143,27,255,132,76,199,230,15,211,23,249,241,211,170,234,1,71,249,33, -46,255,67,149,31,228,242,151,13,89,254,50,119,32,75,119,103,75,223,54,45,250,140,184,77,60,8,157,59,121,118,199,76,140,171,163, -29,139,243,37,99,109,255,206,225,53,91,206,95,83,111,147,177,191,205,69,244,146,172,236,143,155,226,57,81,116,224,17,185,160, -245,231,219,100,139,249,149,171,232,160,197,83,122,183,252,124,15,127,118,28,218,31,44,167,235,45,118,179,10,227,176,213,102, -188,126,201,146,250,71,251,141,252,139,141,125,21,251,247,239,63,16,71,55,162,91,233,91,189,198,22,244,126,151,92,102,17,240, -91,198,171,162,178,243,144,179,171,111,115,79,182,65,71,181,208,92,191,73,183,139,38,200,28,53,106,111,227,74,186,220,195,253, -30,54,141,255,21,221,65,147,158,21,66,184,109,50,5,10,143,88,38,107,20,134,45,92,36,114,109,114,137,74,219,172,151,26,127,105, -137,187,97,142,142,120,229,176,101,220,105,44,31,22,197,126,83,220,110,212,237,55,14,124,131,37,214,187,12,140,245,255,196,122, -186,218,35,238,224,5,16,129,2,139,88,225,175,67,54,205,175,60,139,254,100,153,183,139,95,139,63,112,101,187,153,243,89,67,244, -155,38,84,52,30,50,106,150,24,219,43,108,211,206,89,238,50,93,57,123,45,247,221,104,215,176,217,116,221,38,10,27,224,22,47,137, -5,13,123,77,227,19,198,188,122,12,143,118,217,6,246,206,173,205,152,145,105,187,108,183,113,17,140,143,150,46,151,123,175,233, -249,173,152,35,165,132,233,34,195,87,1,33,136,216,158,74,186,7,54,175,24,238,24,22,115,11,48,118,209,244,77,91,172,110,175,228, -39,227,101,81,7,147,218,70,3,27,22,91,180,178,179,127,255,59,174,180,105,184,157,94,112,203,169,99,222,247,24,203,119,30,49, -177,3,138,238,229,185,7,226,183,236,91,213,191,200,22,219,176,135,239,182,217,228,21,29,123,227,43,140,253,21,135,154,91,227, -13,149,116,92,46,245,143,228,231,119,221,226,86,168,57,96,186,49,241,142,251,228,178,5,77,227,21,33,110,189,213,180,160,13,179, -189,219,16,152,180,121,155,33,246,110,54,237,59,140,165,113,225,181,237,6,151,93,203,38,198,92,45,219,182,93,198,72,133,237,94, -238,18,46,195,101,241,148,141,75,218,80,225,50,74,54,177,20,252,236,117,183,113,183,113,59,59,64,113,129,73,159,54,234,46,196, -0,239,113,161,71,119,254,37,229,244,172,75,60,193,107,185,217,244,96,12,232,246,118,33,130,166,251,43,194,174,52,115,158,23, -107,159,57,16,124,196,180,57,20,109,54,173,235,196,210,91,133,199,118,215,163,159,242,139,121,0,247,154,185,240,166,251,68,161, -223,206,13,26,163,21,24,132,125,139,229,125,141,87,108,111,67,251,218,117,182,119,133,26,40,91,221,206,89,197,99,116,121,92,57, -174,92,35,221,102,231,178,60,125,204,173,198,0,71,68,239,143,30,62,193,219,208,62,98,4,111,182,205,160,177,187,2,61,99,108, -143,152,66,13,131,48,140,67,150,45,251,232,119,153,13,237,93,114,233,237,205,77,210,48,22,61,160,102,215,113,216,34,237,58,240, -229,194,1,83,200,89,89,247,25,107,59,130,188,29,120,161,15,139,194,130,96,53,214,186,125,205,48,154,195,170,193,114,24,232, -105,151,218,241,159,178,13,118,83,148,110,179,5,91,145,224,224,71,132,123,137,26,134,49,103,204,72,84,116,196,141,188,37,198, -190,182,91,132,223,47,59,105,248,72,195,60,250,133,20,204,143,211,29,46,185,216,59,233,25,233,22,249,70,120,204,24,174,232,56, -124,136,227,138,141,142,207,179,13,172,48,236,200,147,131,5,218,113,34,108,182,172,215,102,198,126,73,167,109,194,139,97,72, -172,47,124,27,86,171,52,5,199,199,191,27,230,157,226,179,226,189,58,188,211,251,77,113,208,112,87,180,204,251,98,189,73,55,25, -117,116,136,163,16,182,159,73,191,17,77,159,183,169,29,145,233,81,236,251,138,122,106,103,87,252,130,71,124,10,190,138,16,118, -88,152,134,111,137,113,113,197,133,29,155,247,195,115,110,145,53,249,135,106,141,119,84,40,142,17,22,63,54,74,235,140,69,198, -127,11,43,231,31,162,36,215,88,12,78,185,85,114,126,137,93,50,84,226,81,143,118,137,40,137,130,177,164,36,71,138,214,228,184, -32,91,58,211,108,174,177,132,229,68,233,210,25,94,137,82,94,171,56,6,56,249,51,197,248,140,220,30,227,44,110,107,148,214,148, -46,200,116,119,158,236,189,102,166,127,102,156,93,178,33,195,112,151,156,3,198,26,160,9,82,222,12,147,165,122,75,182,227,179, -39,195,244,96,232,67,37,102,86,54,171,209,144,42,122,51,12,23,24,51,50,114,112,94,12,110,175,26,156,171,180,182,116,97,105,85, -105,168,180,178,180,90,148,88,194,20,57,102,153,129,63,194,104,57,120,208,58,182,112,153,56,88,39,196,109,192,147,192,225,48, -220,30,56,14,60,185,72,136,155,206,18,130,255,145,50,185,182,93,230,33,49,11,200,54,114,92,250,135,56,130,58,46,59,104,189,123, -137,117,185,65,107,196,189,75,132,117,125,189,16,15,212,27,226,231,160,47,3,239,110,16,226,30,224,81,224,96,35,2,188,59,87,182, -235,69,187,7,27,251,196,175,26,133,245,104,147,16,207,2,135,155,133,184,17,248,21,240,151,102,50,132,55,223,16,87,135,118,64, -244,240,210,115,196,109,75,133,120,16,56,6,60,11,92,223,34,196,93,192,195,192,147,192,243,192,27,45,100,9,219,143,201,10,110, -26,69,211,171,151,237,18,15,44,195,8,150,11,241,216,10,104,7,14,175,36,183,59,80,172,196,244,223,61,144,125,114,165,97,92,181, -74,24,215,174,54,141,55,86,11,227,141,54,211,184,171,195,107,220,180,102,204,122,99,173,41,30,239,130,165,186,77,241,100,15, -102,215,99,136,171,214,99,164,27,48,132,141,120,6,158,221,4,221,3,232,99,11,248,192,213,91,13,113,207,86,240,183,193,18,103,195, -186,103,195,2,198,124,193,127,14,10,116,120,253,208,101,152,212,16,38,19,225,159,231,5,189,194,251,46,113,248,160,245,66,132, -107,15,111,23,57,55,1,87,237,200,252,255,74,206,223,244,100,254,239,64,254,173,74,230,255,15,228,223,169,100,254,15,65,254,157, -74,136,212,255,35,200,191,213,201,252,95,130,46,154,249,255,4,77,191,250,29,141,252,61,85,72,253,63,82,219,192,112,133,148,12, -255,123,122,225,87,191,125,231,127,3,111,132,84,191,252,255,15,154,90,158,255,141,182,21,82,191,75,226,127,199,109,135,212,248, -248,223,224,147,214,195,255,38,159,127,204,195,124,254,127,15,255,63,171,27,97,244,48,81,0,0,0,0}; - -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - STATICMETHOD (getAndroidMidiDeviceManager, "getAndroidMidiDeviceManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$MidiDeviceManager;") \ - STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothManager;") - -DECLARE_JNI_CLASS_WITH_BYTECODE (JuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23, javaMidiByteCode) -#undef JNI_CLASS_MEMBERS - -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (getJuceAndroidMidiInputDeviceNameAndIDs, "getJuceAndroidMidiInputDeviceNameAndIDs", "()[Ljava/lang/String;") \ - METHOD (getJuceAndroidMidiOutputDeviceNameAndIDs, "getJuceAndroidMidiOutputDeviceNameAndIDs", "()[Ljava/lang/String;") \ - METHOD (openMidiInputPortWithID, "openMidiInputPortWithID", "(IJ)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") \ - METHOD (openMidiOutputPortWithID, "openMidiOutputPortWithID", "(I)Lcom/rmsl/juce/JuceMidiSupport$JuceMidiPort;") - -DECLARE_JNI_CLASS_WITH_MIN_SDK (MidiDeviceManager, "com/rmsl/juce/JuceMidiSupport$MidiDeviceManager", 23) -#undef JNI_CLASS_MEMBERS - -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - METHOD (start, "start", "()V") \ - METHOD (stop, "stop", "()V") \ - METHOD (close, "close", "()V") \ - METHOD (sendMidi, "sendMidi", "([BII)V") \ - METHOD (getName, "getName", "()Ljava/lang/String;") - -DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiPort", 23) -#undef JNI_CLASS_MEMBERS - -//============================================================================== -class MidiInput::Pimpl -{ -public: - Pimpl (MidiInput* midiInput, int deviceID, juce::MidiInputCallback* midiInputCallback, jobject deviceManager) - : juceMidiInput (midiInput), callback (midiInputCallback), midiConcatenator (2048), - javaMidiDevice (LocalRef(getEnv()->CallObjectMethod (deviceManager, MidiDeviceManager.openMidiInputPortWithID, - (jint) deviceID, (jlong) this))) - { - } - - ~Pimpl() - { - if (jobject d = javaMidiDevice.get()) - { - getEnv()->CallVoidMethod (d, JuceMidiPort.close); - javaMidiDevice.clear(); - } - } - - bool isOpen() const noexcept - { - return javaMidiDevice != nullptr; - } - - void start() - { - if (jobject d = javaMidiDevice.get()) - getEnv()->CallVoidMethod (d, JuceMidiPort.start); - } - - void stop() - { - if (jobject d = javaMidiDevice.get()) - getEnv()->CallVoidMethod (d, JuceMidiPort.stop); - - callback = nullptr; - } - - String getName() const noexcept - { - if (jobject d = javaMidiDevice.get()) - return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); - - return {}; - } - - void handleMidi (jbyteArray byteArray, jlong offset, jint len, jlong timestamp) - { - auto* env = getEnv(); - - jassert (byteArray != nullptr); - auto* data = env->GetByteArrayElements (byteArray, nullptr); - - HeapBlock buffer (static_cast (len)); - std::memcpy (buffer.get(), data + offset, static_cast (len)); - - midiConcatenator.pushMidiData (buffer.get(), - len, static_cast (timestamp) * 1.0e-9, - juceMidiInput, *callback); - - env->ReleaseByteArrayElements (byteArray, data, 0); - } - - static void handleReceive (JNIEnv*, jobject, jlong host, jbyteArray byteArray, - jint offset, jint len, jlong timestamp) - { - auto* myself = reinterpret_cast (host); - - myself->handleMidi (byteArray, offset, len, timestamp); - } - -private: - MidiInput* juceMidiInput; - MidiInputCallback* callback; - MidiDataConcatenator midiConcatenator; - GlobalRef javaMidiDevice; -}; - -//============================================================================== -class MidiOutput::Pimpl -{ -public: - Pimpl (const LocalRef& midiDevice) - : javaMidiDevice (midiDevice) - { - } - - ~Pimpl() - { - if (jobject d = javaMidiDevice.get()) - { - getEnv()->CallVoidMethod (d, JuceMidiPort.close); - javaMidiDevice.clear(); - } - } - - void send (jbyteArray byteArray, jint offset, jint len) - { - if (jobject d = javaMidiDevice.get()) - getEnv()->CallVoidMethod (d, - JuceMidiPort.sendMidi, - byteArray, offset, len); - } - - String getName() const noexcept - { - if (jobject d = javaMidiDevice.get()) - return juceString (LocalRef ((jstring) getEnv()->CallObjectMethod (d, JuceMidiPort.getName))); - - return {}; - } - -private: - GlobalRef javaMidiDevice; -}; - -//============================================================================== -#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - CALLBACK (MidiInput::Pimpl::handleReceive, "handleReceive", "(J[BIIJ)V" ) - -DECLARE_JNI_CLASS_WITH_MIN_SDK (JuceMidiInputPort, "com/rmsl/juce/JuceMidiSupport$JuceMidiInputPort", 23) -#undef JNI_CLASS_MEMBERS - -//============================================================================== -class AndroidMidiDeviceManager -{ -public: - AndroidMidiDeviceManager() - : deviceManager (LocalRef(getEnv()->CallStaticObjectMethod (JuceMidiSupport, - JuceMidiSupport.getAndroidMidiDeviceManager, - getAppContext().get()))) - { - } - - Array getDevices (bool input) - { - if (jobject dm = deviceManager.get()) - { - jobjectArray jDeviceNameAndIDs - = (jobjectArray) getEnv()->CallObjectMethod (dm, input ? MidiDeviceManager.getJuceAndroidMidiInputDeviceNameAndIDs - : MidiDeviceManager.getJuceAndroidMidiOutputDeviceNameAndIDs); - - // Create a local reference as converting this to a JUCE string will call into JNI - LocalRef localDeviceNameAndIDs (jDeviceNameAndIDs); - - auto deviceNameAndIDs = javaStringArrayToJuce (localDeviceNameAndIDs); - deviceNameAndIDs.appendNumbersToDuplicates (false, false, CharPointer_UTF8 ("-"), CharPointer_UTF8 ("")); - - Array devices; - - for (int i = 0; i < deviceNameAndIDs.size(); i += 2) - devices.add ({ deviceNameAndIDs[i], deviceNameAndIDs[i + 1] }); - - return devices; - } - - return {}; - } - - MidiInput::Pimpl* openMidiInputPortWithID (int deviceID, MidiInput* juceMidiInput, juce::MidiInputCallback* callback) - { - if (auto dm = deviceManager.get()) - { - auto androidMidiInput = std::make_unique (juceMidiInput, deviceID, callback, dm); - - if (androidMidiInput->isOpen()) - return androidMidiInput.release(); - } - - return nullptr; - } - - MidiOutput::Pimpl* openMidiOutputPortWithID (int deviceID) - { - if (auto dm = deviceManager.get()) - if (auto javaMidiPort = getEnv()->CallObjectMethod (dm, MidiDeviceManager.openMidiOutputPortWithID, (jint) deviceID)) - return new MidiOutput::Pimpl (LocalRef(javaMidiPort)); - - return nullptr; - } - -private: - GlobalRef deviceManager; -}; - -//============================================================================== -Array MidiInput::getAvailableDevices() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - AndroidMidiDeviceManager manager; - return manager.getDevices (true); -} - -MidiDeviceInfo MidiInput::getDefaultDevice() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - return getAvailableDevices().getFirst(); -} - -std::unique_ptr MidiInput::openDevice (const String& deviceIdentifier, MidiInputCallback* callback) -{ - if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) - return {}; - - AndroidMidiDeviceManager manager; - - std::unique_ptr midiInput (new MidiInput ({}, deviceIdentifier)); - - if (auto* port = manager.openMidiInputPortWithID (deviceIdentifier.getIntValue(), midiInput.get(), callback)) - { - midiInput->internal.reset (port); - midiInput->setName (port->getName()); - - return midiInput; - } - - return {}; -} - -StringArray MidiInput::getDevices() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - StringArray deviceNames; - - for (auto& d : getAvailableDevices()) - deviceNames.add (d.name); - - return deviceNames; -} - -int MidiInput::getDefaultDeviceIndex() -{ - return (getAndroidSDKVersion() < 23 ? -1 : 0); -} - -std::unique_ptr MidiInput::openDevice (int index, MidiInputCallback* callback) -{ - return openDevice (getAvailableDevices()[index].identifier, callback); -} - -MidiInput::MidiInput (const String& deviceName, const String& deviceIdentifier) - : deviceInfo (deviceName, deviceIdentifier) -{ -} - -MidiInput::~MidiInput() = default; - -void MidiInput::start() -{ - if (auto* mi = internal.get()) - mi->start(); -} - -void MidiInput::stop() -{ - if (auto* mi = internal.get()) - mi->stop(); -} - -//============================================================================== -Array MidiOutput::getAvailableDevices() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - AndroidMidiDeviceManager manager; - return manager.getDevices (false); -} - -MidiDeviceInfo MidiOutput::getDefaultDevice() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - return getAvailableDevices().getFirst(); -} - -std::unique_ptr MidiOutput::openDevice (const String& deviceIdentifier) -{ - if (getAndroidSDKVersion() < 23 || deviceIdentifier.isEmpty()) - return {}; - - AndroidMidiDeviceManager manager; - - if (auto* port = manager.openMidiOutputPortWithID (deviceIdentifier.getIntValue())) - { - std::unique_ptr midiOutput (new MidiOutput ({}, deviceIdentifier)); - midiOutput->internal.reset (port); - midiOutput->setName (port->getName()); - - return midiOutput; - } - - return {}; -} - -StringArray MidiOutput::getDevices() -{ - if (getAndroidSDKVersion() < 23) - return {}; - - StringArray deviceNames; - - for (auto& d : getAvailableDevices()) - deviceNames.add (d.name); - - return deviceNames; -} - -int MidiOutput::getDefaultDeviceIndex() -{ - return (getAndroidSDKVersion() < 23 ? -1 : 0); -} - -std::unique_ptr MidiOutput::openDevice (int index) -{ - return openDevice (getAvailableDevices()[index].identifier); -} - -MidiOutput::~MidiOutput() -{ - stopBackgroundThread(); -} - -void MidiOutput::sendMessageNow (const MidiMessage& message) -{ - if (auto* androidMidi = internal.get()) - { - auto* env = getEnv(); - auto messageSize = message.getRawDataSize(); - - LocalRef messageContent (env->NewByteArray (messageSize)); - auto content = messageContent.get(); - - auto* rawBytes = env->GetByteArrayElements (content, nullptr); - std::memcpy (rawBytes, message.getRawData(), static_cast (messageSize)); - env->ReleaseByteArrayElements (content, rawBytes, 0); - - androidMidi->send (content, (jint) 0, (jint) messageSize); - } -} - -} // namespace juce diff --git a/modules/juce_audio_devices/sources/juce_AudioTransportSource.h b/modules/juce_audio_devices/sources/juce_AudioTransportSource.h index 3d82788c00a9..b45bdcac4e59 100644 --- a/modules/juce_audio_devices/sources/juce_AudioTransportSource.h +++ b/modules/juce_audio_devices/sources/juce_AudioTransportSource.h @@ -93,7 +93,7 @@ class JUCE_API AudioTransportSource : public PositionableAudioSource, */ void setPosition (double newPosition); - /** Returns the position that the next data block will be read from + /** Returns the position that the next data block will be read from. This is a time in seconds. */ double getCurrentPosition() const; diff --git a/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp index 079df3f37854..034dcbcdb378 100644 --- a/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp @@ -25,8 +25,8 @@ #if JUCE_MAC || JUCE_IOS -#include -#include +#include +#include namespace juce { diff --git a/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp index e743ae66827a..3fed533790f2 100644 --- a/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_FlacAudioFormat.cpp @@ -111,15 +111,16 @@ namespace FlacNamespace #endif JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", - "-Wshadow", "-Wdeprecated-register", - "-Wswitch-enum", - "-Wswitch-default", + "-Wfloat-equal", "-Wimplicit-fallthrough", - "-Wzero-as-null-pointer-constant", - "-Wsign-conversion", + "-Wlanguage-extension-token", "-Wredundant-decls", - "-Wlanguage-extension-token") + "-Wshadow", + "-Wsign-conversion", + "-Wswitch-default", + "-Wswitch-enum", + "-Wzero-as-null-pointer-constant") #if JUCE_INTEL #if JUCE_32BIT diff --git a/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp index cf105e9bbeb1..fb1339882807 100644 --- a/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_OggVorbisAudioFormat.cpp @@ -37,20 +37,21 @@ namespace OggVorbisNamespace #if JUCE_INCLUDE_OGGVORBIS_CODE || ! defined (JUCE_INCLUDE_OGGVORBIS_CODE) JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4305 4189 4706 4995 4365 4456 4457 4459 6297 6011 6001 6308 6255 6386 6385 6246 6387 6263 6262 28182) - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", - "-Wshadow", - "-Wfloat-conversion", - "-Wdeprecated-register", + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", + "-Wconversion", "-Wdeprecated-declarations", - "-Wswitch-enum", - "-Wzero-as-null-pointer-constant", - "-Wsign-conversion", - "-Wswitch-default", - "-Wredundant-decls", + "-Wdeprecated-register", + "-Wfloat-conversion", + "-Wfloat-equal", + "-Wmaybe-uninitialized", "-Wmisleading-indentation", "-Wmissing-prototypes", - "-Wcast-align", - "-Wmaybe-uninitialized") + "-Wredundant-decls", + "-Wshadow", + "-Wsign-conversion", + "-Wswitch-default", + "-Wswitch-enum", + "-Wzero-as-null-pointer-constant") JUCE_BEGIN_NO_SANITIZE ("undefined") #include "oggvorbis/vorbisenc.h" diff --git a/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp b/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp index c562882ca878..0105a2c3f5cf 100644 --- a/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp +++ b/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp @@ -948,7 +948,7 @@ namespace WavFileHelpers } }; - //============================================================================= + //============================================================================== namespace IXMLChunk { static const std::unordered_set aswgMetadataKeys diff --git a/modules/juce_audio_formats/format/juce_ARAAudioReaders.cpp b/modules/juce_audio_formats/format/juce_ARAAudioReaders.cpp index a8c974d2873f..a285635e6ac7 100644 --- a/modules/juce_audio_formats/format/juce_ARAAudioReaders.cpp +++ b/modules/juce_audio_formats/format/juce_ARAAudioReaders.cpp @@ -67,7 +67,7 @@ void ARAAudioSourceReader::willUpdateAudioSourceProperties (ARAAudioSource* audi ARAAudioSource::PropertiesPtr newProperties) { if (audioSource->getSampleCount() != newProperties->sampleCount - || audioSource->getSampleRate() != newProperties->sampleRate + || ! exactlyEqual (audioSource->getSampleRate(), newProperties->sampleRate) || audioSource->getChannelCount() != newProperties->channelCount) { invalidate(); @@ -277,10 +277,10 @@ void ARAPlaybackRegionReader::willUpdatePlaybackRegionProperties (ARAPlaybackReg { jassert (ARA::contains (playbackRenderer->getPlaybackRegions(), playbackRegion)); - if ((playbackRegion->getStartInAudioModificationTime() != newProperties->startInModificationTime) - || (playbackRegion->getDurationInAudioModificationTime() != newProperties->durationInModificationTime) - || (playbackRegion->getStartInPlaybackTime() != newProperties->startInPlaybackTime) - || (playbackRegion->getDurationInPlaybackTime() != newProperties->durationInPlaybackTime) + if ((! exactlyEqual (playbackRegion->getStartInAudioModificationTime(), newProperties->startInModificationTime)) + || ! exactlyEqual (playbackRegion->getDurationInAudioModificationTime(), newProperties->durationInModificationTime) + || ! exactlyEqual (playbackRegion->getStartInPlaybackTime(), newProperties->startInPlaybackTime) + || ! exactlyEqual (playbackRegion->getDurationInPlaybackTime(), newProperties->durationInPlaybackTime) || (playbackRegion->isTimestretchEnabled() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationTimestretch) != 0)) || (playbackRegion->isTimeStretchReflectingTempo() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationTimestretchReflectingTempo) != 0)) || (playbackRegion->hasContentBasedFadeAtHead() != ((newProperties->transformationFlags & ARA::kARAPlaybackTransformationContentBasedFadeAtHead) != 0)) diff --git a/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp b/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp index 7c47f86a9caf..96f2d5ba4de6 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp +++ b/modules/juce_audio_formats/format/juce_AudioFormatReaderSource.cpp @@ -81,8 +81,14 @@ void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& i } else { - reader->read (info.buffer, info.startSample, - info.numSamples, start, true, true); + const auto samplesToRead = jlimit (int64{}, + (int64) info.numSamples, + reader->lengthInSamples - start); + + reader->read (info.buffer, info.startSample, (int) samplesToRead, start, true, true); + info.buffer->clear ((int) (info.startSample + samplesToRead), + (int) (info.numSamples - samplesToRead)); + nextPlayPos += info.numSamples; } } diff --git a/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp b/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp index 95da52c92013..230188671d87 100644 --- a/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp +++ b/modules/juce_audio_formats/format/juce_BufferingAudioFormatReader.cpp @@ -176,26 +176,6 @@ bool BufferingAudioReader::readNextBufferChunk() //============================================================================== #if JUCE_UNIT_TESTS -static bool operator== (const AudioBuffer& a, const AudioBuffer& b) -{ - if (a.getNumChannels() != b.getNumChannels() || a.getNumSamples() != b.getNumSamples()) - return false; - - for (int channel = 0; channel < a.getNumChannels(); ++channel) - { - auto* aPtr = a.getReadPointer (channel); - auto* bPtr = b.getReadPointer (channel); - - if (std::vector (aPtr, aPtr + a.getNumSamples()) - != std::vector (bPtr, bPtr + b.getNumSamples())) - { - return false; - } - } - - return true; -} - static bool isSilent (const AudioBuffer& b) { for (int channel = 0; channel < b.getNumChannels(); ++channel) @@ -207,15 +187,16 @@ static bool isSilent (const AudioBuffer& b) struct TestAudioFormatReader : public AudioFormatReader { - explicit TestAudioFormatReader (AudioBuffer& b) + explicit TestAudioFormatReader (const AudioBuffer* b) : AudioFormatReader (nullptr, {}), buffer (b) { + jassert (buffer != nullptr); sampleRate = 44100.0f; bitsPerSample = 32; usesFloatingPointData = true; - lengthInSamples = buffer.getNumSamples(); - numChannels = (unsigned int) buffer.getNumChannels(); + lengthInSamples = buffer->getNumSamples(); + numChannels = (unsigned int) buffer->getNumChannels(); } bool readSamples (int* const* destChannels, int numDestChannels, int startOffsetInDestBuffer, @@ -234,7 +215,7 @@ struct TestAudioFormatReader : public AudioFormatReader dest += startOffsetInDestBuffer; if (j < (int) numChannels) - FloatVectorOperations::copy (dest, buffer.getReadPointer (j, (int) startSampleInFile), numSamples); + FloatVectorOperations::copy (dest, buffer->getReadPointer (j, (int) startSampleInFile), numSamples); else FloatVectorOperations::clear (dest, numSamples); } @@ -243,9 +224,20 @@ struct TestAudioFormatReader : public AudioFormatReader return true; } - const AudioBuffer& buffer; + const AudioBuffer* buffer; }; +static AudioBuffer generateTestBuffer (Random& random, int bufferSize) +{ + AudioBuffer buffer { 2, bufferSize }; + + for (int channel = 0; channel < buffer.getNumChannels(); ++channel) + for (int sample = 0; sample < buffer.getNumSamples(); ++sample) + buffer.setSample (channel, sample, random.nextFloat()); + + return buffer; +} + class BufferingAudioReaderTests : public UnitTest { public: @@ -258,44 +250,54 @@ class BufferingAudioReaderTests : public UnitTest beginTest ("Timeout"); { - struct BlockingReader : public AudioFormatReader + struct BlockingReader : public TestAudioFormatReader { - BlockingReader() - : AudioFormatReader (nullptr, {}) + explicit BlockingReader (const AudioBuffer* b) + : TestAudioFormatReader (b) { - sampleRate = 44100.0f; - bitsPerSample = 32; - usesFloatingPointData = true; - lengthInSamples = 1024; - numChannels = 2; } - bool readSamples (int* const*, int, int, int64, int) override + bool readSamples (int* const* destChannels, + int numDestChannels, + int startOffsetInDestBuffer, + int64 startSampleInFile, + int numSamples) override { Thread::sleep (100); - return true; + return TestAudioFormatReader::readSamples (destChannels, numDestChannels, startOffsetInDestBuffer, startSampleInFile, numSamples); } }; - BufferingAudioReader bufferingReader (new BlockingReader(), timeSlice, 64); + Random random { getRandom() }; + + const auto blockingBuffer = generateTestBuffer (random, 1024); + expect (! isSilent (blockingBuffer)); + + BufferingAudioReader bufferingReader (new BlockingReader (&blockingBuffer), timeSlice, 64); bufferingReader.setReadTimeout (10); - AudioBuffer readBuffer { 2, 1024 }; + const auto originalBuffer = generateTestBuffer (random, 1024); + expect (! isSilent (originalBuffer)); + expect (originalBuffer != blockingBuffer); - readBuffer.clear(); - read (bufferingReader, readBuffer); + auto readBuffer = originalBuffer; + expect (readBuffer == originalBuffer); + read (bufferingReader, readBuffer); + expect (readBuffer != originalBuffer); expect (isSilent (readBuffer)); } beginTest ("Read samples"); { + Random random { getRandom() }; + for (auto i = 4; i < 18; ++i) { const auto backgroundBufferSize = 1 << i; - auto buffer = generateTestBuffer (backgroundBufferSize); + const auto buffer = generateTestBuffer (random, backgroundBufferSize); - BufferingAudioReader bufferingReader (new TestAudioFormatReader (buffer), timeSlice, backgroundBufferSize); + BufferingAudioReader bufferingReader (new TestAudioFormatReader (&buffer), timeSlice, backgroundBufferSize); bufferingReader.setReadTimeout (-1); AudioBuffer readBuffer { buffer.getNumChannels(), buffer.getNumSamples() }; @@ -307,19 +309,6 @@ class BufferingAudioReaderTests : public UnitTest } private: - AudioBuffer generateTestBuffer (int bufferSize) const - { - auto random = getRandom(); - - AudioBuffer buffer { 2, random.nextInt ({ bufferSize, bufferSize * 10 }) }; - - for (int channel = 0; channel < buffer.getNumChannels(); ++channel) - for (int sample = 0; sample < buffer.getNumSamples(); ++sample) - buffer.setSample (channel, sample, random.nextFloat()); - - return buffer; - } - void read (BufferingAudioReader& reader, AudioBuffer& readBuffer) { constexpr int blockSize = 1024; diff --git a/modules/juce_audio_formats/juce_audio_formats.h b/modules/juce_audio_formats/juce_audio_formats.h index aa26e9fa2af2..fd4e543152d2 100644 --- a/modules/juce_audio_formats/juce_audio_formats.h +++ b/modules/juce_audio_formats/juce_audio_formats.h @@ -35,7 +35,7 @@ ID: juce_audio_formats vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE audio file format codecs description: Classes for reading and writing various audio file formats. website: http://www.juce.com/juce diff --git a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp b/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp deleted file mode 100644 index f0c7228853df..000000000000 --- a/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp +++ /dev/null @@ -1,2598 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include "../utility/juce_CheckSettingMacros.h" - -#if JucePlugin_Build_AAX && (JUCE_INCLUDED_AAX_IN_MM || defined (_WIN32) || defined (_WIN64)) - -#include "../utility/juce_IncludeSystemHeaders.h" -#include "../utility/juce_IncludeModuleHeaders.h" -#include "../utility/juce_WindowsHooks.h" - -#include - -JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127 4512 4996) -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnon-virtual-dtor", - "-Wsign-conversion", - "-Wextra-semi", - "-Wshift-sign-overflow", - "-Wpragma-pack", - "-Wzero-as-null-pointer-constant", - "-Winconsistent-missing-destructor-override", - "-Wfour-char-constants", - "-Wtautological-overlap-compare", - "-Wdeprecated-declarations") - -#include - -static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p3p0_REVISION, "JUCE requires AAX SDK version 2.3.0 or higher"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined (AAX_SDK_2p3p1_REVISION) && AAX_SDK_2p3p1_REVISION <= AAX_SDK_CURRENT_REVISION - #include - #include -#endif - -#if defined (AAX_SDK_2p4p0_REVISION) && AAX_SDK_2p4p0_REVISION <= AAX_SDK_CURRENT_REVISION - #define JUCE_AAX_HAS_TRANSPORT_NOTIFICATION 1 -#else - #define JUCE_AAX_HAS_TRANSPORT_NOTIFICATION 0 -#endif - -#if JUCE_AAX_HAS_TRANSPORT_NOTIFICATION - #include -#endif - -JUCE_END_IGNORE_WARNINGS_MSVC -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfour-char-constants") - -#if JUCE_WINDOWS - #ifndef JucePlugin_AAXLibs_path - #error "You need to define the JucePlugin_AAXLibs_path macro. (This is best done via the Projucer)" - #endif - - #if JUCE_64BIT - #define JUCE_AAX_LIB "AAXLibrary_x64" - #else - #define JUCE_AAX_LIB "AAXLibrary" - #endif - - #if JUCE_DEBUG - #define JUCE_AAX_LIB_PATH "\\Debug\\" - #define JUCE_AAX_LIB_SUFFIX "_D" - #else - #define JUCE_AAX_LIB_PATH "\\Release\\" - #define JUCE_AAX_LIB_SUFFIX "" - #endif - - #pragma comment(lib, JucePlugin_AAXLibs_path JUCE_AAX_LIB_PATH JUCE_AAX_LIB JUCE_AAX_LIB_SUFFIX ".lib") -#endif - -#undef check - -#include "juce_AAX_Modifier_Injector.h" - -using namespace juce; - -#ifndef JucePlugin_AAX_Chunk_Identifier - #define JucePlugin_AAX_Chunk_Identifier 'juce' -#endif - -const int32_t juceChunkType = JucePlugin_AAX_Chunk_Identifier; - -//============================================================================== -namespace AAXClasses -{ - static int32 getAAXParamHash (AAX_CParamID paramID) noexcept - { - int32 result = 0; - - while (*paramID != 0) - result = (31 * result) + (*paramID++); - - return result; - } - - static void check (AAX_Result result) - { - jassertquiet (result == AAX_SUCCESS); - } - - // maps a channel index of an AAX format to an index of a juce format - struct AAXChannelStreamOrder - { - AAX_EStemFormat aaxStemFormat; - AudioChannelSet::ChannelType speakerOrder[10]; - }; - - static AAX_EStemFormat stemFormatForAmbisonicOrder (int order) - { - switch (order) - { - case 1: return AAX_eStemFormat_Ambi_1_ACN; - case 2: return AAX_eStemFormat_Ambi_2_ACN; - case 3: return AAX_eStemFormat_Ambi_3_ACN; - default: break; - } - - return AAX_eStemFormat_INT32_MAX; - } - - static AAXChannelStreamOrder aaxChannelOrder[] = - { - { AAX_eStemFormat_Mono, { AudioChannelSet::centre, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_Stereo, { AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_LCR, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::unknown, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_LCRS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::centreSurround, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_Quad, { AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_5_0, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_5_1, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, - AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_6_0, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, - AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_6_1, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, - AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_0_SDDS, { AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, - AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_0_DTS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, - AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_1_SDDS, { AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, - AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_1_DTS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, - AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_0_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, - AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, AudioChannelSet::unknown } }, - - { AAX_eStemFormat_7_1_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, - AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight } }, - - { AAX_eStemFormat_None, { AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, - AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown, AudioChannelSet::unknown } }, - }; - - static AAX_EStemFormat aaxFormats[] = - { - AAX_eStemFormat_Mono, - AAX_eStemFormat_Stereo, - AAX_eStemFormat_LCR, - AAX_eStemFormat_LCRS, - AAX_eStemFormat_Quad, - AAX_eStemFormat_5_0, - AAX_eStemFormat_5_1, - AAX_eStemFormat_6_0, - AAX_eStemFormat_6_1, - AAX_eStemFormat_7_0_SDDS, - AAX_eStemFormat_7_1_SDDS, - AAX_eStemFormat_7_0_DTS, - AAX_eStemFormat_7_1_DTS, - AAX_eStemFormat_7_0_2, - AAX_eStemFormat_7_1_2, - AAX_eStemFormat_Ambi_1_ACN, - AAX_eStemFormat_Ambi_2_ACN, - AAX_eStemFormat_Ambi_3_ACN - }; - - static AAX_EStemFormat getFormatForAudioChannelSet (const AudioChannelSet& set, bool ignoreLayout) noexcept - { - // if the plug-in ignores layout, it is ok to convert between formats only by their numchannnels - if (ignoreLayout) - { - auto numChannels = set.size(); - - switch (numChannels) - { - case 0: return AAX_eStemFormat_None; - case 1: return AAX_eStemFormat_Mono; - case 2: return AAX_eStemFormat_Stereo; - case 3: return AAX_eStemFormat_LCR; - case 4: return AAX_eStemFormat_Quad; - case 5: return AAX_eStemFormat_5_0; - case 6: return AAX_eStemFormat_5_1; - case 7: return AAX_eStemFormat_7_0_DTS; - case 8: return AAX_eStemFormat_7_1_DTS; - case 9: return AAX_eStemFormat_7_0_2; - case 10: return AAX_eStemFormat_7_1_2; - default: break; - } - - // check for ambisonics support - auto sqrtMinusOne = std::sqrt (static_cast (numChannels)) - 1.0f; - auto ambisonicOrder = jmax (0, static_cast (std::floor (sqrtMinusOne))); - - if (static_cast (ambisonicOrder) == sqrtMinusOne) - return stemFormatForAmbisonicOrder (ambisonicOrder); - - return AAX_eStemFormat_INT32_MAX; - } - - if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None; - if (set == AudioChannelSet::mono()) return AAX_eStemFormat_Mono; - if (set == AudioChannelSet::stereo()) return AAX_eStemFormat_Stereo; - if (set == AudioChannelSet::createLCR()) return AAX_eStemFormat_LCR; - if (set == AudioChannelSet::createLCRS()) return AAX_eStemFormat_LCRS; - if (set == AudioChannelSet::quadraphonic()) return AAX_eStemFormat_Quad; - if (set == AudioChannelSet::create5point0()) return AAX_eStemFormat_5_0; - if (set == AudioChannelSet::create5point1()) return AAX_eStemFormat_5_1; - if (set == AudioChannelSet::create6point0()) return AAX_eStemFormat_6_0; - if (set == AudioChannelSet::create6point1()) return AAX_eStemFormat_6_1; - if (set == AudioChannelSet::create7point0()) return AAX_eStemFormat_7_0_DTS; - if (set == AudioChannelSet::create7point1()) return AAX_eStemFormat_7_1_DTS; - if (set == AudioChannelSet::create7point0SDDS()) return AAX_eStemFormat_7_0_SDDS; - if (set == AudioChannelSet::create7point1SDDS()) return AAX_eStemFormat_7_1_SDDS; - if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_2; - if (set == AudioChannelSet::create7point1point2()) return AAX_eStemFormat_7_1_2; - - auto order = set.getAmbisonicOrder(); - if (order >= 0) - return stemFormatForAmbisonicOrder (order); - - return AAX_eStemFormat_INT32_MAX; - } - - static AudioChannelSet channelSetFromStemFormat (AAX_EStemFormat format, bool ignoreLayout) noexcept - { - if (! ignoreLayout) - { - switch (format) - { - case AAX_eStemFormat_None: return AudioChannelSet::disabled(); - case AAX_eStemFormat_Mono: return AudioChannelSet::mono(); - case AAX_eStemFormat_Stereo: return AudioChannelSet::stereo(); - case AAX_eStemFormat_LCR: return AudioChannelSet::createLCR(); - case AAX_eStemFormat_LCRS: return AudioChannelSet::createLCRS(); - case AAX_eStemFormat_Quad: return AudioChannelSet::quadraphonic(); - case AAX_eStemFormat_5_0: return AudioChannelSet::create5point0(); - case AAX_eStemFormat_5_1: return AudioChannelSet::create5point1(); - case AAX_eStemFormat_6_0: return AudioChannelSet::create6point0(); - case AAX_eStemFormat_6_1: return AudioChannelSet::create6point1(); - case AAX_eStemFormat_7_0_SDDS: return AudioChannelSet::create7point0SDDS(); - case AAX_eStemFormat_7_0_DTS: return AudioChannelSet::create7point0(); - case AAX_eStemFormat_7_1_SDDS: return AudioChannelSet::create7point1SDDS(); - case AAX_eStemFormat_7_1_DTS: return AudioChannelSet::create7point1(); - case AAX_eStemFormat_7_0_2: return AudioChannelSet::create7point0point2(); - case AAX_eStemFormat_7_1_2: return AudioChannelSet::create7point1point2(); - case AAX_eStemFormat_Ambi_1_ACN: return AudioChannelSet::ambisonic (1); - case AAX_eStemFormat_Ambi_2_ACN: return AudioChannelSet::ambisonic (2); - case AAX_eStemFormat_Ambi_3_ACN: return AudioChannelSet::ambisonic (3); - case AAX_eStemFormat_Reserved_1: - case AAX_eStemFormat_Reserved_2: - case AAX_eStemFormat_Reserved_3: - case AAX_eStemFormatNum: - case AAX_eStemFormat_Any: - case AAX_eStemFormat_INT32_MAX: - default: return AudioChannelSet::disabled(); - } - } - - return AudioChannelSet::discreteChannels (jmax (0, static_cast (AAX_STEM_FORMAT_CHANNEL_COUNT (format)))); - } - - static AAX_EMeterType getMeterTypeForCategory (AudioProcessorParameter::Category category) - { - switch (category) - { - case AudioProcessorParameter::inputMeter: return AAX_eMeterType_Input; - case AudioProcessorParameter::outputMeter: return AAX_eMeterType_Output; - case AudioProcessorParameter::compressorLimiterGainReductionMeter: return AAX_eMeterType_CLGain; - case AudioProcessorParameter::expanderGateGainReductionMeter: return AAX_eMeterType_EGGain; - case AudioProcessorParameter::analysisMeter: return AAX_eMeterType_Analysis; - case AudioProcessorParameter::genericParameter: - case AudioProcessorParameter::inputGain: - case AudioProcessorParameter::outputGain: - case AudioProcessorParameter::otherMeter: - default: return AAX_eMeterType_Other; - } - } - - static Colour getColourFromHighlightEnum (AAX_EHighlightColor colour) noexcept - { - switch (colour) - { - case AAX_eHighlightColor_Red: return Colours::red; - case AAX_eHighlightColor_Blue: return Colours::blue; - case AAX_eHighlightColor_Green: return Colours::green; - case AAX_eHighlightColor_Yellow: return Colours::yellow; - case AAX_eHighlightColor_Num: - default: jassertfalse; break; - } - - return Colours::black; - } - - static int juceChannelIndexToAax (int juceIndex, const AudioChannelSet& channelSet) - { - auto isAmbisonic = (channelSet.getAmbisonicOrder() >= 0); - auto currentLayout = getFormatForAudioChannelSet (channelSet, false); - int layoutIndex; - - if (isAmbisonic && currentLayout != AAX_eStemFormat_INT32_MAX) - return juceIndex; - - for (layoutIndex = 0; aaxChannelOrder[layoutIndex].aaxStemFormat != currentLayout; ++layoutIndex) - if (aaxChannelOrder[layoutIndex].aaxStemFormat == 0) return juceIndex; - - auto& channelOrder = aaxChannelOrder[layoutIndex]; - auto channelType = channelSet.getTypeOfChannel (static_cast (juceIndex)); - auto numSpeakers = numElementsInArray (channelOrder.speakerOrder); - - for (int i = 0; i < numSpeakers && channelOrder.speakerOrder[i] != 0; ++i) - if (channelOrder.speakerOrder[i] == channelType) - return i; - - return juceIndex; - } - - //============================================================================== - class JuceAAX_Processor; - - struct PluginInstanceInfo - { - PluginInstanceInfo (JuceAAX_Processor& p) : parameters (p) {} - - JuceAAX_Processor& parameters; - - JUCE_DECLARE_NON_COPYABLE (PluginInstanceInfo) - }; - - //============================================================================== - struct JUCEAlgorithmContext - { - float** inputChannels; - float** outputChannels; - int32_t* bufferSize; - int32_t* bypass; - - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - AAX_IMIDINode* midiNodeIn; - #endif - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect - AAX_IMIDINode* midiNodeOut; - #endif - - PluginInstanceInfo* pluginInstance; - int32_t* isPrepared; - float* const* meterTapBuffers; - int32_t* sideChainBuffers; - }; - - struct JUCEAlgorithmIDs - { - enum - { - inputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, inputChannels), - outputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, outputChannels), - bufferSize = AAX_FIELD_INDEX (JUCEAlgorithmContext, bufferSize), - bypass = AAX_FIELD_INDEX (JUCEAlgorithmContext, bypass), - - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - midiNodeIn = AAX_FIELD_INDEX (JUCEAlgorithmContext, midiNodeIn), - #endif - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect - midiNodeOut = AAX_FIELD_INDEX (JUCEAlgorithmContext, midiNodeOut), - #endif - - pluginInstance = AAX_FIELD_INDEX (JUCEAlgorithmContext, pluginInstance), - preparedFlag = AAX_FIELD_INDEX (JUCEAlgorithmContext, isPrepared), - - meterTapBuffers = AAX_FIELD_INDEX (JUCEAlgorithmContext, meterTapBuffers), - - sideChainBuffers = AAX_FIELD_INDEX (JUCEAlgorithmContext, sideChainBuffers) - }; - }; - - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - static AAX_IMIDINode* getMidiNodeIn (const JUCEAlgorithmContext& c) noexcept { return c.midiNodeIn; } - #else - static AAX_IMIDINode* getMidiNodeIn (const JUCEAlgorithmContext&) noexcept { return nullptr; } - #endif - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect - AAX_IMIDINode* midiNodeOut; - static AAX_IMIDINode* getMidiNodeOut (const JUCEAlgorithmContext& c) noexcept { return c.midiNodeOut; } - #else - static AAX_IMIDINode* getMidiNodeOut (const JUCEAlgorithmContext&) noexcept { return nullptr; } - #endif - - //============================================================================== - class JuceAAX_Processor; - - class JuceAAX_GUI : public AAX_CEffectGUI, - public ModifierKeyProvider - { - public: - JuceAAX_GUI() = default; - ~JuceAAX_GUI() override { DeleteViewContainer(); } - - static AAX_IEffectGUI* AAX_CALLBACK Create() { return new JuceAAX_GUI(); } - - void CreateViewContents() override; - - void CreateViewContainer() override - { - CreateViewContents(); - - if (void* nativeViewToAttachTo = GetViewContainerPtr()) - { - #if JUCE_MAC - if (GetViewContainerType() == AAX_eViewContainer_Type_NSView) - #else - if (GetViewContainerType() == AAX_eViewContainer_Type_HWND) - #endif - { - component->setVisible (true); - component->addToDesktop (0, nativeViewToAttachTo); - - if (ModifierKeyReceiver* modReceiver = dynamic_cast (component->getPeer())) - modReceiver->setModifierKeyProvider (this); - } - } - } - - void DeleteViewContainer() override - { - if (component != nullptr) - { - JUCE_AUTORELEASEPOOL - { - if (auto* modReceiver = dynamic_cast (component->getPeer())) - modReceiver->removeModifierKeyProvider(); - - component->removeFromDesktop(); - component = nullptr; - } - } - } - - AAX_Result GetViewSize (AAX_Point* viewSize) const override - { - if (component != nullptr) - { - *viewSize = convertToHostBounds ({ (float) component->getHeight(), - (float) component->getWidth() }); - - return AAX_SUCCESS; - } - - return AAX_ERROR_NULL_OBJECT; - } - - AAX_Result ParameterUpdated (AAX_CParamID) override - { - return AAX_SUCCESS; - } - - AAX_Result SetControlHighlightInfo (AAX_CParamID paramID, AAX_CBoolean isHighlighted, AAX_EHighlightColor colour) override - { - if (component != nullptr && component->pluginEditor != nullptr) - { - auto index = getParamIndexFromID (paramID); - - if (index >= 0) - { - AudioProcessorEditor::ParameterControlHighlightInfo info; - info.parameterIndex = index; - info.isHighlighted = (isHighlighted != 0); - info.suggestedColour = getColourFromHighlightEnum (colour); - - component->pluginEditor->setControlHighlight (info); - } - - return AAX_SUCCESS; - } - - return AAX_ERROR_NULL_OBJECT; - } - - int getWin32Modifiers() const override - { - int modifierFlags = 0; - - if (auto* viewContainer = GetViewContainer()) - { - uint32 aaxViewMods = 0; - const_cast (viewContainer)->GetModifiers (&aaxViewMods); - - if ((aaxViewMods & AAX_eModifiers_Shift) != 0) modifierFlags |= ModifierKeys::shiftModifier; - if ((aaxViewMods & AAX_eModifiers_Alt ) != 0) modifierFlags |= ModifierKeys::altModifier; - } - - return modifierFlags; - } - - private: - //============================================================================== - int getParamIndexFromID (AAX_CParamID paramID) const noexcept; - AAX_CParamID getAAXParamIDFromJuceIndex (int index) const noexcept; - - //============================================================================== - static AAX_Point convertToHostBounds (AAX_Point pluginSize) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return pluginSize; - - return { pluginSize.vert * desktopScale, - pluginSize.horz * desktopScale }; - } - - //============================================================================== - struct ContentWrapperComponent : public Component - { - ContentWrapperComponent (JuceAAX_GUI& gui, AudioProcessor& plugin) - : owner (gui) - { - setOpaque (true); - setBroughtToFrontOnMouseClick (true); - - pluginEditor.reset (plugin.createEditorIfNeeded()); - addAndMakeVisible (pluginEditor.get()); - - if (pluginEditor != nullptr) - { - lastValidSize = pluginEditor->getLocalBounds(); - setBounds (lastValidSize); - pluginEditor->addMouseListener (this, true); - } - } - - ~ContentWrapperComponent() override - { - if (pluginEditor != nullptr) - { - PopupMenu::dismissAllActiveMenus(); - pluginEditor->removeMouseListener (this); - pluginEditor->processor.editorBeingDeleted (pluginEditor.get()); - } - } - - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - - template - void callMouseMethod (const MouseEvent& e, MethodType method) - { - if (auto* vc = owner.GetViewContainer()) - { - auto parameterIndex = pluginEditor->getControlParameterIndex (*e.eventComponent); - - if (auto aaxParamID = owner.getAAXParamIDFromJuceIndex (parameterIndex)) - { - uint32_t mods = 0; - vc->GetModifiers (&mods); - - (vc->*method) (aaxParamID, mods); - } - } - } - - void mouseDown (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDown); } - void mouseUp (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseUp); } - void mouseDrag (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDrag); } - - void parentSizeChanged() override - { - resizeHostWindow(); - - if (pluginEditor != nullptr) - pluginEditor->repaint(); - } - - void childBoundsChanged (Component*) override - { - if (resizeHostWindow()) - { - setSize (pluginEditor->getWidth(), pluginEditor->getHeight()); - lastValidSize = getBounds(); - } - else - { - pluginEditor->setBoundsConstrained (pluginEditor->getBounds().withSize (lastValidSize.getWidth(), - lastValidSize.getHeight())); - } - } - - bool resizeHostWindow() - { - if (pluginEditor != nullptr) - { - auto newSize = convertToHostBounds ({ (float) pluginEditor->getHeight(), - (float) pluginEditor->getWidth() }); - - return owner.GetViewContainer()->SetViewSize (newSize) == AAX_SUCCESS; - } - - return false; - } - - std::unique_ptr pluginEditor; - JuceAAX_GUI& owner; - - #if JUCE_WINDOWS - WindowsHooks hooks; - #endif - juce::Rectangle lastValidSize; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) - }; - - std::unique_ptr component; - ScopedJuceInitialiser_GUI libraryInitialiser; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAAX_GUI) - }; - - // Copied here, because not all versions of the AAX SDK define all of these values - enum JUCE_AAX_EFrameRate : std::underlying_type_t - { - JUCE_AAX_eFrameRate_Undeclared = 0, - JUCE_AAX_eFrameRate_24Frame = 1, - JUCE_AAX_eFrameRate_25Frame = 2, - JUCE_AAX_eFrameRate_2997NonDrop = 3, - JUCE_AAX_eFrameRate_2997DropFrame = 4, - JUCE_AAX_eFrameRate_30NonDrop = 5, - JUCE_AAX_eFrameRate_30DropFrame = 6, - JUCE_AAX_eFrameRate_23976 = 7, - JUCE_AAX_eFrameRate_47952 = 8, - JUCE_AAX_eFrameRate_48Frame = 9, - JUCE_AAX_eFrameRate_50Frame = 10, - JUCE_AAX_eFrameRate_5994NonDrop = 11, - JUCE_AAX_eFrameRate_5994DropFrame = 12, - JUCE_AAX_eFrameRate_60NonDrop = 13, - JUCE_AAX_eFrameRate_60DropFrame = 14, - JUCE_AAX_eFrameRate_100Frame = 15, - JUCE_AAX_eFrameRate_11988NonDrop = 16, - JUCE_AAX_eFrameRate_11988DropFrame = 17, - JUCE_AAX_eFrameRate_120NonDrop = 18, - JUCE_AAX_eFrameRate_120DropFrame = 19 - }; - - static void AAX_CALLBACK algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd); - - static Array activeProcessors; - - //============================================================================== - class JuceAAX_Processor : public AAX_CEffectParameters, - public juce::AudioPlayHead, - public AudioProcessorListener, - private AsyncUpdater - { - public: - JuceAAX_Processor() - : pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_AAX)) - { - inParameterChangedCallback = false; - - pluginInstance->setPlayHead (this); - pluginInstance->addListener (this); - - rebuildChannelMapArrays(); - - AAX_CEffectParameters::GetNumberOfChunks (&juceChunkIndex); - activeProcessors.add (this); - } - - ~JuceAAX_Processor() override - { - activeProcessors.removeAllInstancesOf (this); - } - - static AAX_CEffectParameters* AAX_CALLBACK Create() - { - if (PluginHostType::jucePlugInIsRunningInAudioSuiteFn == nullptr) - { - PluginHostType::jucePlugInIsRunningInAudioSuiteFn = [] (AudioProcessor& processor) - { - for (auto* p : activeProcessors) - if (&p->getPluginInstance() == &processor) - return p->isInAudioSuite(); - - return false; - }; - } - - return new JuceAAX_Processor(); - } - - AAX_Result Uninitialize() override - { - cancelPendingUpdate(); - juceParameters.clear(); - - if (isPrepared && pluginInstance != nullptr) - { - isPrepared = false; - processingSidechainChange = false; - - pluginInstance->releaseResources(); - } - - return AAX_CEffectParameters::Uninitialize(); - } - - AAX_Result EffectInit() override - { - cancelPendingUpdate(); - check (Controller()->GetSampleRate (&sampleRate)); - processingSidechainChange = false; - auto err = preparePlugin(); - - if (err != AAX_SUCCESS) - return err; - - addAudioProcessorParameters(); - - return AAX_SUCCESS; - } - - AAX_Result GetNumberOfChunks (int32_t* numChunks) const override - { - // The juceChunk is the last chunk. - *numChunks = juceChunkIndex + 1; - return AAX_SUCCESS; - } - - AAX_Result GetChunkIDFromIndex (int32_t index, AAX_CTypeID* chunkID) const override - { - if (index != juceChunkIndex) - return AAX_CEffectParameters::GetChunkIDFromIndex (index, chunkID); - - *chunkID = juceChunkType; - return AAX_SUCCESS; - } - - AAX_Result GetChunkSize (AAX_CTypeID chunkID, uint32_t* oSize) const override - { - if (chunkID != juceChunkType) - return AAX_CEffectParameters::GetChunkSize (chunkID, oSize); - - auto& chunkMemoryBlock = perThreadFilterData.get(); - - chunkMemoryBlock.data.reset(); - pluginInstance->getStateInformation (chunkMemoryBlock.data); - chunkMemoryBlock.isValid = true; - - *oSize = (uint32_t) chunkMemoryBlock.data.getSize(); - return AAX_SUCCESS; - } - - AAX_Result GetChunk (AAX_CTypeID chunkID, AAX_SPlugInChunk* oChunk) const override - { - if (chunkID != juceChunkType) - return AAX_CEffectParameters::GetChunk (chunkID, oChunk); - - auto& chunkMemoryBlock = perThreadFilterData.get(); - - if (! chunkMemoryBlock.isValid) - return 20700; // AAX_ERROR_PLUGIN_API_INVALID_THREAD - - oChunk->fSize = (int32_t) chunkMemoryBlock.data.getSize(); - chunkMemoryBlock.data.copyTo (oChunk->fData, 0, chunkMemoryBlock.data.getSize()); - chunkMemoryBlock.isValid = false; - - return AAX_SUCCESS; - } - - AAX_Result SetChunk (AAX_CTypeID chunkID, const AAX_SPlugInChunk* chunk) override - { - if (chunkID != juceChunkType) - return AAX_CEffectParameters::SetChunk (chunkID, chunk); - - pluginInstance->setStateInformation ((void*) chunk->fData, chunk->fSize); - - // Notify Pro Tools that the parameters were updated. - // Without it a bug happens in these circumstances: - // * A preset is saved with the RTAS version of the plugin (".tfx" preset format). - // * The preset is loaded in PT 10 using the AAX version. - // * The session is then saved, and closed. - // * The saved session is loaded, but acting as if the preset was never loaded. - // IMPORTANT! If the plugin doesn't manage its own bypass parameter, don't try - // to overwrite the bypass parameter value. - auto numParameters = juceParameters.getNumParameters(); - - for (int i = 0; i < numParameters; ++i) - if (auto* juceParam = juceParameters.getParamForIndex (i)) - if (juceParam != ownedBypassParameter.get()) - if (auto paramID = getAAXParamIDFromJuceIndex (i)) - SetParameterNormalizedValue (paramID, juceParam->getValue()); - - return AAX_SUCCESS; - } - - AAX_Result ResetFieldData (AAX_CFieldIndex fieldIndex, void* data, uint32_t dataSize) const override - { - switch (fieldIndex) - { - case JUCEAlgorithmIDs::pluginInstance: - { - auto numObjects = dataSize / sizeof (PluginInstanceInfo); - auto* objects = static_cast (data); - - jassert (numObjects == 1); // not sure how to handle more than one.. - - for (size_t i = 0; i < numObjects; ++i) - new (objects + i) PluginInstanceInfo (const_cast (*this)); - - break; - } - - case JUCEAlgorithmIDs::preparedFlag: - { - const_cast (this)->preparePlugin(); - - auto numObjects = dataSize / sizeof (uint32_t); - auto* objects = static_cast (data); - - for (size_t i = 0; i < numObjects; ++i) - objects[i] = 1; - - break; - } - - case JUCEAlgorithmIDs::meterTapBuffers: - { - // this is a dummy field only when there are no aaxMeters - jassert (aaxMeters.size() == 0); - - { - auto numObjects = dataSize / sizeof (float*); - auto* objects = static_cast (data); - - for (size_t i = 0; i < numObjects; ++i) - objects[i] = nullptr; - } - break; - } - } - - return AAX_SUCCESS; - } - - void setAudioProcessorParameter (AAX_CParamID paramID, double value) - { - if (auto* param = getParameterFromID (paramID)) - { - auto newValue = static_cast (value); - - if (newValue != param->getValue()) - { - param->setValue (newValue); - - inParameterChangedCallback = true; - param->sendValueChangedMessageToListeners (newValue); - } - } - } - - AAX_Result GetNumberOfChanges (int32_t* numChanges) const override - { - const auto result = AAX_CEffectParameters::GetNumberOfChanges (numChanges); - *numChanges += numSetDirtyCalls; - return result; - } - - AAX_Result UpdateParameterNormalizedValue (AAX_CParamID paramID, double value, AAX_EUpdateSource source) override - { - auto result = AAX_CEffectParameters::UpdateParameterNormalizedValue (paramID, value, source); - setAudioProcessorParameter (paramID, value); - - return result; - } - - AAX_Result GetParameterValueFromString (AAX_CParamID paramID, double* result, const AAX_IString& text) const override - { - if (auto* param = getParameterFromID (paramID)) - { - if (! LegacyAudioParameter::isLegacy (param)) - { - *result = param->getValueForText (text.Get()); - return AAX_SUCCESS; - } - } - - return AAX_CEffectParameters::GetParameterValueFromString (paramID, result, text); - } - - AAX_Result GetParameterStringFromValue (AAX_CParamID paramID, double value, AAX_IString* result, int32_t maxLen) const override - { - if (auto* param = getParameterFromID (paramID)) - result->Set (param->getText ((float) value, maxLen).toRawUTF8()); - - return AAX_SUCCESS; - } - - AAX_Result GetParameterNumberofSteps (AAX_CParamID paramID, int32_t* result) const - { - if (auto* param = getParameterFromID (paramID)) - *result = getSafeNumberOfParameterSteps (*param); - - return AAX_SUCCESS; - } - - AAX_Result GetParameterNormalizedValue (AAX_CParamID paramID, double* result) const override - { - if (auto* param = getParameterFromID (paramID)) - *result = (double) param->getValue(); - else - *result = 0.0; - - return AAX_SUCCESS; - } - - AAX_Result SetParameterNormalizedValue (AAX_CParamID paramID, double newValue) override - { - if (auto* p = mParameterManager.GetParameterByID (paramID)) - p->SetValueWithFloat ((float) newValue); - - setAudioProcessorParameter (paramID, (float) newValue); - - return AAX_SUCCESS; - } - - AAX_Result SetParameterNormalizedRelative (AAX_CParamID paramID, double newDeltaValue) override - { - if (auto* param = getParameterFromID (paramID)) - { - auto newValue = param->getValue() + (float) newDeltaValue; - - setAudioProcessorParameter (paramID, jlimit (0.0f, 1.0f, newValue)); - - if (auto* p = mParameterManager.GetParameterByID (paramID)) - p->SetValueWithFloat (newValue); - } - - return AAX_SUCCESS; - } - - AAX_Result GetParameterNameOfLength (AAX_CParamID paramID, AAX_IString* result, int32_t maxLen) const override - { - if (auto* param = getParameterFromID (paramID)) - result->Set (param->getName (maxLen).toRawUTF8()); - - return AAX_SUCCESS; - } - - AAX_Result GetParameterName (AAX_CParamID paramID, AAX_IString* result) const override - { - if (auto* param = getParameterFromID (paramID)) - result->Set (param->getName (31).toRawUTF8()); - - return AAX_SUCCESS; - } - - AAX_Result GetParameterDefaultNormalizedValue (AAX_CParamID paramID, double* result) const override - { - if (auto* param = getParameterFromID (paramID)) - *result = (double) param->getDefaultValue(); - else - *result = 0.0; - - jassert (*result >= 0 && *result <= 1.0f); - - return AAX_SUCCESS; - } - - AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } - - Optional getPosition() const override - { - PositionInfo info; - - const AAX_ITransport& transport = *Transport(); - - info.setBpm ([&] - { - double bpm = 0.0; - - return transport.GetCurrentTempo (&bpm) == AAX_SUCCESS ? makeOptional (bpm) : nullopt; - }()); - - const auto signature = [&] - { - int32_t num = 4, den = 4; - - return transport.GetCurrentMeter (&num, &den) == AAX_SUCCESS - ? makeOptional (TimeSignature { (int) num, (int) den }) - : nullopt; - }(); - - info.setTimeSignature (signature); - - info.setIsPlaying ([&] - { - bool isPlaying = false; - - return transport.IsTransportPlaying (&isPlaying) == AAX_SUCCESS && isPlaying; - }()); - - info.setIsRecording (recordingState.get().orFallback (false)); - - const auto optionalTimeInSamples = [&info, &transport] - { - int64_t timeInSamples = 0; - return ((! info.getIsPlaying() && transport.GetTimelineSelectionStartPosition (&timeInSamples) == AAX_SUCCESS) - || transport.GetCurrentNativeSampleLocation (&timeInSamples) == AAX_SUCCESS) - ? makeOptional (timeInSamples) - : nullopt; - }(); - - info.setTimeInSamples (optionalTimeInSamples); - info.setTimeInSeconds ((float) optionalTimeInSamples.orFallback (0) / sampleRate); - - const auto tickPosition = [&] - { - int64_t ticks = 0; - - return ((info.getIsPlaying() && transport.GetCustomTickPosition (&ticks, optionalTimeInSamples.orFallback (0))) == AAX_SUCCESS) - || transport.GetCurrentTickPosition (&ticks) == AAX_SUCCESS - ? makeOptional (ticks) - : nullopt; - }(); - - info.setPpqPosition (tickPosition.hasValue() ? makeOptional (static_cast (*tickPosition) / 960'000.0) : nullopt); - - bool isLooping = false; - int64_t loopStartTick = 0, loopEndTick = 0; - - if (transport.GetCurrentLoopPosition (&isLooping, &loopStartTick, &loopEndTick) == AAX_SUCCESS) - { - info.setIsLooping (isLooping); - info.setLoopPoints (LoopPoints { (double) loopStartTick / 960000.0, (double) loopEndTick / 960000.0 }); - } - - AAX_EFrameRate frameRate; - int32_t offset; - - if (transport.GetTimeCodeInfo (&frameRate, &offset) == AAX_SUCCESS) - { - info.setFrameRate ([&]() -> Optional - { - switch ((JUCE_AAX_EFrameRate) frameRate) - { - case JUCE_AAX_eFrameRate_24Frame: return FrameRate().withBaseRate (24); - case JUCE_AAX_eFrameRate_23976: return FrameRate().withBaseRate (24).withPullDown(); - - case JUCE_AAX_eFrameRate_25Frame: return FrameRate().withBaseRate (25); - - case JUCE_AAX_eFrameRate_30NonDrop: return FrameRate().withBaseRate (30); - case JUCE_AAX_eFrameRate_30DropFrame: return FrameRate().withBaseRate (30).withDrop(); - case JUCE_AAX_eFrameRate_2997NonDrop: return FrameRate().withBaseRate (30).withPullDown(); - case JUCE_AAX_eFrameRate_2997DropFrame: return FrameRate().withBaseRate (30).withPullDown().withDrop(); - - case JUCE_AAX_eFrameRate_48Frame: return FrameRate().withBaseRate (48); - case JUCE_AAX_eFrameRate_47952: return FrameRate().withBaseRate (48).withPullDown(); - - case JUCE_AAX_eFrameRate_50Frame: return FrameRate().withBaseRate (50); - - case JUCE_AAX_eFrameRate_60NonDrop: return FrameRate().withBaseRate (60); - case JUCE_AAX_eFrameRate_60DropFrame: return FrameRate().withBaseRate (60).withDrop(); - case JUCE_AAX_eFrameRate_5994NonDrop: return FrameRate().withBaseRate (60).withPullDown(); - case JUCE_AAX_eFrameRate_5994DropFrame: return FrameRate().withBaseRate (60).withPullDown().withDrop(); - - case JUCE_AAX_eFrameRate_100Frame: return FrameRate().withBaseRate (100); - - case JUCE_AAX_eFrameRate_120NonDrop: return FrameRate().withBaseRate (120); - case JUCE_AAX_eFrameRate_120DropFrame: return FrameRate().withBaseRate (120).withDrop(); - case JUCE_AAX_eFrameRate_11988NonDrop: return FrameRate().withBaseRate (120).withPullDown(); - case JUCE_AAX_eFrameRate_11988DropFrame: return FrameRate().withBaseRate (120).withPullDown().withDrop(); - - case JUCE_AAX_eFrameRate_Undeclared: break; - } - - return {}; - }()); - } - - const auto effectiveRate = info.getFrameRate().hasValue() ? info.getFrameRate()->getEffectiveRate() : 0.0; - info.setEditOriginTime (makeOptional (effectiveRate != 0.0 ? offset / effectiveRate : offset)); - - { - int32_t bars{}, beats{}; - int64_t displayTicks{}; - - if (optionalTimeInSamples.hasValue() - && transport.GetBarBeatPosition (&bars, &beats, &displayTicks, *optionalTimeInSamples) == AAX_SUCCESS) - { - info.setBarCount (bars); - - if (signature.hasValue()) - { - const auto ticksSinceBar = static_cast (((beats - 1) * 4 * 960'000) / signature->denominator) + displayTicks; - - if (tickPosition.hasValue() && ticksSinceBar <= tickPosition) - { - const auto barStartInTicks = static_cast (*tickPosition - ticksSinceBar); - info.setPpqPositionOfLastBarStart (barStartInTicks / 960'000.0); - } - } - } - } - - return info; - } - - void audioProcessorParameterChanged (AudioProcessor* /*processor*/, int parameterIndex, float newValue) override - { - if (inParameterChangedCallback.get()) - { - inParameterChangedCallback = false; - return; - } - - if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) - SetParameterNormalizedValue (paramID, (double) newValue); - } - - void audioProcessorChanged (AudioProcessor* processor, const ChangeDetails& details) override - { - ++mNumPlugInChanges; - - if (details.parameterInfoChanged) - { - for (const auto* param : juceParameters) - if (auto* aaxParam = mParameterManager.GetParameterByID (getAAXParamIDFromJuceIndex (param->getParameterIndex()))) - syncParameterAttributes (aaxParam, param); - } - - if (details.latencyChanged) - check (Controller()->SetSignalLatency (processor->getLatencySamples())); - - if (details.nonParameterStateChanged) - ++numSetDirtyCalls; - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int parameterIndex) override - { - if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) - TouchParameter (paramID); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int parameterIndex) override - { - if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) - ReleaseParameter (paramID); - } - - AAX_Result NotificationReceived (AAX_CTypeID type, const void* data, uint32_t size) override - { - switch (type) - { - case AAX_eNotificationEvent_EnteringOfflineMode: pluginInstance->setNonRealtime (true); break; - case AAX_eNotificationEvent_ExitingOfflineMode: pluginInstance->setNonRealtime (false); break; - - case AAX_eNotificationEvent_ASProcessingState: - { - if (data != nullptr && size == sizeof (AAX_EProcessingState)) - { - const auto state = *static_cast (data); - const auto nonRealtime = state == AAX_eProcessingState_StartPass - || state == AAX_eProcessingState_BeginPassGroup; - pluginInstance->setNonRealtime (nonRealtime); - } - - break; - } - - case AAX_eNotificationEvent_TrackNameChanged: - if (data != nullptr) - { - AudioProcessor::TrackProperties props; - props.name = String::fromUTF8 (static_cast (data)->Get()); - - pluginInstance->updateTrackProperties (props); - } - break; - - case AAX_eNotificationEvent_SideChainBeingConnected: - case AAX_eNotificationEvent_SideChainBeingDisconnected: - { - processingSidechainChange = true; - sidechainDesired = (type == AAX_eNotificationEvent_SideChainBeingConnected); - updateSidechainState(); - break; - } - - #if JUCE_AAX_HAS_TRANSPORT_NOTIFICATION - case AAX_eNotificationEvent_TransportStateChanged: - if (data != nullptr) - { - const auto& info = *static_cast (data); - recordingState.set (info.mIsRecording); - } - break; - #endif - } - - return AAX_CEffectParameters::NotificationReceived (type, data, size); - } - - const float* getAudioBufferForInput (const float* const* inputs, int sidechain, int mainNumIns, int idx) const noexcept - { - jassert (idx < (mainNumIns + 1)); - - if (idx < mainNumIns) - return inputs[inputLayoutMap[idx]]; - - return (sidechain != -1 ? inputs[sidechain] : sideChainBuffer.data()); - } - - void process (const float* const* inputs, float* const* outputs, const int sideChainBufferIdx, - const int bufferSize, const bool bypass, - AAX_IMIDINode* midiNodeIn, AAX_IMIDINode* midiNodesOut, - float* const meterBuffers) - { - auto numIns = pluginInstance->getTotalNumInputChannels(); - auto numOuts = pluginInstance->getTotalNumOutputChannels(); - auto numMeters = aaxMeters.size(); - - const ScopedLock sl (pluginInstance->getCallbackLock()); - - bool isSuspended = [this, sideChainBufferIdx] - { - if (processingSidechainChange) - return true; - - bool processWantsSidechain = (sideChainBufferIdx != -1); - - if (hasSidechain && canDisableSidechain && (sidechainDesired != processWantsSidechain)) - { - sidechainDesired = processWantsSidechain; - processingSidechainChange = true; - triggerAsyncUpdate(); - return true; - } - - return pluginInstance->isSuspended(); - }(); - - if (isSuspended) - { - for (int i = 0; i < numOuts; ++i) - FloatVectorOperations::clear (outputs[i], bufferSize); - - if (meterBuffers != nullptr) - FloatVectorOperations::clear (meterBuffers, numMeters); - } - else - { - auto mainNumIns = pluginInstance->getMainBusNumInputChannels(); - auto sidechain = (pluginInstance->getChannelCountOfBus (true, 1) > 0 ? sideChainBufferIdx : -1); - auto numChans = jmax (numIns, numOuts); - - if (numChans == 0) - return; - - if (channelList.size() <= numChans) - channelList.insertMultiple (-1, nullptr, 1 + numChans - channelList.size()); - - float** channels = channelList.getRawDataPointer(); - - if (numOuts >= numIns) - { - for (int i = 0; i < numOuts; ++i) - channels[i] = outputs[outputLayoutMap[i]]; - - for (int i = 0; i < numIns; ++i) - memcpy (channels[i], getAudioBufferForInput (inputs, sidechain, mainNumIns, i), (size_t) bufferSize * sizeof (float)); - - for (int i = numIns; i < numOuts; ++i) - zeromem (channels[i], (size_t) bufferSize * sizeof (float)); - - process (channels, numOuts, bufferSize, bypass, midiNodeIn, midiNodesOut); - } - else - { - for (int i = 0; i < numOuts; ++i) - channels[i] = outputs[outputLayoutMap[i]]; - - for (int i = 0; i < numOuts; ++i) - memcpy (channels[i], getAudioBufferForInput (inputs, sidechain, mainNumIns, i), (size_t) bufferSize * sizeof (float)); - - for (int i = numOuts; i < numIns; ++i) - channels[i] = const_cast (getAudioBufferForInput (inputs, sidechain, mainNumIns, i)); - - process (channels, numIns, bufferSize, bypass, midiNodeIn, midiNodesOut); - } - - if (meterBuffers != nullptr) - for (int i = 0; i < numMeters; ++i) - meterBuffers[i] = aaxMeters[i]->getValue(); - } - } - - //============================================================================== - // In aax, the format of the aux and sidechain buses need to be fully determined - // by the format on the main buses. This function tried to provide such a mapping. - // Returns false if the in/out main layout is not supported - static bool fullBusesLayoutFromMainLayout (const AudioProcessor& p, - const AudioChannelSet& mainInput, const AudioChannelSet& mainOutput, - AudioProcessor::BusesLayout& fullLayout) - { - auto currentLayout = getDefaultLayout (p, true); - bool success = p.checkBusesLayoutSupported (currentLayout); - jassertquiet (success); - - auto numInputBuses = p.getBusCount (true); - auto numOutputBuses = p.getBusCount (false); - - if (auto* bus = p.getBus (true, 0)) - if (! bus->isLayoutSupported (mainInput, ¤tLayout)) - return false; - - if (auto* bus = p.getBus (false, 0)) - if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) - return false; - - // did this change the input again - if (numInputBuses > 0 && currentLayout.inputBuses.getReference (0) != mainInput) - return false; - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - - if (! AudioProcessor::containsLayout (currentLayout, configs)) - return false; - #endif - - bool foundValid = false; - { - auto onlyMains = currentLayout; - - for (int i = 1; i < numInputBuses; ++i) - onlyMains.inputBuses.getReference (i) = AudioChannelSet::disabled(); - - for (int i = 1; i < numOutputBuses; ++i) - onlyMains.outputBuses.getReference (i) = AudioChannelSet::disabled(); - - if (p.checkBusesLayoutSupported (onlyMains)) - { - foundValid = true; - fullLayout = onlyMains; - } - } - - if (numInputBuses > 1) - { - // can the first bus be a sidechain or disabled, if not then we can't use this layout combination - if (auto* bus = p.getBus (true, 1)) - if (! bus->isLayoutSupported (AudioChannelSet::mono(), ¤tLayout) && ! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) - return foundValid; - - // can all the other inputs be disabled, if not then we can't use this layout combination - for (int i = 2; i < numInputBuses; ++i) - if (auto* bus = p.getBus (true, i)) - if (! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) - return foundValid; - - if (auto* bus = p.getBus (true, 0)) - if (! bus->isLayoutSupported (mainInput, ¤tLayout)) - return foundValid; - - if (auto* bus = p.getBus (false, 0)) - if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) - return foundValid; - - // recheck if the format is correct - if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput) - || (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput)) - return foundValid; - - auto& sidechainBus = currentLayout.inputBuses.getReference (1); - - if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) - return foundValid; - - for (int i = 2; i < numInputBuses; ++i) - if (! currentLayout.inputBuses.getReference (i).isDisabled()) - return foundValid; - } - - const bool hasSidechain = (numInputBuses > 1 && currentLayout.inputBuses.getReference (1) == AudioChannelSet::mono()); - - if (hasSidechain) - { - auto onlyMainsAndSidechain = currentLayout; - - for (int i = 1; i < numOutputBuses; ++i) - onlyMainsAndSidechain.outputBuses.getReference (i) = AudioChannelSet::disabled(); - - if (p.checkBusesLayoutSupported (onlyMainsAndSidechain)) - { - foundValid = true; - fullLayout = onlyMainsAndSidechain; - } - } - - if (numOutputBuses > 1) - { - auto copy = currentLayout; - int maxAuxBuses = jmin (16, numOutputBuses); - - for (int i = 1; i < maxAuxBuses; ++i) - copy.outputBuses.getReference (i) = mainOutput; - - for (int i = maxAuxBuses; i < numOutputBuses; ++i) - copy.outputBuses.getReference (i) = AudioChannelSet::disabled(); - - if (p.checkBusesLayoutSupported (copy)) - { - fullLayout = copy; - foundValid = true; - } - else - { - for (int i = 1; i < maxAuxBuses; ++i) - if (currentLayout.outputBuses.getReference (i).isDisabled()) - return foundValid; - - for (int i = maxAuxBuses; i < numOutputBuses; ++i) - if (auto* bus = p.getBus (false, i)) - if (! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) - return foundValid; - - if (auto* bus = p.getBus (true, 0)) - if (! bus->isLayoutSupported (mainInput, ¤tLayout)) - return foundValid; - - if (auto* bus = p.getBus (false, 0)) - if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) - return foundValid; - - if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput) - || (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput)) - return foundValid; - - if (numInputBuses > 1) - { - auto& sidechainBus = currentLayout.inputBuses.getReference (1); - - if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) - return foundValid; - } - - for (int i = maxAuxBuses; i < numOutputBuses; ++i) - if (! currentLayout.outputBuses.getReference (i).isDisabled()) - return foundValid; - - fullLayout = currentLayout; - foundValid = true; - } - } - - return foundValid; - } - - bool isInAudioSuite() - { - AAX_CBoolean res; - Controller()->GetIsAudioSuite (&res); - - return res > 0; - } - - private: - friend class JuceAAX_GUI; - friend void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd); - - void process (float* const* channels, const int numChans, const int bufferSize, - const bool bypass, [[maybe_unused]] AAX_IMIDINode* midiNodeIn, [[maybe_unused]] AAX_IMIDINode* midiNodesOut) - { - AudioBuffer buffer (channels, numChans, bufferSize); - midiBuffer.clear(); - - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - { - auto* midiStream = midiNodeIn->GetNodeBuffer(); - auto numMidiEvents = midiStream->mBufferSize; - - for (uint32_t i = 0; i < numMidiEvents; ++i) - { - auto& m = midiStream->mBuffer[i]; - jassert ((int) m.mTimestamp < bufferSize); - - midiBuffer.addEvent (m.mData, (int) m.mLength, - jlimit (0, (int) bufferSize - 1, (int) m.mTimestamp)); - } - } - #endif - - { - if (lastBufferSize != bufferSize) - { - lastBufferSize = bufferSize; - pluginInstance->setRateAndBufferSizeDetails (sampleRate, lastBufferSize); - - // we only call prepareToPlay here if the new buffer size is larger than - // the one used last time prepareToPlay was called. - // currently, this should never actually happen, because as of Pro Tools 12, - // the maximum possible value is 1024, and we call prepareToPlay with that - // value during initialisation. - if (bufferSize > maxBufferSize) - prepareProcessorWithSampleRateAndBufferSize (sampleRate, bufferSize); - } - - if (bypass && pluginInstance->getBypassParameter() == nullptr) - pluginInstance->processBlockBypassed (buffer, midiBuffer); - else - pluginInstance->processBlock (buffer, midiBuffer); - } - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - { - AAX_CMidiPacket packet; - packet.mIsImmediate = false; - - for (const auto metadata : midiBuffer) - { - jassert (isPositiveAndBelow (metadata.samplePosition, bufferSize)); - - if (metadata.numBytes <= 4) - { - packet.mTimestamp = (uint32_t) metadata.samplePosition; - packet.mLength = (uint32_t) metadata.numBytes; - memcpy (packet.mData, metadata.data, (size_t) metadata.numBytes); - - check (midiNodesOut->PostMIDIPacket (&packet)); - } - } - } - #endif - } - - bool isBypassPartOfRegularParemeters() const - { - auto& audioProcessor = getPluginInstance(); - - int n = juceParameters.getNumParameters(); - - if (auto* bypassParam = audioProcessor.getBypassParameter()) - for (int i = 0; i < n; ++i) - if (juceParameters.getParamForIndex (i) == bypassParam) - return true; - - return false; - } - - // Some older Pro Tools control surfaces (EUCON [PT version 12.4] and - // Avid S6 before version 2.1) cannot cope with a large number of - // parameter steps. - static int32_t getSafeNumberOfParameterSteps (const AudioProcessorParameter& param) - { - return jmin (param.getNumSteps(), 2048); - } - - void addAudioProcessorParameters() - { - auto& audioProcessor = getPluginInstance(); - - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - const bool forceLegacyParamIDs = true; - #else - const bool forceLegacyParamIDs = false; - #endif - - auto bypassPartOfRegularParams = isBypassPartOfRegularParemeters(); - - juceParameters.update (audioProcessor, forceLegacyParamIDs); - - auto* bypassParameter = pluginInstance->getBypassParameter(); - - if (bypassParameter == nullptr) - { - ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false)); - bypassParameter = ownedBypassParameter.get(); - } - - if (! bypassPartOfRegularParams) - juceParameters.addNonOwning (bypassParameter); - - int parameterIndex = 0; - - for (auto* juceParam : juceParameters) - { - auto isBypassParameter = (juceParam == bypassParameter); - - auto category = juceParam->getCategory(); - auto paramID = isBypassParameter ? String (cDefaultMasterBypassID) - : juceParameters.getParamID (audioProcessor, parameterIndex); - - aaxParamIDs.add (paramID); - auto* aaxParamID = aaxParamIDs.getReference (parameterIndex++).toRawUTF8(); - - paramMap.set (AAXClasses::getAAXParamHash (aaxParamID), juceParam); - - // is this a meter? - if (((category & 0xffff0000) >> 16) == 2) - { - aaxMeters.add (juceParam); - continue; - } - - auto parameter = new AAX_CParameter (aaxParamID, - AAX_CString (juceParam->getName (31).toRawUTF8()), - juceParam->getDefaultValue(), - AAX_CLinearTaperDelegate(), - AAX_CNumberDisplayDelegate(), - juceParam->isAutomatable()); - - parameter->AddShortenedName (juceParam->getName (4).toRawUTF8()); - - auto parameterNumSteps = getSafeNumberOfParameterSteps (*juceParam); - parameter->SetNumberOfSteps ((uint32_t) parameterNumSteps); - - #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - parameter->SetType (parameterNumSteps > 1000 ? AAX_eParameterType_Continuous - : AAX_eParameterType_Discrete); - #else - parameter->SetType (juceParam->isDiscrete() ? AAX_eParameterType_Discrete - : AAX_eParameterType_Continuous); - #endif - - parameter->SetOrientation (juceParam->isOrientationInverted() - ? (AAX_eParameterOrientation_RightMinLeftMax | AAX_eParameterOrientation_TopMinBottomMax - | AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryRightMinLeftMax) - : (AAX_eParameterOrientation_LeftMinRightMax | AAX_eParameterOrientation_BottomMinTopMax - | AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryLeftMinRightMax)); - - mParameterManager.AddParameter (parameter); - - if (isBypassParameter) - mPacketDispatcher.RegisterPacket (aaxParamID, JUCEAlgorithmIDs::bypass); - } - } - - bool getMainBusFormats (AudioChannelSet& inputSet, AudioChannelSet& outputSet) - { - auto& audioProcessor = getPluginInstance(); - - #if JucePlugin_IsMidiEffect - // MIDI effect plug-ins do not support any audio channels - jassert (audioProcessor.getTotalNumInputChannels() == 0 - && audioProcessor.getTotalNumOutputChannels() == 0); - - inputSet = outputSet = AudioChannelSet(); - return true; - #else - auto inputBuses = audioProcessor.getBusCount (true); - auto outputBuses = audioProcessor.getBusCount (false); - - AAX_EStemFormat inputStemFormat = AAX_eStemFormat_None; - check (Controller()->GetInputStemFormat (&inputStemFormat)); - - AAX_EStemFormat outputStemFormat = AAX_eStemFormat_None; - check (Controller()->GetOutputStemFormat (&outputStemFormat)); - - #if JucePlugin_IsSynth - if (inputBuses == 0) - inputStemFormat = AAX_eStemFormat_None; - #endif - - inputSet = (inputBuses > 0 ? channelSetFromStemFormat (inputStemFormat, false) : AudioChannelSet()); - outputSet = (outputBuses > 0 ? channelSetFromStemFormat (outputStemFormat, false) : AudioChannelSet()); - - if ((inputSet == AudioChannelSet::disabled() && inputStemFormat != AAX_eStemFormat_None) || (outputSet == AudioChannelSet::disabled() && outputStemFormat != AAX_eStemFormat_None) - || (inputSet != AudioChannelSet::disabled() && inputBuses == 0) || (outputSet != AudioChannelSet::disabled() && outputBuses == 0)) - return false; - - return true; - #endif - } - - AAX_Result preparePlugin() - { - auto& audioProcessor = getPluginInstance(); - auto oldLayout = audioProcessor.getBusesLayout(); - AudioChannelSet inputSet, outputSet; - - if (! getMainBusFormats (inputSet, outputSet)) - { - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - AudioProcessor::BusesLayout newLayout; - - if (! fullBusesLayoutFromMainLayout (audioProcessor, inputSet, outputSet, newLayout)) - { - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - hasSidechain = (newLayout.getNumChannels (true, 1) == 1); - - if (hasSidechain) - { - sidechainDesired = true; - - auto disabledSidechainLayout = newLayout; - disabledSidechainLayout.inputBuses.getReference (1) = AudioChannelSet::disabled(); - - canDisableSidechain = audioProcessor.checkBusesLayoutSupported (disabledSidechainLayout); - - if (canDisableSidechain && ! lastSideChainState) - { - sidechainDesired = false; - newLayout = disabledSidechainLayout; - } - } - - if (isInAudioSuite()) - { - // AudioSuite doesn't support multiple output buses - for (int i = 1; i < newLayout.outputBuses.size(); ++i) - newLayout.outputBuses.getReference (i) = AudioChannelSet::disabled(); - - if (! audioProcessor.checkBusesLayoutSupported (newLayout)) - { - // your plug-in needs to support a single output bus if running in AudioSuite - jassertfalse; - - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - return AAX_ERROR_UNIMPLEMENTED; - } - } - - const bool layoutChanged = (oldLayout != newLayout); - - if (layoutChanged) - { - if (! audioProcessor.setBusesLayout (newLayout)) - { - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - rebuildChannelMapArrays(); - } - - if (layoutChanged || (! isPrepared)) - { - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - prepareProcessorWithSampleRateAndBufferSize (sampleRate, lastBufferSize); - - midiBuffer.ensureSize (2048); - midiBuffer.clear(); - } - - check (Controller()->SetSignalLatency (audioProcessor.getLatencySamples())); - isPrepared = true; - - return AAX_SUCCESS; - } - - void rebuildChannelMapArrays() - { - auto& audioProcessor = getPluginInstance(); - - for (int dir = 0; dir < 2; ++dir) - { - bool isInput = (dir == 0); - auto& layoutMap = isInput ? inputLayoutMap : outputLayoutMap; - layoutMap.clear(); - - auto numBuses = audioProcessor.getBusCount (isInput); - int chOffset = 0; - - for (int busIdx = 0; busIdx < numBuses; ++busIdx) - { - auto channelFormat = audioProcessor.getChannelLayoutOfBus (isInput, busIdx); - - if (channelFormat != AudioChannelSet::disabled()) - { - auto numChannels = channelFormat.size(); - - for (int ch = 0; ch < numChannels; ++ch) - layoutMap.add (juceChannelIndexToAax (ch, channelFormat) + chOffset); - - chOffset += numChannels; - } - } - } - } - - static void algorithmCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd) - { - for (auto iter = instancesBegin; iter < instancesEnd; ++iter) - { - auto& i = **iter; - - int sideChainBufferIdx = i.pluginInstance->parameters.hasSidechain && i.sideChainBuffers != nullptr - ? static_cast (*i.sideChainBuffers) : -1; - - // sidechain index of zero is an invalid index - if (sideChainBufferIdx <= 0) - sideChainBufferIdx = -1; - - auto numMeters = i.pluginInstance->parameters.aaxMeters.size(); - float* const meterTapBuffers = (i.meterTapBuffers != nullptr && numMeters > 0 ? *i.meterTapBuffers : nullptr); - - i.pluginInstance->parameters.process (i.inputChannels, i.outputChannels, sideChainBufferIdx, - *(i.bufferSize), *(i.bypass) != 0, - getMidiNodeIn(i), getMidiNodeOut(i), - meterTapBuffers); - } - } - - void prepareProcessorWithSampleRateAndBufferSize (double sr, int bs) - { - maxBufferSize = jmax (maxBufferSize, bs); - - auto& audioProcessor = getPluginInstance(); - audioProcessor.setRateAndBufferSizeDetails (sr, maxBufferSize); - audioProcessor.prepareToPlay (sr, maxBufferSize); - sideChainBuffer.resize (static_cast (maxBufferSize)); - } - - //============================================================================== - void updateSidechainState() - { - if (! processingSidechainChange) - return; - - auto& audioProcessor = getPluginInstance(); - const auto sidechainActual = audioProcessor.getChannelCountOfBus (true, 1) > 0; - - if (hasSidechain && canDisableSidechain && sidechainDesired != sidechainActual) - { - lastSideChainState = sidechainDesired; - - if (isPrepared) - { - isPrepared = false; - audioProcessor.releaseResources(); - } - - if (auto* bus = audioProcessor.getBus (true, 1)) - bus->setCurrentLayout (lastSideChainState ? AudioChannelSet::mono() - : AudioChannelSet::disabled()); - - prepareProcessorWithSampleRateAndBufferSize (audioProcessor.getSampleRate(), maxBufferSize); - isPrepared = true; - } - - processingSidechainChange = false; - } - - void handleAsyncUpdate() override - { - updateSidechainState(); - } - - //============================================================================== - static AudioProcessor::CurveData::Type aaxCurveTypeToJUCE (AAX_CTypeID type) noexcept - { - switch (type) - { - case AAX_eCurveType_EQ: return AudioProcessor::CurveData::Type::EQ; - case AAX_eCurveType_Dynamics: return AudioProcessor::CurveData::Type::Dynamics; - case AAX_eCurveType_Reduction: return AudioProcessor::CurveData::Type::GainReduction; - default: break; - } - - return AudioProcessor::CurveData::Type::Unknown; - } - - uint32_t getAAXMeterIdForParamId (const String& paramID) const noexcept - { - int idx; - - for (idx = 0; idx < aaxMeters.size(); ++idx) - if (LegacyAudioParameter::getParamID (aaxMeters[idx], false) == paramID) - break; - - // you specified a parameter id in your curve but the parameter does not have the meter - // category - jassert (idx < aaxMeters.size()); - return 'Metr' + static_cast (idx); - } - - //============================================================================== - AAX_Result GetCurveData (AAX_CTypeID iCurveType, const float * iValues, uint32_t iNumValues, float * oValues ) const override - { - auto curveType = aaxCurveTypeToJUCE (iCurveType); - - if (curveType != AudioProcessor::CurveData::Type::Unknown) - { - auto& audioProcessor = getPluginInstance(); - auto curve = audioProcessor.getResponseCurve (curveType); - - if (curve.curve) - { - if (oValues != nullptr && iValues != nullptr) - { - for (uint32_t i = 0; i < iNumValues; ++i) - oValues[i] = curve.curve (iValues[i]); - } - - return AAX_SUCCESS; - } - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - AAX_Result GetCurveDataMeterIds (AAX_CTypeID iCurveType, uint32_t *oXMeterId, uint32_t *oYMeterId) const override - { - auto curveType = aaxCurveTypeToJUCE (iCurveType); - - if (curveType != AudioProcessor::CurveData::Type::Unknown) - { - auto& audioProcessor = getPluginInstance(); - auto curve = audioProcessor.getResponseCurve (curveType); - - if (curve.curve && curve.xMeterID.isNotEmpty() && curve.yMeterID.isNotEmpty()) - { - if (oXMeterId != nullptr) *oXMeterId = getAAXMeterIdForParamId (curve.xMeterID); - if (oYMeterId != nullptr) *oYMeterId = getAAXMeterIdForParamId (curve.yMeterID); - - return AAX_SUCCESS; - } - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - AAX_Result GetCurveDataDisplayRange (AAX_CTypeID iCurveType, float *oXMin, float *oXMax, float *oYMin, float *oYMax) const override - { - auto curveType = aaxCurveTypeToJUCE (iCurveType); - - if (curveType != AudioProcessor::CurveData::Type::Unknown) - { - auto& audioProcessor = getPluginInstance(); - auto curve = audioProcessor.getResponseCurve (curveType); - - if (curve.curve) - { - if (oXMin != nullptr) *oXMin = curve.xRange.getStart(); - if (oXMax != nullptr) *oXMax = curve.xRange.getEnd(); - if (oYMin != nullptr) *oYMin = curve.yRange.getStart(); - if (oYMax != nullptr) *oYMax = curve.yRange.getEnd(); - - return AAX_SUCCESS; - } - } - - return AAX_ERROR_UNIMPLEMENTED; - } - - //============================================================================== - inline int getParamIndexFromID (AAX_CParamID paramID) const noexcept - { - if (auto* param = getParameterFromID (paramID)) - return LegacyAudioParameter::getParamIndex (getPluginInstance(), param); - - return -1; - } - - inline AAX_CParamID getAAXParamIDFromJuceIndex (int index) const noexcept - { - if (isPositiveAndBelow (index, aaxParamIDs.size())) - return aaxParamIDs.getReference (index).toRawUTF8(); - - return nullptr; - } - - AudioProcessorParameter* getParameterFromID (AAX_CParamID paramID) const noexcept - { - return paramMap [AAXClasses::getAAXParamHash (paramID)]; - } - - //============================================================================== - static AudioProcessor::BusesLayout getDefaultLayout (const AudioProcessor& p, bool enableAll) - { - AudioProcessor::BusesLayout defaultLayout; - - for (int dir = 0; dir < 2; ++dir) - { - bool isInput = (dir == 0); - auto numBuses = p.getBusCount (isInput); - auto& layouts = (isInput ? defaultLayout.inputBuses : defaultLayout.outputBuses); - - for (int i = 0; i < numBuses; ++i) - if (auto* bus = p.getBus (isInput, i)) - layouts.add (enableAll || bus->isEnabledByDefault() ? bus->getDefaultLayout() : AudioChannelSet()); - } - - return defaultLayout; - } - - static AudioProcessor::BusesLayout getDefaultLayout (AudioProcessor& p) - { - auto defaultLayout = getDefaultLayout (p, true); - - if (! p.checkBusesLayoutSupported (defaultLayout)) - defaultLayout = getDefaultLayout (p, false); - - // Your processor must support the default layout - jassert (p.checkBusesLayoutSupported (defaultLayout)); - return defaultLayout; - } - - void syncParameterAttributes (AAX_IParameter* aaxParam, const AudioProcessorParameter* juceParam) - { - if (juceParam == nullptr) - return; - - { - auto newName = juceParam->getName (31); - - if (aaxParam->Name() != newName.toRawUTF8()) - aaxParam->SetName (AAX_CString (newName.toRawUTF8())); - } - - { - auto newType = juceParam->isDiscrete() ? AAX_eParameterType_Discrete : AAX_eParameterType_Continuous; - - if (aaxParam->GetType() != newType) - aaxParam->SetType (newType); - } - - { - auto newNumSteps = static_cast (juceParam->getNumSteps()); - - if (aaxParam->GetNumberOfSteps() != newNumSteps) - aaxParam->SetNumberOfSteps (newNumSteps); - } - - { - auto defaultValue = juceParam->getDefaultValue(); - - if (! approximatelyEqual (static_cast (aaxParam->GetNormalizedDefaultValue()), defaultValue)) - aaxParam->SetNormalizedDefaultValue (defaultValue); - } - } - - //============================================================================== - ScopedJuceInitialiser_GUI libraryInitialiser; - - std::unique_ptr pluginInstance; - - static constexpr auto maxSamplesPerBlock = 1 << AAX_eAudioBufferLength_Max; - - bool isPrepared = false; - MidiBuffer midiBuffer; - Array channelList; - int32_t juceChunkIndex = 0, numSetDirtyCalls = 0; - AAX_CSampleRate sampleRate = 0; - int lastBufferSize = maxSamplesPerBlock, maxBufferSize = maxSamplesPerBlock; - bool hasSidechain = false, canDisableSidechain = false, lastSideChainState = false; - - /* Pro Tools 2021 sends TransportStateChanged on the main thread, but we read - the recording state on the audio thread. - I'm not sure whether Pro Tools ensures that these calls are mutually - exclusive, so to ensure there are no data races, we store the recording - state in an atomic int and convert it to/from an Optional as necessary. - */ - class RecordingState - { - public: - /* This uses Optional rather than std::optional for consistency with get() */ - void set (const Optional newState) - { - state.store (newState.hasValue() ? (flagValid | (*newState ? flagActive : 0)) - : 0, - std::memory_order_relaxed); - } - - /* PositionInfo::setIsRecording takes an Optional, so we use that type rather - than std::optional to avoid having to convert. - */ - Optional get() const - { - const auto loaded = state.load (std::memory_order_relaxed); - return ((loaded & flagValid) != 0) ? makeOptional ((loaded & flagActive) != 0) - : nullopt; - } - - private: - enum RecordingFlags - { - flagValid = 1 << 0, - flagActive = 1 << 1 - }; - - std::atomic state { 0 }; - }; - - RecordingState recordingState; - - std::atomic processingSidechainChange, sidechainDesired; - - std::vector sideChainBuffer; - Array inputLayoutMap, outputLayoutMap; - - Array aaxParamIDs; - HashMap paramMap; - LegacyAudioParametersWrapper juceParameters; - std::unique_ptr ownedBypassParameter; - - Array aaxMeters; - - struct ChunkMemoryBlock - { - juce::MemoryBlock data; - bool isValid; - }; - - // temporary filter data is generated in GetChunkSize - // and the size of the data returned. To avoid generating - // it again in GetChunk, we need to store it somewhere. - // However, as GetChunkSize and GetChunk can be called - // on different threads, we store it in thread dependent storage - // in a hash map with the thread id as a key. - mutable ThreadLocalValue perThreadFilterData; - CriticalSection perThreadDataLock; - - ThreadLocalValue inParameterChangedCallback; - - JUCE_DECLARE_NON_COPYABLE (JuceAAX_Processor) - }; - - //============================================================================== - void JuceAAX_GUI::CreateViewContents() - { - if (component == nullptr) - { - if (auto* params = dynamic_cast (GetEffectParameters())) - component.reset (new ContentWrapperComponent (*this, params->getPluginInstance())); - else - jassertfalse; - } - } - - int JuceAAX_GUI::getParamIndexFromID (AAX_CParamID paramID) const noexcept - { - if (auto* params = dynamic_cast (GetEffectParameters())) - return params->getParamIndexFromID (paramID); - - return -1; - } - - AAX_CParamID JuceAAX_GUI::getAAXParamIDFromJuceIndex (int index) const noexcept - { - if (auto* params = dynamic_cast (GetEffectParameters())) - return params->getAAXParamIDFromJuceIndex (index); - - return nullptr; - } - - //============================================================================== - struct AAXFormatConfiguration - { - AAXFormatConfiguration() noexcept {} - - AAXFormatConfiguration (AAX_EStemFormat inFormat, AAX_EStemFormat outFormat) noexcept - : inputFormat (inFormat), outputFormat (outFormat) {} - - AAX_EStemFormat inputFormat = AAX_eStemFormat_None, - outputFormat = AAX_eStemFormat_None; - - bool operator== (const AAXFormatConfiguration other) const noexcept - { - return inputFormat == other.inputFormat && outputFormat == other.outputFormat; - } - - bool operator< (const AAXFormatConfiguration other) const noexcept - { - return inputFormat == other.inputFormat ? (outputFormat < other.outputFormat) - : (inputFormat < other.inputFormat); - } - }; - - //============================================================================== - static int addAAXMeters (AudioProcessor& p, AAX_IEffectDescriptor& descriptor) - { - LegacyAudioParametersWrapper params; - - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - const bool forceLegacyParamIDs = true; - #else - const bool forceLegacyParamIDs = false; - #endif - - params.update (p, forceLegacyParamIDs); - - int meterIdx = 0; - - for (auto* param : params) - { - auto category = param->getCategory(); - - // is this a meter? - if (((category & 0xffff0000) >> 16) == 2) - { - if (auto* meterProperties = descriptor.NewPropertyMap()) - { - meterProperties->AddProperty (AAX_eProperty_Meter_Type, getMeterTypeForCategory (category)); - meterProperties->AddProperty (AAX_eProperty_Meter_Orientation, AAX_eMeterOrientation_TopRight); - - descriptor.AddMeterDescription ('Metr' + static_cast (meterIdx++), - param->getName (1024).toRawUTF8(), meterProperties); - } - } - } - - return meterIdx; - } - - static void createDescriptor (AAX_IComponentDescriptor& desc, - const AudioProcessor::BusesLayout& fullLayout, - AudioProcessor& processor, - Array& pluginIds, - const int numMeters) - { - auto aaxInputFormat = getFormatForAudioChannelSet (fullLayout.getMainInputChannelSet(), false); - auto aaxOutputFormat = getFormatForAudioChannelSet (fullLayout.getMainOutputChannelSet(), false); - - #if JucePlugin_IsSynth - if (aaxInputFormat == AAX_eStemFormat_None) - aaxInputFormat = aaxOutputFormat; - #endif - - #if JucePlugin_IsMidiEffect - aaxInputFormat = aaxOutputFormat = AAX_eStemFormat_Mono; - #endif - - check (desc.AddAudioIn (JUCEAlgorithmIDs::inputChannels)); - check (desc.AddAudioOut (JUCEAlgorithmIDs::outputChannels)); - - check (desc.AddAudioBufferLength (JUCEAlgorithmIDs::bufferSize)); - check (desc.AddDataInPort (JUCEAlgorithmIDs::bypass, sizeof (int32_t))); - - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - check (desc.AddMIDINode (JUCEAlgorithmIDs::midiNodeIn, AAX_eMIDINodeType_LocalInput, - JucePlugin_Name, 0xffff)); - #endif - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect - check (desc.AddMIDINode (JUCEAlgorithmIDs::midiNodeOut, AAX_eMIDINodeType_LocalOutput, - JucePlugin_Name " Out", 0xffff)); - #endif - - check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo))); - check (desc.AddPrivateData (JUCEAlgorithmIDs::preparedFlag, sizeof (int32_t))); - - if (numMeters > 0) - { - HeapBlock meterIDs (static_cast (numMeters)); - - for (int i = 0; i < numMeters; ++i) - meterIDs[i] = 'Metr' + static_cast (i); - - check (desc.AddMeters (JUCEAlgorithmIDs::meterTapBuffers, meterIDs.getData(), static_cast (numMeters))); - } - else - { - // AAX does not allow there to be any gaps in the fields of the algorithm context structure - // so just add a dummy one here if there aren't any meters - check (desc.AddPrivateData (JUCEAlgorithmIDs::meterTapBuffers, sizeof (uintptr_t))); - } - - // Create a property map - AAX_IPropertyMap* const properties = desc.NewPropertyMap(); - jassert (properties != nullptr); - - properties->AddProperty (AAX_eProperty_ManufacturerID, JucePlugin_AAXManufacturerCode); - properties->AddProperty (AAX_eProperty_ProductID, JucePlugin_AAXProductId); - - #if JucePlugin_AAXDisableBypass - properties->AddProperty (AAX_eProperty_CanBypass, false); - #else - properties->AddProperty (AAX_eProperty_CanBypass, true); - #endif - - properties->AddProperty (AAX_eProperty_InputStemFormat, static_cast (aaxInputFormat)); - properties->AddProperty (AAX_eProperty_OutputStemFormat, static_cast (aaxOutputFormat)); - - // This value needs to match the RTAS wrapper's Type ID, so that - // the host knows that the RTAS/AAX plugins are equivalent. - const int32 pluginID = processor.getAAXPluginIDForMainBusConfig (fullLayout.getMainInputChannelSet(), - fullLayout.getMainOutputChannelSet(), - false); - - // The plugin id generated from your AudioProcessor's getAAXPluginIDForMainBusConfig callback - // it not unique. Please fix your implementation! - jassert (! pluginIds.contains (pluginID)); - pluginIds.add (pluginID); - - properties->AddProperty (AAX_eProperty_PlugInID_Native, pluginID); - - #if ! JucePlugin_AAXDisableAudioSuite - properties->AddProperty (AAX_eProperty_PlugInID_AudioSuite, - processor.getAAXPluginIDForMainBusConfig (fullLayout.getMainInputChannelSet(), - fullLayout.getMainOutputChannelSet(), - true)); - #endif - - #if JucePlugin_AAXDisableMultiMono - properties->AddProperty (AAX_eProperty_Constraint_MultiMonoSupport, false); - #else - properties->AddProperty (AAX_eProperty_Constraint_MultiMonoSupport, true); - #endif - - #if JucePlugin_AAXDisableDynamicProcessing - properties->AddProperty (AAX_eProperty_Constraint_AlwaysProcess, true); - #endif - - #if JucePlugin_AAXDisableDefaultSettingsChunks - properties->AddProperty (AAX_eProperty_Constraint_DoNotApplyDefaultSettings, true); - #endif - - #if JucePlugin_AAXDisableSaveRestore - properties->AddProperty (AAX_eProperty_SupportsSaveRestore, false); - #endif - - #if JUCE_AAX_HAS_TRANSPORT_NOTIFICATION - properties->AddProperty (AAX_eProperty_ObservesTransportState, true); - #endif - - if (fullLayout.getChannelSet (true, 1) == AudioChannelSet::mono()) - { - check (desc.AddSideChainIn (JUCEAlgorithmIDs::sideChainBuffers)); - properties->AddProperty (AAX_eProperty_SupportsSideChainInput, true); - } - else - { - // AAX does not allow there to be any gaps in the fields of the algorithm context structure - // so just add a dummy one here if there aren't any side chains - check (desc.AddPrivateData (JUCEAlgorithmIDs::sideChainBuffers, sizeof (uintptr_t))); - } - - auto maxAuxBuses = jmax (0, jmin (15, fullLayout.outputBuses.size() - 1)); - - // add the output buses - // This is incredibly dumb: the output bus format must be well defined - // for every main bus in/out format pair. This means that there cannot - // be two configurations with different aux formats but - // identical main bus in/out formats. - for (int busIdx = 1; busIdx < maxAuxBuses + 1; ++busIdx) - { - auto set = fullLayout.getChannelSet (false, busIdx); - - if (set.isDisabled()) - break; - - auto auxFormat = getFormatForAudioChannelSet (set, true); - - if (auxFormat != AAX_eStemFormat_INT32_MAX && auxFormat != AAX_eStemFormat_None) - { - auto& name = processor.getBus (false, busIdx)->getName(); - check (desc.AddAuxOutputStem (0, static_cast (auxFormat), name.toRawUTF8())); - } - } - - check (desc.AddProcessProc_Native (algorithmProcessCallback, properties)); - } - - static bool hostSupportsStemFormat (AAX_EStemFormat stemFormat, const AAX_IFeatureInfo* featureInfo) - { - if (featureInfo != nullptr) - { - AAX_ESupportLevel supportLevel; - - if (featureInfo->SupportLevel (supportLevel) == AAX_SUCCESS && supportLevel == AAX_eSupportLevel_ByProperty) - { - std::unique_ptr props (featureInfo->AcquireProperties()); - - // Due to a bug in ProTools 12.8, ProTools thinks that AAX_eStemFormat_Ambi_1_ACN is not supported - // To workaround this bug, check if ProTools supports AAX_eStemFormat_Ambi_2_ACN, and, if yes, - // we can safely assume that it will also support AAX_eStemFormat_Ambi_1_ACN - if (stemFormat == AAX_eStemFormat_Ambi_1_ACN) - stemFormat = AAX_eStemFormat_Ambi_2_ACN; - - if (props != nullptr && props->GetProperty ((AAX_EProperty) stemFormat, (AAX_CPropertyValue*) &supportLevel) != 0) - return (supportLevel == AAX_eSupportLevel_Supported); - } - } - - return (AAX_STEM_FORMAT_INDEX (stemFormat) <= 12); - } - - static void getPlugInDescription (AAX_IEffectDescriptor& descriptor, [[maybe_unused]] const AAX_IFeatureInfo* featureInfo) - { - auto plugin = createPluginFilterOfType (AudioProcessor::wrapperType_AAX); - auto numInputBuses = plugin->getBusCount (true); - auto numOutputBuses = plugin->getBusCount (false); - - auto pluginNames = plugin->getAlternateDisplayNames(); - - pluginNames.insert (0, JucePlugin_Name); - - pluginNames.removeDuplicates (false); - - for (auto name : pluginNames) - descriptor.AddName (name.toRawUTF8()); - - descriptor.AddCategory (JucePlugin_AAXCategory); - - const int numMeters = addAAXMeters (*plugin, descriptor); - - #ifdef JucePlugin_AAXPageTableFile - // optional page table setting - define this macro in your project if you want - // to set this value - see Avid documentation for details about its format. - descriptor.AddResourceInfo (AAX_eResourceType_PageTable, JucePlugin_AAXPageTableFile); - #endif - - check (descriptor.AddProcPtr ((void*) JuceAAX_GUI::Create, kAAX_ProcPtrID_Create_EffectGUI)); - check (descriptor.AddProcPtr ((void*) JuceAAX_Processor::Create, kAAX_ProcPtrID_Create_EffectParameters)); - - Array pluginIds; - #if JucePlugin_IsMidiEffect - // MIDI effect plug-ins do not support any audio channels - jassert (numInputBuses == 0 && numOutputBuses == 0); - - if (auto* desc = descriptor.NewComponentDescriptor()) - { - createDescriptor (*desc, plugin->getBusesLayout(), *plugin, pluginIds, numMeters); - check (descriptor.AddComponent (desc)); - } - #else - const int numIns = numInputBuses > 0 ? numElementsInArray (aaxFormats) : 0; - const int numOuts = numOutputBuses > 0 ? numElementsInArray (aaxFormats) : 0; - - for (int inIdx = 0; inIdx < jmax (numIns, 1); ++inIdx) - { - auto aaxInFormat = numIns > 0 ? aaxFormats[inIdx] : AAX_eStemFormat_None; - auto inLayout = channelSetFromStemFormat (aaxInFormat, false); - - for (int outIdx = 0; outIdx < jmax (numOuts, 1); ++outIdx) - { - auto aaxOutFormat = numOuts > 0 ? aaxFormats[outIdx] : AAX_eStemFormat_None; - auto outLayout = channelSetFromStemFormat (aaxOutFormat, false); - - if (hostSupportsStemFormat (aaxInFormat, featureInfo) - && hostSupportsStemFormat (aaxOutFormat, featureInfo)) - { - AudioProcessor::BusesLayout fullLayout; - - if (! JuceAAX_Processor::fullBusesLayoutFromMainLayout (*plugin, inLayout, outLayout, fullLayout)) - continue; - - if (auto* desc = descriptor.NewComponentDescriptor()) - { - createDescriptor (*desc, fullLayout, *plugin, pluginIds, numMeters); - check (descriptor.AddComponent (desc)); - } - } - } - } - - // You don't have any supported layouts - jassert (pluginIds.size() > 0); - #endif - } -} // namespace AAXClasses - -void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd) -{ - AAXClasses::JuceAAX_Processor::algorithmCallback (instancesBegin, instancesEnd); -} - -//============================================================================== -AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*); -AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection) -{ - ScopedJuceInitialiser_GUI libraryInitialiser; - - std::unique_ptr stemFormatFeatureInfo; - - if (const auto* hostDescription = collection->DescriptionHost()) - stemFormatFeatureInfo.reset (hostDescription->AcquireFeatureProperties (AAXATTR_ClientFeature_StemFormat)); - - if (auto* descriptor = collection->NewDescriptor()) - { - AAXClasses::getPlugInDescription (*descriptor, stemFormatFeatureInfo.get()); - collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor); - - collection->SetManufacturerName (JucePlugin_Manufacturer); - collection->AddPackageName (JucePlugin_Desc); - collection->AddPackageName (JucePlugin_Name); - collection->SetPackageVersion (JucePlugin_VersionCode); - - return AAX_SUCCESS; - } - - return AAX_ERROR_NULL_OBJECT; -} - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -//============================================================================== -#if _MSC_VER || JUCE_MINGW -extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) Process::setCurrentModuleInstanceHandle (instance); return true; } -#endif - -#endif diff --git a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm deleted file mode 100644 index 4d63a0596665..000000000000 --- a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm +++ /dev/null @@ -1,2432 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include -#include "../utility/juce_CheckSettingMacros.h" - -#if JucePlugin_Build_AU - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wshorten-64-to-32", - "-Wunused-parameter", - "-Wdeprecated-declarations", - "-Wsign-conversion", - "-Wconversion", - "-Woverloaded-virtual", - "-Wextra-semi", - "-Wcast-align", - "-Wshadow", - "-Wswitch-enum", - "-Wzero-as-null-pointer-constant", - "-Wnullable-to-nonnull-conversion", - "-Wgnu-zero-variadic-macro-arguments", - "-Wformat-pedantic", - "-Wdeprecated-anon-enum-enum-conversion") - -#include "../utility/juce_IncludeSystemHeaders.h" - -#include -#include -#include -#include -#include -#include "AudioUnitSDK/MusicDeviceBase.h" - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 - -#include "../utility/juce_IncludeModuleHeaders.h" - -#include -#include -#include -#include - -#if JucePlugin_Enable_ARA - #include - #include - #if ARA_SUPPORT_VERSION_1 - #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current JUCE ARA implementation" - #endif -#endif - -#include - -//============================================================================== -using namespace juce; - -static Array activePlugins, activeUIs; - -static const AudioUnitPropertyID juceFilterObjectPropertyID = 0x1a45ffe9; - -template <> struct ContainerDeletePolicy { static void destroy (const __CFString* o) { if (o != nullptr) CFRelease (o); } }; - -// make sure the audio processor is initialized before the AUBase class -struct AudioProcessorHolder -{ - AudioProcessorHolder (bool initialiseGUI) - { - if (initialiseGUI) - initialiseJuce_GUI(); - - juceFilter = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnit); - - // audio units do not have a notion of enabled or un-enabled buses - juceFilter->enableAllBuses(); - } - - std::unique_ptr juceFilter; -}; - -//============================================================================== -class JuceAU : public AudioProcessorHolder, - public ausdk::MusicDeviceBase, - public AudioProcessorListener, - public AudioProcessorParameter::Listener -{ -public: - JuceAU (AudioUnit component) - : AudioProcessorHolder (activePlugins.size() + activeUIs.size() == 0), - MusicDeviceBase (component, - (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true), - (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false)) - { - inParameterChangedCallback = false; - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - const int numConfigs = sizeof (configs) / sizeof (short[2]); - - jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); - juceFilter->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024); - - for (int i = 0; i < numConfigs; ++i) - { - AUChannelInfo info; - - info.inChannels = configs[i][0]; - info.outChannels = configs[i][1]; - - channelInfo.add (info); - } - #else - channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter); - #endif - - AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this); - - totalInChannels = juceFilter->getTotalNumInputChannels(); - totalOutChannels = juceFilter->getTotalNumOutputChannels(); - - juceFilter->addListener (this); - - addParameters(); - - activePlugins.add (this); - - zerostruct (auEvent); - auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance(); - auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global; - auEvent.mArgument.mParameter.mElement = 0; - - zerostruct (midiCallback); - - CreateElements(); - - if (syncAudioUnitWithProcessor() != noErr) - jassertfalse; - } - - ~JuceAU() override - { - if (bypassParam != nullptr) - bypassParam->removeListener (this); - - deleteActiveEditors(); - juceFilter = nullptr; - clearPresetsArray(); - - jassert (activePlugins.contains (this)); - activePlugins.removeFirstMatchingValue (this); - - if (activePlugins.size() + activeUIs.size() == 0) - shutdownJuce_GUI(); - } - - //============================================================================== - ComponentResult Initialize() override - { - ComponentResult err; - - if ((err = syncProcessorWithAudioUnit()) != noErr) - return err; - - if ((err = MusicDeviceBase::Initialize()) != noErr) - return err; - - mapper.alloc (*juceFilter); - pulledSucceeded.calloc (static_cast (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true))); - - prepareToPlay(); - - return noErr; - } - - void Cleanup() override - { - MusicDeviceBase::Cleanup(); - - pulledSucceeded.free(); - mapper.release(); - - if (juceFilter != nullptr) - juceFilter->releaseResources(); - - audioBuffer.release(); - midiEvents.clear(); - incomingEvents.clear(); - prepared = false; - } - - ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) override - { - if (! prepared) - prepareToPlay(); - - if (juceFilter != nullptr) - juceFilter->reset(); - - return MusicDeviceBase::Reset (inScope, inElement); - } - - //============================================================================== - void prepareToPlay() - { - if (juceFilter != nullptr) - { - juceFilter->setRateAndBufferSizeDetails (getSampleRate(), (int) GetMaxFramesPerSlice()); - - audioBuffer.prepare (AudioUnitHelpers::getBusesLayout (juceFilter.get()), (int) GetMaxFramesPerSlice() + 32); - juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice()); - - midiEvents.ensureSize (2048); - midiEvents.clear(); - incomingEvents.ensureSize (2048); - incomingEvents.clear(); - - prepared = true; - } - } - - //============================================================================== - bool BusCountWritable ([[maybe_unused]] AudioUnitScope scope) override - { - #ifdef JucePlugin_PreferredChannelConfigurations - return false; - #else - bool isInput; - - if (scopeToDirection (scope, isInput) != noErr) - return false; - - #if JucePlugin_IsMidiEffect - return false; - #elif JucePlugin_IsSynth - if (isInput) return false; - #endif - - const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); - return (juceFilter->canAddBus (isInput) || (busCount > 0 && juceFilter->canRemoveBus (isInput))); - #endif - } - - OSStatus SetBusCount (AudioUnitScope scope, UInt32 count) override - { - OSStatus err = noErr; - bool isInput; - - if ((err = scopeToDirection (scope, isInput)) != noErr) - return err; - - if (count != (UInt32) AudioUnitHelpers::getBusCount (*juceFilter, isInput)) - { - #ifdef JucePlugin_PreferredChannelConfigurations - return kAudioUnitErr_PropertyNotWritable; - #else - const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); - - if ((! juceFilter->canAddBus (isInput)) && ((busCount == 0) || (! juceFilter->canRemoveBus (isInput)))) - return kAudioUnitErr_PropertyNotWritable; - - // we need to already create the underlying elements so that we can change their formats - err = MusicDeviceBase::SetBusCount (scope, count); - - if (err != noErr) - return err; - - // however we do need to update the format tag: we need to do the same thing in SetFormat, for example - const int requestedNumBus = static_cast (count); - { - (isInput ? currentInputLayout : currentOutputLayout).resize (requestedNumBus); - - int busNr; - - for (busNr = (busCount - 1); busNr != (requestedNumBus - 1); busNr += (requestedNumBus > busCount ? 1 : -1)) - { - if (requestedNumBus > busCount) - { - if (! juceFilter->addBus (isInput)) - break; - - err = syncAudioUnitWithChannelSet (isInput, busNr, - juceFilter->getBus (isInput, busNr + 1)->getDefaultLayout()); - if (err != noErr) - break; - } - else - { - if (! juceFilter->removeBus (isInput)) - break; - } - } - - err = (busNr == (requestedNumBus - 1) ? (OSStatus) noErr : (OSStatus) kAudioUnitErr_FormatNotSupported); - } - - // was there an error? - if (err != noErr) - { - // restore bus state - const int newBusCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); - for (int i = newBusCount; i != busCount; i += (busCount > newBusCount ? 1 : -1)) - { - if (busCount > newBusCount) - juceFilter->addBus (isInput); - else - juceFilter->removeBus (isInput); - } - - (isInput ? currentInputLayout : currentOutputLayout).resize (busCount); - MusicDeviceBase::SetBusCount (scope, static_cast (busCount)); - - return kAudioUnitErr_FormatNotSupported; - } - - // update total channel count - totalInChannels = juceFilter->getTotalNumInputChannels(); - totalOutChannels = juceFilter->getTotalNumOutputChannels(); - - addSupportedLayoutTagsForDirection (isInput); - - if (err != noErr) - return err; - #endif - } - - return noErr; - } - - UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) override - { - if (outInfo != nullptr) - *outInfo = channelInfo.getRawDataPointer(); - - return (UInt32) channelInfo.size(); - } - - //============================================================================== - ComponentResult GetPropertyInfo (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - UInt32& outDataSize, - bool& outWritable) override - { - if (inScope == kAudioUnitScope_Global) - { - switch (inID) - { - case juceFilterObjectPropertyID: - outWritable = false; - outDataSize = sizeof (void*) * 2; - return noErr; - - case kAudioUnitProperty_OfflineRender: - outWritable = true; - outDataSize = sizeof (UInt32); - return noErr; - - case kMusicDeviceProperty_InstrumentCount: - outDataSize = sizeof (UInt32); - outWritable = false; - return noErr; - - case kAudioUnitProperty_CocoaUI: - outDataSize = sizeof (AudioUnitCocoaViewInfo); - outWritable = true; - return noErr; - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - case kAudioUnitProperty_MIDIOutputCallbackInfo: - outDataSize = sizeof (CFArrayRef); - outWritable = false; - return noErr; - - case kAudioUnitProperty_MIDIOutputCallback: - outDataSize = sizeof (AUMIDIOutputCallbackStruct); - outWritable = true; - return noErr; - #endif - - case kAudioUnitProperty_ParameterStringFromValue: - outDataSize = sizeof (AudioUnitParameterStringFromValue); - outWritable = false; - return noErr; - - case kAudioUnitProperty_ParameterValueFromString: - outDataSize = sizeof (AudioUnitParameterValueFromString); - outWritable = false; - return noErr; - - case kAudioUnitProperty_BypassEffect: - outDataSize = sizeof (UInt32); - outWritable = true; - return noErr; - - case kAudioUnitProperty_SupportsMPE: - outDataSize = sizeof (UInt32); - outWritable = false; - return noErr; - - #if JucePlugin_Enable_ARA - case ARA::kAudioUnitProperty_ARAFactory: - outWritable = false; - outDataSize = sizeof (ARA::ARAAudioUnitFactory); - return noErr; - case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles: - outWritable = false; - outDataSize = sizeof (ARA::ARAAudioUnitPlugInExtensionBinding); - return noErr; - #endif - - default: break; - } - } - - return MusicDeviceBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); - } - - ComponentResult GetProperty (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - void* outData) override - { - if (inScope == kAudioUnitScope_Global) - { - switch (inID) - { - case kAudioUnitProperty_ParameterClumpName: - - if (auto* clumpNameInfo = (AudioUnitParameterNameInfo*) outData) - { - if (juceFilter != nullptr) - { - auto clumpIndex = clumpNameInfo->inID - 1; - const auto* group = parameterGroups[(int) clumpIndex]; - auto name = group->getName(); - - while (group->getParent() != &juceFilter->getParameterTree()) - { - group = group->getParent(); - name = group->getName() + group->getSeparator() + name; - } - - clumpNameInfo->outName = name.toCFString(); - return noErr; - } - } - - // Failed to find a group corresponding to the clump ID. - jassertfalse; - break; - - //============================================================================== - #if JucePlugin_Enable_ARA - case ARA::kAudioUnitProperty_ARAFactory: - { - auto auFactory = static_cast (outData); - if (auFactory->inOutMagicNumber != ARA::kARAAudioUnitMagic) - return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics - - auFactory->outFactory = createARAFactory(); - return noErr; - } - - case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles: - { - auto binding = static_cast (outData); - if (binding->inOutMagicNumber != ARA::kARAAudioUnitMagic) - return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics - - AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast (juceFilter.get()); - binding->outPlugInExtension = araAudioProcessorExtension->bindToARA (binding->inDocumentControllerRef, binding->knownRoles, binding->assignedRoles); - if (binding->outPlugInExtension == nullptr) - return kAudioUnitErr_CannotDoInCurrentContext; // bindToARA() returns null if binding is already established - - return noErr; - } - #endif - - case juceFilterObjectPropertyID: - ((void**) outData)[0] = (void*) static_cast (juceFilter.get()); - ((void**) outData)[1] = (void*) this; - return noErr; - - case kAudioUnitProperty_OfflineRender: - *(UInt32*) outData = (juceFilter != nullptr && juceFilter->isNonRealtime()) ? 1 : 0; - return noErr; - - case kMusicDeviceProperty_InstrumentCount: - *(UInt32*) outData = 1; - return noErr; - - case kAudioUnitProperty_BypassEffect: - if (bypassParam != nullptr) - *(UInt32*) outData = (bypassParam->getValue() != 0.0f ? 1 : 0); - else - *(UInt32*) outData = isBypassed ? 1 : 0; - return noErr; - - case kAudioUnitProperty_SupportsMPE: - *(UInt32*) outData = (juceFilter != nullptr && juceFilter->supportsMPE()) ? 1 : 0; - return noErr; - - case kAudioUnitProperty_CocoaUI: - { - JUCE_AUTORELEASEPOOL - { - static JuceUICreationClass cls; - - // (NB: this may be the host's bundle, not necessarily the component's) - NSBundle* bundle = [NSBundle bundleForClass: cls.cls]; - - AudioUnitCocoaViewInfo* info = static_cast (outData); - info->mCocoaAUViewClass[0] = (CFStringRef) [juceStringToNS (class_getName (cls.cls)) retain]; - info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [bundle bundlePath]] retain]; - } - - return noErr; - } - - break; - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - case kAudioUnitProperty_MIDIOutputCallbackInfo: - { - CFStringRef strs[1]; - strs[0] = CFSTR ("MIDI Callback"); - - CFArrayRef callbackArray = CFArrayCreate (nullptr, (const void**) strs, 1, &kCFTypeArrayCallBacks); - *(CFArrayRef*) outData = callbackArray; - return noErr; - } - #endif - - case kAudioUnitProperty_ParameterValueFromString: - { - if (AudioUnitParameterValueFromString* pv = (AudioUnitParameterValueFromString*) outData) - { - if (juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (pv->inParamID)) - { - const String text (String::fromCFString (pv->inString)); - - if (LegacyAudioParameter::isLegacy (param)) - pv->outValue = text.getFloatValue(); - else - pv->outValue = param->getValueForText (text) * getMaximumParameterValue (param); - - - return noErr; - } - } - } - } - break; - - case kAudioUnitProperty_ParameterStringFromValue: - { - if (AudioUnitParameterStringFromValue* pv = (AudioUnitParameterStringFromValue*) outData) - { - if (juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (pv->inParamID)) - { - const float value = (float) *(pv->inValue); - String text; - - if (LegacyAudioParameter::isLegacy (param)) - text = String (value); - else - text = param->getText (value / getMaximumParameterValue (param), 0); - - pv->outString = text.toCFString(); - - return noErr; - } - } - } - } - break; - - default: - break; - } - } - - return MusicDeviceBase::GetProperty (inID, inScope, inElement, outData); - } - - ComponentResult SetProperty (AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - const void* inData, - UInt32 inDataSize) override - { - if (inScope == kAudioUnitScope_Global) - { - switch (inID) - { - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - case kAudioUnitProperty_MIDIOutputCallback: - if (inDataSize < sizeof (AUMIDIOutputCallbackStruct)) - return kAudioUnitErr_InvalidPropertyValue; - - if (AUMIDIOutputCallbackStruct* callbackStruct = (AUMIDIOutputCallbackStruct*) inData) - midiCallback = *callbackStruct; - - return noErr; - #endif - - case kAudioUnitProperty_BypassEffect: - { - if (inDataSize < sizeof (UInt32)) - return kAudioUnitErr_InvalidPropertyValue; - - const bool newBypass = *((UInt32*) inData) != 0; - const bool currentlyBypassed = (bypassParam != nullptr ? (bypassParam->getValue() != 0.0f) : isBypassed); - - if (newBypass != currentlyBypassed) - { - if (bypassParam != nullptr) - bypassParam->setValueNotifyingHost (newBypass ? 1.0f : 0.0f); - else - isBypassed = newBypass; - - if (! currentlyBypassed && IsInitialized()) // turning bypass off and we're initialized - Reset (0, 0); - } - - return noErr; - } - - case kAudioUnitProperty_OfflineRender: - { - const auto shouldBeOffline = (*reinterpret_cast (inData) != 0); - - if (juceFilter != nullptr) - { - const auto isOffline = juceFilter->isNonRealtime(); - - if (isOffline != shouldBeOffline) - { - const ScopedLock sl (juceFilter->getCallbackLock()); - - juceFilter->setNonRealtime (shouldBeOffline); - - if (prepared) - juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice()); - } - } - - return noErr; - } - - case kAudioUnitProperty_AUHostIdentifier: - { - if (inDataSize < sizeof (AUHostVersionIdentifier)) - return kAudioUnitErr_InvalidPropertyValue; - - const auto* identifier = static_cast (inData); - PluginHostType::hostIdReportedByWrapper = String::fromCFString (identifier->hostName); - - return noErr; - } - - default: break; - } - } - - return MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize); - } - - //============================================================================== - ComponentResult SaveState (CFPropertyListRef* outData) override - { - ComponentResult err = MusicDeviceBase::SaveState (outData); - - if (err != noErr) - return err; - - jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID()); - - CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData; - - if (juceFilter != nullptr) - { - juce::MemoryBlock state; - - #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES - juceFilter->getCurrentProgramStateInformation (state); - #else - juceFilter->getStateInformation (state); - #endif - - if (state.getSize() > 0) - { - CFUniquePtr ourState (CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), (CFIndex) state.getSize())); - CFUniquePtr key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8)); - CFDictionarySetValue (dict, key.get(), ourState.get()); - } - } - - return noErr; - } - - ComponentResult RestoreState (CFPropertyListRef inData) override - { - const ScopedValueSetter scope { restoringState, true }; - - { - // Remove the data entry from the state to prevent the superclass loading the parameters - CFUniquePtr copyWithoutData (CFDictionaryCreateMutableCopy (nullptr, 0, (CFDictionaryRef) inData)); - CFDictionaryRemoveValue (copyWithoutData.get(), CFSTR (kAUPresetDataKey)); - ComponentResult err = MusicDeviceBase::RestoreState (copyWithoutData.get()); - - if (err != noErr) - return err; - } - - if (juceFilter != nullptr) - { - CFDictionaryRef dict = (CFDictionaryRef) inData; - CFDataRef data = nullptr; - - CFUniquePtr key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8)); - - bool valuePresent = CFDictionaryGetValueIfPresent (dict, key.get(), (const void**) &data); - - if (valuePresent) - { - if (data != nullptr) - { - const int numBytes = (int) CFDataGetLength (data); - const juce::uint8* const rawBytes = CFDataGetBytePtr (data); - - if (numBytes > 0) - { - #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES - juceFilter->setCurrentProgramStateInformation (rawBytes, numBytes); - #else - juceFilter->setStateInformation (rawBytes, numBytes); - #endif - } - } - } - } - - return noErr; - } - - //============================================================================== - bool busIgnoresLayout ([[maybe_unused]] bool isInput, [[maybe_unused]] int busNr) const - { - #ifdef JucePlugin_PreferredChannelConfigurations - return true; - #else - if (const AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNr)) - { - AudioChannelSet discreteRangeSet; - const int n = bus->getDefaultLayout().size(); - for (int i = 0; i < n; ++i) - discreteRangeSet.addChannel ((AudioChannelSet::ChannelType) (256 + i)); - - // if the audioprocessor supports this it cannot - // really be interested in the bus layouts - return bus->isLayoutSupported (discreteRangeSet); - } - - return true; - #endif - } - - UInt32 GetAudioChannelLayout (AudioUnitScope scope, - AudioUnitElement element, - AudioChannelLayout* outLayoutPtr, - bool& outWritable) override - { - outWritable = false; - - const auto info = getElementInfo (scope, element); - - if (info.error != noErr) - return 0; - - if (busIgnoresLayout (info.isInput, info.busNr)) - return 0; - - outWritable = true; - - const size_t sizeInBytes = sizeof (AudioChannelLayout) - sizeof (AudioChannelDescription); - - if (outLayoutPtr != nullptr) - { - zeromem (outLayoutPtr, sizeInBytes); - outLayoutPtr->mChannelLayoutTag = getCurrentLayout (info.isInput, info.busNr); - } - - return sizeInBytes; - } - - std::vector GetChannelLayoutTags (AudioUnitScope inScope, AudioUnitElement inElement) override - { - const auto info = getElementInfo (inScope, inElement); - - if (info.error != noErr) - return {}; - - if (busIgnoresLayout (info.isInput, info.busNr)) - return {}; - - return getSupportedBusLayouts (info.isInput, info.busNr); - } - - OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override - { - const auto info = getElementInfo (scope, element); - - if (info.error != noErr) - return info.error; - - if (busIgnoresLayout (info.isInput, info.busNr)) - return kAudioUnitErr_PropertyNotWritable; - - if (inLayout == nullptr) - return kAudioUnitErr_InvalidPropertyValue; - - auto& ioElement = IOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element); - - const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout); - const int currentNumChannels = static_cast (ioElement.NumberChannels()); - const int newChannelNum = newChannelSet.size(); - - if (currentNumChannels != newChannelNum) - return kAudioUnitErr_InvalidPropertyValue; - - // check if the new layout could be potentially set - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs)) - return kAudioUnitErr_FormatNotSupported; - #else - if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet)) - return kAudioUnitErr_FormatNotSupported; - #endif - - getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet); - - return noErr; - } - - //============================================================================== - // When parameters are discrete we need to use integer values. - float getMaximumParameterValue ([[maybe_unused]] AudioProcessorParameter* juceParam) - { - #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - return 1.0f; - #else - return juceParam->isDiscrete() ? (float) (juceParam->getNumSteps() - 1) : 1.0f; - #endif - } - - ComponentResult GetParameterInfo (AudioUnitScope inScope, - AudioUnitParameterID inParameterID, - AudioUnitParameterInfo& outParameterInfo) override - { - if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (inParameterID)) - { - outParameterInfo.unit = kAudioUnitParameterUnit_Generic; - outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable - | kAudioUnitParameterFlag_IsReadable - | kAudioUnitParameterFlag_HasCFNameString - | kAudioUnitParameterFlag_ValuesHaveStrings); - - #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution; - #endif - - const String name = param->getName (1024); - - // Set whether the param is automatable (unnamed parameters aren't allowed to be automated) - if (name.isEmpty() || ! param->isAutomatable()) - outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; - - const bool isParameterDiscrete = param->isDiscrete(); - - if (! isParameterDiscrete) - outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp; - - if (param->isMetaParameter()) - outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta; - - auto parameterGroupHierarchy = juceFilter->getParameterTree().getGroupsForParameter (param); - - if (! parameterGroupHierarchy.isEmpty()) - { - outParameterInfo.flags |= kAudioUnitParameterFlag_HasClump; - outParameterInfo.clumpID = (UInt32) parameterGroups.indexOf (parameterGroupHierarchy.getLast()) + 1; - } - - // Is this a meter? - if ((((unsigned int) param->getCategory() & 0xffff0000) >> 16) == 2) - { - outParameterInfo.flags &= ~kAudioUnitParameterFlag_IsWritable; - outParameterInfo.flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic; - outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain; - } - else - { - #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - if (isParameterDiscrete) - outParameterInfo.unit = param->isBoolean() ? kAudioUnitParameterUnit_Boolean - : kAudioUnitParameterUnit_Indexed; - #endif - } - - MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true); - - outParameterInfo.minValue = 0.0f; - outParameterInfo.maxValue = getMaximumParameterValue (param); - outParameterInfo.defaultValue = param->getDefaultValue() * getMaximumParameterValue (param); - jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue - && outParameterInfo.defaultValue <= outParameterInfo.maxValue); - - return noErr; - } - } - - return kAudioUnitErr_InvalidParameter; - } - - ComponentResult GetParameterValueStrings (AudioUnitScope inScope, - AudioUnitParameterID inParameterID, - CFArrayRef *outStrings) override - { - if (outStrings == nullptr) - return noErr; - - if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (inParameterID)) - { - if (param->isDiscrete()) - { - auto index = LegacyAudioParameter::getParamIndex (*juceFilter, param); - - if (auto* valueStrings = parameterValueStringArrays[index]) - { - *outStrings = CFArrayCreate (nullptr, - (const void **) valueStrings->getRawDataPointer(), - valueStrings->size(), - nullptr); - - return noErr; - } - } - } - } - - return kAudioUnitErr_InvalidParameter; - } - - ComponentResult GetParameter (AudioUnitParameterID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - Float32& outValue) override - { - if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (inID)) - { - const auto normValue = param->getValue(); - - outValue = normValue * getMaximumParameterValue (param); - return noErr; - } - } - - return MusicDeviceBase::GetParameter (inID, inScope, inElement, outValue); - } - - ComponentResult SetParameter (AudioUnitParameterID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - Float32 inValue, - UInt32 inBufferOffsetInFrames) override - { - if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) - { - if (auto* param = getParameterForAUParameterID (inID)) - { - auto value = inValue / getMaximumParameterValue (param); - - if (value != param->getValue()) - { - inParameterChangedCallback = true; - param->setValueNotifyingHost (value); - } - - return noErr; - } - } - - return MusicDeviceBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames); - } - - // No idea what this method actually does or what it should return. Current Apple docs say nothing about it. - // (Note that this isn't marked 'override' in case older versions of the SDK don't include it) - bool CanScheduleParameters() const override { return false; } - - //============================================================================== - bool SupportsTail() override { return true; } - Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); } - - double getSampleRate() - { - if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0) - return Output (0).GetStreamFormat().mSampleRate; - - return 44100.0; - } - - Float64 GetLatency() override - { - const double rate = getSampleRate(); - jassert (rate > 0); - #if JucePlugin_Enable_ARA - jassert (juceFilter->getLatencySamples() == 0 || ! dynamic_cast (juceFilter.get())->isBoundToARA()); - #endif - return rate > 0 ? juceFilter->getLatencySamples() / rate : 0; - } - - class ScopedPlayHead : private AudioPlayHead - { - public: - explicit ScopedPlayHead (JuceAU& juceAudioUnit) - : audioUnit (juceAudioUnit) - { - audioUnit.juceFilter->setPlayHead (this); - } - - ~ScopedPlayHead() override - { - audioUnit.juceFilter->setPlayHead (nullptr); - } - - private: - Optional getPosition() const override - { - PositionInfo info; - - info.setFrameRate ([this]() -> Optional - { - switch (audioUnit.lastTimeStamp.mSMPTETime.mType) - { - case kSMPTETimeType2398: return FrameRate().withBaseRate (24).withPullDown(); - case kSMPTETimeType24: return FrameRate().withBaseRate (24); - case kSMPTETimeType25: return FrameRate().withBaseRate (25); - case kSMPTETimeType30Drop: return FrameRate().withBaseRate (30).withDrop(); - case kSMPTETimeType30: return FrameRate().withBaseRate (30); - case kSMPTETimeType2997: return FrameRate().withBaseRate (30).withPullDown(); - case kSMPTETimeType2997Drop: return FrameRate().withBaseRate (30).withPullDown().withDrop(); - case kSMPTETimeType60: return FrameRate().withBaseRate (60); - case kSMPTETimeType60Drop: return FrameRate().withBaseRate (60).withDrop(); - case kSMPTETimeType5994: return FrameRate().withBaseRate (60).withPullDown(); - case kSMPTETimeType5994Drop: return FrameRate().withBaseRate (60).withPullDown().withDrop(); - case kSMPTETimeType50: return FrameRate().withBaseRate (50); - default: break; - } - - return {}; - }()); - - double ppqPosition = 0.0; - double bpm = 0.0; - - if (audioUnit.CallHostBeatAndTempo (&ppqPosition, &bpm) == noErr) - { - info.setPpqPosition (ppqPosition); - info.setBpm (bpm); - } - - UInt32 outDeltaSampleOffsetToNextBeat; - double outCurrentMeasureDownBeat; - float num; - UInt32 den; - - if (audioUnit.CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, - &num, - &den, - &outCurrentMeasureDownBeat) == noErr) - { - info.setTimeSignature (TimeSignature { (int) num, (int) den }); - info.setPpqPositionOfLastBarStart (outCurrentMeasureDownBeat); - } - - double outCurrentSampleInTimeLine = 0, outCycleStartBeat = 0, outCycleEndBeat = 0; - Boolean playing = false, looping = false, playchanged; - - const auto setTimeInSamples = [&] (auto timeInSamples) - { - info.setTimeInSamples ((int64) (timeInSamples + 0.5)); - info.setTimeInSeconds (*info.getTimeInSamples() / audioUnit.getSampleRate()); - }; - - if (audioUnit.CallHostTransportState (&playing, - &playchanged, - &outCurrentSampleInTimeLine, - &looping, - &outCycleStartBeat, - &outCycleEndBeat) == noErr) - { - info.setIsPlaying (playing); - info.setIsLooping (looping); - info.setLoopPoints (LoopPoints { outCycleStartBeat, outCycleEndBeat }); - setTimeInSamples (outCurrentSampleInTimeLine); - } - else - { - // If the host doesn't support this callback, then use the sample time from lastTimeStamp - setTimeInSamples (audioUnit.lastTimeStamp.mSampleTime); - } - - info.setHostTimeNs ((audioUnit.lastTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0 - ? makeOptional (audioUnit.timeConversions.hostTimeToNanos (audioUnit.lastTimeStamp.mHostTime)) - : nullopt); - - return info; - } - - JuceAU& audioUnit; - }; - - //============================================================================== - void sendAUEvent (const AudioUnitEventType type, const int juceParamIndex) - { - if (restoringState) - return; - - auEvent.mEventType = type; - auEvent.mArgument.mParameter.mParameterID = getAUParameterIDForIndex (juceParamIndex); - AUEventListenerNotify (nullptr, nullptr, &auEvent); - } - - void audioProcessorParameterChanged (AudioProcessor*, int index, float /*newValue*/) override - { - if (inParameterChangedCallback.get()) - { - inParameterChangedCallback = false; - return; - } - - sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override - { - sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override - { - sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); - } - - void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override - { - audioProcessorChangedUpdater.update (details); - } - - //============================================================================== - // this will only ever be called by the bypass parameter - void parameterValueChanged (int, float) override - { - if (! restoringState) - PropertyChanged (kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); - } - - void parameterGestureChanged (int, bool) override {} - - //============================================================================== - bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) override - { - const auto info = getElementInfo (scope, element); - - return ((! IsInitialized()) && (info.error == noErr)); - } - - bool ValidFormat (AudioUnitScope inScope, - AudioUnitElement inElement, - const AudioStreamBasicDescription& inNewFormat) override - { - // DSP Quattro incorrectly uses global scope for the ValidFormat call - if (inScope == kAudioUnitScope_Global) - return ValidFormat (kAudioUnitScope_Input, inElement, inNewFormat) - || ValidFormat (kAudioUnitScope_Output, inElement, inNewFormat); - - const auto info = getElementInfo (inScope, inElement); - - if (info.error != noErr) - return false; - - if (info.kind == BusKind::wrapperOnly) - return true; - - const auto newNumChannels = static_cast (inNewFormat.mChannelsPerFrame); - const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); - - if (newNumChannels == oldNumChannels) - return true; - - if ([[maybe_unused]] AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr)) - { - if (! MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat)) - return false; - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - return AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs); - #else - return bus->isNumberOfChannelsSupported (newNumChannels); - #endif - } - - return false; - } - - // AU requires us to override this for the sole reason that we need to find a default layout tag if the number of channels have changed - OSStatus ChangeStreamFormat (AudioUnitScope inScope, - AudioUnitElement inElement, - const AudioStreamBasicDescription& inPrevFormat, - const AudioStreamBasicDescription& inNewFormat) override - { - const auto info = getElementInfo (inScope, inElement); - - if (info.error != noErr) - return info.error; - - AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr); - - const auto newNumChannels = static_cast (inNewFormat.mChannelsPerFrame); - const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs)) - return kAudioUnitErr_FormatNotSupported; - #endif - - // predict channel layout - const auto set = [&] - { - if (info.kind == BusKind::wrapperOnly) - return AudioChannelSet::discreteChannels (newNumChannels); - - if (newNumChannels != oldNumChannels) - return juceFilter->getBus (info.isInput, info.busNr)->supportedLayoutWithChannels (newNumChannels); - - return juceFilter->getChannelLayoutOfBus (info.isInput, info.busNr); - }(); - - if (set == AudioChannelSet()) - return kAudioUnitErr_FormatNotSupported; - - const auto err = MusicDeviceBase::ChangeStreamFormat (inScope, inElement, inPrevFormat, inNewFormat); - - if (err == noErr) - currentTag = CoreAudioLayouts::toCoreAudio (set); - - return err; - } - - //============================================================================== - ComponentResult Render (AudioUnitRenderActionFlags& ioActionFlags, - const AudioTimeStamp& inTimeStamp, - const UInt32 nFrames) override - { - lastTimeStamp = inTimeStamp; - - // prepare buffers - { - pullInputAudio (ioActionFlags, inTimeStamp, nFrames); - prepareOutputBuffers (nFrames); - audioBuffer.reset(); - } - - ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; - - const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); - const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); - - // set buffer pointers to minimize copying - { - int chIdx = 0, numChannels = 0; - bool interleaved = false; - AudioBufferList* buffer = nullptr; - - // use output pointers - for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) - { - GetAudioBufferList (false, busIdx, buffer, interleaved, numChannels); - const int* outLayoutMap = mapper.get (false, busIdx); - - for (int ch = 0; ch < numChannels; ++ch) - audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast (buffer->mBuffers[outLayoutMap[ch]].mData)); - } - - // use input pointers on remaining channels - for (int busIdx = 0; chIdx < totalInChannels;) - { - int channelIndexInBus = juceFilter->getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx); - const bool badData = ! pulledSucceeded[busIdx]; - - if (! badData) - GetAudioBufferList (true, busIdx, buffer, interleaved, numChannels); - - const int* inLayoutMap = mapper.get (true, busIdx); - - const int n = juceFilter->getChannelCountOfBus (true, busIdx); - for (int ch = channelIndexInBus; ch < n; ++ch) - audioBuffer.setBuffer (chIdx++, interleaved || badData ? nullptr : static_cast (buffer->mBuffers[inLayoutMap[ch]].mData)); - } - } - - // copy input - { - for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) - { - if (pulledSucceeded[busIdx]) - audioBuffer.set (busIdx, Input ((UInt32) busIdx).GetBufferList(), mapper.get (true, busIdx)); - else - audioBuffer.clearInputBus (busIdx, (int) nFrames); - } - - audioBuffer.clearUnusedChannels ((int) nFrames); - } - - // swap midi buffers - { - const ScopedLock sl (incomingMidiLock); - midiEvents.clear(); - incomingEvents.swapWith (midiEvents); - } - - // process audio - processBlock (audioBuffer.getBuffer (nFrames), midiEvents); - - // copy back - { - for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) - audioBuffer.get (busIdx, Output ((UInt32) busIdx).GetBufferList(), mapper.get (false, busIdx)); - } - - // process midi output - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - if (! midiEvents.isEmpty() && midiCallback.midiOutputCallback != nullptr) - pushMidiOutput (nFrames); - #endif - - midiEvents.clear(); - - return noErr; - } - - //============================================================================== - ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID*, UInt32, const MusicDeviceNoteParams&) override { return noErr; } - ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; } - - //============================================================================== - OSStatus HandleMIDIEvent ([[maybe_unused]] UInt8 inStatus, - [[maybe_unused]] UInt8 inChannel, - [[maybe_unused]] UInt8 inData1, - [[maybe_unused]] UInt8 inData2, - [[maybe_unused]] UInt32 inStartFrame) override - { - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - const juce::uint8 data[] = { (juce::uint8) (inStatus | inChannel), - (juce::uint8) inData1, - (juce::uint8) inData2 }; - - const ScopedLock sl (incomingMidiLock); - incomingEvents.addEvent (data, 3, (int) inStartFrame); - return noErr; - #else - return kAudioUnitErr_PropertyNotInUse; - #endif - } - - OSStatus HandleSysEx ([[maybe_unused]] const UInt8* inData, [[maybe_unused]] UInt32 inLength) override - { - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - const ScopedLock sl (incomingMidiLock); - incomingEvents.addEvent (inData, (int) inLength, 0); - return noErr; - #else - return kAudioUnitErr_PropertyNotInUse; - #endif - } - - //============================================================================== - ComponentResult GetPresets (CFArrayRef* outData) const override - { - if (outData != nullptr) - { - const int numPrograms = juceFilter->getNumPrograms(); - - clearPresetsArray(); - presetsArray.insertMultiple (0, AUPreset(), numPrograms); - - CFMutableArrayRef presetsArrayRef = CFArrayCreateMutable (nullptr, numPrograms, nullptr); - - for (int i = 0; i < numPrograms; ++i) - { - String name (juceFilter->getProgramName(i)); - if (name.isEmpty()) - name = "Untitled"; - - AUPreset& p = presetsArray.getReference(i); - p.presetNumber = i; - p.presetName = name.toCFString(); - - CFArrayAppendValue (presetsArrayRef, &p); - } - - *outData = (CFArrayRef) presetsArrayRef; - } - - return noErr; - } - - OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override - { - const int numPrograms = juceFilter->getNumPrograms(); - const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber; - - if (chosenPresetNumber >= numPrograms) - return kAudioUnitErr_InvalidProperty; - - AUPreset chosenPreset; - chosenPreset.presetNumber = chosenPresetNumber; - chosenPreset.presetName = juceFilter->getProgramName (chosenPresetNumber).toCFString(); - - juceFilter->setCurrentProgram (chosenPresetNumber); - SetAFactoryPresetAsCurrent (chosenPreset); - - return noErr; - } - - //============================================================================== - class EditorCompHolder : public Component - { - public: - EditorCompHolder (AudioProcessorEditor* const editor) - { - addAndMakeVisible (editor); - - #if ! JucePlugin_EditorRequiresKeyboardFocus - setWantsKeyboardFocus (false); - #else - setWantsKeyboardFocus (true); - #endif - - setBounds (getSizeToContainChild()); - - lastBounds = getBounds(); - } - - ~EditorCompHolder() override - { - deleteAllChildren(); // note that we can't use a std::unique_ptr because the editor may - // have been transferred to another parent which takes over ownership. - } - - Rectangle getSizeToContainChild() - { - if (auto* editor = getChildComponent (0)) - return getLocalArea (editor, editor->getLocalBounds()); - - return {}; - } - - static NSView* createViewFor (AudioProcessor* filter, JuceAU* au, AudioProcessorEditor* const editor) - { - auto* editorCompHolder = new EditorCompHolder (editor); - auto r = convertToHostBounds (makeNSRect (editorCompHolder->getSizeToContainChild())); - - static JuceUIViewClass cls; - auto* view = [[cls.createInstance() initWithFrame: r] autorelease]; - - JuceUIViewClass::setFilter (view, filter); - JuceUIViewClass::setAU (view, au); - JuceUIViewClass::setEditor (view, editorCompHolder); - - [view setHidden: NO]; - [view setPostsFrameChangedNotifications: YES]; - - [[NSNotificationCenter defaultCenter] addObserver: view - selector: @selector (applicationWillTerminate:) - name: NSApplicationWillTerminateNotification - object: nil]; - activeUIs.add (view); - - editorCompHolder->addToDesktop (0, (void*) view); - editorCompHolder->setVisible (view); - - return view; - } - - void parentSizeChanged() override - { - resizeHostWindow(); - - if (auto* editor = getChildComponent (0)) - editor->repaint(); - } - - void childBoundsChanged (Component*) override - { - auto b = getSizeToContainChild(); - - if (lastBounds != b) - { - lastBounds = b; - setSize (jmax (32, b.getWidth()), jmax (32, b.getHeight())); - - resizeHostWindow(); - } - } - - bool keyPressed (const KeyPress&) override - { - if (getHostType().isAbletonLive()) - { - static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event - NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; - - if (lastEventTime != eventTime) - { - lastEventTime = eventTime; - - NSView* view = (NSView*) getWindowHandle(); - NSView* hostView = [view superview]; - NSWindow* hostWindow = [hostView window]; - - [hostWindow makeFirstResponder: hostView]; - [hostView keyDown: (NSEvent*) [NSApp currentEvent]]; - [hostWindow makeFirstResponder: view]; - } - } - - return false; - } - - void resizeHostWindow() - { - [CATransaction begin]; - [CATransaction setValue:(id) kCFBooleanTrue forKey:kCATransactionDisableActions]; - - auto rect = convertToHostBounds (makeNSRect (lastBounds)); - auto* view = (NSView*) getWindowHandle(); - - auto superRect = [[view superview] frame]; - superRect.size.width = rect.size.width; - superRect.size.height = rect.size.height; - - [[view superview] setFrame: superRect]; - [view setFrame: rect]; - [CATransaction commit]; - - [view setNeedsDisplay: YES]; - } - - private: - Rectangle lastBounds; - - JUCE_DECLARE_NON_COPYABLE (EditorCompHolder) - }; - - void deleteActiveEditors() - { - for (int i = activeUIs.size(); --i >= 0;) - { - id ui = (id) activeUIs.getUnchecked(i); - - if (JuceUIViewClass::getAU (ui) == this) - JuceUIViewClass::deleteEditor (ui); - } - } - - //============================================================================== - struct JuceUIViewClass : public ObjCClass - { - JuceUIViewClass() : ObjCClass ("JUCEAUView_") - { - addIvar ("filter"); - addIvar ("au"); - addIvar ("editor"); - - addMethod (@selector (dealloc), dealloc); - addMethod (@selector (applicationWillTerminate:), applicationWillTerminate); - addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow); - addMethod (@selector (mouseDownCanMoveWindow), mouseDownCanMoveWindow); - - registerClass(); - } - - static void deleteEditor (id self) - { - std::unique_ptr editorComp (getEditor (self)); - - if (editorComp != nullptr) - { - if (editorComp->getChildComponent(0) != nullptr - && activePlugins.contains (getAU (self))) // plugin may have been deleted before the UI - { - AudioProcessor* const filter = getIvar (self, "filter"); - filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0)); - } - - editorComp = nullptr; - setEditor (self, nullptr); - } - } - - static JuceAU* getAU (id self) { return getIvar (self, "au"); } - static EditorCompHolder* getEditor (id self) { return getIvar (self, "editor"); } - - static void setFilter (id self, AudioProcessor* filter) { object_setInstanceVariable (self, "filter", filter); } - static void setAU (id self, JuceAU* au) { object_setInstanceVariable (self, "au", au); } - static void setEditor (id self, EditorCompHolder* e) { object_setInstanceVariable (self, "editor", e); } - - private: - static void dealloc (id self, SEL) - { - if (activeUIs.contains (self)) - shutdown (self); - - sendSuperclassMessage (self, @selector (dealloc)); - } - - static void applicationWillTerminate (id self, SEL, NSNotification*) - { - shutdown (self); - } - - static void shutdown (id self) - { - [[NSNotificationCenter defaultCenter] removeObserver: self]; - deleteEditor (self); - - jassert (activeUIs.contains (self)); - activeUIs.removeFirstMatchingValue (self); - - if (activePlugins.size() + activeUIs.size() == 0) - { - // there's some kind of component currently modal, but the host - // is trying to delete our plugin.. - jassert (Component::getCurrentlyModalComponent() == nullptr); - - shutdownJuce_GUI(); - } - } - - static void viewDidMoveToWindow (id self, SEL) - { - if (NSWindow* w = [(NSView*) self window]) - { - [w setAcceptsMouseMovedEvents: YES]; - - if (EditorCompHolder* const editorComp = getEditor (self)) - [w makeFirstResponder: (NSView*) editorComp->getWindowHandle()]; - } - } - - static BOOL mouseDownCanMoveWindow (id, SEL) - { - return NO; - } - }; - - //============================================================================== - struct JuceUICreationClass : public ObjCClass - { - JuceUICreationClass() : ObjCClass ("JUCE_AUCocoaViewClass_") - { - addMethod (@selector (interfaceVersion), interfaceVersion); - addMethod (@selector (description), description); - addMethod (@selector (uiViewForAudioUnit:withSize:), uiViewForAudioUnit); - - addProtocol (@protocol (AUCocoaUIBase)); - - registerClass(); - } - - private: - static unsigned int interfaceVersion (id, SEL) { return 0; } - - static NSString* description (id, SEL) - { - return [NSString stringWithString: nsStringLiteral (JucePlugin_Name)]; - } - - static NSView* uiViewForAudioUnit (id, SEL, AudioUnit inAudioUnit, NSSize) - { - void* pointers[2]; - UInt32 propertySize = sizeof (pointers); - - if (AudioUnitGetProperty (inAudioUnit, juceFilterObjectPropertyID, - kAudioUnitScope_Global, 0, pointers, &propertySize) == noErr) - { - if (AudioProcessor* filter = static_cast (pointers[0])) - if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded()) - { - #if JucePlugin_Enable_ARA - jassert (dynamic_cast (editorComp) != nullptr); - // for proper view embedding, ARA plug-ins must be resizable - jassert (editorComp->isResizable()); - #endif - return EditorCompHolder::createViewFor (filter, static_cast (pointers[1]), editorComp); - } - } - - return nil; - } - }; - -private: - //============================================================================== - /* The call to AUBase::PropertyChanged may allocate hence the need for this class */ - class AudioProcessorChangedUpdater final : private AsyncUpdater - { - public: - explicit AudioProcessorChangedUpdater (JuceAU& o) : owner (o) {} - ~AudioProcessorChangedUpdater() override { cancelPendingUpdate(); } - - void update (const ChangeDetails& details) - { - int flags = 0; - - if (details.latencyChanged) - flags |= latencyChangedFlag; - - if (details.parameterInfoChanged) - flags |= parameterInfoChangedFlag; - - if (details.programChanged) - flags |= programChangedFlag; - - if (flags != 0) - { - callbackFlags.fetch_or (flags); - - if (MessageManager::getInstance()->isThisTheMessageThread()) - handleAsyncUpdate(); - else - triggerAsyncUpdate(); - } - } - - private: - void handleAsyncUpdate() override - { - const auto flags = callbackFlags.exchange (0); - - if ((flags & latencyChangedFlag) != 0) - owner.PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0); - - if ((flags & parameterInfoChangedFlag) != 0) - { - owner.PropertyChanged (kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0); - owner.PropertyChanged (kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, 0); - } - - owner.PropertyChanged (kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0); - - if ((flags & programChangedFlag) != 0) - { - owner.refreshCurrentPreset(); - owner.PropertyChanged (kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0); - } - } - - JuceAU& owner; - - static constexpr int latencyChangedFlag = 1 << 0, - parameterInfoChangedFlag = 1 << 1, - programChangedFlag = 1 << 2; - - std::atomic callbackFlags { 0 }; - }; - - //============================================================================== - AudioUnitHelpers::CoreAudioBufferList audioBuffer; - MidiBuffer midiEvents, incomingEvents; - bool prepared = false, isBypassed = false, restoringState = false; - - //============================================================================== - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - static constexpr bool forceUseLegacyParamIDs = true; - #else - static constexpr bool forceUseLegacyParamIDs = false; - #endif - - //============================================================================== - LegacyAudioParametersWrapper juceParameters; - std::unordered_map paramMap; - Array auParamIDs; - Array parameterGroups; - - // Stores the parameter IDs in the order that they will be reported to the host. - std::vector cachedParameterList; - - //============================================================================== - // According to the docs, this is the maximum size of a MIDIPacketList. - static constexpr UInt32 packetListBytes = 65536; - - CoreAudioTimeConversions timeConversions; - AudioUnitEvent auEvent; - mutable Array presetsArray; - CriticalSection incomingMidiLock; - AUMIDIOutputCallbackStruct midiCallback; - AudioTimeStamp lastTimeStamp; - int totalInChannels, totalOutChannels; - HeapBlock pulledSucceeded; - HeapBlock packetList { packetListBytes, 1 }; - - ThreadLocalValue inParameterChangedCallback; - - AudioProcessorChangedUpdater audioProcessorChangedUpdater { *this }; - - //============================================================================== - Array channelInfo; - Array> supportedInputLayouts, supportedOutputLayouts; - Array currentInputLayout, currentOutputLayout; - - //============================================================================== - AudioUnitHelpers::ChannelRemapper mapper; - - //============================================================================== - OwnedArray> parameterValueStringArrays; - - //============================================================================== - AudioProcessorParameter* bypassParam = nullptr; - - //============================================================================== - static NSRect convertToHostBounds (NSRect pluginRect) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return pluginRect; - - return NSMakeRect (static_cast (pluginRect.origin.x * desktopScale), - static_cast (pluginRect.origin.y * desktopScale), - static_cast (pluginRect.size.width * desktopScale), - static_cast (pluginRect.size.height * desktopScale)); - } - - static NSRect convertFromHostBounds (NSRect hostRect) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return hostRect; - - return NSMakeRect (static_cast (hostRect.origin.x / desktopScale), - static_cast (hostRect.origin.y / desktopScale), - static_cast (hostRect.size.width / desktopScale), - static_cast (hostRect.size.height / desktopScale)); - } - - //============================================================================== - void pullInputAudio (AudioUnitRenderActionFlags& flags, const AudioTimeStamp& timestamp, const UInt32 nFrames) noexcept - { - const unsigned int numInputBuses = GetScope (kAudioUnitScope_Input).GetNumberOfElements(); - - for (unsigned int i = 0; i < numInputBuses; ++i) - { - auto& input = Input (i); - - const bool succeeded = (input.PullInput (flags, timestamp, i, nFrames) == noErr); - - if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded) - AudioUnitHelpers::clearAudioBuffer (input.GetBufferList()); - - pulledSucceeded[i] = succeeded; - } - } - - void prepareOutputBuffers (const UInt32 nFrames) noexcept - { - const auto numProcessorBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); - const auto numWrapperBuses = GetScope (kAudioUnitScope_Output).GetNumberOfElements(); - - for (UInt32 busIdx = 0; busIdx < numWrapperBuses; ++busIdx) - { - auto& output = Output (busIdx); - - if (output.WillAllocateBuffer()) - output.PrepareBuffer (nFrames); - - if (busIdx >= (UInt32) numProcessorBuses) - AudioUnitHelpers::clearAudioBuffer (output.GetBufferList()); - } - } - - void processBlock (juce::AudioBuffer& buffer, MidiBuffer& midiBuffer) noexcept - { - const ScopedLock sl (juceFilter->getCallbackLock()); - const ScopedPlayHead playhead { *this }; - - if (juceFilter->isSuspended()) - { - buffer.clear(); - } - else if (bypassParam == nullptr && isBypassed) - { - juceFilter->processBlockBypassed (buffer, midiBuffer); - } - else - { - juceFilter->processBlock (buffer, midiBuffer); - } - } - - void pushMidiOutput ([[maybe_unused]] UInt32 nFrames) noexcept - { - MIDIPacket* end = nullptr; - - const auto init = [&] - { - end = MIDIPacketListInit (packetList); - }; - - const auto send = [&] - { - midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList); - }; - - const auto add = [&] (const MidiMessageMetadata& metadata) - { - end = MIDIPacketListAdd (packetList, - packetListBytes, - end, - static_cast (metadata.samplePosition), - static_cast (metadata.numBytes), - metadata.data); - }; - - init(); - - for (const auto metadata : midiEvents) - { - jassert (isPositiveAndBelow (metadata.samplePosition, nFrames)); - - add (metadata); - - if (end == nullptr) - { - send(); - init(); - add (metadata); - - if (end == nullptr) - { - // If this is hit, the size of this midi packet exceeds the maximum size of - // a MIDIPacketList. Large SysEx messages should be broken up into smaller - // chunks. - jassertfalse; - init(); - } - } - } - - send(); - } - - void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels) - { - auto* element = Element (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast (busIdx)).AsIOElement(); - jassert (element != nullptr); - - bufferList = &element->GetBufferList(); - - jassert (bufferList->mNumberBuffers > 0); - - interleaved = AudioUnitHelpers::isAudioBufferInterleaved (*bufferList); - numChannels = static_cast (interleaved ? bufferList->mBuffers[0].mNumberChannels : bufferList->mNumberBuffers); - } - - //============================================================================== - static OSStatus scopeToDirection (AudioUnitScope scope, bool& isInput) noexcept - { - isInput = (scope == kAudioUnitScope_Input); - - return (scope != kAudioUnitScope_Input - && scope != kAudioUnitScope_Output) - ? (OSStatus) kAudioUnitErr_InvalidScope : (OSStatus) noErr; - } - - enum class BusKind - { - processor, - wrapperOnly, - }; - - struct ElementInfo - { - int busNr; - BusKind kind; - bool isInput; - OSStatus error; - }; - - ElementInfo getElementInfo (AudioUnitScope scope, AudioUnitElement element) noexcept - { - bool isInput = false; - OSStatus err; - - if ((err = scopeToDirection (scope, isInput)) != noErr) - return { {}, {}, {}, err }; - - const auto busIdx = static_cast (element); - - if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCount (*juceFilter, isInput))) - return { busIdx, BusKind::processor, isInput, noErr }; - - if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCountForWrapper (*juceFilter, isInput))) - return { busIdx, BusKind::wrapperOnly, isInput, noErr }; - - return { {}, {}, {}, kAudioUnitErr_InvalidElement }; - } - - OSStatus GetParameterList (AudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters) override - { - if (forceUseLegacyParamIDs || inScope != kAudioUnitScope_Global) - return MusicDeviceBase::GetParameterList (inScope, outParameterList, outNumParameters); - - outNumParameters = (UInt32) juceParameters.size(); - - if (outParameterList == nullptr) - return noErr; - - if (cachedParameterList.empty()) - { - struct ParamInfo - { - AudioUnitParameterID identifier; - int versionHint; - }; - - std::vector vec; - vec.reserve (juceParameters.size()); - - for (const auto* param : juceParameters) - vec.push_back ({ generateAUParameterID (*param), param->getVersionHint() }); - - std::sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.identifier < b.identifier; }); - std::stable_sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.versionHint < b.versionHint; }); - std::transform (vec.begin(), vec.end(), std::back_inserter (cachedParameterList), [] (auto x) { return x.identifier; }); - } - - std::copy (cachedParameterList.begin(), cachedParameterList.end(), outParameterList); - - return noErr; - } - - //============================================================================== - void addParameters() - { - parameterGroups = juceFilter->getParameterTree().getSubgroups (true); - - juceParameters.update (*juceFilter, forceUseLegacyParamIDs); - const int numParams = juceParameters.getNumParameters(); - - if (forceUseLegacyParamIDs) - { - Globals()->UseIndexedParameters (static_cast (numParams)); - } - else - { - for (auto* param : juceParameters) - { - const AudioUnitParameterID auParamID = generateAUParameterID (*param); - - // Consider yourself very unlucky if you hit this assertion. The hash codes of your - // parameter ids are not unique. - jassert (paramMap.find (static_cast (auParamID)) == paramMap.end()); - - auParamIDs.add (auParamID); - paramMap.emplace (static_cast (auParamID), param); - Globals()->SetParameter (auParamID, param->getValue()); - } - } - - #if JUCE_DEBUG - // Some hosts can't handle the huge numbers of discrete parameter values created when - // using the default number of steps. - for (auto* param : juceParameters) - if (param->isDiscrete()) - jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps()); - #endif - - parameterValueStringArrays.ensureStorageAllocated (numParams); - - for (auto* param : juceParameters) - { - OwnedArray* stringValues = nullptr; - - auto initialValue = param->getValue(); - bool paramIsLegacy = dynamic_cast (param) != nullptr; - - if (param->isDiscrete() && (! forceUseLegacyParamIDs)) - { - const auto numSteps = param->getNumSteps(); - stringValues = new OwnedArray(); - stringValues->ensureStorageAllocated (numSteps); - - const auto maxValue = getMaximumParameterValue (param); - - auto getTextValue = [param, paramIsLegacy] (float value) - { - if (paramIsLegacy) - { - param->setValue (value); - return param->getCurrentValueAsText(); - } - - return param->getText (value, 256); - }; - - for (int i = 0; i < numSteps; ++i) - { - auto value = (float) i / maxValue; - stringValues->add (CFStringCreateCopy (nullptr, (getTextValue (value).toCFString()))); - } - } - - if (paramIsLegacy) - param->setValue (initialValue); - - parameterValueStringArrays.add (stringValues); - } - - if ((bypassParam = juceFilter->getBypassParameter()) != nullptr) - bypassParam->addListener (this); - } - - //============================================================================== - static AudioUnitParameterID generateAUParameterID (const AudioProcessorParameter& param) - { - const String& juceParamID = LegacyAudioParameter::getParamID (¶m, forceUseLegacyParamIDs); - AudioUnitParameterID paramHash = static_cast (juceParamID.hashCode()); - - #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS - // studio one doesn't like negative parameters - paramHash &= ~(((AudioUnitParameterID) 1) << (sizeof (AudioUnitParameterID) * 8 - 1)); - #endif - - return forceUseLegacyParamIDs ? static_cast (juceParamID.getIntValue()) - : paramHash; - } - - inline AudioUnitParameterID getAUParameterIDForIndex (int paramIndex) const noexcept - { - return forceUseLegacyParamIDs ? static_cast (paramIndex) - : auParamIDs.getReference (paramIndex); - } - - AudioProcessorParameter* getParameterForAUParameterID (AudioUnitParameterID address) const noexcept - { - const auto index = static_cast (address); - - if (forceUseLegacyParamIDs) - return juceParameters.getParamForIndex (index); - - const auto iter = paramMap.find (index); - return iter != paramMap.end() ? iter->second : nullptr; - } - - //============================================================================== - OSStatus syncAudioUnitWithProcessor() - { - OSStatus err = noErr; - const auto numWrapperInputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true); - const auto numWrapperOutputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false); - - if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Input, static_cast (numWrapperInputs))) != noErr) - return err; - - if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Output, static_cast (numWrapperOutputs))) != noErr) - return err; - - addSupportedLayoutTags(); - - const auto numProcessorInputs = AudioUnitHelpers::getBusCount (*juceFilter, true); - const auto numProcessorOutputs = AudioUnitHelpers::getBusCount (*juceFilter, false); - - for (int i = 0; i < numProcessorInputs; ++i) - if ((err = syncAudioUnitWithChannelSet (true, i, juceFilter->getChannelLayoutOfBus (true, i))) != noErr) - return err; - - for (int i = 0; i < numProcessorOutputs; ++i) - if ((err = syncAudioUnitWithChannelSet (false, i, juceFilter->getChannelLayoutOfBus (false, i))) != noErr) - return err; - - return noErr; - } - - OSStatus syncProcessorWithAudioUnit() - { - const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); - const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); - - const int numInputElements = static_cast (GetScope (kAudioUnitScope_Input). GetNumberOfElements()); - const int numOutputElements = static_cast (GetScope (kAudioUnitScope_Output).GetNumberOfElements()); - - AudioProcessor::BusesLayout requestedLayouts; - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int n = (isInput ? numInputBuses : numOutputBuses); - const int numAUElements = (isInput ? numInputElements : numOutputElements); - Array& requestedBuses = (isInput ? requestedLayouts.inputBuses : requestedLayouts.outputBuses); - - for (int busIdx = 0; busIdx < n; ++busIdx) - { - const auto* element = (busIdx < numAUElements ? &IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr); - const int numChannels = (element != nullptr ? static_cast (element->NumberChannels()) : 0); - - AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx]; - const int tagNumChannels = currentLayoutTag & 0xffff; - - if (numChannels != tagNumChannels) - return kAudioUnitErr_FormatNotSupported; - - requestedBuses.add (CoreAudioLayouts::fromCoreAudio (currentLayoutTag)); - } - } - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - if (! AudioProcessor::containsLayout (requestedLayouts, configs)) - return kAudioUnitErr_FormatNotSupported; - #endif - - if (! AudioUnitHelpers::setBusesLayout (juceFilter.get(), requestedLayouts)) - return kAudioUnitErr_FormatNotSupported; - - // update total channel count - totalInChannels = juceFilter->getTotalNumInputChannels(); - totalOutChannels = juceFilter->getTotalNumOutputChannels(); - - return noErr; - } - - OSStatus syncAudioUnitWithChannelSet (bool isInput, int busNr, const AudioChannelSet& channelSet) - { - const int numChannels = channelSet.size(); - - getCurrentLayout (isInput, busNr) = CoreAudioLayouts::toCoreAudio (channelSet); - - // is this bus activated? - if (numChannels == 0) - return noErr; - - auto& element = IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr); - - element.SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName())); - - const auto streamDescription = ausdk::ASBD::CreateCommonFloat32 (getSampleRate(), (UInt32) numChannels); - return element.SetStreamFormat (streamDescription); - } - - //============================================================================== - void clearPresetsArray() const - { - for (int i = presetsArray.size(); --i >= 0;) - CFRelease (presetsArray.getReference(i).presetName); - - presetsArray.clear(); - } - - void refreshCurrentPreset() - { - // this will make the AU host re-read and update the current preset name - // in case it was changed here in the plug-in: - - const int currentProgramNumber = juceFilter->getCurrentProgram(); - const String currentProgramName = juceFilter->getProgramName (currentProgramNumber); - - AUPreset currentPreset; - currentPreset.presetNumber = currentProgramNumber; - currentPreset.presetName = currentProgramName.toCFString(); - - SetAFactoryPresetAsCurrent (currentPreset); - } - - //============================================================================== - std::vector& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } - const std::vector& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } - AudioChannelLayoutTag& getCurrentLayout (bool isInput, int bus) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); } - AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[bus]; } - - //============================================================================== - std::vector getSupportedLayoutTagsForBus (bool isInput, int busNum) const - { - std::set tags; - - if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum)) - { - #ifndef JucePlugin_PreferredChannelConfigurations - auto& knownTags = CoreAudioLayouts::getKnownCoreAudioTags(); - - for (auto tag : knownTags) - if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag))) - tags.insert (tag); - #endif - - // add discrete layout tags - int n = bus->getMaxSupportedChannels (maxChannelsToProbeFor()); - - for (int ch = 0; ch < n; ++ch) - { - #ifdef JucePlugin_PreferredChannelConfigurations - const short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - if (AudioUnitHelpers::isLayoutSupported (*juceFilter, isInput, busNum, ch, configs)) - tags.insert (static_cast ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); - #else - if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch))) - tags.insert (static_cast ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); - #endif - } - } - - return std::vector (tags.begin(), tags.end()); - } - - void addSupportedLayoutTagsForDirection (bool isInput) - { - auto& layouts = isInput ? supportedInputLayouts : supportedOutputLayouts; - layouts.clearQuick(); - auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput); - - for (int busNr = 0; busNr < numBuses; ++busNr) - layouts.add (getSupportedLayoutTagsForBus (isInput, busNr)); - } - - void addSupportedLayoutTags() - { - currentInputLayout.clear(); currentOutputLayout.clear(); - - currentInputLayout. resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true)); - currentOutputLayout.resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false)); - - addSupportedLayoutTagsForDirection (true); - addSupportedLayoutTagsForDirection (false); - } - - static int maxChannelsToProbeFor() - { - return (getHostType().isLogic() ? 8 : 64); - } - - //============================================================================== - void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement) - { - if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName - && juceFilter != nullptr && GetContextName() != nullptr) - { - AudioProcessor::TrackProperties props; - props.name = String::fromCFString (GetContextName()); - - juceFilter->updateTrackProperties (props); - } - } - - static void auPropertyListenerDispatcher (void* inRefCon, AudioUnit, AudioUnitPropertyID propId, - AudioUnitScope scope, AudioUnitElement element) - { - static_cast (inRefCon)->auPropertyListener (propId, scope, element); - } - - JUCE_DECLARE_NON_COPYABLE (JuceAU) -}; - -//============================================================================== -#if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - #define FACTORY_BASE_CLASS ausdk::AUMusicDeviceFactory -#else - #define FACTORY_BASE_CLASS ausdk::AUBaseFactory -#endif - -AUSDK_COMPONENT_ENTRY (FACTORY_BASE_CLASS, JuceAU) - -#define JUCE_AU_ENTRY_POINT_NAME JUCE_CONCAT (JucePlugin_AUExportPrefix, Factory) - - extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc); -AUSDK_EXPORT extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc) -{ - return JuceAUFactory (inDesc); -} - -#endif diff --git a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm deleted file mode 100644 index cab14a473ba2..000000000000 --- a/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm +++ /dev/null @@ -1,2027 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include "../utility/juce_CheckSettingMacros.h" - -#if JucePlugin_Build_AUv3 - -#if JUCE_MAC && ! (defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) - #error AUv3 needs Deployment Target OS X 10.11 or higher to compile -#endif - -#if (JUCE_IOS && defined (__IPHONE_15_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0) \ - || (JUCE_MAC && defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0) - #define JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED 1 -#endif - -#ifndef __OBJC2__ - #error AUv3 needs Objective-C 2 support (compile with 64-bit) -#endif - -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 - -#include "../utility/juce_IncludeSystemHeaders.h" -#include "../utility/juce_IncludeModuleHeaders.h" - -#import -#import -#import - -#include -#include -#include -#include -#include - -#if JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED - #include -#endif - -#define JUCE_VIEWCONTROLLER_OBJC_NAME(x) JUCE_JOIN_MACRO (x, FactoryAUv3) - -#if JUCE_IOS - #define JUCE_IOS_MAC_VIEW UIView -#else - #define JUCE_IOS_MAC_VIEW NSView -#endif - -#define JUCE_AUDIOUNIT_OBJC_NAME(x) JUCE_JOIN_MACRO (x, AUv3) - -#include - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullability-completeness") - -using namespace juce; - -struct AudioProcessorHolder : public ReferenceCountedObject -{ - AudioProcessorHolder() = default; - explicit AudioProcessorHolder (std::unique_ptr p) : processor (std::move (p)) {} - AudioProcessor& operator*() noexcept { return *processor; } - AudioProcessor* operator->() noexcept { return processor.get(); } - AudioProcessor* get() noexcept { return processor.get(); } - - struct ViewConfig - { - double width; - double height; - bool hostHasMIDIController; - }; - - std::unique_ptr viewConfiguration; - - using Ptr = ReferenceCountedObjectPtr; - -private: - std::unique_ptr processor; - - AudioProcessorHolder& operator= (AudioProcessor*) = delete; - AudioProcessorHolder (AudioProcessorHolder&) = delete; - AudioProcessorHolder& operator= (AudioProcessorHolder&) = delete; -}; - -//============================================================================== -//=========================== The actual AudioUnit ============================= -//============================================================================== -class JuceAudioUnitv3 : public AudioProcessorListener, - public AudioPlayHead, - private AudioProcessorParameter::Listener -{ -public: - JuceAudioUnitv3 (const AudioProcessorHolder::Ptr& processor, - const AudioComponentDescription& descr, - AudioComponentInstantiationOptions options, - NSError** error) - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wobjc-method-access") - : au ([getClass().createInstance() initWithComponentDescription: descr - options: options - error: error - juceClass: this]), - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - processorHolder (processor) - { - init(); - } - - JuceAudioUnitv3 (AUAudioUnit* audioUnit, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**) - : au (audioUnit), - processorHolder (new AudioProcessorHolder (createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))) - { - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - initialiseJuce_GUI(); - - init(); - } - - ~JuceAudioUnitv3() override - { - auto& processor = getAudioProcessor(); - processor.removeListener (this); - - if (bypassParam != nullptr) - bypassParam->removeListener (this); - - removeEditor (processor); - } - - //============================================================================== - void init() - { - inParameterChangedCallback = false; - - AudioProcessor& processor = getAudioProcessor(); - const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - const int numConfigs = sizeof (configs) / sizeof (short[2]); - - jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); - processor.setPlayConfigDetails (configs[0][0], configs[0][1], kDefaultSampleRate, static_cast (maxFrames)); - - Array channelInfos; - - for (int i = 0; i < numConfigs; ++i) - { - AUChannelInfo channelInfo; - - channelInfo.inChannels = configs[i][0]; - channelInfo.outChannels = configs[i][1]; - - channelInfos.add (channelInfo); - } - #else - Array channelInfos = AudioUnitHelpers::getAUChannelInfo (processor); - #endif - - processor.setPlayHead (this); - - totalInChannels = processor.getTotalNumInputChannels(); - totalOutChannels = processor.getTotalNumOutputChannels(); - - { - channelCapabilities.reset ([[NSMutableArray alloc] init]); - - for (int i = 0; i < channelInfos.size(); ++i) - { - AUChannelInfo& info = channelInfos.getReference (i); - - [channelCapabilities.get() addObject: [NSNumber numberWithInteger: info.inChannels]]; - [channelCapabilities.get() addObject: [NSNumber numberWithInteger: info.outChannels]]; - } - } - - internalRenderBlock = CreateObjCBlock (this, &JuceAudioUnitv3::renderCallback); - - processor.setRateAndBufferSizeDetails (kDefaultSampleRate, static_cast (maxFrames)); - processor.prepareToPlay (kDefaultSampleRate, static_cast (maxFrames)); - processor.addListener (this); - - addParameters(); - addPresets(); - - addAudioUnitBusses (true); - addAudioUnitBusses (false); - } - - AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; } - - //============================================================================== - void reset() - { - midiMessages.clear(); - lastTimeStamp.mSampleTime = std::numeric_limits::max(); - lastTimeStamp.mFlags = 0; - } - - //============================================================================== - AUAudioUnitPreset* getCurrentPreset() const - { - return factoryPresets.getAtIndex (getAudioProcessor().getCurrentProgram()); - } - - void setCurrentPreset (AUAudioUnitPreset* preset) - { - getAudioProcessor().setCurrentProgram (static_cast ([preset number])); - } - - NSArray* getFactoryPresets() const - { - return factoryPresets.get(); - } - - NSDictionary* getFullState() const - { - NSMutableDictionary* retval = [[NSMutableDictionary alloc] init]; - - { - auto* superRetval = ObjCMsgSendSuper*> (au, @selector (fullState)); - - if (superRetval != nullptr) - [retval addEntriesFromDictionary:superRetval]; - } - - juce::MemoryBlock state; - - #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES - getAudioProcessor().getCurrentProgramStateInformation (state); - #else - getAudioProcessor().getStateInformation (state); - #endif - - if (state.getSize() > 0) - { - NSData* ourState = [[NSData alloc] initWithBytes: state.getData() - length: state.getSize()]; - - NSString* nsKey = [[NSString alloc] initWithUTF8String: JUCE_STATE_DICTIONARY_KEY]; - - [retval setObject: ourState - forKey: nsKey]; - - [nsKey release]; - [ourState release]; - } - - return [retval autorelease]; - } - - void setFullState (NSDictionary* state) - { - if (state == nullptr) - return; - - NSMutableDictionary* modifiedState = [[NSMutableDictionary alloc] init]; - [modifiedState addEntriesFromDictionary: state]; - - NSString* nsPresetKey = [[NSString alloc] initWithUTF8String: kAUPresetDataKey]; - [modifiedState removeObjectForKey: nsPresetKey]; - [nsPresetKey release]; - - ObjCMsgSendSuper (au, @selector (setFullState:), state); - - NSString* nsKey = [[NSString alloc] initWithUTF8String: JUCE_STATE_DICTIONARY_KEY]; - NSObject* obj = [modifiedState objectForKey: nsKey]; - [nsKey release]; - - if (obj != nullptr) - { - if ([obj isKindOfClass:[NSData class]]) - { - NSData* data = reinterpret_cast (obj); - const int numBytes = static_cast ([data length]); - const juce::uint8* const rawBytes = reinterpret_cast< const juce::uint8* const> ([data bytes]); - - if (numBytes > 0) - { - #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES - getAudioProcessor().setCurrentProgramStateInformation (rawBytes, numBytes); - #else - getAudioProcessor().setStateInformation (rawBytes, numBytes); - #endif - } - } - } - - [modifiedState release]; - } - - AUParameterTree* getParameterTree() const - { - return paramTree.get(); - } - - NSArray* parametersForOverviewWithCount (int count) const - { - auto* retval = [[[NSMutableArray alloc] init] autorelease]; - - for (const auto& address : addressForIndex) - { - if (static_cast (count) <= [retval count]) - break; - - [retval addObject: [NSNumber numberWithUnsignedLongLong: address]]; - } - - return retval; - } - - //============================================================================== - NSTimeInterval getLatency() const - { - auto& p = getAudioProcessor(); - return p.getLatencySamples() / p.getSampleRate(); - } - - NSTimeInterval getTailTime() const - { - return getAudioProcessor().getTailLengthSeconds(); - } - - //============================================================================== - AUAudioUnitBusArray* getInputBusses() const { return inputBusses.get(); } - AUAudioUnitBusArray* getOutputBusses() const { return outputBusses.get(); } - NSArray* getChannelCapabilities() const { return channelCapabilities.get(); } - - bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* auBus) - { - const bool isInput = ([auBus busType] == AUAudioUnitBusTypeInput); - const int busIdx = static_cast ([auBus index]); - const int newNumChannels = static_cast ([format channelCount]); - - AudioProcessor& processor = getAudioProcessor(); - - if ([[maybe_unused]] AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx)) - { - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - if (! AudioUnitHelpers::isLayoutSupported (processor, isInput, busIdx, newNumChannels, configs)) - return false; - #else - const AVAudioChannelLayout* layout = [format channelLayout]; - const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0); - - if (layoutTag != 0) - { - AudioChannelSet newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag); - - if (newLayout.size() != newNumChannels) - return false; - - if (! bus->isLayoutSupported (newLayout)) - return false; - } - else - { - if (! bus->isNumberOfChannelsSupported (newNumChannels)) - return false; - } - #endif - - return true; - } - - return false; - } - - //============================================================================== - int getVirtualMIDICableCount() const - { - #if JucePlugin_WantsMidiInput - return 1; - #else - return 0; - #endif - } - - bool getSupportsMPE() const - { - return getAudioProcessor().supportsMPE(); - } - - NSArray* getMIDIOutputNames() const - { - #if JucePlugin_ProducesMidiOutput - return @[@"MIDI Out"]; - #else - return @[]; - #endif - } - - //============================================================================== - AUInternalRenderBlock getInternalRenderBlock() const { return internalRenderBlock; } - bool getRenderingOffline() const { return getAudioProcessor().isNonRealtime(); } - void setRenderingOffline (bool offline) - { - auto& processor = getAudioProcessor(); - auto isCurrentlyNonRealtime = processor.isNonRealtime(); - - if (isCurrentlyNonRealtime != offline) - { - ScopedLock callbackLock (processor.getCallbackLock()); - - processor.setNonRealtime (offline); - processor.prepareToPlay (processor.getSampleRate(), processor.getBlockSize()); - } - } - - bool getShouldBypassEffect() const - { - if (bypassParam != nullptr) - return (bypassParam->getValue() != 0.0f); - - return (ObjCMsgSendSuper (au, @selector (shouldBypassEffect)) == YES); - } - - void setShouldBypassEffect (bool shouldBypass) - { - if (bypassParam != nullptr) - bypassParam->setValue (shouldBypass ? 1.0f : 0.0f); - - ObjCMsgSendSuper (au, @selector (setShouldBypassEffect:), shouldBypass ? YES : NO); - } - - //============================================================================== - NSString* getContextName() const { return juceStringToNS (contextName); } - void setContextName (NSString* str) - { - if (str != nullptr) - { - AudioProcessor::TrackProperties props; - props.name = nsStringToJuce (str); - - getAudioProcessor().updateTrackProperties (props); - } - } - - //============================================================================== - bool allocateRenderResourcesAndReturnError (NSError **outError) - { - AudioProcessor& processor = getAudioProcessor(); - const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; - - if (ObjCMsgSendSuper (au, @selector (allocateRenderResourcesAndReturnError:), outError) == NO) - return false; - - if (outError != nullptr) - *outError = nullptr; - - AudioProcessor::BusesLayout layouts; - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - const int n = AudioUnitHelpers::getBusCountForWrapper (processor, isInput); - Array& channelSets = (isInput ? layouts.inputBuses : layouts.outputBuses); - - AUAudioUnitBusArray* auBuses = (isInput ? [au inputBusses] : [au outputBusses]); - jassert ([auBuses count] == static_cast (n)); - - for (int busIdx = 0; busIdx < n; ++busIdx) - { - if (AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx)) - { - AVAudioFormat* format = [[auBuses objectAtIndexedSubscript:static_cast (busIdx)] format]; - - AudioChannelSet newLayout; - const AVAudioChannelLayout* layout = [format channelLayout]; - const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0); - - if (layoutTag != 0) - newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag); - else - newLayout = bus->supportedLayoutWithChannels (static_cast ([format channelCount])); - - if (newLayout.isDisabled()) - return false; - - channelSets.add (newLayout); - } - } - } - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - - if (! AudioProcessor::containsLayout (layouts, configs)) - { - if (outError != nullptr) - *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr]; - - return false; - } - #endif - - if (! AudioUnitHelpers::setBusesLayout (&getAudioProcessor(), layouts)) - { - if (outError != nullptr) - *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr]; - - return false; - } - - totalInChannels = processor.getTotalNumInputChannels(); - totalOutChannels = processor.getTotalNumOutputChannels(); - - allocateBusBuffer (true); - allocateBusBuffer (false); - - mapper.alloc (processor); - - audioBuffer.prepare (AudioUnitHelpers::getBusesLayout (&processor), static_cast (maxFrames)); - - auto sampleRate = [&] - { - for (auto* buffer : { inputBusses.get(), outputBusses.get() }) - if ([buffer count] > 0) - return [[[buffer objectAtIndexedSubscript: 0] format] sampleRate]; - - return 44100.0; - }(); - - processor.setRateAndBufferSizeDetails (sampleRate, static_cast (maxFrames)); - processor.prepareToPlay (sampleRate, static_cast (maxFrames)); - - midiMessages.ensureSize (2048); - midiMessages.clear(); - - hostMusicalContextCallback = [au musicalContextBlock]; - hostTransportStateCallback = [au transportStateBlock]; - - if (@available (macOS 10.13, iOS 11.0, *)) - midiOutputEventBlock = [au MIDIOutputEventBlock]; - - reset(); - - return true; - } - - void deallocateRenderResources() - { - midiOutputEventBlock = nullptr; - - hostMusicalContextCallback = nullptr; - hostTransportStateCallback = nullptr; - - getAudioProcessor().releaseResources(); - audioBuffer.release(); - - inBusBuffers. clear(); - outBusBuffers.clear(); - - mapper.release(); - - ObjCMsgSendSuper (au, @selector (deallocateRenderResources)); - } - - //============================================================================== - struct ScopedKeyChange - { - ScopedKeyChange (AUAudioUnit* a, NSString* k) - : au (a), key (k) - { - [au willChangeValueForKey: key]; - } - - ~ScopedKeyChange() - { - [au didChangeValueForKey: key]; - } - - AUAudioUnit* au; - NSString* key; - }; - - //============================================================================== - void audioProcessorChanged ([[maybe_unused]] AudioProcessor* processor, const ChangeDetails& details) override - { - if (details.programChanged) - { - { - ScopedKeyChange scope (au, @"allParameterValues"); - addPresets(); - } - - { - ScopedKeyChange scope (au, @"currentPreset"); - } - } - - if (details.latencyChanged) - { - ScopedKeyChange scope (au, @"latency"); - } - - if (details.parameterInfoChanged) - { - ScopedKeyChange scope (au, @"parameterTree"); - auto nodes = createParameterNodes (processor->getParameterTree()); - installNewParameterTree (std::move (nodes.nodeArray)); - } - } - - void sendParameterEvent (int idx, const float* newValue, AUParameterAutomationEventType type) - { - if (inParameterChangedCallback.get()) - { - inParameterChangedCallback = false; - return; - } - - if (auto* juceParam = juceParameters.getParamForIndex (idx)) - { - if (auto* param = [paramTree.get() parameterWithAddress: getAUParameterAddressForIndex (idx)]) - { - const auto value = (newValue != nullptr ? *newValue : juceParam->getValue()) * getMaximumParameterValue (*juceParam); - - if (@available (macOS 10.12, iOS 10.0, *)) - { - [param setValue: value - originator: editorObserverToken.get() - atHostTime: lastTimeStamp.mHostTime - eventType: type]; - } - else if (type == AUParameterAutomationEventTypeValue) - { - [param setValue: value originator: editorObserverToken.get()]; - } - } - } - } - - void audioProcessorParameterChanged (AudioProcessor*, int idx, float newValue) override - { - sendParameterEvent (idx, &newValue, AUParameterAutomationEventTypeValue); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int idx) override - { - sendParameterEvent (idx, nullptr, AUParameterAutomationEventTypeTouch); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int idx) override - { - sendParameterEvent (idx, nullptr, AUParameterAutomationEventTypeRelease); - } - - //============================================================================== - Optional getPosition() const override - { - PositionInfo info; - info.setTimeInSamples ((int64) (lastTimeStamp.mSampleTime + 0.5)); - info.setTimeInSeconds (*info.getTimeInSamples() / getAudioProcessor().getSampleRate()); - - info.setFrameRate ([this] - { - switch (lastTimeStamp.mSMPTETime.mType) - { - case kSMPTETimeType2398: return FrameRate().withBaseRate (24).withPullDown(); - case kSMPTETimeType24: return FrameRate().withBaseRate (24); - case kSMPTETimeType25: return FrameRate().withBaseRate (25); - case kSMPTETimeType30Drop: return FrameRate().withBaseRate (30).withDrop(); - case kSMPTETimeType30: return FrameRate().withBaseRate (30); - case kSMPTETimeType2997: return FrameRate().withBaseRate (30).withPullDown(); - case kSMPTETimeType2997Drop: return FrameRate().withBaseRate (30).withPullDown().withDrop(); - case kSMPTETimeType60: return FrameRate().withBaseRate (60); - case kSMPTETimeType60Drop: return FrameRate().withBaseRate (60).withDrop(); - case kSMPTETimeType5994: return FrameRate().withBaseRate (60).withPullDown(); - case kSMPTETimeType5994Drop: return FrameRate().withBaseRate (60).withPullDown().withDrop(); - case kSMPTETimeType50: return FrameRate().withBaseRate (50); - default: break; - } - - return FrameRate(); - }()); - - double num; - NSInteger den; - NSInteger outDeltaSampleOffsetToNextBeat; - double outCurrentMeasureDownBeat, bpm; - double ppqPosition; - - if (hostMusicalContextCallback != nullptr) - { - AUHostMusicalContextBlock musicalContextCallback = hostMusicalContextCallback; - - if (musicalContextCallback (&bpm, &num, &den, &ppqPosition, &outDeltaSampleOffsetToNextBeat, &outCurrentMeasureDownBeat)) - { - info.setTimeSignature (TimeSignature { (int) num, (int) den }); - info.setPpqPositionOfLastBarStart (outCurrentMeasureDownBeat); - info.setBpm (bpm); - info.setPpqPosition (ppqPosition); - } - } - - double outCurrentSampleInTimeLine = 0, outCycleStartBeat = 0, outCycleEndBeat = 0; - AUHostTransportStateFlags flags; - - if (hostTransportStateCallback != nullptr) - { - AUHostTransportStateBlock transportStateCallback = hostTransportStateCallback; - - if (transportStateCallback (&flags, &outCurrentSampleInTimeLine, &outCycleStartBeat, &outCycleEndBeat)) - { - info.setTimeInSamples ((int64) (outCurrentSampleInTimeLine + 0.5)); - info.setTimeInSeconds (*info.getTimeInSamples() / getAudioProcessor().getSampleRate()); - info.setIsPlaying ((flags & AUHostTransportStateMoving) != 0); - info.setIsLooping ((flags & AUHostTransportStateCycling) != 0); - info.setIsRecording ((flags & AUHostTransportStateRecording) != 0); - info.setLoopPoints (LoopPoints { outCycleStartBeat, outCycleEndBeat }); - } - } - - if ((lastTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0) - info.setHostTimeNs (timeConversions.hostTimeToNanos (lastTimeStamp.mHostTime)); - - return info; - } - - //============================================================================== - static void removeEditor (AudioProcessor& processor) - { - ScopedLock editorLock (processor.getCallbackLock()); - - if (AudioProcessorEditor* editor = processor.getActiveEditor()) - { - processor.editorBeingDeleted (editor); - delete editor; - } - } - - AUAudioUnit* getAudioUnit() const { return au; } - -private: - struct Class : public ObjCClass - { - Class() : ObjCClass ("AUAudioUnit_") - { - addIvar ("cppObject"); - - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (initWithComponentDescription:options:error:juceClass:), [] (id _self, - SEL, - AudioComponentDescription descr, - AudioComponentInstantiationOptions options, - NSError** error, - JuceAudioUnitv3* juceAU) - { - AUAudioUnit* self = _self; - - self = ObjCMsgSendSuper (self, @selector(initWithComponentDescription:options:error:), descr, options, error); - - setThis (self, juceAU); - return self; - }); - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - addMethod (@selector (initWithComponentDescription:options:error:), [] (id _self, - SEL, - AudioComponentDescription descr, - AudioComponentInstantiationOptions options, - NSError** error) - { - AUAudioUnit* self = _self; - - self = ObjCMsgSendSuper (self, @selector (initWithComponentDescription:options:error:), descr, options, error); - - auto* juceAU = JuceAudioUnitv3::create (self, descr, options, error); - - setThis (self, juceAU); - return self; - }); - - addMethod (@selector (dealloc), [] (id self, SEL) - { - if (! MessageManager::getInstance()->isThisTheMessageThread()) - { - WaitableEvent deletionEvent; - - struct AUDeleter : public CallbackMessage - { - AUDeleter (id selfToDelete, WaitableEvent& event) - : parentSelf (selfToDelete), parentDeletionEvent (event) - { - } - - void messageCallback() override - { - delete _this (parentSelf); - parentDeletionEvent.signal(); - } - - id parentSelf; - WaitableEvent& parentDeletionEvent; - }; - - (new AUDeleter (self, deletionEvent))->post(); - deletionEvent.wait (-1); - } - else - { - delete _this (self); - } - }); - - //============================================================================== - addMethod (@selector (reset), [] (id self, SEL) { return _this (self)->reset(); }); - - //============================================================================== - addMethod (@selector (currentPreset), [] (id self, SEL) { return _this (self)->getCurrentPreset(); }); - addMethod (@selector (setCurrentPreset:), [] (id self, SEL, AUAudioUnitPreset* preset) { return _this (self)->setCurrentPreset (preset); }); - addMethod (@selector (factoryPresets), [] (id self, SEL) { return _this (self)->getFactoryPresets(); }); - addMethod (@selector (fullState), [] (id self, SEL) { return _this (self)->getFullState(); }); - addMethod (@selector (setFullState:), [] (id self, SEL, NSDictionary* state) { return _this (self)->setFullState (state); }); - addMethod (@selector (parameterTree), [] (id self, SEL) { return _this (self)->getParameterTree(); }); - addMethod (@selector (parametersForOverviewWithCount:), [] (id self, SEL, NSInteger count) { return _this (self)->parametersForOverviewWithCount (static_cast (count)); }); - - //============================================================================== - addMethod (@selector (latency), [] (id self, SEL) { return _this (self)->getLatency(); }); - addMethod (@selector (tailTime), [] (id self, SEL) { return _this (self)->getTailTime(); }); - - //============================================================================== - addMethod (@selector (inputBusses), [] (id self, SEL) { return _this (self)->getInputBusses(); }); - addMethod (@selector (outputBusses), [] (id self, SEL) { return _this (self)->getOutputBusses(); }); - addMethod (@selector (channelCapabilities), [] (id self, SEL) { return _this (self)->getChannelCapabilities(); }); - addMethod (@selector (shouldChangeToFormat:forBus:), [] (id self, SEL, AVAudioFormat* format, AUAudioUnitBus* bus) { return _this (self)->shouldChangeToFormat (format, bus) ? YES : NO; }); - - //============================================================================== - addMethod (@selector (virtualMIDICableCount), [] (id self, SEL) { return _this (self)->getVirtualMIDICableCount(); }); - - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (supportsMPE), [] (id self, SEL) { return _this (self)->getSupportsMPE() ? YES : NO; }); - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - if (@available (macOS 10.13, iOS 11.0, *)) - addMethod (@selector (MIDIOutputNames), [] (id self, SEL) { return _this (self)->getMIDIOutputNames(); }); - - //============================================================================== - addMethod (@selector (internalRenderBlock), [] (id self, SEL) { return _this (self)->getInternalRenderBlock(); }); - addMethod (@selector (canProcessInPlace), [] (id, SEL) { return NO; }); - addMethod (@selector (isRenderingOffline), [] (id self, SEL) { return _this (self)->getRenderingOffline() ? YES : NO; }); - addMethod (@selector (setRenderingOffline:), [] (id self, SEL, BOOL renderingOffline) { return _this (self)->setRenderingOffline (renderingOffline); }); - addMethod (@selector (shouldBypassEffect), [] (id self, SEL) { return _this (self)->getShouldBypassEffect() ? YES : NO; }); - addMethod (@selector (setShouldBypassEffect:), [] (id self, SEL, BOOL shouldBypass) { return _this (self)->setShouldBypassEffect (shouldBypass); }); - addMethod (@selector (allocateRenderResourcesAndReturnError:), [] (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }); - addMethod (@selector (deallocateRenderResources), [] (id self, SEL) { return _this (self)->deallocateRenderResources(); }); - - //============================================================================== - addMethod (@selector (contextName), [] (id self, SEL) { return _this (self)->getContextName(); }); - addMethod (@selector (setContextName:), [](id self, SEL, NSString* str) { return _this (self)->setContextName (str); }); - - //============================================================================== - if (@available (macOS 10.13, iOS 11.0, *)) - { - addMethod (@selector (supportedViewConfigurations:), [] (id self, SEL, NSArray* configs) - { - auto supportedViewIndices = [[NSMutableIndexSet alloc] init]; - auto n = [configs count]; - - if (auto* editor = _this (self)->getAudioProcessor().createEditorIfNeeded()) - { - // If you hit this assertion then your plug-in's editor is reporting that it doesn't support - // any host MIDI controller configurations! - jassert (editor->supportsHostMIDIControllerPresence (true) || editor->supportsHostMIDIControllerPresence (false)); - - for (auto i = 0u; i < n; ++i) - { - if (auto viewConfiguration = [configs objectAtIndex: i]) - { - if (editor->supportsHostMIDIControllerPresence ([viewConfiguration hostHasController] == YES)) - { - auto* constrainer = editor->getConstrainer(); - auto height = (int) [viewConfiguration height]; - auto width = (int) [viewConfiguration width]; - - const auto maxLimits = std::numeric_limits::max() / 2; - const Rectangle requestedBounds { width, height }; - auto modifiedBounds = requestedBounds; - constrainer->checkBounds (modifiedBounds, editor->getBounds().withZeroOrigin(), { maxLimits, maxLimits }, false, false, false, false); - - if (modifiedBounds == requestedBounds) - [supportedViewIndices addIndex: i]; - } - } - } - } - - return [supportedViewIndices autorelease]; - }); - - addMethod (@selector (selectViewConfiguration:), [] (id self, SEL, AUAudioUnitViewConfiguration* config) - { - _this (self)->processorHolder->viewConfiguration.reset (new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES }); - }); - } - - registerClass(); - } - - //============================================================================== - static JuceAudioUnitv3* _this (id self) { return getIvar (self, "cppObject"); } - static void setThis (id self, JuceAudioUnitv3* cpp) { object_setInstanceVariable (self, "cppObject", cpp); } - }; - - static JuceAudioUnitv3* create (AUAudioUnit* audioUnit, AudioComponentDescription descr, AudioComponentInstantiationOptions options, NSError** error) - { - return new JuceAudioUnitv3 (audioUnit, descr, options, error); - } - - //============================================================================== - static Class& getClass() - { - static Class result; - return result; - } - - //============================================================================== - struct BusBuffer - { - BusBuffer (AUAudioUnitBus* bus, int maxFramesPerBuffer) - : auBus (bus), - maxFrames (maxFramesPerBuffer), - numberOfChannels (static_cast ([[auBus format] channelCount])), - isInterleaved ([[auBus format] isInterleaved]) - { - alloc(); - } - - //============================================================================== - void alloc() - { - const int numBuffers = isInterleaved ? 1 : numberOfChannels; - int bytes = static_cast (sizeof (AudioBufferList)) - + ((numBuffers - 1) * static_cast (sizeof (::AudioBuffer))); - jassert (bytes > 0); - - bufferListStorage.calloc (static_cast (bytes)); - bufferList = reinterpret_cast (bufferListStorage.getData()); - - const int bufferChannels = isInterleaved ? numberOfChannels : 1; - scratchBuffer.setSize (numBuffers, bufferChannels * maxFrames); - } - - void dealloc() - { - bufferList = nullptr; - bufferListStorage.free(); - scratchBuffer.setSize (0, 0); - } - - //============================================================================== - int numChannels() const noexcept { return numberOfChannels; } - bool interleaved() const noexcept { return isInterleaved; } - AudioBufferList* get() const noexcept { return bufferList; } - - //============================================================================== - void prepare (UInt32 nFrames, const AudioBufferList* other = nullptr) noexcept - { - const int numBuffers = isInterleaved ? 1 : numberOfChannels; - const bool isCompatible = isCompatibleWith (other); - - bufferList->mNumberBuffers = static_cast (numBuffers); - - for (int i = 0; i < numBuffers; ++i) - { - const UInt32 bufferChannels = static_cast (isInterleaved ? numberOfChannels : 1); - bufferList->mBuffers[i].mNumberChannels = bufferChannels; - bufferList->mBuffers[i].mData = (isCompatible ? other->mBuffers[i].mData - : scratchBuffer.getWritePointer (i)); - bufferList->mBuffers[i].mDataByteSize = nFrames * bufferChannels * sizeof (float); - } - } - - //============================================================================== - bool isCompatibleWith (const AudioBufferList* other) const noexcept - { - if (other == nullptr) - return false; - - if (other->mNumberBuffers > 0) - { - const bool otherInterleaved = AudioUnitHelpers::isAudioBufferInterleaved (*other); - const int otherChannels = static_cast (otherInterleaved ? other->mBuffers[0].mNumberChannels - : other->mNumberBuffers); - - return otherInterleaved == isInterleaved - && numberOfChannels == otherChannels; - } - - return numberOfChannels == 0; - } - - private: - AUAudioUnitBus* auBus; - HeapBlock bufferListStorage; - AudioBufferList* bufferList = nullptr; - int maxFrames, numberOfChannels; - bool isInterleaved; - juce::AudioBuffer scratchBuffer; - }; - - class FactoryPresets - { - public: - using Presets = std::unique_ptr, NSObjectDeleter>; - - void set (Presets newPresets) - { - std::lock_guard lock (mutex); - std::swap (presets, newPresets); - } - - NSArray* get() const - { - std::lock_guard lock (mutex); - return presets.get(); - } - - AUAudioUnitPreset* getAtIndex (int index) const - { - std::lock_guard lock (mutex); - - if (index < (int) [presets.get() count]) - return [presets.get() objectAtIndex: (unsigned int) index]; - - return nullptr; - } - - private: - Presets presets; - mutable std::mutex mutex; - }; - - //============================================================================== - void addAudioUnitBusses (bool isInput) - { - std::unique_ptr, NSObjectDeleter> array ([[NSMutableArray alloc] init]); - AudioProcessor& processor = getAudioProcessor(); - const auto numWrapperBuses = AudioUnitHelpers::getBusCountForWrapper (processor, isInput); - const auto numProcessorBuses = AudioUnitHelpers::getBusCount (processor, isInput); - - for (int i = 0; i < numWrapperBuses; ++i) - { - using AVAudioFormatPtr = std::unique_ptr; - - const auto audioFormat = [&]() -> AVAudioFormatPtr - { - const auto tag = i < numProcessorBuses ? CoreAudioLayouts::toCoreAudio (processor.getChannelLayoutOfBus (isInput, i)) - : kAudioChannelLayoutTag_Stereo; - const std::unique_ptr layout { [[AVAudioChannelLayout alloc] initWithLayoutTag: tag] }; - - if (auto format = AVAudioFormatPtr { [[AVAudioFormat alloc] initStandardFormatWithSampleRate: kDefaultSampleRate - channelLayout: layout.get()] }) - return format; - - const auto channels = i < numProcessorBuses ? processor.getChannelCountOfBus (isInput, i) - : 2; - - // According to the docs, this will fail if the number of channels is greater than 2. - if (auto format = AVAudioFormatPtr { [[AVAudioFormat alloc] initStandardFormatWithSampleRate: kDefaultSampleRate - channels: static_cast (channels)] }) - return format; - - jassertfalse; - return nullptr; - }(); - - using AUAudioUnitBusPtr = std::unique_ptr; - - const auto audioUnitBus = [&]() -> AUAudioUnitBusPtr - { - if (audioFormat != nullptr) - return AUAudioUnitBusPtr { [[AUAudioUnitBus alloc] initWithFormat: audioFormat.get() error: nullptr] }; - - jassertfalse; - return nullptr; - }(); - - if (audioUnitBus != nullptr) - [array.get() addObject: audioUnitBus.get()]; - } - - (isInput ? inputBusses : outputBusses).reset ([[AUAudioUnitBusArray alloc] initWithAudioUnit: au - busType: (isInput ? AUAudioUnitBusTypeInput : AUAudioUnitBusTypeOutput) - busses: array.get()]); - } - - // When parameters are discrete we need to use integer values. - static float getMaximumParameterValue ([[maybe_unused]] const AudioProcessorParameter& juceParam) - { - #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - return 1.0f; - #else - return juceParam.isDiscrete() ? (float) (juceParam.getNumSteps() - 1) : 1.0f; - #endif - } - - static auto createParameter (const AudioProcessorParameter& parameter) - { - const String name (parameter.getName (512)); - - AudioUnitParameterUnit unit = kAudioUnitParameterUnit_Generic; - AudioUnitParameterOptions flags = (UInt32) (kAudioUnitParameterFlag_IsWritable - | kAudioUnitParameterFlag_IsReadable - | kAudioUnitParameterFlag_HasCFNameString - | kAudioUnitParameterFlag_ValuesHaveStrings); - - #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution; - #endif - - // Set whether the param is automatable (unnamed parameters aren't allowed to be automated). - if (name.isEmpty() || ! parameter.isAutomatable()) - flags |= kAudioUnitParameterFlag_NonRealTime; - - const bool isParameterDiscrete = parameter.isDiscrete(); - - if (! isParameterDiscrete) - flags |= kAudioUnitParameterFlag_CanRamp; - - if (parameter.isMetaParameter()) - flags |= kAudioUnitParameterFlag_IsGlobalMeta; - - std::unique_ptr valueStrings; - - // Is this a meter? - if (((parameter.getCategory() & 0xffff0000) >> 16) == 2) - { - flags &= ~kAudioUnitParameterFlag_IsWritable; - flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic; - unit = kAudioUnitParameterUnit_LinearGain; - } - else - { - #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - if (parameter.isDiscrete()) - { - unit = parameter.isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed; - auto maxValue = getMaximumParameterValue (parameter); - auto numSteps = parameter.getNumSteps(); - - // Some hosts can't handle the huge numbers of discrete parameter values created when - // using the default number of steps. - jassert (numSteps != AudioProcessor::getDefaultNumParameterSteps()); - - valueStrings.reset ([NSMutableArray new]); - - for (int i = 0; i < numSteps; ++i) - [valueStrings.get() addObject: juceStringToNS (parameter.getText ((float) i / maxValue, 0))]; - } - #endif - } - - const auto address = generateAUParameterAddress (parameter); - - auto getParameterIdentifier = [¶meter] - { - if (const auto* paramWithID = dynamic_cast (¶meter)) - return paramWithID->paramID; - - // This could clash if any groups have been given integer IDs! - return String (parameter.getParameterIndex()); - }; - - std::unique_ptr param; - - @try - { - // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h - param.reset([[AUParameterTree createParameterWithIdentifier: juceStringToNS (getParameterIdentifier()) - name: juceStringToNS (name) - address: address - min: 0.0f - max: getMaximumParameterValue (parameter) - unit: unit - unitName: nullptr - flags: flags - valueStrings: valueStrings.get() - dependentParameters: nullptr] - retain]); - } - - @catch (NSException* exception) - { - // Do you have duplicate identifiers in any of your groups or parameters, - // or do your identifiers have unusual characters in them? - jassertfalse; - } - - [param.get() setValue: parameter.getDefaultValue()]; - return param; - } - - struct NodeArrayResult - { - std::unique_ptr, NSObjectDeleter> nodeArray { [NSMutableArray new] }; - - void addParameter (const AudioProcessorParameter&, std::unique_ptr auParam) - { - [nodeArray.get() addObject: [auParam.get() retain]]; - } - - void addGroup (const AudioProcessorParameterGroup& group, const NodeArrayResult& r) - { - @try - { - // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h - [nodeArray.get() addObject: [[AUParameterTree createGroupWithIdentifier: juceStringToNS (group.getID()) - name: juceStringToNS (group.getName()) - children: r.nodeArray.get()] retain]]; - } - @catch (NSException* exception) - { - // Do you have duplicate identifiers in any of your groups or parameters, - // or do your identifiers have unusual characters in them? - jassertfalse; - } - } - }; - - struct AddressedNodeArrayResult - { - NodeArrayResult nodeArray; - std::map addressForIndex; - - void addParameter (const AudioProcessorParameter& juceParam, std::unique_ptr auParam) - { - const auto index = juceParam.getParameterIndex(); - const auto address = [auParam.get() address]; - - if (const auto iter = addressForIndex.find (index); iter == addressForIndex.cend()) - addressForIndex.emplace (index, address); - else - jassertfalse; // If you hit this assertion then you have put a parameter in two groups. - - nodeArray.addParameter (juceParam, std::move (auParam)); - } - - void addGroup (const AudioProcessorParameterGroup& group, const AddressedNodeArrayResult& r) - { - nodeArray.addGroup (group, r.nodeArray); - - [[maybe_unused]] const auto initialSize = addressForIndex.size(); - addressForIndex.insert (r.addressForIndex.begin(), r.addressForIndex.end()); - [[maybe_unused]] const auto finalSize = addressForIndex.size(); - - // If this is hit, the same parameter index exists in multiple groups. - jassert (finalSize == initialSize + r.addressForIndex.size()); - } - }; - - template - static Result createParameterNodes (const AudioProcessorParameterGroup& group) - { - Result result; - - for (auto* node : group) - { - if (auto* childGroup = node->getGroup()) - { - result.addGroup (*childGroup, createParameterNodes (*childGroup)); - } - else if (auto* juceParam = node->getParameter()) - { - result.addParameter (*juceParam, createParameter (*juceParam)); - } - else - { - // No group or parameter at this node! - jassertfalse; - } - } - - return result; - } - - void addParameters() - { - auto& processor = getAudioProcessor(); - juceParameters.update (processor, forceLegacyParamIDs); - - if ((bypassParam = processor.getBypassParameter()) != nullptr) - bypassParam->addListener (this); - - auto nodes = createParameterNodes (processor.getParameterTree()); - installNewParameterTree (std::move (nodes.nodeArray.nodeArray)); - - // When we first create the parameter tree, we also create structures to allow lookup by index/address. - // These structures are not rebuilt, i.e. we assume that the parameter addresses and indices are stable. - // These structures aren't modified after creation, so there should be no need to synchronize access to them. - - addressForIndex = [&] - { - std::vector addresses (static_cast (processor.getParameters().size())); - - for (size_t i = 0; i < addresses.size(); ++i) - { - if (const auto iter = nodes.addressForIndex.find (static_cast (i)); iter != nodes.addressForIndex.cend()) - addresses[i] = iter->second; - else - jassertfalse; // Somehow, there's a parameter missing... - } - - return addresses; - }(); - - #if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS - indexForAddress = [&] - { - std::map indices; - - for (const auto& [index, address] : nodes.addressForIndex) - { - if (const auto iter = indices.find (address); iter == indices.cend()) - indices.emplace (address, index); - else - jassertfalse; // The parameter at index 'iter->first' has the same address as the parameter at index 'index' - } - - return indices; - }(); - #endif - } - - void installNewParameterTree (std::unique_ptr, NSObjectDeleter> topLevelNodes) - { - editorObserverToken.reset(); - - @try - { - // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h - paramTree.reset ([[AUParameterTree createTreeWithChildren: topLevelNodes.get()] retain]); - } - @catch (NSException* exception) - { - // Do you have duplicate identifiers in any of your groups or parameters, - // or do your identifiers have unusual characters in them? - jassertfalse; - } - - [paramTree.get() setImplementorValueObserver: paramObserver]; - [paramTree.get() setImplementorValueProvider: paramProvider]; - [paramTree.get() setImplementorStringFromValueCallback: stringFromValueProvider]; - [paramTree.get() setImplementorValueFromStringCallback: valueFromStringProvider]; - - if (getAudioProcessor().hasEditor()) - { - editorObserverToken = ObserverPtr ([paramTree.get() tokenByAddingParameterObserver: editorParamObserver], - ObserverDestructor { paramTree.get() }); - } - } - - void setAudioProcessorParameter (AudioProcessorParameter* juceParam, float value) - { - if (value != juceParam->getValue()) - { - juceParam->setValue (value); - - inParameterChangedCallback = true; - juceParam->sendValueChangedMessageToListeners (value); - } - } - - void addPresets() - { - FactoryPresets::Presets newPresets { [[NSMutableArray alloc] init] }; - - const int n = getAudioProcessor().getNumPrograms(); - - for (int idx = 0; idx < n; ++idx) - { - String name = getAudioProcessor().getProgramName (idx); - - std::unique_ptr preset ([[AUAudioUnitPreset alloc] init]); - [preset.get() setName: juceStringToNS (name)]; - [preset.get() setNumber: static_cast (idx)]; - - [newPresets.get() addObject: preset.get()]; - } - - factoryPresets.set (std::move (newPresets)); - } - - //============================================================================== - void allocateBusBuffer (bool isInput) - { - OwnedArray& busBuffers = isInput ? inBusBuffers : outBusBuffers; - busBuffers.clear(); - - const int n = AudioUnitHelpers::getBusCountForWrapper (getAudioProcessor(), isInput); - const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; - - for (int busIdx = 0; busIdx < n; ++busIdx) - busBuffers.add (new BusBuffer ([(isInput ? inputBusses.get() : outputBusses.get()) objectAtIndexedSubscript: static_cast (busIdx)], - static_cast (maxFrames))); - } - - //============================================================================== - void processEvents (const AURenderEvent *__nullable realtimeEventListHead, [[maybe_unused]] int numParams, AUEventSampleTime startTime) - { - for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; event = event->head.next) - { - switch (event->head.eventType) - { - case AURenderEventMIDI: - { - const AUMIDIEvent& midiEvent = event->MIDI; - midiMessages.addEvent (midiEvent.data, midiEvent.length, static_cast (midiEvent.eventSampleTime - startTime)); - } - break; - - #if JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED - case AURenderEventMIDIEventList: - { - const auto& list = event->MIDIEventsList.eventList; - auto* packet = &list.packet[0]; - - for (uint32_t i = 0; i < list.numPackets; ++i) - { - converter.dispatch (reinterpret_cast (packet->words), - reinterpret_cast (packet->words + packet->wordCount), - static_cast (packet->timeStamp - (MIDITimeStamp) startTime), - [this] (const MidiMessage& message) { midiMessages.addEvent (message, int (message.getTimeStamp())); }); - - packet = MIDIEventPacketNext (packet); - } - } - break; - #endif - - case AURenderEventParameter: - case AURenderEventParameterRamp: - { - const AUParameterEvent& paramEvent = event->parameter; - - if (auto* p = getJuceParameterForAUAddress (paramEvent.parameterAddress)) - { - auto normalisedValue = paramEvent.value / getMaximumParameterValue (*p); - setAudioProcessorParameter (p, normalisedValue); - } - } - break; - - case AURenderEventMIDISysEx: - default: - break; - } - } - } - - AUAudioUnitStatus renderCallback (AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp, AUAudioFrameCount frameCount, - NSInteger outputBusNumber, AudioBufferList* outputData, const AURenderEvent *__nullable realtimeEventListHead, - AURenderPullInputBlock __nullable pullInputBlock) - { - auto& processor = getAudioProcessor(); - jassert (static_cast (frameCount) <= getAudioProcessor().getBlockSize()); - - const auto numProcessorBusesOut = AudioUnitHelpers::getBusCount (processor, false); - - if (lastTimeStamp.mSampleTime != timestamp->mSampleTime) - { - // process params and incoming midi (only once for a given timestamp) - midiMessages.clear(); - - const int numParams = juceParameters.getNumParameters(); - processEvents (realtimeEventListHead, numParams, static_cast (timestamp->mSampleTime)); - - lastTimeStamp = *timestamp; - - const auto numWrapperBusesIn = AudioUnitHelpers::getBusCountForWrapper (processor, true); - const auto numWrapperBusesOut = AudioUnitHelpers::getBusCountForWrapper (processor, false); - const auto numProcessorBusesIn = AudioUnitHelpers::getBusCount (processor, true); - - // prepare buffers - { - for (int busIdx = 0; busIdx < numWrapperBusesOut; ++busIdx) - { - BusBuffer& busBuffer = *outBusBuffers[busIdx]; - const bool canUseDirectOutput = - (busIdx == outputBusNumber && outputData != nullptr && outputData->mNumberBuffers > 0); - - busBuffer.prepare (frameCount, canUseDirectOutput ? outputData : nullptr); - - if (numProcessorBusesOut <= busIdx) - AudioUnitHelpers::clearAudioBuffer (*busBuffer.get()); - } - - for (int busIdx = 0; busIdx < numWrapperBusesIn; ++busIdx) - { - BusBuffer& busBuffer = *inBusBuffers[busIdx]; - busBuffer.prepare (frameCount, busIdx < numWrapperBusesOut ? outBusBuffers[busIdx]->get() : nullptr); - } - - audioBuffer.reset(); - } - - // pull inputs - { - for (int busIdx = 0; busIdx < numProcessorBusesIn; ++busIdx) - { - BusBuffer& busBuffer = *inBusBuffers[busIdx]; - AudioBufferList* buffer = busBuffer.get(); - - if (pullInputBlock == nullptr || pullInputBlock (actionFlags, timestamp, frameCount, busIdx, buffer) != noErr) - AudioUnitHelpers::clearAudioBuffer (*buffer); - - if (actionFlags != nullptr && (*actionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0) - AudioUnitHelpers::clearAudioBuffer (*buffer); - } - } - - // set buffer pointer to minimize copying - { - int chIdx = 0; - - for (int busIdx = 0; busIdx < numProcessorBusesOut; ++busIdx) - { - BusBuffer& busBuffer = *outBusBuffers[busIdx]; - AudioBufferList* buffer = busBuffer.get(); - - const bool interleaved = busBuffer.interleaved(); - const int numChannels = busBuffer.numChannels(); - - const int* outLayoutMap = mapper.get (false, busIdx); - - for (int ch = 0; ch < numChannels; ++ch) - audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast (buffer->mBuffers[outLayoutMap[ch]].mData)); - } - - // use input pointers on remaining channels - - for (int busIdx = 0; chIdx < totalInChannels;) - { - const int channelOffset = processor.getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx); - - BusBuffer& busBuffer = *inBusBuffers[busIdx]; - AudioBufferList* buffer = busBuffer.get(); - - const int* inLayoutMap = mapper.get (true, busIdx); - audioBuffer.setBuffer (chIdx++, busBuffer.interleaved() ? nullptr : static_cast (buffer->mBuffers[inLayoutMap[channelOffset]].mData)); - } - } - - // copy input - { - for (int busIdx = 0; busIdx < numProcessorBusesIn; ++busIdx) - audioBuffer.set (busIdx, *inBusBuffers[busIdx]->get(), mapper.get (true, busIdx)); - - audioBuffer.clearUnusedChannels ((int) frameCount); - } - - // process audio - processBlock (audioBuffer.getBuffer (frameCount), midiMessages); - - // send MIDI - #if JucePlugin_ProducesMidiOutput - if (@available (macOS 10.13, iOS 11.0, *)) - { - if (auto midiOut = midiOutputEventBlock) - for (const auto metadata : midiMessages) - if (isPositiveAndBelow (metadata.samplePosition, frameCount)) - midiOut ((int64_t) metadata.samplePosition + (int64_t) (timestamp->mSampleTime + 0.5), - 0, - metadata.numBytes, - metadata.data); - } - #endif - } - - // copy back - if (outputBusNumber < numProcessorBusesOut && outputData != nullptr) - audioBuffer.get ((int) outputBusNumber, *outputData, mapper.get (false, (int) outputBusNumber)); - - return noErr; - } - - void processBlock (juce::AudioBuffer& buffer, MidiBuffer& midiBuffer) noexcept - { - auto& processor = getAudioProcessor(); - const ScopedLock sl (processor.getCallbackLock()); - - if (processor.isSuspended()) - buffer.clear(); - else if (bypassParam == nullptr && [au shouldBypassEffect]) - processor.processBlockBypassed (buffer, midiBuffer); - else - processor.processBlock (buffer, midiBuffer); - } - - //============================================================================== - void valueChangedFromHost (AUParameter* param, AUValue value) - { - if (param != nullptr) - { - if (auto* p = getJuceParameterForAUAddress ([param address])) - { - auto normalisedValue = value / getMaximumParameterValue (*p); - setAudioProcessorParameter (p, normalisedValue); - } - } - } - - AUValue getValue (AUParameter* param) const - { - if (param != nullptr) - { - if (auto* p = getJuceParameterForAUAddress ([param address])) - return p->getValue() * getMaximumParameterValue (*p); - } - - return 0; - } - - void valueChangedForObserver (AUParameterAddress, AUValue) - { - // this will have already been handled by valueChangedFromHost - } - - NSString* stringFromValue (AUParameter* param, const AUValue* value) - { - String text; - - if (param != nullptr && value != nullptr) - { - if (auto* p = getJuceParameterForAUAddress ([param address])) - { - if (LegacyAudioParameter::isLegacy (p)) - text = String (*value); - else - text = p->getText (*value / getMaximumParameterValue (*p), 0); - } - } - - return juceStringToNS (text); - } - - AUValue valueFromString (AUParameter* param, NSString* str) - { - if (param != nullptr && str != nullptr) - { - if (auto* p = getJuceParameterForAUAddress ([param address])) - { - const String text (nsStringToJuce (str)); - - if (LegacyAudioParameter::isLegacy (p)) - return text.getFloatValue(); - - return p->getValueForText (text) * getMaximumParameterValue (*p); - } - } - - return 0; - } - - //============================================================================== - // this is only ever called for the bypass parameter - void parameterValueChanged (int, float newValue) override - { - JuceAudioUnitv3::setShouldBypassEffect (newValue != 0.0f); - } - - void parameterGestureChanged (int, bool) override {} - - //============================================================================== - inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept - { - if (isPositiveAndBelow (paramIndex, addressForIndex.size())) - return addressForIndex[static_cast (paramIndex)]; - - return {}; - } - - inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept - { - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - return static_cast (address); - #else - if (const auto iter = indexForAddress.find (address); iter != indexForAddress.cend()) - return iter->second; - - return {}; - #endif - } - - static AUParameterAddress generateAUParameterAddress (const AudioProcessorParameter& param) - { - const String& juceParamID = LegacyAudioParameter::getParamID (¶m, forceLegacyParamIDs); - - return static_cast (forceLegacyParamIDs ? juceParamID.getIntValue() - : juceParamID.hashCode64()); - } - - AudioProcessorParameter* getJuceParameterForAUAddress (AUParameterAddress address) const noexcept - { - return juceParameters.getParamForIndex (getJuceParameterIndexForAUAddress (address)); - } - - //============================================================================== - static constexpr double kDefaultSampleRate = 44100.0; - - struct ObserverDestructor - { - void operator() (AUParameterObserverToken ptr) const - { - if (ptr != nullptr) - [tree removeParameterObserver: ptr]; - } - - AUParameterTree* tree; - }; - - using ObserverPtr = std::unique_ptr, ObserverDestructor>; - - AUAudioUnit* au; - AudioProcessorHolder::Ptr processorHolder; - - int totalInChannels, totalOutChannels; - - CoreAudioTimeConversions timeConversions; - std::unique_ptr inputBusses, outputBusses; - - ObjCBlock paramObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedFromHost); - ObjCBlock paramProvider = CreateObjCBlock (this, &JuceAudioUnitv3::getValue); - ObjCBlock stringFromValueProvider = CreateObjCBlock (this, &JuceAudioUnitv3::stringFromValue); - ObjCBlock valueFromStringProvider = CreateObjCBlock (this, &JuceAudioUnitv3::valueFromString); - - #if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS - std::map indexForAddress; - #endif - std::vector addressForIndex; - LegacyAudioParametersWrapper juceParameters; - - // to avoid recursion on parameter changes, we need to add an - // editor observer to do the parameter changes - std::unique_ptr paramTree; - ObjCBlock editorParamObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedForObserver); - ObserverPtr editorObserverToken; - - std::unique_ptr, NSObjectDeleter> channelCapabilities; - - FactoryPresets factoryPresets; - - ObjCBlock internalRenderBlock; - - AudioUnitHelpers::CoreAudioBufferList audioBuffer; - AudioUnitHelpers::ChannelRemapper mapper; - - OwnedArray inBusBuffers, outBusBuffers; - MidiBuffer midiMessages; - AUMIDIOutputEventBlock midiOutputEventBlock = nullptr; - - #if JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED - ump::ToBytestreamDispatcher converter { 2048 }; - #endif - - ObjCBlock hostMusicalContextCallback; - ObjCBlock hostTransportStateCallback; - - AudioTimeStamp lastTimeStamp; - - String contextName; - - ThreadLocalValue inParameterChangedCallback; - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - static constexpr bool forceLegacyParamIDs = true; - #else - static constexpr bool forceLegacyParamIDs = false; - #endif - AudioProcessorParameter* bypassParam = nullptr; -}; - -#if JUCE_IOS -namespace juce -{ -struct UIViewPeerControllerReceiver -{ - virtual ~UIViewPeerControllerReceiver(); - virtual void setViewController (UIViewController*) = 0; -}; -} -#endif - -//============================================================================== -class JuceAUViewController -{ -public: - JuceAUViewController (AUViewController* p) - : myself (p) - { - initialiseJuce_GUI(); - } - - ~JuceAUViewController() - { - JUCE_ASSERT_MESSAGE_THREAD - - if (processorHolder.get() != nullptr) - JuceAudioUnitv3::removeEditor (getAudioProcessor()); - } - - //============================================================================== - void loadView() - { - JUCE_ASSERT_MESSAGE_THREAD - - if (auto p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3)) - { - processorHolder = new AudioProcessorHolder (std::move (p)); - auto& processor = getAudioProcessor(); - - if (processor.hasEditor()) - { - if (AudioProcessorEditor* editor = processor.createEditorIfNeeded()) - { - preferredSize = editor->getBounds(); - - JUCE_IOS_MAC_VIEW* view = [[[JUCE_IOS_MAC_VIEW alloc] initWithFrame: convertToCGRect (editor->getBounds())] autorelease]; - [myself setView: view]; - - #if JUCE_IOS - editor->setVisible (false); - #else - editor->setVisible (true); - #endif - - editor->addToDesktop (0, view); - - #if JUCE_IOS - if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0]) - [peerView setContentMode: UIViewContentModeTop]; - - if (auto* peer = dynamic_cast (editor->getPeer())) - peer->setViewController (myself); - #endif - } - } - } - } - - void viewDidLayoutSubviews() - { - if (auto holder = processorHolder.get()) - { - if ([myself view] != nullptr) - { - if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) - { - if (holder->viewConfiguration != nullptr) - editor->hostMIDIControllerIsAvailable (holder->viewConfiguration->hostHasMIDIController); - - editor->setBounds (convertToRectInt ([[myself view] bounds])); - - if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0]) - { - #if JUCE_IOS - [peerView setNeedsDisplay]; - #else - [peerView setNeedsDisplay: YES]; - #endif - } - } - } - } - } - - void didReceiveMemoryWarning() - { - if (auto ptr = processorHolder.get()) - if (auto* processor = ptr->get()) - processor->memoryWarningReceived(); - } - - void viewDidAppear (bool) - { - if (processorHolder.get() != nullptr) - if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) - editor->setVisible (true); - } - - void viewDidDisappear (bool) - { - if (processorHolder.get() != nullptr) - if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) - editor->setVisible (false); - } - - CGSize getPreferredContentSize() const - { - return CGSizeMake (static_cast (preferredSize.getWidth()), - static_cast (preferredSize.getHeight())); - } - - //============================================================================== - AUAudioUnit* createAudioUnit (const AudioComponentDescription& descr, NSError** error) - { - const auto holder = [&] - { - if (auto initialisedHolder = processorHolder.get()) - return initialisedHolder; - - waitForExecutionOnMainThread ([this] { [myself view]; }); - return processorHolder.get(); - }(); - - if (holder == nullptr) - return nullptr; - - return [(new JuceAudioUnitv3 (holder, descr, 0, error))->getAudioUnit() autorelease]; - } - -private: - template - static void waitForExecutionOnMainThread (Callback&& callback) - { - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - callback(); - return; - } - - std::promise promise; - - MessageManager::callAsync ([&] - { - callback(); - promise.set_value(); - }); - - promise.get_future().get(); - } - - // There's a chance that createAudioUnit will be called from a background - // thread while the processorHolder is being updated on the main thread. - class LockedProcessorHolder - { - public: - AudioProcessorHolder::Ptr get() const - { - const ScopedLock lock (mutex); - return holder; - } - - LockedProcessorHolder& operator= (const AudioProcessorHolder::Ptr& other) - { - const ScopedLock lock (mutex); - holder = other; - return *this; - } - - private: - mutable CriticalSection mutex; - AudioProcessorHolder::Ptr holder; - }; - - //============================================================================== - AUViewController* myself; - LockedProcessorHolder processorHolder; - Rectangle preferredSize { 1, 1 }; - - //============================================================================== - AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder.get(); } -}; - -//============================================================================== -// necessary glue code -@interface JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix) : AUViewController -@end - -@implementation JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix) -{ - std::unique_ptr cpp; -} - -- (instancetype) initWithNibName: (nullable NSString*) nib bundle: (nullable NSBundle*) bndl { self = [super initWithNibName: nib bundle: bndl]; cpp.reset (new JuceAUViewController (self)); return self; } -- (void) loadView { cpp->loadView(); } -- (AUAudioUnit *) createAudioUnitWithComponentDescription: (AudioComponentDescription) desc error: (NSError **) error { return cpp->createAudioUnit (desc, error); } -- (CGSize) preferredContentSize { return cpp->getPreferredContentSize(); } - -// NSViewController and UIViewController have slightly different names for this function -- (void) viewDidLayoutSubviews { cpp->viewDidLayoutSubviews(); } -- (void) viewDidLayout { cpp->viewDidLayoutSubviews(); } - -- (void) didReceiveMemoryWarning { cpp->didReceiveMemoryWarning(); } -#if JUCE_IOS -- (void) viewDidAppear: (BOOL) animated { cpp->viewDidAppear (animated); [super viewDidAppear:animated]; } -- (void) viewDidDisappear: (BOOL) animated { cpp->viewDidDisappear (animated); [super viewDidDisappear:animated]; } -#endif -@end - -//============================================================================== -#if JUCE_IOS -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - -bool JUCE_CALLTYPE juce_isInterAppAudioConnected() { return false; } -void JUCE_CALLTYPE juce_switchToHostApplication() {} -Image JUCE_CALLTYPE juce_getIAAHostIcon (int) { return {}; } - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#endif - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#endif diff --git a/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp b/modules/juce_audio_plugin_client/LV2/juce_LV2ManifestHelper.cpp similarity index 91% rename from modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp rename to modules/juce_audio_plugin_client/LV2/juce_LV2ManifestHelper.cpp index c4ca28b39c22..9d018f754975 100644 --- a/modules/juce_audio_plugin_client/LV2/juce_LV2TurtleDumpProgram.cpp +++ b/modules/juce_audio_plugin_client/LV2/juce_LV2ManifestHelper.cpp @@ -39,7 +39,7 @@ #include HMODULE dlopen (const TCHAR* filename, int) { return LoadLibrary (filename); } FARPROC dlsym (HMODULE handle, const char* name) { return GetProcAddress (handle, name); } - void printError() + static void printError() { constexpr DWORD numElements = 256; TCHAR messageBuffer[numElements]{}; @@ -76,7 +76,7 @@ LPWSTR* argv = CommandLineToArgvW (GetCommandLineW(), &argc); }; - std::vector toUTF8 (const TCHAR* str) + static std::vector toUTF8 (const TCHAR* str) { const auto numBytes = WideCharToMultiByte (CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); std::vector result (numBytes); @@ -86,7 +86,7 @@ #else #include - void printError() { printf ("%s\n", dlerror()); } + static void printError() { printf ("%s\n", dlerror()); } class ArgList { public: @@ -106,7 +106,7 @@ const char** argv = nullptr; }; - std::vector toUTF8 (const char* str) { return std::vector (str, str + std::strlen (str) + 1); } + static std::vector toUTF8 (const char* str) { return std::vector (str, str + std::strlen (str) + 1); } #endif // Replicating part of the LV2 header here so that we don't have to set up any diff --git a/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp b/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp deleted file mode 100644 index 2c1619b6288d..000000000000 --- a/modules/juce_audio_plugin_client/LV2/juce_LV2_Client.cpp +++ /dev/null @@ -1,1814 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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_LV2 && (! (JUCE_ANDROID || JUCE_IOS)) - -#ifndef _SCL_SECURE_NO_WARNINGS - #define _SCL_SECURE_NO_WARNINGS -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS -#endif - -#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 -#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 -#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 - -#include -#include -#include - -#include -#include - -#include "JuceLV2Defines.h" -#include - -#include - -#define JUCE_TURTLE_RECALL_URI "https://lv2-extensions.juce.com/turtle_recall" - -#ifndef JucePlugin_LV2URI - #error "You need to define the JucePlugin_LV2URI value! If you're using the Projucer/CMake, the definition will be written into JuceLV2Defines.h automatically." -#endif - -namespace juce -{ -namespace lv2_client -{ - -constexpr auto uriSeparator = ":"; -const auto JucePluginLV2UriUi = String (JucePlugin_LV2URI) + uriSeparator + "UI"; -const auto JucePluginLV2UriState = String (JucePlugin_LV2URI) + uriSeparator + "StateString"; -const auto JucePluginLV2UriProgram = String (JucePlugin_LV2URI) + uriSeparator + "Program"; - -static const LV2_Feature* findMatchingFeature (const LV2_Feature* const* features, const char* uri) -{ - for (auto feature = features; *feature != nullptr; ++feature) - if (std::strcmp ((*feature)->URI, uri) == 0) - return *feature; - - return nullptr; -} - -static bool hasFeature (const LV2_Feature* const* features, const char* uri) -{ - return findMatchingFeature (features, uri) != nullptr; -} - -template -Data findMatchingFeatureData (const LV2_Feature* const* features, const char* uri) -{ - if (const auto* feature = findMatchingFeature (features, uri)) - return static_cast (feature->data); - - return {}; -} - -static const LV2_Options_Option* findMatchingOption (const LV2_Options_Option* options, LV2_URID urid) -{ - for (auto option = options; option->value != nullptr; ++option) - if (option->key == urid) - return option; - - return nullptr; -} - -class ParameterStorage : private AudioProcessorListener -{ -public: - ParameterStorage (AudioProcessor& proc, LV2_URID_Map map) - : processor (proc), - mapFeature (map), - legacyParameters (proc, false) - { - processor.addListener (this); - } - - ~ParameterStorage() override - { - processor.removeListener (this); - } - - /* This is the string that will be used to uniquely identify the parameter. - - This string will be written into the plugin's manifest as an IRI, so it must be - syntactically valid. - - We escape this string rather than writing the user-defined parameter ID directly to avoid - writing a malformed manifest in the case that user IDs contain spaces or other reserved - characters. This should allow users to keep the same param IDs for all plugin formats. - */ - static String getIri (const AudioProcessorParameter& param) - { - const auto urlSanitised = URL::addEscapeChars (LegacyAudioParameter::getParamID (¶m, false), true); - const auto ttlSanitised = lv2_shared::sanitiseStringAsTtlName (urlSanitised); - - // If this is hit, the parameter ID could not be represented directly in the plugin ttl. - // We'll replace offending characters with '_'. - jassert (urlSanitised == ttlSanitised); - - return ttlSanitised; - } - - void setValueFromHost (LV2_URID urid, float value) noexcept - { - const auto it = uridToIndexMap.find (urid); - - if (it == uridToIndexMap.end()) - { - // No such parameter. - jassertfalse; - return; - } - - if (auto* param = legacyParameters.getParamForIndex ((int) it->second)) - { - const auto scaledValue = [&] - { - if (auto* rangedParam = dynamic_cast (param)) - return rangedParam->convertTo0to1 (value); - - return value; - }(); - - if (scaledValue != param->getValue()) - { - ScopedValueSetter scope (ignoreCallbacks, true); - param->setValueNotifyingHost (scaledValue); - } - } - } - - struct Options - { - bool parameterValue, gestureBegin, gestureEnd; - }; - - static constexpr auto newClientValue = 1 << 0, - gestureBegan = 1 << 1, - gestureEnded = 1 << 2; - - template - void forEachChangedParameter (Callback&& callback) - { - stateCache.ifSet ([this, &callback] (size_t parameterIndex, float, uint32_t bits) - { - const Options options { (bits & newClientValue) != 0, - (bits & gestureBegan) != 0, - (bits & gestureEnded) != 0 }; - - callback (*legacyParameters.getParamForIndex ((int) parameterIndex), - indexToUridMap[parameterIndex], - options); - }); - } - -private: - void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float value) override - { - if (! ignoreCallbacks) - stateCache.setValueAndBits ((size_t) parameterIndex, value, newClientValue); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int parameterIndex) override - { - if (! ignoreCallbacks) - stateCache.setBits ((size_t) parameterIndex, gestureBegan); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int parameterIndex) override - { - if (! ignoreCallbacks) - stateCache.setBits ((size_t) parameterIndex, gestureEnded); - } - - void audioProcessorChanged (AudioProcessor*, const ChangeDetails&) override {} - - AudioProcessor& processor; - const LV2_URID_Map mapFeature; - const LegacyAudioParametersWrapper legacyParameters; - const std::vector indexToUridMap = [&] - { - std::vector result; - - for (auto* param : legacyParameters) - { - jassert ((size_t) param->getParameterIndex() == result.size()); - - const auto uri = JucePlugin_LV2URI + String (uriSeparator) + getIri (*param); - const auto urid = mapFeature.map (mapFeature.handle, uri.toRawUTF8()); - result.push_back (urid); - } - - // If this is hit, some parameters have duplicate IDs. - // This may be because the IDs resolve to the same string when removing characters that - // are invalid in a TTL name. - jassert (std::set (result.begin(), result.end()).size() == result.size()); - - return result; - }(); - const std::map uridToIndexMap = [&] - { - std::map result; - size_t index = 0; - - for (const auto& urid : indexToUridMap) - result.emplace (urid, index++); - - return result; - }(); - FlaggedFloatCache<3> stateCache { (size_t) legacyParameters.getNumParameters() }; - bool ignoreCallbacks = false; - - JUCE_LEAK_DETECTOR (ParameterStorage) -}; - -enum class PortKind { seqInput, seqOutput, latencyOutput, freeWheelingInput, enabledInput }; - -struct PortIndices -{ - PortIndices (int numInputsIn, int numOutputsIn) - : numInputs (numInputsIn), numOutputs (numOutputsIn) {} - - int getPortIndexForAudioInput (int audioIndex) const noexcept - { - return audioIndex; - } - - int getPortIndexForAudioOutput (int audioIndex) const noexcept - { - return audioIndex + numInputs; - } - - int getPortIndexFor (PortKind p) const noexcept { return getMaxAudioPortIndex() + (int) p; } - - // Audio ports are numbered from 0 to numInputs + numOutputs - int getMaxAudioPortIndex() const noexcept { return numInputs + numOutputs; } - - int numInputs, numOutputs; -}; - -//============================================================================== -class PlayHead : public AudioPlayHead -{ -public: - PlayHead (LV2_URID_Map mapFeatureIn, double sampleRateIn) - : parser (mapFeatureIn), sampleRate (sampleRateIn) - { - } - - void invalidate() { info = nullopt; } - - void readNewInfo (const LV2_Atom_Event* event) - { - if (event->body.type != mLV2_ATOM__Object && event->body.type != mLV2_ATOM__Blank) - return; - - const auto* object = reinterpret_cast (&event->body); - - if (object->body.otype != mLV2_TIME__Position) - return; - - const LV2_Atom* atomFrame = nullptr; - const LV2_Atom* atomSpeed = nullptr; - const LV2_Atom* atomBar = nullptr; - const LV2_Atom* atomBeat = nullptr; - const LV2_Atom* atomBeatUnit = nullptr; - const LV2_Atom* atomBeatsPerBar = nullptr; - const LV2_Atom* atomBeatsPerMinute = nullptr; - - LV2_Atom_Object_Query query[] { { mLV2_TIME__frame, &atomFrame }, - { mLV2_TIME__speed, &atomSpeed }, - { mLV2_TIME__bar, &atomBar }, - { mLV2_TIME__beat, &atomBeat }, - { mLV2_TIME__beatUnit, &atomBeatUnit }, - { mLV2_TIME__beatsPerBar, &atomBeatsPerBar }, - { mLV2_TIME__beatsPerMinute, &atomBeatsPerMinute }, - LV2_ATOM_OBJECT_QUERY_END }; - - lv2_atom_object_query (object, query); - - info.emplace(); - - // Carla always seems to give us an integral 'beat' even though I'd expect - // it to be a floating-point value - - const auto numerator = parser.parseNumericAtom (atomBeatsPerBar); - const auto denominator = parser.parseNumericAtom (atomBeatUnit); - - if (numerator.hasValue() && denominator.hasValue()) - info->setTimeSignature (TimeSignature { (int) *numerator, (int) *denominator }); - - info->setBpm (parser.parseNumericAtom (atomBeatsPerMinute)); - info->setPpqPosition (parser.parseNumericAtom (atomBeat)); - info->setIsPlaying (parser.parseNumericAtom (atomSpeed).orFallback (0.0f) != 0.0f); - info->setBarCount (parser.parseNumericAtom (atomBar)); - - if (const auto parsed = parser.parseNumericAtom (atomFrame)) - { - info->setTimeInSamples (*parsed); - info->setTimeInSeconds ((double) *parsed / sampleRate); - } - } - - Optional getPosition() const override - { - return info; - } - -private: - lv2_shared::NumericAtomParser parser; - Optional info; - double sampleRate; - - #define X(str) const LV2_URID m##str = parser.map (str); - X (LV2_ATOM__Blank) - X (LV2_ATOM__Object) - X (LV2_TIME__Position) - X (LV2_TIME__beat) - X (LV2_TIME__beatUnit) - X (LV2_TIME__beatsPerBar) - X (LV2_TIME__beatsPerMinute) - X (LV2_TIME__frame) - X (LV2_TIME__speed) - X (LV2_TIME__bar) - #undef X - - JUCE_LEAK_DETECTOR (PlayHead) -}; - -//============================================================================== -class Ports -{ -public: - Ports (LV2_URID_Map map, int numInputsIn, int numOutputsIn) - : forge (map), - indices (numInputsIn, numOutputsIn), - mLV2_ATOM__Sequence (map.map (map.handle, LV2_ATOM__Sequence)) - { - audioBuffers.resize (static_cast (numInputsIn + numOutputsIn), nullptr); - } - - void connect (int port, void* data) - { - // The following is not UB _if_ data really points to an object with the expected type. - - if (port == indices.getPortIndexFor (PortKind::seqInput)) - { - inputData = static_cast (data); - } - else if (port == indices.getPortIndexFor (PortKind::seqOutput)) - { - outputData = static_cast (data); - } - else if (port == indices.getPortIndexFor (PortKind::latencyOutput)) - { - latency = static_cast (data); - } - else if (port == indices.getPortIndexFor (PortKind::freeWheelingInput)) - { - freeWheeling = static_cast (data); - } - else if (port == indices.getPortIndexFor (PortKind::enabledInput)) - { - enabled = static_cast (data); - } - else if (isPositiveAndBelow (port, indices.getMaxAudioPortIndex())) - { - audioBuffers[(size_t) port] = static_cast (data); - } - else - { - // This port was not declared! - jassertfalse; - } - } - - template - void forEachInputEvent (Callback&& callback) - { - if (inputData != nullptr && inputData->atom.type == mLV2_ATOM__Sequence) - for (const auto* event : lv2_shared::SequenceIterator { lv2_shared::SequenceWithSize { inputData } }) - callback (event); - } - - void prepareToWrite() - { - // Note: Carla seems to have a bug (verified with the eg-fifths plugin) where - // the output buffer size is incorrect on alternate calls. - forge.setBuffer (reinterpret_cast (outputData), outputData->atom.size); - } - - void writeLatency (int value) - { - if (latency != nullptr) - *latency = (float) value; - } - - const float* getBufferForAudioInput (int index) const noexcept - { - return audioBuffers[(size_t) indices.getPortIndexForAudioInput (index)]; - } - - float* getBufferForAudioOutput (int index) const noexcept - { - return audioBuffers[(size_t) indices.getPortIndexForAudioOutput (index)]; - } - - bool isFreeWheeling() const noexcept - { - if (freeWheeling != nullptr) - return *freeWheeling > 0.5f; - - return false; - } - - bool isEnabled() const noexcept - { - if (enabled != nullptr) - return *enabled > 0.5f; - - return true; - } - - lv2_shared::AtomForge forge; - PortIndices indices; - -private: - static constexpr auto numParamPorts = 3; - const LV2_Atom_Sequence* inputData = nullptr; - LV2_Atom_Sequence* outputData = nullptr; - float* latency = nullptr; - float* freeWheeling = nullptr; - float* enabled = nullptr; - std::vector audioBuffers; - const LV2_URID mLV2_ATOM__Sequence; - - JUCE_LEAK_DETECTOR (Ports) -}; - -class LV2PluginInstance : private AudioProcessorListener -{ -public: - LV2PluginInstance (double sampleRate, - int64_t maxBlockSize, - const char*, - LV2_URID_Map mapFeatureIn) - : mapFeature (mapFeatureIn), - playHead (mapFeature, sampleRate) - { - processor->addListener (this); - processor->setPlayHead (&playHead); - prepare (sampleRate, (int) maxBlockSize); - } - - void connect (uint32_t port, void* data) - { - ports.connect ((int) port, data); - } - - void activate() {} - - template - static void iterateAudioBuffer (AudioBuffer& ab, UnaryFunction fn) - { - float* const* sampleData = ab.getArrayOfWritePointers(); - - for (int c = ab.getNumChannels(); --c >= 0;) - for (int s = ab.getNumSamples(); --s >= 0;) - fn (sampleData[c][s]); - } - - static int countNaNs (AudioBuffer& ab) noexcept - { - int count = 0; - iterateAudioBuffer (ab, [&count] (float s) - { - if (std::isnan (s)) - ++count; - }); - - return count; - } - - void run (uint32_t numSteps) - { - // If this is hit, the host is trying to process more samples than it told us to prepare - jassert (static_cast (numSteps) <= processor->getBlockSize()); - - midi.clear(); - playHead.invalidate(); - audio.setSize (audio.getNumChannels(), static_cast (numSteps), true, false, true); - - ports.forEachInputEvent ([&] (const LV2_Atom_Event* event) - { - struct Callback - { - explicit Callback (LV2PluginInstance& s) : self (s) {} - - void setParameter (LV2_URID property, float value) const noexcept - { - self.parameters.setValueFromHost (property, value); - } - - // The host probably shouldn't send us 'touched' messages. - void gesture (LV2_URID, bool) const noexcept {} - - LV2PluginInstance& self; - }; - - patchSetHelper.processPatchSet (event, Callback { *this }); - - playHead.readNewInfo (event); - - if (event->body.type == mLV2_MIDI__MidiEvent) - midi.addEvent (event + 1, static_cast (event->body.size), static_cast (event->time.frames)); - }); - - processor->setNonRealtime (ports.isFreeWheeling()); - - for (auto i = 0, end = processor->getTotalNumInputChannels(); i < end; ++i) - audio.copyFrom (i, 0, ports.getBufferForAudioInput (i), audio.getNumSamples()); - - jassert (countNaNs (audio) == 0); - - { - const ScopedLock lock { processor->getCallbackLock() }; - - if (processor->isSuspended()) - { - for (auto i = 0, end = processor->getTotalNumOutputChannels(); i < end; ++i) - { - const auto ptr = ports.getBufferForAudioOutput (i); - std::fill (ptr, ptr + numSteps, 0.0f); - } - } - else - { - const auto isEnabled = ports.isEnabled(); - - if (auto* param = processor->getBypassParameter()) - { - param->setValueNotifyingHost (isEnabled ? 0.0f : 1.0f); - processor->processBlock (audio, midi); - } - else if (isEnabled) - { - processor->processBlock (audio, midi); - } - else - { - processor->processBlockBypassed (audio, midi); - } - } - } - - for (auto i = 0, end = processor->getTotalNumOutputChannels(); i < end; ++i) - { - const auto src = audio.getReadPointer (i); - const auto dst = ports.getBufferForAudioOutput (i); - - if (dst != nullptr) - std::copy (src, src + numSteps, dst); - } - - ports.prepareToWrite(); - auto* forge = ports.forge.get(); - lv2_shared::SequenceFrame sequence { forge, (uint32_t) 0 }; - - parameters.forEachChangedParameter ([&] (const AudioProcessorParameter& param, - LV2_URID paramUrid, - const ParameterStorage::Options& options) - { - const auto sendTouched = [&] (bool state) - { - // TODO Implement begin/end change gesture support once it's supported by LV2 - ignoreUnused (state); - }; - - if (options.gestureBegin) - sendTouched (true); - - if (options.parameterValue) - { - lv2_atom_forge_frame_time (forge, 0); - - lv2_shared::ObjectFrame object { forge, (uint32_t) 0, patchSetHelper.mLV2_PATCH__Set }; - - lv2_atom_forge_key (forge, patchSetHelper.mLV2_PATCH__property); - lv2_atom_forge_urid (forge, paramUrid); - - lv2_atom_forge_key (forge, patchSetHelper.mLV2_PATCH__value); - lv2_atom_forge_float (forge, [&] - { - if (auto* rangedParam = dynamic_cast (¶m)) - return rangedParam->convertFrom0to1 (rangedParam->getValue()); - - return param.getValue(); - }()); - } - - if (options.gestureEnd) - sendTouched (false); - }); - - if (shouldSendStateChange.exchange (false)) - { - lv2_atom_forge_frame_time (forge, 0); - lv2_shared::ObjectFrame { forge, (uint32_t) 0, mLV2_STATE__StateChanged }; - } - - for (const auto meta : midi) - { - const auto bytes = static_cast (meta.numBytes); - lv2_atom_forge_frame_time (forge, meta.samplePosition); - lv2_atom_forge_atom (forge, bytes, mLV2_MIDI__MidiEvent); - lv2_atom_forge_write (forge, meta.data, bytes); - } - - ports.writeLatency (processor->getLatencySamples()); - } - - void deactivate() {} - - LV2_State_Status store (LV2_State_Store_Function storeFn, - LV2_State_Handle handle, - uint32_t, - const LV2_Feature* const*) - { - MemoryBlock block; - processor->getStateInformation (block); - const auto text = block.toBase64Encoding(); - storeFn (handle, - mJucePluginLV2UriState, - text.toRawUTF8(), - text.getNumBytesAsUTF8() + 1, - mLV2_ATOM__String, - LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); - - return LV2_STATE_SUCCESS; - } - - LV2_State_Status retrieve (LV2_State_Retrieve_Function retrieveFn, - LV2_State_Handle handle, - uint32_t, - const LV2_Feature* const*) - { - size_t size = 0; - uint32_t type = 0; - uint32_t dataFlags = 0; - - // Try retrieving a port index (if this is a 'program' preset). - const auto* programData = retrieveFn (handle, mJucePluginLV2UriProgram, &size, &type, &dataFlags); - - if (programData != nullptr && type == mLV2_ATOM__Int && size == sizeof (int32_t)) - { - const auto programIndex = readUnaligned (programData); - processor->setCurrentProgram (programIndex); - return LV2_STATE_SUCCESS; - } - - // This doesn't seem to be a 'program' preset, try setting the full state from a string instead. - const auto* data = retrieveFn (handle, mJucePluginLV2UriState, &size, &type, &dataFlags); - - if (data == nullptr) - return LV2_STATE_ERR_NO_PROPERTY; - - if (type != mLV2_ATOM__String) - return LV2_STATE_ERR_BAD_TYPE; - - String text (static_cast (data), (size_t) size); - MemoryBlock block; - block.fromBase64Encoding (text); - processor->setStateInformation (block.getData(), (int) block.getSize()); - - return LV2_STATE_SUCCESS; - } - - std::unique_ptr createEditor() - { - return std::unique_ptr (processor->createEditorIfNeeded()); - } - - void editorBeingDeleted (AudioProcessorEditor* editor) - { - processor->editorBeingDeleted (editor); - } - - static std::unique_ptr createProcessorInstance() - { - auto result = createPluginFilterOfType (AudioProcessor::wrapperType_LV2); - - #if defined (JucePlugin_PreferredChannelConfigurations) - constexpr short channelConfigurations[][2] { JucePlugin_PreferredChannelConfigurations }; - - static_assert (numElementsInArray (channelConfigurations) > 0, - "JucePlugin_PreferredChannelConfigurations must contain at least one entry"); - static_assert (channelConfigurations[0][0] > 0 || channelConfigurations[0][1] > 0, - "JucePlugin_PreferredChannelConfigurations must have at least one input or output channel"); - result->setPlayConfigDetails (channelConfigurations[0][0], channelConfigurations[0][1], 44100.0, 1024); - - const auto desiredChannels = std::make_tuple (channelConfigurations[0][0], channelConfigurations[0][1]); - const auto actualChannels = std::make_tuple (result->getTotalNumInputChannels(), result->getTotalNumOutputChannels()); - - if (desiredChannels != actualChannels) - Logger::outputDebugString ("Failed to apply requested channel configuration!"); - #else - result->enableAllBuses(); - #endif - - return result; - } - -private: - void audioProcessorParameterChanged (AudioProcessor*, int, float) override {} - - void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override - { - // Only check for non-parameter state here because: - // - Latency is automatically written every block. - // - There's no way for an LV2 plugin to report an internal program change. - // - Parameter info is hard-coded in the plugin's turtle description. - if (details.nonParameterStateChanged) - shouldSendStateChange = true; - } - - void prepare (double sampleRate, int maxBlockSize) - { - jassert (processor != nullptr); - processor->setRateAndBufferSizeDetails (sampleRate, maxBlockSize); - processor->prepareToPlay (sampleRate, maxBlockSize); - - const auto numChannels = jmax (processor->getTotalNumInputChannels(), - processor->getTotalNumOutputChannels()); - - midi.ensureSize (8192); - audio.setSize (numChannels, maxBlockSize); - audio.clear(); - } - - LV2_URID map (StringRef uri) const { return mapFeature.map (mapFeature.handle, uri); } - - ScopedJuceInitialiser_GUI scopedJuceInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - std::unique_ptr processor = createProcessorInstance(); - const LV2_URID_Map mapFeature; - ParameterStorage parameters { *processor, mapFeature }; - Ports ports { mapFeature, - processor->getTotalNumInputChannels(), - processor->getTotalNumOutputChannels() }; - lv2_shared::PatchSetHelper patchSetHelper { mapFeature, JucePlugin_LV2URI }; - PlayHead playHead; - MidiBuffer midi; - AudioBuffer audio; - std::atomic shouldSendStateChange { false }; - - #define X(str) const LV2_URID m##str = map (str); - X (JucePluginLV2UriProgram) - X (JucePluginLV2UriState) - X (LV2_ATOM__Int) - X (LV2_ATOM__String) - X (LV2_BUF_SIZE__maxBlockLength) - X (LV2_BUF_SIZE__sequenceSize) - X (LV2_MIDI__MidiEvent) - X (LV2_PATCH__Set) - X (LV2_STATE__StateChanged) - #undef X - - JUCE_LEAK_DETECTOR (LV2PluginInstance) -}; - -//============================================================================== -struct RecallFeature -{ - int (*doRecall) (const char*) = [] (const char* libraryPath) -> int - { - const ScopedJuceInitialiser_GUI scope; - const auto processor = LV2PluginInstance::createProcessorInstance(); - - const String pathString { CharPointer_UTF8 { libraryPath } }; - - const auto absolutePath = File::isAbsolutePath (pathString) ? File (pathString) - : File::getCurrentWorkingDirectory().getChildFile (pathString); - - const auto writers = { writeManifestTtl, writeDspTtl, writeUiTtl }; - - const auto wroteSuccessfully = [&processor, &absolutePath] (auto* fn) - { - const auto result = fn (*processor, absolutePath); - - if (! result.wasOk()) - std::cerr << result.getErrorMessage() << '\n'; - - return result.wasOk(); - }; - - return std::all_of (writers.begin(), writers.end(), wroteSuccessfully) ? 0 : 1; - }; - -private: - static String getPresetUri (int index) - { - return JucePlugin_LV2URI + String (uriSeparator) + "preset" + String (index + 1); - } - - static FileOutputStream openStream (const File& libraryPath, StringRef name) - { - return FileOutputStream { libraryPath.getSiblingFile (name + ".ttl") }; - } - - static Result prepareStream (FileOutputStream& stream) - { - if (const auto result = stream.getStatus(); ! result) - return result; - - stream.setPosition (0); - stream.truncate(); - return Result::ok(); - } - - static Result writeManifestTtl (AudioProcessor& proc, const File& libraryPath) - { - auto os = openStream (libraryPath, "manifest"); - - if (const auto result = prepareStream (os); ! result) - return result; - - os << "@prefix lv2: .\n" - "@prefix rdfs: .\n" - "@prefix pset: .\n" - "@prefix state: .\n" - "@prefix ui: .\n" - "@prefix xsd: .\n" - "\n" - "<" JucePlugin_LV2URI ">\n" - "\ta lv2:Plugin ;\n" - "\tlv2:binary <" << URL::addEscapeChars (libraryPath.getFileName(), false) << "> ;\n" - "\trdfs:seeAlso .\n"; - - if (proc.hasEditor()) - { - #if JUCE_MAC - #define JUCE_LV2_UI_KIND "CocoaUI" - #elif JUCE_WINDOWS - #define JUCE_LV2_UI_KIND "WindowsUI" - #elif JUCE_LINUX || JUCE_BSD - #define JUCE_LV2_UI_KIND "X11UI" - #else - #error "LV2 UI is unsupported on this platform" - #endif - - os << "\n" - "<" << JucePluginLV2UriUi << ">\n" - "\ta ui:" JUCE_LV2_UI_KIND " ;\n" - "\tlv2:binary <" << URL::addEscapeChars (libraryPath.getFileName(), false) << "> ;\n" - "\trdfs:seeAlso .\n" - "\n"; - } - - for (auto i = 0, end = proc.getNumPrograms(); i < end; ++i) - { - os << "<" << getPresetUri (i) << ">\n" - "\ta pset:Preset ;\n" - "\tlv2:appliesTo <" JucePlugin_LV2URI "> ;\n" - "\trdfs:label \"" << proc.getProgramName (i) << "\" ;\n" - "\tstate:state [ <" << JucePluginLV2UriProgram << "> \"" << i << "\"^^xsd:int ; ] .\n" - "\n"; - } - - return Result::ok(); - } - - static std::vector findAllSubgroupsDepthFirst (const AudioProcessorParameterGroup& group, - std::vector foundSoFar = {}) - { - foundSoFar.push_back (&group); - - for (auto* node : group) - { - if (auto* subgroup = node->getGroup()) - foundSoFar = findAllSubgroupsDepthFirst (*subgroup, std::move (foundSoFar)); - } - - return foundSoFar; - } - - using GroupSymbolMap = std::map; - - static String getFlattenedGroupSymbol (const AudioProcessorParameterGroup& group, String symbol = "") - { - if (auto* parent = group.getParent()) - return getFlattenedGroupSymbol (*parent, group.getID() + (symbol.isEmpty() ? "" : group.getSeparator() + symbol)); - - return symbol; - } - - static String getSymbolForGroup (const AudioProcessorParameterGroup& group) - { - const String allowedCharacters ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"); - const auto base = getFlattenedGroupSymbol (group); - - if (base.isEmpty()) - return {}; - - String copy; - - for (const auto character : base) - copy << String::charToString (allowedCharacters.containsChar (character) ? character : (juce_wchar) '_'); - - return "paramgroup_" + copy; - } - - static GroupSymbolMap getGroupsAndSymbols (const std::vector& groups) - { - std::set symbols; - GroupSymbolMap result; - - for (const auto& group : groups) - { - const auto symbol = [&] - { - const auto idealSymbol = getSymbolForGroup (*group); - - if (symbols.find (idealSymbol) == symbols.cend()) - return idealSymbol; - - for (auto i = 2; i < std::numeric_limits::max(); ++i) - { - const auto toTest = idealSymbol + "_" + String (i); - - if (symbols.find (toTest) == symbols.cend()) - return toTest; - } - - jassertfalse; - return String(); - }(); - - symbols.insert (symbol); - result.emplace (group, symbol); - } - - return result; - } - - template - static void visitAllParameters (const GroupSymbolMap& groups, Fn&& fn) - { - for (const auto& group : groups) - for (const auto* node : *group.first) - if (auto* param = node->getParameter()) - fn (group.second, *param); - } - - static Result writeDspTtl (AudioProcessor& proc, const File& libraryPath) - { - auto os = openStream (libraryPath, "dsp"); - - if (const auto result = prepareStream (os); ! result) - return result; - - os << "@prefix atom: .\n" - "@prefix bufs: .\n" - "@prefix doap: .\n" - "@prefix foaf: .\n" - "@prefix lv2: .\n" - "@prefix midi: .\n" - "@prefix opts: .\n" - "@prefix param: .\n" - "@prefix patch: .\n" - "@prefix pg: .\n" - "@prefix plug: <" JucePlugin_LV2URI << uriSeparator << "> .\n" - "@prefix pprop: .\n" - "@prefix rdfs: .\n" - "@prefix rdf: .\n" - "@prefix rsz: .\n" - "@prefix state: .\n" - "@prefix time: .\n" - "@prefix ui: .\n" - "@prefix units: .\n" - "@prefix urid: .\n" - "@prefix xsd: .\n" - "\n"; - - LegacyAudioParametersWrapper legacyParameters (proc, false); - - const auto allGroups = findAllSubgroupsDepthFirst (legacyParameters.getGroup()); - const auto groupsAndSymbols = getGroupsAndSymbols (allGroups); - - const auto parameterVisitor = [&] (const String& symbol, - const AudioProcessorParameter& param) - { - os << "plug:" << ParameterStorage::getIri (param) << "\n" - "\ta lv2:Parameter ;\n" - "\trdfs:label \"" << param.getName (1024) << "\" ;\n"; - - if (symbol.isNotEmpty()) - os << "\tpg:group plug:" << symbol << " ;\n"; - - os << "\trdfs:range atom:Float ;\n"; - - if (auto* rangedParam = dynamic_cast (¶m)) - { - os << "\tlv2:default " << rangedParam->convertFrom0to1 (rangedParam->getDefaultValue()) << " ;\n" - "\tlv2:minimum " << rangedParam->getNormalisableRange().start << " ;\n" - "\tlv2:maximum " << rangedParam->getNormalisableRange().end; - } - else - { - os << "\tlv2:default " << param.getDefaultValue() << " ;\n" - "\tlv2:minimum 0.0 ;\n" - "\tlv2:maximum 1.0"; - } - - // Avoid writing out loads of scale points for parameters with lots of steps - constexpr auto stepLimit = 1000; - const auto numSteps = param.getNumSteps(); - - if (param.isDiscrete() && 2 <= numSteps && numSteps < stepLimit) - { - os << "\t ;\n" - "\tlv2:portProperty lv2:enumeration " << (param.isBoolean() ? ", lv2:toggled " : "") << ";\n" - "\tlv2:scalePoint "; - - const auto maxIndex = numSteps - 1; - - for (int i = 0; i < numSteps; ++i) - { - const auto value = (float) i / (float) maxIndex; - const auto text = param.getText (value, 1024); - - os << (i != 0 ? ", " : "") << "[\n" - "\t\trdfs:label \"" << text << "\" ;\n" - "\t\trdf:value " << value << " ;\n" - "\t]"; - } - } - - os << " .\n\n"; - }; - - visitAllParameters (groupsAndSymbols, parameterVisitor); - - for (const auto& groupInfo : groupsAndSymbols) - { - if (groupInfo.second.isEmpty()) - continue; - - os << "plug:" << groupInfo.second << "\n" - "\ta pg:Group ;\n"; - - if (auto* parent = groupInfo.first->getParent()) - { - if (parent->getParent() != nullptr) - { - const auto it = groupsAndSymbols.find (parent); - - if (it != groupsAndSymbols.cend()) - os << "\tpg:subGroupOf plug:" << it->second << " ;\n"; - } - } - - os << "\tlv2:symbol \"" << groupInfo.second << "\" ;\n" - "\tlv2:name \"" << groupInfo.first->getName() << "\" .\n\n"; - } - - const auto getBaseBusName = [] (bool isInput) { return isInput ? "input_group_" : "output_group_"; }; - - for (const auto isInput : { true, false }) - { - const auto baseBusName = getBaseBusName (isInput); - const auto groupKind = isInput ? "InputGroup" : "OutputGroup"; - const auto busCount = proc.getBusCount (isInput); - - for (auto i = 0; i < busCount; ++i) - { - if (const auto* bus = proc.getBus (isInput, i)) - { - os << "plug:" << baseBusName << (i + 1) << "\n" - "\ta pg:" << groupKind << " ;\n" - "\tlv2:name \"" << bus->getName() << "\" ;\n" - "\tlv2:symbol \"" << baseBusName << (i + 1) << "\" .\n\n"; - } - } - } - - os << "<" JucePlugin_LV2URI ">\n"; - - if (proc.hasEditor()) - os << "\tui:ui <" << JucePluginLV2UriUi << "> ;\n"; - - const auto versionParts = StringArray::fromTokens (JucePlugin_VersionString, ".", ""); - - const auto getVersionOrZero = [&] (int indexFromBack) - { - const auto str = versionParts[versionParts.size() - indexFromBack]; - return str.isEmpty() ? 0 : str.getIntValue(); - }; - - const auto minorVersion = getVersionOrZero (2); - const auto microVersion = getVersionOrZero (1); - - os << "\ta " - #if JucePlugin_IsSynth - "lv2:InstrumentPlugin" - #else - "lv2:Plugin" - #endif - " ;\n" - "\tdoap:name \"" JucePlugin_Name "\" ;\n" - "\tdoap:description \"" JucePlugin_Desc "\" ;\n" - "\tlv2:minorVersion " << minorVersion << " ;\n" - "\tlv2:microVersion " << microVersion << " ;\n" - "\tdoap:maintainer [\n" - "\t\ta foaf:Person ;\n" - "\t\tfoaf:name \"" JucePlugin_Manufacturer "\" ;\n" - "\t\tfoaf:homepage <" JucePlugin_ManufacturerWebsite "> ;\n" - "\t\tfoaf:mbox <" JucePlugin_ManufacturerEmail "> ;\n" - "\t] ;\n" - "\tdoap:release [\n" - "\t\ta doap:Version ;\n" - "\t\tdoap:revision \"" JucePlugin_VersionString "\" ;\n" - "\t] ;\n" - "\tlv2:optionalFeature\n" - "\t\tlv2:hardRTCapable ;\n" - "\tlv2:extensionData\n" - "\t\tstate:interface ;\n" - "\tlv2:requiredFeature\n" - "\t\turid:map ,\n" - "\t\topts:options ,\n" - "\t\tbufs:boundedBlockLength ;\n"; - - for (const auto isInput : { true, false }) - { - const auto kind = isInput ? "mainInput" : "mainOutput"; - - if (proc.getBusCount (isInput) > 0) - os << "\tpg:" << kind << " plug:" << getBaseBusName (isInput) << "1 ;\n"; - } - - if (legacyParameters.size() != 0) - { - for (const auto header : { "writable", "readable" }) - { - os << "\tpatch:" << header; - - bool isFirst = true; - - for (const auto* param : legacyParameters) - { - os << (isFirst ? "" : " ,") << "\n\t\tplug:" << ParameterStorage::getIri (*param); - isFirst = false; - } - - os << " ;\n"; - } - } - - os << "\tlv2:port [\n"; - - const PortIndices indices (proc.getTotalNumInputChannels(), - proc.getTotalNumOutputChannels()); - - const auto designationMap = [&] - { - std::map result; - - for (const auto& pair : lv2_shared::channelDesignationMap) - result.emplace (pair.second, pair.first); - - return result; - }(); - - // TODO add support for specific audio group kinds - for (const auto isInput : { true, false }) - { - const auto baseBusName = getBaseBusName (isInput); - const auto portKind = isInput ? "InputPort" : "OutputPort"; - const auto portName = isInput ? "Audio In " : "Audio Out "; - const auto portSymbol = isInput ? "audio_in_" : "audio_out_"; - const auto busCount = proc.getBusCount (isInput); - - auto channelCounter = 0; - - for (auto busIndex = 0; busIndex < busCount; ++busIndex) - { - if (const auto* bus = proc.getBus (isInput, busIndex)) - { - const auto channelCount = bus->getNumberOfChannels(); - const auto optionalBus = ! bus->isEnabledByDefault(); - - for (auto channelIndex = 0; channelIndex < channelCount; ++channelIndex, ++channelCounter) - { - const auto portIndex = isInput ? indices.getPortIndexForAudioInput (channelCounter) - : indices.getPortIndexForAudioOutput (channelCounter); - - os << "\t\ta lv2:" << portKind << " , lv2:AudioPort ;\n" - "\t\tlv2:index " << portIndex << " ;\n" - "\t\tlv2:symbol \"" << portSymbol << (channelCounter + 1) << "\" ;\n" - "\t\tlv2:name \"" << portName << (channelCounter + 1) << "\" ;\n" - "\t\tpg:group plug:" << baseBusName << (busIndex + 1) << " ;\n"; - - if (optionalBus) - os << "\t\tlv2:portProperty lv2:connectionOptional ;\n"; - - const auto designation = bus->getCurrentLayout().getTypeOfChannel (channelIndex); - const auto it = designationMap.find (designation); - - if (it != designationMap.end()) - os << "\t\tlv2:designation <" << it->second << "> ;\n"; - - os << "\t] , [\n"; - } - } - } - } - - // In the event that the plugin decides to send all of its parameters in one go, - // we should ensure that the output buffer is large enough to accommodate, with some - // extra room for the sequence header, MIDI messages etc.. - const auto patchSetSizeBytes = 72; - const auto additionalSize = 8192; - const auto atomPortMinSize = proc.getParameters().size() * patchSetSizeBytes + additionalSize; - - os << "\t\ta lv2:InputPort , atom:AtomPort ;\n" - "\t\trsz:minimumSize " << atomPortMinSize << " ;\n" - "\t\tatom:bufferType atom:Sequence ;\n" - "\t\tatom:supports\n"; - - #if ! JucePlugin_IsSynth && ! JucePlugin_IsMidiEffect - if (proc.acceptsMidi()) - #endif - os << "\t\t\tmidi:MidiEvent ,\n"; - - os << "\t\t\tpatch:Message ,\n" - "\t\t\ttime:Position ;\n" - "\t\tlv2:designation lv2:control ;\n" - "\t\tlv2:index " << indices.getPortIndexFor (PortKind::seqInput) << " ;\n" - "\t\tlv2:symbol \"in\" ;\n" - "\t\tlv2:name \"In\" ;\n" - "\t] , [\n" - "\t\ta lv2:OutputPort , atom:AtomPort ;\n" - "\t\trsz:minimumSize " << atomPortMinSize << " ;\n" - "\t\tatom:bufferType atom:Sequence ;\n" - "\t\tatom:supports\n"; - - #if ! JucePlugin_IsMidiEffect - if (proc.producesMidi()) - #endif - os << "\t\t\tmidi:MidiEvent ,\n"; - - os << "\t\t\tpatch:Message ;\n" - "\t\tlv2:designation lv2:control ;\n" - "\t\tlv2:index " << indices.getPortIndexFor (PortKind::seqOutput) << " ;\n" - "\t\tlv2:symbol \"out\" ;\n" - "\t\tlv2:name \"Out\" ;\n" - "\t] , [\n" - "\t\ta lv2:OutputPort , lv2:ControlPort ;\n" - "\t\tlv2:designation lv2:latency ;\n" - "\t\tlv2:symbol \"latency\" ;\n" - "\t\tlv2:name \"Latency\" ;\n" - "\t\tlv2:index " << indices.getPortIndexFor (PortKind::latencyOutput) << " ;\n" - "\t\tlv2:portProperty lv2:reportsLatency , lv2:integer , lv2:connectionOptional , pprop:notOnGUI ;\n" - "\t\tunits:unit units:frame ;\n" - "\t] , [\n" - "\t\ta lv2:InputPort , lv2:ControlPort ;\n" - "\t\tlv2:designation lv2:freeWheeling ;\n" - "\t\tlv2:symbol \"freeWheeling\" ;\n" - "\t\tlv2:name \"Free Wheeling\" ;\n" - "\t\tlv2:default 0.0 ;\n" - "\t\tlv2:minimum 0.0 ;\n" - "\t\tlv2:maximum 1.0 ;\n" - "\t\tlv2:index " << indices.getPortIndexFor (PortKind::freeWheelingInput) << " ;\n" - "\t\tlv2:portProperty lv2:toggled , lv2:connectionOptional , pprop:notOnGUI ;\n" - "\t] , [\n" - "\t\ta lv2:InputPort , lv2:ControlPort ;\n" - "\t\tlv2:designation lv2:enabled ;\n" - "\t\tlv2:symbol \"enabled\" ;\n" - "\t\tlv2:name \"Enabled\" ;\n" - "\t\tlv2:default 1.0 ;\n" - "\t\tlv2:minimum 0.0 ;\n" - "\t\tlv2:maximum 1.0 ;\n" - "\t\tlv2:index " << indices.getPortIndexFor (PortKind::enabledInput) << " ;\n" - "\t\tlv2:portProperty lv2:toggled , lv2:connectionOptional , pprop:notOnGUI ;\n" - "\t] ;\n" - "\topts:supportedOption\n" - "\t\tbufs:maxBlockLength .\n"; - - return Result::ok(); - } - - static Result writeUiTtl (AudioProcessor& proc, const File& libraryPath) - { - if (! proc.hasEditor()) - return Result::ok(); - - auto os = openStream (libraryPath, "ui"); - - if (const auto result = prepareStream (os); ! result) - return result; - - const auto editorInstance = rawToUniquePtr (proc.createEditor()); - const auto resizeFeatureString = editorInstance->isResizable() ? "ui:resize" : "ui:noUserResize"; - - os << "@prefix lv2: .\n" - "@prefix opts: .\n" - "@prefix param: .\n" - "@prefix ui: .\n" - "@prefix urid: .\n" - "\n" - "<" << JucePluginLV2UriUi << ">\n" - "\tlv2:extensionData\n" - #if JUCE_LINUX || JUCE_BSD - "\t\tui:idleInterface ,\n" - #endif - "\t\topts:interface ,\n" - "\t\tui:noUserResize ,\n" // resize and noUserResize are always present in the extension data array - "\t\tui:resize ;\n" - "\n" - "\tlv2:requiredFeature\n" - #if JUCE_LINUX || JUCE_BSD - "\t\tui:idleInterface ,\n" - #endif - "\t\turid:map ,\n" - "\t\tui:parent ,\n" - "\t\t ;\n" - "\n" - "\tlv2:optionalFeature\n" - "\t\t" << resizeFeatureString << " ,\n" - "\t\topts:interface ,\n" - "\t\topts:options ;\n\n" - "\topts:supportedOption\n" - "\t\tui:scaleFactor ,\n" - "\t\tparam:sampleRate .\n"; - - return Result::ok(); - } - - JUCE_LEAK_DETECTOR (RecallFeature) -}; - -//============================================================================== -LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor (uint32_t index) -{ - if (index != 0) - return nullptr; - - static const LV2_Descriptor descriptor - { - JucePlugin_LV2URI, // TODO some constexpr check that this is a valid URI in terms of RFC 3986 - [] (const LV2_Descriptor*, - double sampleRate, - const char* pathToBundle, - const LV2_Feature* const* features) -> LV2_Handle - { - const auto* mapFeature = findMatchingFeatureData (features, LV2_URID__map); - - if (mapFeature == nullptr) - { - // The host doesn't provide the 'urid map' feature - jassertfalse; - return nullptr; - } - - const auto boundedBlockLength = hasFeature (features, LV2_BUF_SIZE__boundedBlockLength); - - if (! boundedBlockLength) - { - // The host doesn't provide the 'bounded block length' feature - jassertfalse; - return nullptr; - } - - const auto* options = findMatchingFeatureData (features, LV2_OPTIONS__options); - - if (options == nullptr) - { - // The host doesn't provide the 'options' feature - jassertfalse; - return nullptr; - } - - const lv2_shared::NumericAtomParser parser { *mapFeature }; - const auto blockLengthUrid = mapFeature->map (mapFeature->handle, LV2_BUF_SIZE__maxBlockLength); - const auto blockSize = parser.parseNumericOption (findMatchingOption (options, blockLengthUrid)); - - if (! blockSize.hasValue()) - { - // The host doesn't specify a maximum block size - jassertfalse; - return nullptr; - } - - return new LV2PluginInstance { sampleRate, *blockSize, pathToBundle, *mapFeature }; - }, - [] (LV2_Handle instance, uint32_t port, void* data) - { - static_cast (instance)->connect (port, data); - }, - [] (LV2_Handle instance) { static_cast (instance)->activate(); }, - [] (LV2_Handle instance, uint32_t sampleCount) - { - static_cast (instance)->run (sampleCount); - }, - [] (LV2_Handle instance) { static_cast (instance)->deactivate(); }, - [] (LV2_Handle instance) - { - JUCE_AUTORELEASEPOOL - { - delete static_cast (instance); - } - }, - [] (const char* uri) -> const void* - { - const auto uriMatches = [&] (const LV2_Feature& f) { return std::strcmp (f.URI, uri) == 0; }; - - static RecallFeature recallFeature; - - static LV2_State_Interface stateInterface - { - [] (LV2_Handle instance, - LV2_State_Store_Function store, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature* const* features) -> LV2_State_Status - { - return static_cast (instance)->store (store, handle, flags, features); - }, - [] (LV2_Handle instance, - LV2_State_Retrieve_Function retrieve, - LV2_State_Handle handle, - uint32_t flags, - const LV2_Feature* const* features) -> LV2_State_Status - { - return static_cast (instance)->retrieve (retrieve, handle, flags, features); - } - }; - - static const LV2_Feature features[] { { JUCE_TURTLE_RECALL_URI, &recallFeature }, - { LV2_STATE__interface, &stateInterface } }; - - const auto it = std::find_if (std::begin (features), std::end (features), uriMatches); - return it != std::end (features) ? it->data : nullptr; - } - }; - - return &descriptor; -} - -static Optional findScaleFactor (const LV2_URID_Map* symap, const LV2_Options_Option* options) -{ - if (options == nullptr || symap == nullptr) - return {}; - - const lv2_shared::NumericAtomParser parser { *symap }; - const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); - const auto* scaleFactorOption = findMatchingOption (options, scaleFactorUrid); - return parser.parseNumericOption (scaleFactorOption); -} - -class LV2UIInstance : private Component, - private ComponentListener -{ -public: - LV2UIInstance (const char*, - const char*, - LV2UI_Write_Function writeFunctionIn, - LV2UI_Controller controllerIn, - LV2UI_Widget* widget, - LV2PluginInstance* pluginIn, - LV2UI_Widget parentIn, - const LV2_URID_Map* symapIn, - const LV2UI_Resize* resizeFeatureIn, - Optional scaleFactorIn) - : writeFunction (writeFunctionIn), - controller (controllerIn), - plugin (pluginIn), - parent (parentIn), - symap (symapIn), - resizeFeature (resizeFeatureIn), - scaleFactor (scaleFactorIn), - editor (plugin->createEditor()) - { - jassert (plugin != nullptr); - jassert (parent != nullptr); - jassert (editor != nullptr); - - if (editor == nullptr) - return; - - const auto bounds = getSizeToContainChild(); - setSize (bounds.getWidth(), bounds.getHeight()); - - addAndMakeVisible (*editor); - - setBroughtToFrontOnMouseClick (true); - setOpaque (true); - setVisible (false); - removeFromDesktop(); - addToDesktop (0, parent); - editor->addComponentListener (this); - - *widget = getWindowHandle(); - - setVisible (true); - - editor->setScaleFactor (getScaleFactor()); - requestResize(); - } - - ~LV2UIInstance() override - { - plugin->editorBeingDeleted (editor.get()); - } - - // This is called by the host when a parameter changes. - // We don't care, our UI will listen to the processor directly. - void portEvent (uint32_t, uint32_t, uint32_t, const void*) {} - - // Called when the host requests a resize - int resize (int width, int height) - { - const ScopedValueSetter scope (hostRequestedResize, true); - setSize (width, height); - return 0; - } - - // Called by the host to give us an opportunity to process UI events - void idleCallback() - { - #if JUCE_LINUX || JUCE_BSD - messageThread->processPendingEvents(); - #endif - } - - void resized() override - { - const ScopedValueSetter scope (hostRequestedResize, true); - - if (editor != nullptr) - { - const auto localArea = editor->getLocalArea (this, getLocalBounds()); - editor->setBoundsConstrained ({ localArea.getWidth(), localArea.getHeight() }); - } - } - - void paint (Graphics& g) override { g.fillAll (Colours::black); } - - uint32_t getOptions (LV2_Options_Option* options) - { - const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); - const auto floatUrid = symap->map (symap->handle, LV2_ATOM__Float);; - - for (auto* opt = options; opt->key != 0; ++opt) - { - if (opt->context != LV2_OPTIONS_INSTANCE || opt->subject != 0 || opt->key != scaleFactorUrid) - continue; - - if (scaleFactor.hasValue()) - { - opt->type = floatUrid; - opt->size = sizeof (float); - opt->value = &(*scaleFactor); - } - } - - return LV2_OPTIONS_SUCCESS; - } - - uint32_t setOptions (const LV2_Options_Option* options) - { - const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); - const auto floatUrid = symap->map (symap->handle, LV2_ATOM__Float);; - - for (auto* opt = options; opt->key != 0; ++opt) - { - if (opt->context != LV2_OPTIONS_INSTANCE - || opt->subject != 0 - || opt->key != scaleFactorUrid - || opt->type != floatUrid - || opt->size != sizeof (float)) - { - continue; - } - - scaleFactor = *static_cast (opt->value); - updateScale(); - } - - return LV2_OPTIONS_SUCCESS; - } - -private: - void updateScale() - { - editor->setScaleFactor (getScaleFactor()); - requestResize(); - } - - Rectangle getSizeToContainChild() const - { - if (editor != nullptr) - return getLocalArea (editor.get(), editor->getLocalBounds()); - - return {}; - } - - float getScaleFactor() const noexcept - { - return scaleFactor.hasValue() ? *scaleFactor : 1.0f; - } - - void componentMovedOrResized (Component&, bool, bool wasResized) override - { - if (! hostRequestedResize && wasResized) - requestResize(); - } - - void write (uint32_t portIndex, uint32_t bufferSize, uint32_t portProtocol, const void* data) - { - writeFunction (controller, portIndex, bufferSize, portProtocol, data); - } - - void requestResize() - { - if (editor == nullptr) - return; - - const auto bounds = getSizeToContainChild(); - - if (resizeFeature == nullptr) - return; - - if (auto* fn = resizeFeature->ui_resize) - fn (resizeFeature->handle, bounds.getWidth(), bounds.getHeight()); - - setSize (bounds.getWidth(), bounds.getHeight()); - repaint(); - } - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - LV2UI_Write_Function writeFunction; - LV2UI_Controller controller; - LV2PluginInstance* plugin; - LV2UI_Widget parent; - const LV2_URID_Map* symap = nullptr; - const LV2UI_Resize* resizeFeature = nullptr; - Optional scaleFactor; - std::unique_ptr editor; - bool hostRequestedResize = false; - - JUCE_LEAK_DETECTOR (LV2UIInstance) -}; - -LV2_SYMBOL_EXPORT const LV2UI_Descriptor* lv2ui_descriptor (uint32_t index) -{ - if (index != 0) - return nullptr; - - static const LV2UI_Descriptor descriptor - { - JucePluginLV2UriUi.toRawUTF8(), // TODO some constexpr check that this is a valid URI in terms of RFC 3986 - [] (const LV2UI_Descriptor*, - const char* pluginUri, - const char* bundlePath, - LV2UI_Write_Function writeFunction, - LV2UI_Controller controller, - LV2UI_Widget* widget, - const LV2_Feature* const* features) -> LV2UI_Handle - { - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - auto* plugin = findMatchingFeatureData (features, LV2_INSTANCE_ACCESS_URI); - - if (plugin == nullptr) - { - // No instance access - jassertfalse; - return nullptr; - } - - auto* parent = findMatchingFeatureData (features, LV2_UI__parent); - - if (parent == nullptr) - { - // No parent access - jassertfalse; - return nullptr; - } - - auto* resizeFeature = findMatchingFeatureData (features, LV2_UI__resize); - - const auto* symap = findMatchingFeatureData (features, LV2_URID__map); - const auto scaleFactor = findScaleFactor (symap, findMatchingFeatureData (features, LV2_OPTIONS__options)); - - return new LV2UIInstance { pluginUri, - bundlePath, - writeFunction, - controller, - widget, - plugin, - parent, - symap, - resizeFeature, - scaleFactor }; - }, - [] (LV2UI_Handle ui) - { - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - JUCE_AUTORELEASEPOOL - { - delete static_cast (ui); - } - }, - [] (LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) - { - JUCE_ASSERT_MESSAGE_THREAD - static_cast (ui)->portEvent (portIndex, bufferSize, format, buffer); - }, - [] (const char* uri) -> const void* - { - const auto uriMatches = [&] (const LV2_Feature& f) { return std::strcmp (f.URI, uri) == 0; }; - - static LV2UI_Resize resize { nullptr, [] (LV2UI_Feature_Handle handle, int width, int height) -> int - { - JUCE_ASSERT_MESSAGE_THREAD - return static_cast (handle)->resize (width, height); - } }; - - static LV2UI_Idle_Interface idle { [] (LV2UI_Handle handle) - { - static_cast (handle)->idleCallback(); - return 0; - } }; - - static LV2_Options_Interface options - { - [] (LV2_Handle handle, LV2_Options_Option* optionsIn) - { - return static_cast (handle)->getOptions (optionsIn); - }, - [] (LV2_Handle handle, const LV2_Options_Option* optionsIn) - { - return static_cast (handle)->setOptions (optionsIn); - } - }; - - // We'll always define noUserResize and idle in the extension data array, but we'll - // only declare them in the ui.ttl if the UI is actually non-resizable, or requires - // idle callbacks. - // Well-behaved hosts should check the ttl before trying to search the - // extension-data array. - static const LV2_Feature features[] { { LV2_UI__resize, &resize }, - { LV2_UI__noUserResize, nullptr }, - { LV2_UI__idleInterface, &idle }, - { LV2_OPTIONS__interface, &options } }; - - const auto it = std::find_if (std::begin (features), std::end (features), uriMatches); - return it != std::end (features) ? it->data : nullptr; - } - }; - - return &descriptor; -} - -} -} - -#endif diff --git a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp deleted file mode 100644 index 1f13a1d8a9ac..000000000000 --- a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include "../utility/juce_CheckSettingMacros.h" - -#include "../utility/juce_IncludeSystemHeaders.h" -#include "../utility/juce_IncludeModuleHeaders.h" -#include "../utility/juce_WindowsHooks.h" - -#include -#include -#include - -// You can set this flag in your build if you need to specify a different -// standalone JUCEApplication class for your app to use. If you don't -// set it then by default we'll just create a simple one as below. -#if ! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP - -#include "juce_StandaloneFilterWindow.h" - -namespace juce -{ - -//============================================================================== -class StandaloneFilterApp : public JUCEApplication -{ -public: - StandaloneFilterApp() - { - PropertiesFile::Options options; - - options.applicationName = getApplicationName(); - options.filenameSuffix = ".settings"; - options.osxLibrarySubFolder = "Application Support"; - #if JUCE_LINUX || JUCE_BSD - options.folderName = "~/.config"; - #else - options.folderName = ""; - #endif - - appProperties.setStorageParameters (options); - } - - const String getApplicationName() override { return CharPointer_UTF8 (JucePlugin_Name); } - const String getApplicationVersion() override { return JucePlugin_VersionString; } - bool moreThanOneInstanceAllowed() override { return true; } - void anotherInstanceStarted (const String&) override {} - - virtual StandaloneFilterWindow* createWindow() - { - #ifdef JucePlugin_PreferredChannelConfigurations - StandalonePluginHolder::PluginInOuts channels[] = { JucePlugin_PreferredChannelConfigurations }; - #endif - - return new StandaloneFilterWindow (getApplicationName(), - LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId), - appProperties.getUserSettings(), - false, {}, nullptr - #ifdef JucePlugin_PreferredChannelConfigurations - , juce::Array (channels, juce::numElementsInArray (channels)) - #else - , {} - #endif - #if JUCE_DONT_AUTO_OPEN_MIDI_DEVICES_ON_MOBILE - , false - #endif - ); - } - - //============================================================================== - void initialise (const String&) override - { - mainWindow.reset (createWindow()); - - #if JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE - Desktop::getInstance().setKioskModeComponent (mainWindow.get(), false); - #endif - - mainWindow->setVisible (true); - } - - void shutdown() override - { - mainWindow = nullptr; - appProperties.saveIfNeeded(); - } - - //============================================================================== - void systemRequestedQuit() override - { - if (mainWindow.get() != nullptr) - mainWindow->pluginHolder->savePluginState(); - - if (ModalComponentManager::getInstance()->cancelAllModalComponents()) - { - Timer::callAfterDelay (100, []() - { - if (auto app = JUCEApplicationBase::getInstance()) - app->systemRequestedQuit(); - }); - } - else - { - quit(); - } - } - -protected: - ApplicationProperties appProperties; - std::unique_ptr mainWindow; -}; - -} // namespace juce - -#if JucePlugin_Build_Standalone && JUCE_IOS - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - -using namespace juce; - -bool JUCE_CALLTYPE juce_isInterAppAudioConnected() -{ - if (auto holder = StandalonePluginHolder::getInstance()) - return holder->isInterAppAudioConnected(); - - return false; -} - -void JUCE_CALLTYPE juce_switchToHostApplication() -{ - if (auto holder = StandalonePluginHolder::getInstance()) - holder->switchToHostApplication(); -} - -Image JUCE_CALLTYPE juce_getIAAHostIcon (int size) -{ - if (auto holder = StandalonePluginHolder::getInstance()) - return holder->getIAAHostIcon (size); - - return Image(); -} - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -#endif - -#endif diff --git a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h index 6a96c9beba47..e74caf185ea6 100644 --- a/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h +++ b/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h @@ -26,7 +26,7 @@ #pragma once #ifndef DOXYGEN - #include "../utility/juce_CreatePluginFilter.h" + #include #endif namespace juce @@ -209,9 +209,12 @@ class StandalonePluginHolder : private AudioIODeviceCallback, processor->getStateInformation (data); if (! fc.getResult().replaceWithData (data.getData(), data.getSize())) - AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, - TRANS("Error whilst saving"), - TRANS("Couldn't write to the specified file!")); + { + auto opts = MessageBoxOptions::makeOptionsOk (AlertWindow::WarningIcon, + TRANS ("Error whilst saving"), + TRANS ("Couldn't write to the specified file!")); + messageBox = AlertWindow::showScopedAsync (opts, nullptr); + } }); } @@ -234,11 +237,16 @@ class StandalonePluginHolder : private AudioIODeviceCallback, MemoryBlock data; if (fc.getResult().loadFileAsData (data)) + { processor->setStateInformation (data.getData(), (int) data.getSize()); + } else - AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, - TRANS("Error whilst loading"), - TRANS("Couldn't read from the specified file!")); + { + auto opts = MessageBoxOptions::makeOptionsOk (AlertWindow::WarningIcon, + TRANS ("Error whilst loading"), + TRANS ("Couldn't read from the specified file!")); + messageBox = AlertWindow::showScopedAsync (opts, nullptr); + } }); } @@ -417,6 +425,7 @@ class StandalonePluginHolder : private AudioIODeviceCallback, Array lastMidiDevices; std::unique_ptr stateFileChooser; + ScopedMessageBox messageBox; private: /* This class can be used to ensure that audio callbacks use buffers with a @@ -1080,57 +1089,17 @@ class StandaloneFilterWindow : public DocumentWindow, accordingly. The end result is that the peer is resized twice in a row to different sizes, which can appear glitchy/flickery to the user. */ - struct DecoratorConstrainer : public ComponentBoundsConstrainer + class DecoratorConstrainer : public BorderedComponentBoundsConstrainer { - void checkBounds (Rectangle& bounds, - const Rectangle& previousBounds, - const Rectangle& limits, - bool isStretchingTop, - bool isStretchingLeft, - bool isStretchingBottom, - bool isStretchingRight) override + public: + ComponentBoundsConstrainer* getWrappedConstrainer() const override { - auto* decorated = contentComponent != nullptr ? contentComponent->getEditorConstrainer() - : nullptr; + return contentComponent != nullptr ? contentComponent->getEditorConstrainer() : nullptr; + } - if (decorated != nullptr) - { - const auto border = contentComponent->computeBorder(); - const auto requestedBounds = bounds; - - border.subtractFrom (bounds); - decorated->checkBounds (bounds, - border.subtractedFrom (previousBounds), - limits, - isStretchingTop, - isStretchingLeft, - isStretchingBottom, - isStretchingRight); - border.addTo (bounds); - bounds = bounds.withPosition (requestedBounds.getPosition()); - - if (isStretchingTop && ! isStretchingBottom) - bounds = bounds.withBottomY (previousBounds.getBottom()); - - if (! isStretchingTop && isStretchingBottom) - bounds = bounds.withY (previousBounds.getY()); - - if (isStretchingLeft && ! isStretchingRight) - bounds = bounds.withRightX (previousBounds.getRight()); - - if (! isStretchingLeft && isStretchingRight) - bounds = bounds.withX (previousBounds.getX()); - } - else - { - ComponentBoundsConstrainer::checkBounds (bounds, - previousBounds, - limits, - isStretchingTop, - isStretchingLeft, - isStretchingBottom, - isStretchingRight); - } + BorderSize getAdditionalBorder() const override + { + return contentComponent != nullptr ? contentComponent->computeBorder() : BorderSize{}; } void setMainContentComponent (MainContentComponent* in) { contentComponent = in; } diff --git a/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h b/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h index 6bdcdcbe7a45..c0ce9c71acd5 100644 --- a/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h +++ b/modules/juce_audio_plugin_client/Unity/juce_UnityPluginInterface.h @@ -29,7 +29,7 @@ //============================================================================== #define UNITY_AUDIO_PLUGIN_API_VERSION 0x010401 -#if JUCE_MSVC +#if JUCE_WINDOWS #define UNITY_INTERFACE_API __stdcall #define UNITY_INTERFACE_EXPORT __declspec(dllexport) #else diff --git a/modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp b/modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp deleted file mode 100644 index e2cc0f692f3e..000000000000 --- a/modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp +++ /dev/null @@ -1,774 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 - -#if JucePlugin_Build_Unity - -#include "../utility/juce_IncludeModuleHeaders.h" -#include - -#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 getBounds() const override { return bounds; } - Point localToGlobal (Point relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); } - Point globalToLocal (Point screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); } - - using ComponentPeer::localToGlobal; - using ComponentPeer::globalToLocal; - - StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); } - - void setBounds (const Rectangle& newBounds, bool) override - { - bounds = newBounds; - mouseWatcher.setBoundsToWatch (bounds); - } - - bool contains (Point 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 (&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 position, ModifierKeys mods) - { - ModifierKeys::currentModifiers = mods; - - handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::defaultPressure, - juce::MouseInputSource::defaultOrientation, 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) - { - } - - std::unique_ptr createType() const override - { - return std::make_unique(); - } - - std::unique_ptr createLowLevelContext() override - { - return std::make_unique (Image (this)); - } - - void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, [[maybe_unused]] Image::BitmapData::ReadWriteMode mode) override - { - const auto offset = (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride; - bitmap.data = imageData + offset; - bitmap.size = (size_t) (lineStride * height) - offset; - 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::defaultPressure, juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis()); - - lastMousePos = pos; - } - - } - - void setBoundsToWatch (Rectangle b) - { - if (boundsToWatch != b) - boundsToWatch = b; - - startTimer (250); - } - - ComponentPeer& owner; - Rectangle boundsToWatch; - Point 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 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; } - OptionalBorderSize getFrameSizeIfPresent() const override { return {}; } - BorderSize getFrameSize() const override { return {}; } - void setVisible (bool) override {} - void setTitle (const String&) override {} - void setIcon (const Image&) override {} - void textInputRequired (Point, TextInputTarget&) override {} - void setAlpha (float) override {} - void performAnyPendingRepaintsNow() override {} - void repaint (const Rectangle&) override {} - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer) -}; - -static ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); } - -//============================================================================== -class AudioProcessorUnityWrapper -{ -public: - AudioProcessorUnityWrapper (bool isTemporary) - { - pluginInstance = 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 = static_cast (state->dspBufferSize); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - const int numConfigs = sizeof (configs) / sizeof (short[2]); - - jassertquiet (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); - - pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], state->sampleRate, samplesPerBlock); - #else - pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock); - #endif - - 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, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed) - { - // If the plugin has a bypass parameter, set it to the current bypass state - if (auto* param = pluginInstance->getBypassParameter()) - if (isBypassed != (param->getValue() >= 0.5f)) - param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f); - - for (int pos = 0; pos < bufferSize;) - { - auto max = jmin (bufferSize - pos, samplesPerBlock); - processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed); - - pos += max; - } - } - - void declareParameters (UnityAudioEffectDefinition& definition) - { - static std::unique_ptr parametersPtr; - static int numParams = 0; - - if (parametersPtr == nullptr) - { - numParams = (int) juceParameters.size(); - - parametersPtr.reset (static_cast (std::calloc (static_cast (numParams), - sizeof (UnityAudioParameterDefinition)))); - - parameterDescriptions.clear(); - - for (int i = 0; i < numParams; ++i) - { - auto* parameter = juceParameters.getParamForIndex (i); - auto& paramDef = parametersPtr.get()[i]; - - const auto nameLength = (size_t) numElementsInArray (paramDef.name); - const auto unitLength = (size_t) numElementsInArray (paramDef.unit); - - parameter->getName ((int) nameLength - 1).copyToUTF8 (paramDef.name, nameLength); - - if (parameter->getLabel().isNotEmpty()) - parameter->getLabel().copyToUTF8 (paramDef.unit, unitLength); - - parameterDescriptions.add (parameter->getName (15)); - paramDef.description = parameterDescriptions[i].toRawUTF8(); - - paramDef.defaultVal = parameter->getDefaultValue(); - paramDef.min = 0.0f; - paramDef.max = 1.0f; - paramDef.displayScale = 1.0f; - paramDef.displayExponent = 1.0f; - } - } - - definition.numParameters = static_cast (numParams); - definition.parameterDefintions = parametersPtr.get(); - } - - void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValueNotifyingHost (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 (pluginInstanceEditor->getPeer()); - - jassert (peer != nullptr); - return *peer; - } - -private: - //============================================================================== - void processBuffers (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed) - { - int ch; - for (ch = 0; ch < numInChannels; ++ch) - { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; - - 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->getBypassParameter() == nullptr) - pluginInstance->processBlockBypassed (scratchBuffer, mb); - else - pluginInstance->processBlock (scratchBuffer, mb); - } - } - - for (ch = 0; ch < numOutChannels; ++ch) - { - using DstSampleType = AudioData::Pointer; - using SrcSampleType = AudioData::Pointer; - - DstSampleType dstData (outBuffer + ch, numOutChannels); - SrcSampleType srcData (scratchBuffer.getReadPointer (ch)); - dstData.convertSamples (srcData, bufferSize); - } - } - - //============================================================================== - std::unique_ptr pluginInstance; - std::unique_ptr pluginInstanceEditor; - - int samplesPerBlock = 1024; - StringArray parameterDescriptions; - - AudioBuffer scratchBuffer; - - LegacyAudioParametersWrapper juceParameters; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper) -}; - -//============================================================================== -static HashMap& getWrapperMap() -{ - static HashMap 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); -} - -//============================================================================== -static UnityAudioEffectDefinition getEffectDefinition() -{ - const auto wrapper = std::make_unique (true); - const String originalName { JucePlugin_Name }; - const auto name = (! originalName.startsWithIgnoreCase ("audioplugin") ? "audioplugin_" : "") + originalName; - - UnityAudioEffectDefinition result{}; - name.copyToUTF8 (result.name, (size_t) numElementsInArray (result.name)); - - result.structSize = sizeof (UnityAudioEffectDefinition); - result.parameterStructSize = sizeof (UnityAudioParameterDefinition); - - result.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION; - result.pluginVersion = JucePlugin_VersionCode; - - // effects must set this to 0, generators > 0 - result.channels = (wrapper->getNumInputChannels() != 0 ? 0 - : static_cast (wrapper->getNumOutputChannels())); - - wrapper->declareParameters (result); - - result.create = [] (UnityAudioEffectState* state) - { - auto* pluginInstance = new AudioProcessorUnityWrapper (false); - pluginInstance->create (state); - - state->effectData = pluginInstance; - - onWrapperCreation (pluginInstance); - - return 0; - }; - - result.release = [] (UnityAudioEffectState* state) - { - auto* pluginInstance = state->getEffectData(); - pluginInstance->release(); - - onWrapperDeletion (pluginInstance); - delete pluginInstance; - - if (getWrapperMap().size() == 0) - shutdownJuce_GUI(); - - return 0; - }; - - result.reset = [] (UnityAudioEffectState* state) - { - auto* pluginInstance = state->getEffectData(); - pluginInstance->reset(); - - return 0; - }; - - result.setPosition = [] (UnityAudioEffectState* state, unsigned int pos) - { - ignoreUnused (state, pos); - return 0; - }; - - result.process = [] (UnityAudioEffectState* state, - float* inBuffer, - float* outBuffer, - unsigned int bufferSize, - int numInChannels, - int numOutChannels) - { - auto* pluginInstance = state->getEffectData(); - - if (pluginInstance != nullptr) - { - auto isPlaying = ((state->flags & stateIsPlaying) != 0); - auto isMuted = ((state->flags & stateIsMuted) != 0); - auto isPaused = ((state->flags & stateIsPaused) != 0); - - const auto bypassed = ! isPlaying || (isMuted || isPaused); - pluginInstance->process (inBuffer, outBuffer, static_cast (bufferSize), numInChannels, numOutChannels, bypassed); - } - else - { - FloatVectorOperations::clear (outBuffer, static_cast (bufferSize) * numOutChannels); - } - - return 0; - }; - - result.setFloatParameter = [] (UnityAudioEffectState* state, int index, float value) - { - auto* pluginInstance = state->getEffectData(); - pluginInstance->setParameter (index, value); - - return 0; - }; - - result.getFloatParameter = [] (UnityAudioEffectState* state, int index, float* value, char* valueStr) - { - auto* pluginInstance = state->getEffectData(); - *value = pluginInstance->getParameter (index); - - pluginInstance->getParameterString (index).copyToUTF8 (valueStr, 15); - - return 0; - }; - - result.getFloatBuffer = [] (UnityAudioEffectState* state, const char* kind, float* buffer, int numSamples) - { - ignoreUnused (numSamples); - - const StringRef kindStr { kind }; - - if (kindStr == StringRef ("Editor")) - { - auto* pluginInstance = state->getEffectData(); - - buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f; - } - else if (kindStr == StringRef ("ID")) - { - auto* pluginInstance = state->getEffectData(); - - for (HashMap::Iterator i (getWrapperMap()); i.next();) - { - if (i.getValue() == pluginInstance) - { - buffer[0] = (float) i.getKey(); - break; - } - } - - return 0; - } - else if (kindStr == StringRef ("Size")) - { - auto* pluginInstance = state->getEffectData(); - - 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; - }; - - return result; -} - -} // namespace juce - -// From reading the example code, it seems that the triple indirection indicates -// an out-value of an array of pointers. That is, after calling this function, definitionsPtr -// should point to a pre-existing/static array of pointer-to-effect-definition. -UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr) -{ - if (juce::getWrapperMap().size() == 0) - juce::initialiseJuce_GUI(); - - static std::once_flag flag; - std::call_once (flag, [] { juce::juce_createUnityPeerFn = juce::createUnityPeer; }); - - static auto definition = juce::getEffectDefinition(); - static UnityAudioEffectDefinition* definitions[] { &definition }; - *definitionsPtr = definitions; - - 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 UNITY_INTERFACE_API unityInitialiseTexture (int id, void* data, int w, int h) -{ - getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast (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 - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - - extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) - { - if (reason == DLL_PROCESS_ATTACH) - juce::Process::setCurrentModuleInstanceHandle (instance); - - return true; - } - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#endif - -#endif diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp deleted file mode 100644 index 55226c66a649..000000000000 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ /dev/null @@ -1,2256 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include -#include "../utility/juce_CheckSettingMacros.h" - -#if JucePlugin_Build_VST - -JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996 4100) - -#include "../utility/juce_IncludeSystemHeaders.h" -#include - -#if JucePlugin_VersionCode < 0x010000 // Major < 0 - - #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeds 9 - JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'minor' exceeding 9") - #endif - - #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeds 9 - JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'bugfix' exceeding 9") - #endif - -#elif JucePlugin_VersionCode >= 0x650000 // Major >= 101 - - #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeds 99 - JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'minor' exceeding 99") - #endif - - #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeds 99 - JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'bugfix' exceeding 99") - #endif - -#endif - -#ifdef PRAGMA_ALIGN_SUPPORTED - #undef PRAGMA_ALIGN_SUPPORTED - #define PRAGMA_ALIGN_SUPPORTED 1 -#endif - -#if ! JUCE_MSVC - #define __cdecl -#endif - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", - "-Wshadow", - "-Wdeprecated-register", - "-Wdeprecated-declarations", - "-Wunused-parameter", - "-Wdeprecated-writable-strings", - "-Wnon-virtual-dtor", - "-Wzero-as-null-pointer-constant") -JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4458) - -#define VST_FORCE_DEPRECATED 0 - -namespace Vst2 -{ -// If the following files cannot be found then you are probably trying to build -// a VST2 plug-in or a VST2-compatible VST3 plug-in. To do this you must have a -// VST2 SDK in your header search paths or use the "VST (Legacy) SDK Folder" -// field in the Projucer. The VST2 SDK can be obtained from the -// vstsdk3610_11_06_2018_build_37 (or older) VST3 SDK or JUCE version 5.3.2. You -// also need a VST2 license from Steinberg to distribute VST2 plug-ins. -#include "pluginterfaces/vst2.x/aeffect.h" -#include "pluginterfaces/vst2.x/aeffectx.h" -} - -JUCE_END_IGNORE_WARNINGS_MSVC -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -//============================================================================== -#if JUCE_MSVC - #pragma pack (push, 8) -#endif - -#define JUCE_VSTINTERFACE_H_INCLUDED 1 -#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 - -#include "../utility/juce_IncludeModuleHeaders.h" - -using namespace juce; - -#include "../utility/juce_WindowsHooks.h" -#include "../utility/juce_LinuxMessageThread.h" - -#include -#include - -#ifdef JUCE_MSVC - #pragma pack (pop) -#endif - -#undef MemoryBlock - -class JuceVSTWrapper; -static bool recursionCheck = false; - -namespace juce -{ - #if JUCE_MAC - extern JUCE_API void initialiseMacVST(); - extern JUCE_API void* attachComponentToWindowRefVST (Component*, void* parent, bool isNSView); - extern JUCE_API void detachComponentFromWindowRefVST (Component*, void* window, bool isNSView); - extern JUCE_API void setNativeHostWindowSizeVST (void* window, Component*, int newWidth, int newHeight, bool isNSView); - extern JUCE_API void checkWindowVisibilityVST (void* window, Component*, bool isNSView); - extern JUCE_API bool forwardCurrentKeyEventToHostVST (Component*, bool isNSView); - #if ! JUCE_64BIT - extern JUCE_API void updateEditorCompBoundsVST (Component*); - #endif - #endif - -#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - extern JUCE_API double getScaleFactorForWindow (HWND); -#endif - - extern JUCE_API bool handleManufacturerSpecificVST2Opcode (int32, pointer_sized_int, void*, float); -} - - -//============================================================================== -#if JUCE_WINDOWS - -namespace -{ - // Returns the actual container window, unlike GetParent, which can also return a separate owner window. - static HWND getWindowParent (HWND w) noexcept { return GetAncestor (w, GA_PARENT); } - - static HWND findMDIParentOf (HWND w) - { - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - while (w != nullptr) - { - auto parent = getWindowParent (w); - - if (parent == nullptr) - break; - - TCHAR windowType[32] = { 0 }; - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase ("MDIClient")) - return parent; - - RECT windowPos, parentPos; - GetWindowRect (w, &windowPos); - GetWindowRect (parent, &parentPos); - - auto dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - auto dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - if (dw > 100 || dh > 100) - break; - - w = parent; - - if (dw == 2 * frameThickness) - break; - } - - return w; - } - - static int numActivePlugins = 0; - static bool messageThreadIsDefinitelyCorrect = false; -} - -#endif - -//============================================================================== -// Ableton Live host specific commands -struct AbletonLiveHostSpecific -{ - enum - { - KCantBeSuspended = (1 << 2) - }; - - uint32 magic; // 'AbLi' - int cmd; // 5 = realtime properties - size_t commandSize; // sizeof (int) - int flags; // KCantBeSuspended = (1 << 2) -}; - -//============================================================================== -/** - This is an AudioEffectX object that holds and wraps our AudioProcessor... -*/ -class JuceVSTWrapper : public AudioProcessorListener, - public AudioPlayHead, - private Timer, - private AudioProcessorParameter::Listener -{ -private: - //============================================================================== - template - struct VstTempBuffers - { - VstTempBuffers() {} - ~VstTempBuffers() { release(); } - - void release() noexcept - { - for (auto* c : tempChannels) - delete[] c; - - tempChannels.clear(); - } - - HeapBlock channels; - Array tempChannels; // see note in processReplacing() - juce::AudioBuffer processTempBuffer; - }; - - /** Use the same names as the VST SDK. */ - struct VstOpCodeArguments - { - int32 index; - pointer_sized_int value; - void* ptr; - float opt; - }; - -public: - //============================================================================== - JuceVSTWrapper (Vst2::audioMasterCallback cb, std::unique_ptr af) - : hostCallback (cb), - processor (std::move (af)) - { - inParameterChangedCallback = false; - - // VST-2 does not support disabling buses: so always enable all of them - processor->enableAllBuses(); - - findMaxTotalChannels (maxNumInChannels, maxNumOutChannels); - - // You must at least have some channels - jassert (processor->isMidiEffect() || (maxNumInChannels > 0 || maxNumOutChannels > 0)); - - if (processor->isMidiEffect()) - maxNumInChannels = maxNumOutChannels = 2; - - #ifdef JucePlugin_PreferredChannelConfigurations - processor->setPlayConfigDetails (maxNumInChannels, maxNumOutChannels, 44100.0, 1024); - #endif - - processor->setRateAndBufferSizeDetails (0, 0); - processor->setPlayHead (this); - processor->addListener (this); - - if (auto* juceParam = processor->getBypassParameter()) - juceParam->addListener (this); - - juceParameters.update (*processor, false); - - memset (&vstEffect, 0, sizeof (vstEffect)); - vstEffect.magic = 0x56737450 /* 'VstP' */; - vstEffect.dispatcher = (Vst2::AEffectDispatcherProc) dispatcherCB; - vstEffect.process = nullptr; - vstEffect.setParameter = (Vst2::AEffectSetParameterProc) setParameterCB; - vstEffect.getParameter = (Vst2::AEffectGetParameterProc) getParameterCB; - vstEffect.numPrograms = jmax (1, processor->getNumPrograms()); - vstEffect.numParams = juceParameters.getNumParameters(); - vstEffect.numInputs = maxNumInChannels; - vstEffect.numOutputs = maxNumOutChannels; - vstEffect.initialDelay = processor->getLatencySamples(); - vstEffect.object = this; - vstEffect.uniqueID = JucePlugin_VSTUniqueID; - - #ifdef JucePlugin_VSTChunkStructureVersion - vstEffect.version = JucePlugin_VSTChunkStructureVersion; - #else - vstEffect.version = JucePlugin_VersionCode; - #endif - - vstEffect.processReplacing = (Vst2::AEffectProcessProc) processReplacingCB; - vstEffect.processDoubleReplacing = (Vst2::AEffectProcessDoubleProc) processDoubleReplacingCB; - - vstEffect.flags |= Vst2::effFlagsHasEditor; - - vstEffect.flags |= Vst2::effFlagsCanReplacing; - if (processor->supportsDoublePrecisionProcessing()) - vstEffect.flags |= Vst2::effFlagsCanDoubleReplacing; - - vstEffect.flags |= Vst2::effFlagsProgramChunks; - - #if JucePlugin_IsSynth - vstEffect.flags |= Vst2::effFlagsIsSynth; - #else - if (processor->getTailLengthSeconds() == 0.0) - vstEffect.flags |= Vst2::effFlagsNoSoundInStop; - #endif - - #if JUCE_WINDOWS - ++numActivePlugins; - #endif - } - - ~JuceVSTWrapper() override - { - JUCE_AUTORELEASEPOOL - { - #if JUCE_LINUX || JUCE_BSD - MessageManagerLock mmLock; - #endif - - stopTimer(); - deleteEditor (false); - - hasShutdown = true; - - processor = nullptr; - - jassert (editorComp == nullptr); - - deleteTempChannels(); - - #if JUCE_WINDOWS - if (--numActivePlugins == 0) - messageThreadIsDefinitelyCorrect = false; - #endif - } - } - - Vst2::AEffect* getAEffect() noexcept { return &vstEffect; } - - template - void internalProcessReplacing (FloatType** inputs, FloatType** outputs, - int32 numSamples, VstTempBuffers& tmpBuffers) - { - const bool isMidiEffect = processor->isMidiEffect(); - - if (firstProcessCallback) - { - firstProcessCallback = false; - - // if this fails, the host hasn't called resume() before processing - jassert (isProcessing); - - // (tragically, some hosts actually need this, although it's stupid to have - // to do it here.) - if (! isProcessing) - resume(); - - processor->setNonRealtime (isProcessLevelOffline()); - - #if JUCE_WINDOWS - if (getHostType().isWavelab()) - { - int priority = GetThreadPriority (GetCurrentThread()); - - if (priority <= THREAD_PRIORITY_NORMAL && priority >= THREAD_PRIORITY_LOWEST) - processor->setNonRealtime (true); - } - #endif - } - - #if JUCE_DEBUG && ! (JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect) - const int numMidiEventsComingIn = midiEvents.getNumEvents(); - #endif - - { - const int numIn = processor->getTotalNumInputChannels(); - const int numOut = processor->getTotalNumOutputChannels(); - - const ScopedLock sl (processor->getCallbackLock()); - - if (processor->isSuspended()) - { - for (int i = 0; i < numOut; ++i) - if (outputs[i] != nullptr) - FloatVectorOperations::clear (outputs[i], numSamples); - } - else - { - updateCallbackContextInfo(); - - int i; - for (i = 0; i < numOut; ++i) - { - auto* chan = tmpBuffers.tempChannels.getUnchecked(i); - - if (chan == nullptr) - { - chan = outputs[i]; - - bool bufferPointerReusedForOtherChannels = false; - - for (int j = i; --j >= 0;) - { - if (outputs[j] == chan) - { - bufferPointerReusedForOtherChannels = true; - break; - } - } - - // if some output channels are disabled, some hosts supply the same buffer - // for multiple channels or supply a nullptr - this buggers up our method - // of copying the inputs over the outputs, so we need to create unique temp - // buffers in this case.. - if (bufferPointerReusedForOtherChannels || chan == nullptr) - { - chan = new FloatType [(size_t) blockSize * 2]; - tmpBuffers.tempChannels.set (i, chan); - } - } - - if (i < numIn) - { - if (chan != inputs[i]) - memcpy (chan, inputs[i], (size_t) numSamples * sizeof (FloatType)); - } - else - { - FloatVectorOperations::clear (chan, numSamples); - } - - tmpBuffers.channels[i] = chan; - } - - for (; i < numIn; ++i) - tmpBuffers.channels[i] = inputs[i]; - - { - const int numChannels = jmax (numIn, numOut); - AudioBuffer chans (tmpBuffers.channels, isMidiEffect ? 0 : numChannels, numSamples); - - if (isBypassed && processor->getBypassParameter() == nullptr) - processor->processBlockBypassed (chans, midiEvents); - else - processor->processBlock (chans, midiEvents); - } - - // copy back any temp channels that may have been used.. - for (i = 0; i < numOut; ++i) - if (auto* chan = tmpBuffers.tempChannels.getUnchecked(i)) - if (auto* dest = outputs[i]) - memcpy (dest, chan, (size_t) numSamples * sizeof (FloatType)); - } - } - - if (! midiEvents.isEmpty()) - { - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - auto numEvents = midiEvents.getNumEvents(); - - outgoingEvents.ensureSize (numEvents); - outgoingEvents.clear(); - - for (const auto metadata : midiEvents) - { - jassert (metadata.samplePosition >= 0 && metadata.samplePosition < numSamples); - - outgoingEvents.addEvent (metadata.data, metadata.numBytes, metadata.samplePosition); - } - - // Send VST events to the host. - if (hostCallback != nullptr) - hostCallback (&vstEffect, Vst2::audioMasterProcessEvents, 0, 0, outgoingEvents.events, 0); - #elif JUCE_DEBUG - /* This assertion is caused when you've added some events to the - midiMessages array in your processBlock() method, which usually means - that you're trying to send them somewhere. But in this case they're - getting thrown away. - - If your plugin does want to send midi messages, you'll need to set - the JucePlugin_ProducesMidiOutput macro to 1 in your - JucePluginCharacteristics.h file. - - If you don't want to produce any midi output, then you should clear the - midiMessages array at the end of your processBlock() method, to - indicate that you don't want any of the events to be passed through - to the output. - */ - jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); - #endif - - midiEvents.clear(); - } - } - - void processReplacing (float** inputs, float** outputs, int32 sampleFrames) - { - jassert (! processor->isUsingDoublePrecision()); - internalProcessReplacing (inputs, outputs, sampleFrames, floatTempBuffers); - } - - static void processReplacingCB (Vst2::AEffect* vstInterface, float** inputs, float** outputs, int32 sampleFrames) - { - getWrapper (vstInterface)->processReplacing (inputs, outputs, sampleFrames); - } - - void processDoubleReplacing (double** inputs, double** outputs, int32 sampleFrames) - { - jassert (processor->isUsingDoublePrecision()); - internalProcessReplacing (inputs, outputs, sampleFrames, doubleTempBuffers); - } - - static void processDoubleReplacingCB (Vst2::AEffect* vstInterface, double** inputs, double** outputs, int32 sampleFrames) - { - getWrapper (vstInterface)->processDoubleReplacing (inputs, outputs, sampleFrames); - } - - //============================================================================== - void resume() - { - if (processor != nullptr) - { - isProcessing = true; - - auto numInAndOutChannels = static_cast (vstEffect.numInputs + vstEffect.numOutputs); - floatTempBuffers .channels.calloc (numInAndOutChannels); - doubleTempBuffers.channels.calloc (numInAndOutChannels); - - auto currentRate = sampleRate; - auto currentBlockSize = blockSize; - - firstProcessCallback = true; - - processor->setNonRealtime (isProcessLevelOffline()); - processor->setRateAndBufferSizeDetails (currentRate, currentBlockSize); - - deleteTempChannels(); - - processor->prepareToPlay (currentRate, currentBlockSize); - - midiEvents.ensureSize (2048); - midiEvents.clear(); - - vstEffect.initialDelay = processor->getLatencySamples(); - - /** If this plug-in is a synth or it can receive midi events we need to tell the - host that we want midi. In the SDK this method is marked as deprecated, but - some hosts rely on this behaviour. - */ - if (vstEffect.flags & Vst2::effFlagsIsSynth || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect) - { - if (hostCallback != nullptr) - hostCallback (&vstEffect, Vst2::audioMasterWantMidi, 0, 1, nullptr, 0); - } - - if (getHostType().isAbletonLive() - && hostCallback != nullptr - && processor->getTailLengthSeconds() == std::numeric_limits::infinity()) - { - AbletonLiveHostSpecific hostCmd; - - hostCmd.magic = 0x41624c69; // 'AbLi' - hostCmd.cmd = 5; - hostCmd.commandSize = sizeof (int); - hostCmd.flags = AbletonLiveHostSpecific::KCantBeSuspended; - - hostCallback (&vstEffect, Vst2::audioMasterVendorSpecific, 0, 0, &hostCmd, 0.0f); - } - - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - outgoingEvents.ensureSize (512); - #endif - } - } - - void suspend() - { - if (processor != nullptr) - { - processor->releaseResources(); - outgoingEvents.freeEvents(); - - isProcessing = false; - floatTempBuffers.channels.free(); - doubleTempBuffers.channels.free(); - - deleteTempChannels(); - } - } - - void updateCallbackContextInfo() - { - const Vst2::VstTimeInfo* ti = nullptr; - - if (hostCallback != nullptr) - { - int32 flags = Vst2::kVstPpqPosValid | Vst2::kVstTempoValid - | Vst2::kVstBarsValid | Vst2::kVstCyclePosValid - | Vst2::kVstTimeSigValid | Vst2::kVstSmpteValid - | Vst2::kVstClockValid | Vst2::kVstNanosValid; - - auto result = hostCallback (&vstEffect, Vst2::audioMasterGetTime, 0, flags, nullptr, 0); - ti = reinterpret_cast (result); - } - - if (ti == nullptr || ti->sampleRate <= 0) - { - currentPosition.reset(); - return; - } - - auto& info = currentPosition.emplace(); - info.setBpm ((ti->flags & Vst2::kVstTempoValid) != 0 ? makeOptional (ti->tempo) : nullopt); - - info.setTimeSignature ((ti->flags & Vst2::kVstTimeSigValid) != 0 ? makeOptional (TimeSignature { ti->timeSigNumerator, ti->timeSigDenominator }) - : nullopt); - - info.setTimeInSamples ((int64) (ti->samplePos + 0.5)); - info.setTimeInSeconds (ti->samplePos / ti->sampleRate); - info.setPpqPosition ((ti->flags & Vst2::kVstPpqPosValid) != 0 ? makeOptional (ti->ppqPos) : nullopt); - info.setPpqPositionOfLastBarStart ((ti->flags & Vst2::kVstBarsValid) != 0 ? makeOptional (ti->barStartPos) : nullopt); - - if ((ti->flags & Vst2::kVstSmpteValid) != 0) - { - info.setFrameRate ([&]() -> Optional - { - switch (ti->smpteFrameRate) - { - case Vst2::kVstSmpte24fps: return FrameRate().withBaseRate (24); - case Vst2::kVstSmpte239fps: return FrameRate().withBaseRate (24).withPullDown(); - - case Vst2::kVstSmpte25fps: return FrameRate().withBaseRate (25); - case Vst2::kVstSmpte249fps: return FrameRate().withBaseRate (25).withPullDown(); - - case Vst2::kVstSmpte30fps: return FrameRate().withBaseRate (30); - case Vst2::kVstSmpte30dfps: return FrameRate().withBaseRate (30).withDrop(); - case Vst2::kVstSmpte2997fps: return FrameRate().withBaseRate (30).withPullDown(); - case Vst2::kVstSmpte2997dfps: return FrameRate().withBaseRate (30).withPullDown().withDrop(); - - case Vst2::kVstSmpte60fps: return FrameRate().withBaseRate (60); - case Vst2::kVstSmpte599fps: return FrameRate().withBaseRate (60).withPullDown(); - - case Vst2::kVstSmpteFilm16mm: - case Vst2::kVstSmpteFilm35mm: return FrameRate().withBaseRate (24); - } - - return nullopt; - }()); - - const auto effectiveRate = info.getFrameRate().hasValue() ? info.getFrameRate()->getEffectiveRate() : 0.0; - info.setEditOriginTime (effectiveRate != 0.0 ? makeOptional (ti->smpteOffset / (80.0 * effectiveRate)) : nullopt); - } - - info.setIsRecording ((ti->flags & Vst2::kVstTransportRecording) != 0); - info.setIsPlaying ((ti->flags & (Vst2::kVstTransportRecording | Vst2::kVstTransportPlaying)) != 0); - info.setIsLooping ((ti->flags & Vst2::kVstTransportCycleActive) != 0); - - info.setLoopPoints ((ti->flags & Vst2::kVstCyclePosValid) != 0 ? makeOptional (LoopPoints { ti->cycleStartPos, ti->cycleEndPos }) - : nullopt); - - info.setHostTimeNs ((ti->flags & Vst2::kVstNanosValid) != 0 ? makeOptional ((uint64_t) ti->nanoSeconds) : nullopt); - } - - //============================================================================== - Optional getPosition() const override - { - return currentPosition; - } - - //============================================================================== - float getParameter (int32 index) const - { - if (auto* param = juceParameters.getParamForIndex (index)) - return param->getValue(); - - return 0.0f; - } - - static float getParameterCB (Vst2::AEffect* vstInterface, int32 index) - { - return getWrapper (vstInterface)->getParameter (index); - } - - void setParameter (int32 index, float value) - { - if (auto* param = juceParameters.getParamForIndex (index)) - setValueAndNotifyIfChanged (*param, value); - } - - static void setParameterCB (Vst2::AEffect* vstInterface, int32 index, float value) - { - getWrapper (vstInterface)->setParameter (index, value); - } - - void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override - { - if (inParameterChangedCallback.get()) - { - inParameterChangedCallback = false; - return; - } - - if (hostCallback != nullptr) - hostCallback (&vstEffect, Vst2::audioMasterAutomate, index, 0, nullptr, newValue); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override - { - if (hostCallback != nullptr) - hostCallback (&vstEffect, Vst2::audioMasterBeginEdit, index, 0, nullptr, 0); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override - { - if (hostCallback != nullptr) - hostCallback (&vstEffect, Vst2::audioMasterEndEdit, index, 0, nullptr, 0); - } - - void parameterValueChanged (int, float newValue) override - { - // this can only come from the bypass parameter - isBypassed = (newValue >= 0.5f); - } - - void parameterGestureChanged (int, bool) override {} - - void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override - { - hostChangeUpdater.update (details); - } - - bool getPinProperties (Vst2::VstPinProperties& properties, bool direction, int index) const - { - if (processor->isMidiEffect()) - return false; - - int channelIdx, busIdx; - - // fill with default - properties.flags = 0; - properties.label[0] = 0; - properties.shortLabel[0] = 0; - properties.arrangementType = Vst2::kSpeakerArrEmpty; - - if ((channelIdx = processor->getOffsetInBusBufferForAbsoluteChannelIndex (direction, index, busIdx)) >= 0) - { - auto& bus = *processor->getBus (direction, busIdx); - auto& channelSet = bus.getCurrentLayout(); - auto channelType = channelSet.getTypeOfChannel (channelIdx); - - properties.flags = Vst2::kVstPinIsActive | Vst2::kVstPinUseSpeaker; - properties.arrangementType = SpeakerMappings::channelSetToVstArrangementType (channelSet); - String label = bus.getName(); - - #ifdef JucePlugin_PreferredChannelConfigurations - label += " " + String (channelIdx); - #else - if (channelSet.size() > 1) - label += " " + AudioChannelSet::getAbbreviatedChannelTypeName (channelType); - #endif - - label.copyToUTF8 (properties.label, (size_t) (Vst2::kVstMaxLabelLen + 1)); - label.copyToUTF8 (properties.shortLabel, (size_t) (Vst2::kVstMaxShortLabelLen + 1)); - - if (channelType == AudioChannelSet::left - || channelType == AudioChannelSet::leftSurround - || channelType == AudioChannelSet::leftCentre - || channelType == AudioChannelSet::leftSurroundSide - || channelType == AudioChannelSet::topFrontLeft - || channelType == AudioChannelSet::topRearLeft - || channelType == AudioChannelSet::leftSurroundRear - || channelType == AudioChannelSet::wideLeft) - properties.flags |= Vst2::kVstPinIsStereo; - - return true; - } - - return false; - } - - //============================================================================== - void timerCallback() override - { - if (shouldDeleteEditor) - { - shouldDeleteEditor = false; - deleteEditor (true); - } - - { - ScopedLock lock (stateInformationLock); - - if (chunkMemoryTime > 0 - && chunkMemoryTime < juce::Time::getApproximateMillisecondCounter() - 2000 - && ! recursionCheck) - { - chunkMemory.reset(); - chunkMemoryTime = 0; - } - } - - if (editorComp != nullptr) - editorComp->checkVisibility(); - } - - void setHasEditorFlag (bool shouldSetHasEditor) - { - auto hasEditor = (vstEffect.flags & Vst2::effFlagsHasEditor) != 0; - - if (shouldSetHasEditor == hasEditor) - return; - - if (shouldSetHasEditor) - vstEffect.flags |= Vst2::effFlagsHasEditor; - else - vstEffect.flags &= ~Vst2::effFlagsHasEditor; - } - - void createEditorComp() - { - if (hasShutdown || processor == nullptr) - return; - - if (editorComp == nullptr) - { - if (auto* ed = processor->createEditorIfNeeded()) - { - setHasEditorFlag (true); - editorComp.reset (new EditorCompWrapper (*this, *ed, editorScaleFactor)); - } - else - { - setHasEditorFlag (false); - } - } - - shouldDeleteEditor = false; - } - - void deleteEditor (bool canDeleteLaterIfModal) - { - JUCE_AUTORELEASEPOOL - { - PopupMenu::dismissAllActiveMenus(); - - jassert (! recursionCheck); - ScopedValueSetter svs (recursionCheck, true, false); - - if (editorComp != nullptr) - { - if (auto* modalComponent = Component::getCurrentlyModalComponent()) - { - modalComponent->exitModalState (0); - - if (canDeleteLaterIfModal) - { - shouldDeleteEditor = true; - return; - } - } - - editorComp->detachHostWindow(); - - if (auto* ed = editorComp->getEditorComp()) - processor->editorBeingDeleted (ed); - - editorComp = nullptr; - - // there's some kind of component currently modal, but the host - // is trying to delete our plugin. You should try to avoid this happening.. - jassert (Component::getCurrentlyModalComponent() == nullptr); - } - } - } - - pointer_sized_int dispatcher (int32 opCode, VstOpCodeArguments args) - { - if (hasShutdown) - return 0; - - switch (opCode) - { - case Vst2::effOpen: return handleOpen (args); - case Vst2::effClose: return handleClose (args); - case Vst2::effSetProgram: return handleSetCurrentProgram (args); - case Vst2::effGetProgram: return handleGetCurrentProgram (args); - case Vst2::effSetProgramName: return handleSetCurrentProgramName (args); - case Vst2::effGetProgramName: return handleGetCurrentProgramName (args); - case Vst2::effGetParamLabel: return handleGetParameterLabel (args); - case Vst2::effGetParamDisplay: return handleGetParameterText (args); - case Vst2::effGetParamName: return handleGetParameterName (args); - case Vst2::effSetSampleRate: return handleSetSampleRate (args); - case Vst2::effSetBlockSize: return handleSetBlockSize (args); - case Vst2::effMainsChanged: return handleResumeSuspend (args); - case Vst2::effEditGetRect: return handleGetEditorBounds (args); - case Vst2::effEditOpen: return handleOpenEditor (args); - case Vst2::effEditClose: return handleCloseEditor (args); - case Vst2::effIdentify: return (pointer_sized_int) ByteOrder::bigEndianInt ("NvEf"); - case Vst2::effGetChunk: return handleGetData (args); - case Vst2::effSetChunk: return handleSetData (args); - case Vst2::effProcessEvents: return handlePreAudioProcessingEvents (args); - case Vst2::effCanBeAutomated: return handleIsParameterAutomatable (args); - case Vst2::effString2Parameter: return handleParameterValueForText (args); - case Vst2::effGetProgramNameIndexed: return handleGetProgramName (args); - case Vst2::effGetInputProperties: return handleGetInputPinProperties (args); - case Vst2::effGetOutputProperties: return handleGetOutputPinProperties (args); - case Vst2::effGetPlugCategory: return handleGetPlugInCategory (args); - case Vst2::effSetSpeakerArrangement: return handleSetSpeakerConfiguration (args); - case Vst2::effSetBypass: return handleSetBypass (args); - case Vst2::effGetEffectName: return handleGetPlugInName (args); - case Vst2::effGetProductString: return handleGetPlugInName (args); - case Vst2::effGetVendorString: return handleGetManufacturerName (args); - case Vst2::effGetVendorVersion: return handleGetManufacturerVersion (args); - case Vst2::effVendorSpecific: return handleManufacturerSpecific (args); - case Vst2::effCanDo: return handleCanPlugInDo (args); - case Vst2::effGetTailSize: return handleGetTailSize (args); - case Vst2::effKeysRequired: return handleKeyboardFocusRequired (args); - case Vst2::effGetVstVersion: return handleGetVstInterfaceVersion (args); - case Vst2::effGetCurrentMidiProgram: return handleGetCurrentMidiProgram (args); - case Vst2::effGetSpeakerArrangement: return handleGetSpeakerConfiguration (args); - case Vst2::effSetTotalSampleToProcess: return handleSetNumberOfSamplesToProcess (args); - case Vst2::effSetProcessPrecision: return handleSetSampleFloatType (args); - case Vst2::effGetNumMidiInputChannels: return handleGetNumMidiInputChannels(); - case Vst2::effGetNumMidiOutputChannels: return handleGetNumMidiOutputChannels(); - case Vst2::effEditIdle: return handleEditIdle(); - default: return 0; - } - } - - static pointer_sized_int dispatcherCB (Vst2::AEffect* vstInterface, int32 opCode, int32 index, - pointer_sized_int value, void* ptr, float opt) - { - auto* wrapper = getWrapper (vstInterface); - VstOpCodeArguments args = { index, value, ptr, opt }; - - if (opCode == Vst2::effClose) - { - wrapper->dispatcher (opCode, args); - delete wrapper; - return 1; - } - - return wrapper->dispatcher (opCode, args); - } - - //============================================================================== - // A component to hold the AudioProcessorEditor, and cope with some housekeeping - // chores when it changes or repaints. - struct EditorCompWrapper : public Component - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - , public Timer - #endif - { - EditorCompWrapper (JuceVSTWrapper& w, AudioProcessorEditor& editor, [[maybe_unused]] float initialScale) - : wrapper (w) - { - editor.setOpaque (true); - #if ! JUCE_MAC - editor.setScaleFactor (initialScale); - #endif - addAndMakeVisible (editor); - - auto editorBounds = getSizeToContainChild(); - setSize (editorBounds.getWidth(), editorBounds.getHeight()); - - #if JUCE_WINDOWS - if (! getHostType().isReceptor()) - addMouseListener (this, true); - #endif - - setOpaque (true); - } - - ~EditorCompWrapper() override - { - deleteAllChildren(); // note that we can't use a std::unique_ptr because the editor may - // have been transferred to another parent which takes over ownership. - } - - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - - void getEditorBounds (Vst2::ERect& bounds) - { - auto editorBounds = getSizeToContainChild(); - bounds = convertToHostBounds ({ 0, 0, (int16) editorBounds.getHeight(), (int16) editorBounds.getWidth() }); - } - - void attachToHost (VstOpCodeArguments args) - { - setVisible (false); - - #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD - addToDesktop (0, args.ptr); - hostWindow = (HostWindowType) args.ptr; - - #if JUCE_LINUX || JUCE_BSD - X11Symbols::getInstance()->xReparentWindow (display, - (Window) getWindowHandle(), - (HostWindowType) hostWindow, - 0, 0); - // The host is likely to attempt to move/resize the window directly after this call, - // and we need to ensure that the X server knows that our window has been attached - // before that happens. - X11Symbols::getInstance()->xFlush (display); - #elif JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - checkHostWindowScaleFactor (true); - startTimer (500); - #endif - #elif JUCE_MAC - hostWindow = attachComponentToWindowRefVST (this, args.ptr, wrapper.useNSView); - #endif - - setVisible (true); - } - - void detachHostWindow() - { - #if JUCE_MAC - if (hostWindow != nullptr) - detachComponentFromWindowRefVST (this, hostWindow, wrapper.useNSView); - #endif - - hostWindow = {}; - } - - void checkVisibility() - { - #if JUCE_MAC - if (hostWindow != nullptr) - checkWindowVisibilityVST (hostWindow, this, wrapper.useNSView); - #endif - } - - AudioProcessorEditor* getEditorComp() const noexcept - { - return dynamic_cast (getChildComponent (0)); - } - - void resized() override - { - if (auto* pluginEditor = getEditorComp()) - { - if (! resizingParent) - { - auto newBounds = getLocalBounds(); - - { - const ScopedValueSetter resizingChildSetter (resizingChild, true); - pluginEditor->setBounds (pluginEditor->getLocalArea (this, newBounds).withPosition (0, 0)); - } - - lastBounds = newBounds; - } - - updateWindowSize(); - } - - #if JUCE_MAC && ! JUCE_64BIT - if (! wrapper.useNSView) - updateEditorCompBoundsVST (this); - #endif - } - - void parentSizeChanged() override - { - updateWindowSize(); - repaint(); - } - - void childBoundsChanged (Component*) override - { - if (resizingChild) - return; - - auto newBounds = getSizeToContainChild(); - - if (newBounds != lastBounds) - { - updateWindowSize(); - lastBounds = newBounds; - } - } - - juce::Rectangle getSizeToContainChild() - { - if (auto* pluginEditor = getEditorComp()) - return getLocalArea (pluginEditor, pluginEditor->getLocalBounds()); - - return {}; - } - - void resizeHostWindow (juce::Rectangle bounds) - { - auto rect = convertToHostBounds ({ 0, 0, (int16) bounds.getHeight(), (int16) bounds.getWidth() }); - const auto newWidth = rect.right - rect.left; - const auto newHeight = rect.bottom - rect.top; - - bool sizeWasSuccessful = false; - - if (auto host = wrapper.hostCallback) - { - auto status = host (wrapper.getAEffect(), Vst2::audioMasterCanDo, 0, 0, const_cast ("sizeWindow"), 0); - - if (status == (pointer_sized_int) 1 || getHostType().isAbletonLive()) - { - const ScopedValueSetter resizingParentSetter (resizingParent, true); - - sizeWasSuccessful = (host (wrapper.getAEffect(), Vst2::audioMasterSizeWindow, - newWidth, newHeight, nullptr, 0) != 0); - } - } - - // some hosts don't support the sizeWindow call, so do it manually.. - if (! sizeWasSuccessful) - { - const ScopedValueSetter resizingParentSetter (resizingParent, true); - - #if JUCE_MAC - setNativeHostWindowSizeVST (hostWindow, this, newWidth, newHeight, wrapper.useNSView); - #elif JUCE_LINUX || JUCE_BSD - // (Currently, all linux hosts support sizeWindow, so this should never need to happen) - setSize (newWidth, newHeight); - #else - int dw = 0; - int dh = 0; - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - HWND w = (HWND) getWindowHandle(); - - while (w != nullptr) - { - HWND parent = getWindowParent (w); - - if (parent == nullptr) - break; - - TCHAR windowType [32] = { 0 }; - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase ("MDIClient")) - break; - - RECT windowPos, parentPos; - GetWindowRect (w, &windowPos); - GetWindowRect (parent, &parentPos); - - if (w != (HWND) getWindowHandle()) - SetWindowPos (w, nullptr, 0, 0, newWidth + dw, newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); - - dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - w = parent; - - if (dw == 2 * frameThickness) - break; - - if (dw > 100 || dh > 100) - w = nullptr; - } - - if (w != nullptr) - SetWindowPos (w, nullptr, 0, 0, newWidth + dw, newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); - #endif - } - - #if JUCE_LINUX || JUCE_BSD - X11Symbols::getInstance()->xResizeWindow (display, (Window) getWindowHandle(), - static_cast (rect.right - rect.left), - static_cast (rect.bottom - rect.top)); - #endif - } - - void setContentScaleFactor (float scale) - { - if (auto* pluginEditor = getEditorComp()) - { - auto prevEditorBounds = pluginEditor->getLocalArea (this, lastBounds); - - { - const ScopedValueSetter resizingChildSetter (resizingChild, true); - - pluginEditor->setScaleFactor (scale); - pluginEditor->setBounds (prevEditorBounds.withPosition (0, 0)); - } - - lastBounds = getSizeToContainChild(); - updateWindowSize(); - } - } - - #if JUCE_WINDOWS - void mouseDown (const MouseEvent&) override - { - broughtToFront(); - } - - void broughtToFront() override - { - // for hosts like nuendo, need to also pop the MDI container to the - // front when our comp is clicked on. - if (! isCurrentlyBlockedByAnotherModalComponent()) - if (HWND parent = findMDIParentOf ((HWND) getWindowHandle())) - SetWindowPos (parent, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } - - #if JUCE_WIN_PER_MONITOR_DPI_AWARE - void checkHostWindowScaleFactor (bool force = false) - { - auto hostWindowScale = (float) getScaleFactorForWindow ((HostWindowType) hostWindow); - - if (force || (hostWindowScale > 0.0f && ! approximatelyEqual (hostWindowScale, wrapper.editorScaleFactor))) - wrapper.handleSetContentScaleFactor (hostWindowScale, force); - } - - void timerCallback() override - { - checkHostWindowScaleFactor(); - } - #endif - #endif - - #if JUCE_MAC - bool keyPressed (const KeyPress&) override - { - // If we have an unused keypress, move the key-focus to a host window - // and re-inject the event.. - return forwardCurrentKeyEventToHostVST (this, wrapper.useNSView); - } - #endif - - private: - void updateWindowSize() - { - if (! resizingParent - && getEditorComp() != nullptr - && hostWindow != HostWindowType{}) - { - const auto editorBounds = getSizeToContainChild(); - resizeHostWindow (editorBounds); - - { - const ScopedValueSetter resizingParentSetter (resizingParent, true); - - // setSize() on linux causes renoise and energyxt to fail. - // We'll resize our peer during resizeHostWindow() instead. - #if ! (JUCE_LINUX || JUCE_BSD) - setSize (editorBounds.getWidth(), editorBounds.getHeight()); - #endif - - if (auto* p = getPeer()) - p->updateBounds(); - } - - #if JUCE_MAC - resizeHostWindow (editorBounds); // (doing this a second time seems to be necessary in tracktion) - #endif - } - } - - //============================================================================== - static Vst2::ERect convertToHostBounds (const Vst2::ERect& rect) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return rect; - - return { (int16) roundToInt (rect.top * desktopScale), - (int16) roundToInt (rect.left * desktopScale), - (int16) roundToInt (rect.bottom * desktopScale), - (int16) roundToInt (rect.right * desktopScale) }; - } - - //============================================================================== - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostEventLoop; - #endif - - //============================================================================== - JuceVSTWrapper& wrapper; - bool resizingChild = false, resizingParent = false; - - juce::Rectangle lastBounds; - - #if JUCE_LINUX || JUCE_BSD - using HostWindowType = ::Window; - ::Display* display = XWindowSystem::getInstance()->getDisplay(); - #elif JUCE_WINDOWS - using HostWindowType = HWND; - WindowsHooks hooks; - #else - using HostWindowType = void*; - #endif - - HostWindowType hostWindow = {}; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper) - }; - - //============================================================================== -private: - struct HostChangeUpdater : private AsyncUpdater - { - explicit HostChangeUpdater (JuceVSTWrapper& o) : owner (o) {} - ~HostChangeUpdater() override { cancelPendingUpdate(); } - - void update (const ChangeDetails& details) - { - if (details.latencyChanged) - { - owner.vstEffect.initialDelay = owner.processor->getLatencySamples(); - callbackBits |= audioMasterIOChangedBit; - } - - if (details.parameterInfoChanged || details.programChanged) - callbackBits |= audioMasterUpdateDisplayBit; - - triggerAsyncUpdate(); - } - - private: - void handleAsyncUpdate() override - { - const auto callbacksToFire = callbackBits.exchange (0); - - if (auto* callback = owner.hostCallback) - { - struct FlagPair - { - Vst2::AudioMasterOpcodesX opcode; - int bit; - }; - - constexpr FlagPair pairs[] { { Vst2::audioMasterUpdateDisplay, audioMasterUpdateDisplayBit }, - { Vst2::audioMasterIOChanged, audioMasterIOChangedBit } }; - - for (const auto& pair : pairs) - if ((callbacksToFire & pair.bit) != 0) - callback (&owner.vstEffect, pair.opcode, 0, 0, nullptr, 0); - } - } - - static constexpr auto audioMasterUpdateDisplayBit = 1 << 0; - static constexpr auto audioMasterIOChangedBit = 1 << 1; - - JuceVSTWrapper& owner; - std::atomic callbackBits { 0 }; - }; - - static JuceVSTWrapper* getWrapper (Vst2::AEffect* v) noexcept { return static_cast (v->object); } - - bool isProcessLevelOffline() - { - return hostCallback != nullptr - && (int32) hostCallback (&vstEffect, Vst2::audioMasterGetCurrentProcessLevel, 0, 0, nullptr, 0) == 4; - } - - static int32 convertHexVersionToDecimal (const unsigned int hexVersion) - { - #if JUCE_VST_RETURN_HEX_VERSION_NUMBER_DIRECTLY - return (int32) hexVersion; - #else - // Currently, only Cubase displays the version number to the user - // We are hoping here that when other DAWs start to display the version - // number, that they do so according to yfede's encoding table in the link - // below. If not, then this code will need an if (isSteinberg()) in the - // future. - int major = (hexVersion >> 16) & 0xff; - int minor = (hexVersion >> 8) & 0xff; - int bugfix = hexVersion & 0xff; - - // for details, see: https://forum.juce.com/t/issues-with-version-integer-reported-by-vst2/23867 - - // Encoding B - if (major < 1) - return major * 1000 + minor * 100 + bugfix * 10; - - // Encoding E - if (major > 100) - return major * 10000000 + minor * 100000 + bugfix * 1000; - - // Encoding D - return static_cast (hexVersion); - #endif - } - - //============================================================================== - #if JUCE_WINDOWS - // Workarounds for hosts which attempt to open editor windows on a non-GUI thread.. (Grrrr...) - static void checkWhetherMessageThreadIsCorrect() - { - auto host = getHostType(); - - if (host.isWavelab() || host.isCubaseBridged() || host.isPremiere()) - { - if (! messageThreadIsDefinitelyCorrect) - { - MessageManager::getInstance()->setCurrentThreadAsMessageThread(); - - struct MessageThreadCallback : public CallbackMessage - { - MessageThreadCallback (bool& tr) : triggered (tr) {} - void messageCallback() override { triggered = true; } - - bool& triggered; - }; - - (new MessageThreadCallback (messageThreadIsDefinitelyCorrect))->post(); - } - } - } - #else - static void checkWhetherMessageThreadIsCorrect() {} - #endif - - void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) - { - if (param.getValue() == newValue) - return; - - inParameterChangedCallback = true; - param.setValueNotifyingHost (newValue); - } - - //============================================================================== - template - void deleteTempChannels (VstTempBuffers& tmpBuffers) - { - tmpBuffers.release(); - - if (processor != nullptr) - tmpBuffers.tempChannels.insertMultiple (0, nullptr, vstEffect.numInputs - + vstEffect.numOutputs); - } - - void deleteTempChannels() - { - deleteTempChannels (floatTempBuffers); - deleteTempChannels (doubleTempBuffers); - } - - //============================================================================== - void findMaxTotalChannels (int& maxTotalIns, int& maxTotalOuts) - { - #ifdef JucePlugin_PreferredChannelConfigurations - int configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - maxTotalIns = maxTotalOuts = 0; - - for (auto& config : configs) - { - maxTotalIns = jmax (maxTotalIns, config[0]); - maxTotalOuts = jmax (maxTotalOuts, config[1]); - } - #else - auto numInputBuses = processor->getBusCount (true); - auto numOutputBuses = processor->getBusCount (false); - - if (numInputBuses > 1 || numOutputBuses > 1) - { - maxTotalIns = maxTotalOuts = 0; - - for (int i = 0; i < numInputBuses; ++i) - maxTotalIns += processor->getChannelCountOfBus (true, i); - - for (int i = 0; i < numOutputBuses; ++i) - maxTotalOuts += processor->getChannelCountOfBus (false, i); - } - else - { - maxTotalIns = numInputBuses > 0 ? processor->getBus (true, 0)->getMaxSupportedChannels (64) : 0; - maxTotalOuts = numOutputBuses > 0 ? processor->getBus (false, 0)->getMaxSupportedChannels (64) : 0; - } - #endif - } - - bool pluginHasSidechainsOrAuxs() const { return (processor->getBusCount (true) > 1 || processor->getBusCount (false) > 1); } - - //============================================================================== - /** Host to plug-in calls. */ - - pointer_sized_int handleOpen (VstOpCodeArguments) - { - // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. - setHasEditorFlag (processor->hasEditor()); - - return 0; - } - - pointer_sized_int handleClose (VstOpCodeArguments) - { - // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. - stopTimer(); - - if (MessageManager::getInstance()->isThisTheMessageThread()) - deleteEditor (false); - - return 0; - } - - pointer_sized_int handleSetCurrentProgram (VstOpCodeArguments args) - { - if (processor != nullptr && isPositiveAndBelow ((int) args.value, processor->getNumPrograms())) - processor->setCurrentProgram ((int) args.value); - - return 0; - } - - pointer_sized_int handleGetCurrentProgram (VstOpCodeArguments) - { - return (processor != nullptr && processor->getNumPrograms() > 0 ? processor->getCurrentProgram() : 0); - } - - pointer_sized_int handleSetCurrentProgramName (VstOpCodeArguments args) - { - if (processor != nullptr && processor->getNumPrograms() > 0) - processor->changeProgramName (processor->getCurrentProgram(), (char*) args.ptr); - - return 0; - } - - pointer_sized_int handleGetCurrentProgramName (VstOpCodeArguments args) - { - if (processor != nullptr && processor->getNumPrograms() > 0) - processor->getProgramName (processor->getCurrentProgram()).copyToUTF8 ((char*) args.ptr, 24 + 1); - - return 0; - } - - pointer_sized_int handleGetParameterLabel (VstOpCodeArguments args) - { - if (auto* param = juceParameters.getParamForIndex (args.index)) - { - // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - param->getLabel().copyToUTF8 ((char*) args.ptr, 24 + 1); - } - - return 0; - } - - pointer_sized_int handleGetParameterText (VstOpCodeArguments args) - { - if (auto* param = juceParameters.getParamForIndex (args.index)) - { - // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - param->getCurrentValueAsText().copyToUTF8 ((char*) args.ptr, 24 + 1); - } - - return 0; - } - - pointer_sized_int handleGetParameterName (VstOpCodeArguments args) - { - if (auto* param = juceParameters.getParamForIndex (args.index)) - { - // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - param->getName (32).copyToUTF8 ((char*) args.ptr, 32 + 1); - } - - return 0; - } - - pointer_sized_int handleSetSampleRate (VstOpCodeArguments args) - { - sampleRate = args.opt; - return 0; - } - - pointer_sized_int handleSetBlockSize (VstOpCodeArguments args) - { - blockSize = (int32) args.value; - return 0; - } - - pointer_sized_int handleResumeSuspend (VstOpCodeArguments args) - { - if (args.value) - resume(); - else - suspend(); - - return 0; - } - - pointer_sized_int handleGetEditorBounds (VstOpCodeArguments args) - { - checkWhetherMessageThreadIsCorrect(); - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - #else - const MessageManagerLock mmLock; - #endif - createEditorComp(); - - if (editorComp != nullptr) - { - editorComp->getEditorBounds (editorRect); - *((Vst2::ERect**) args.ptr) = &editorRect; - return (pointer_sized_int) &editorRect; - } - - return 0; - } - - pointer_sized_int handleOpenEditor (VstOpCodeArguments args) - { - checkWhetherMessageThreadIsCorrect(); - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - #else - const MessageManagerLock mmLock; - #endif - jassert (! recursionCheck); - - startTimerHz (4); // performs misc housekeeping chores - - deleteEditor (true); - createEditorComp(); - - if (editorComp != nullptr) - { - editorComp->attachToHost (args); - return 1; - } - - return 0; - } - - pointer_sized_int handleCloseEditor (VstOpCodeArguments) - { - checkWhetherMessageThreadIsCorrect(); - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - #else - const MessageManagerLock mmLock; - #endif - - deleteEditor (true); - - return 0; - } - - pointer_sized_int handleGetData (VstOpCodeArguments args) - { - if (processor == nullptr) - return 0; - - auto data = (void**) args.ptr; - bool onlyStoreCurrentProgramData = (args.index != 0); - - MemoryBlock block; - - if (onlyStoreCurrentProgramData) - processor->getCurrentProgramStateInformation (block); - else - processor->getStateInformation (block); - - // IMPORTANT! Don't call getStateInfo while holding this lock! - const ScopedLock lock (stateInformationLock); - - chunkMemory = std::move (block); - *data = (void*) chunkMemory.getData(); - - // because the chunk is only needed temporarily by the host (or at least you'd - // hope so) we'll give it a while and then free it in the timer callback. - chunkMemoryTime = juce::Time::getApproximateMillisecondCounter(); - - return (int32) chunkMemory.getSize(); - } - - pointer_sized_int handleSetData (VstOpCodeArguments args) - { - if (processor != nullptr) - { - void* data = args.ptr; - int32 byteSize = (int32) args.value; - bool onlyRestoreCurrentProgramData = (args.index != 0); - - { - const ScopedLock lock (stateInformationLock); - - chunkMemory.reset(); - chunkMemoryTime = 0; - } - - if (byteSize > 0 && data != nullptr) - { - if (onlyRestoreCurrentProgramData) - processor->setCurrentProgramStateInformation (data, byteSize); - else - processor->setStateInformation (data, byteSize); - } - } - - return 0; - } - - pointer_sized_int handlePreAudioProcessingEvents ([[maybe_unused]] VstOpCodeArguments args) - { - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - VSTMidiEventList::addEventsToMidiBuffer ((Vst2::VstEvents*) args.ptr, midiEvents); - return 1; - #else - return 0; - #endif - } - - pointer_sized_int handleIsParameterAutomatable (VstOpCodeArguments args) - { - if (auto* param = juceParameters.getParamForIndex (args.index)) - { - const bool isMeter = ((((unsigned int) param->getCategory() & 0xffff0000) >> 16) == 2); - return (param->isAutomatable() && (! isMeter) ? 1 : 0); - } - - return 0; - } - - pointer_sized_int handleParameterValueForText (VstOpCodeArguments args) - { - if (auto* param = juceParameters.getParamForIndex (args.index)) - { - if (! LegacyAudioParameter::isLegacy (param)) - { - setValueAndNotifyIfChanged (*param, param->getValueForText (String::fromUTF8 ((char*) args.ptr))); - return 1; - } - } - - return 0; - } - - pointer_sized_int handleGetProgramName (VstOpCodeArguments args) - { - if (processor != nullptr && isPositiveAndBelow (args.index, processor->getNumPrograms())) - { - processor->getProgramName (args.index).copyToUTF8 ((char*) args.ptr, 24 + 1); - return 1; - } - - return 0; - } - - pointer_sized_int handleGetInputPinProperties (VstOpCodeArguments args) - { - return (processor != nullptr && getPinProperties (*(Vst2::VstPinProperties*) args.ptr, true, args.index)) ? 1 : 0; - } - - pointer_sized_int handleGetOutputPinProperties (VstOpCodeArguments args) - { - return (processor != nullptr && getPinProperties (*(Vst2::VstPinProperties*) args.ptr, false, args.index)) ? 1 : 0; - } - - pointer_sized_int handleGetPlugInCategory (VstOpCodeArguments) - { - return Vst2::JucePlugin_VSTCategory; - } - - pointer_sized_int handleSetSpeakerConfiguration (VstOpCodeArguments args) - { - auto* pluginInput = reinterpret_cast (args.value); - auto* pluginOutput = reinterpret_cast (args.ptr); - - if (processor->isMidiEffect()) - return 0; - - auto numIns = processor->getBusCount (true); - auto numOuts = processor->getBusCount (false); - - if (pluginInput != nullptr && pluginInput->type >= 0) - { - // inconsistent request? - if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput).size() != pluginInput->numChannels) - return 0; - } - - if (pluginOutput != nullptr && pluginOutput->type >= 0) - { - // inconsistent request? - if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput).size() != pluginOutput->numChannels) - return 0; - } - - if (pluginInput != nullptr && pluginInput->numChannels > 0 && numIns == 0) - return 0; - - if (pluginOutput != nullptr && pluginOutput->numChannels > 0 && numOuts == 0) - return 0; - - auto layouts = processor->getBusesLayout(); - - if (pluginInput != nullptr && pluginInput-> numChannels >= 0 && numIns > 0) - layouts.getChannelSet (true, 0) = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput); - - if (pluginOutput != nullptr && pluginOutput->numChannels >= 0 && numOuts > 0) - layouts.getChannelSet (false, 0) = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - if (! AudioProcessor::containsLayout (layouts, configs)) - return 0; - #endif - - return processor->setBusesLayout (layouts) ? 1 : 0; - } - - pointer_sized_int handleSetBypass (VstOpCodeArguments args) - { - isBypassed = args.value != 0; - - if (auto* param = processor->getBypassParameter()) - param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f); - - return 1; - } - - pointer_sized_int handleGetPlugInName (VstOpCodeArguments args) - { - String (JucePlugin_Name).copyToUTF8 ((char*) args.ptr, 64 + 1); - return 1; - } - - pointer_sized_int handleGetManufacturerName (VstOpCodeArguments args) - { - String (JucePlugin_Manufacturer).copyToUTF8 ((char*) args.ptr, 64 + 1); - return 1; - } - - pointer_sized_int handleGetManufacturerVersion (VstOpCodeArguments) - { - return convertHexVersionToDecimal (JucePlugin_VersionCode); - } - - pointer_sized_int handleManufacturerSpecific (VstOpCodeArguments args) - { - if (handleManufacturerSpecificVST2Opcode (args.index, args.value, args.ptr, args.opt)) - return 1; - - if (args.index == (int32) ByteOrder::bigEndianInt ("PreS") - && args.value == (int32) ByteOrder::bigEndianInt ("AeCs")) - return handleSetContentScaleFactor (args.opt); - - if (args.index == Vst2::effGetParamDisplay) - return handleCockosGetParameterText (args.value, args.ptr, args.opt); - - if (auto callbackHandler = dynamic_cast (processor.get())) - return callbackHandler->handleVstManufacturerSpecific (args.index, args.value, args.ptr, args.opt); - - return 0; - } - - pointer_sized_int handleCanPlugInDo (VstOpCodeArguments args) - { - auto text = (const char*) args.ptr; - auto matches = [=] (const char* s) { return strcmp (text, s) == 0; }; - - if (matches ("receiveVstEvents") - || matches ("receiveVstMidiEvent") - || matches ("receiveVstMidiEvents")) - { - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - return 1; - #else - return -1; - #endif - } - - if (matches ("sendVstEvents") - || matches ("sendVstMidiEvent") - || matches ("sendVstMidiEvents")) - { - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - return 1; - #else - return -1; - #endif - } - - if (matches ("receiveVstTimeInfo") - || matches ("conformsToWindowRules") - || matches ("supportsViewDpiScaling") - || matches ("bypass")) - { - return 1; - } - - // This tells Wavelab to use the UI thread to invoke open/close, - // like all other hosts do. - if (matches ("openCloseAnyThread")) - return -1; - - if (matches ("MPE")) - return processor->supportsMPE() ? 1 : 0; - - #if JUCE_MAC - if (matches ("hasCockosViewAsConfig")) - { - useNSView = true; - return (int32) 0xbeef0000; - } - #endif - - if (matches ("hasCockosExtensions")) - return (int32) 0xbeef0000; - - if (auto callbackHandler = dynamic_cast (processor.get())) - return callbackHandler->handleVstPluginCanDo (args.index, args.value, args.ptr, args.opt); - - return 0; - } - - pointer_sized_int handleGetTailSize (VstOpCodeArguments) - { - if (processor != nullptr) - { - int32 result; - - auto tailSeconds = processor->getTailLengthSeconds(); - - if (tailSeconds == std::numeric_limits::infinity()) - result = std::numeric_limits::max(); - else - result = static_cast (tailSeconds * sampleRate); - - return result; // Vst2 expects an int32 upcasted to a intptr_t here - } - - return 0; - } - - pointer_sized_int handleKeyboardFocusRequired (VstOpCodeArguments) - { - JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6326) - return (JucePlugin_EditorRequiresKeyboardFocus != 0) ? 1 : 0; - JUCE_END_IGNORE_WARNINGS_MSVC - } - - pointer_sized_int handleGetVstInterfaceVersion (VstOpCodeArguments) - { - return kVstVersion; - } - - pointer_sized_int handleGetCurrentMidiProgram (VstOpCodeArguments) - { - return -1; - } - - pointer_sized_int handleGetSpeakerConfiguration (VstOpCodeArguments args) - { - auto** pluginInput = reinterpret_cast (args.value); - auto** pluginOutput = reinterpret_cast (args.ptr); - - if (pluginHasSidechainsOrAuxs() || processor->isMidiEffect()) - return false; - - auto inputLayout = processor->getChannelLayoutOfBus (true, 0); - auto outputLayout = processor->getChannelLayoutOfBus (false, 0); - - const auto speakerBaseSize = offsetof (Vst2::VstSpeakerArrangement, speakers); - - cachedInArrangement .malloc (speakerBaseSize + (static_cast (inputLayout. size()) * sizeof (Vst2::VstSpeakerProperties)), 1); - cachedOutArrangement.malloc (speakerBaseSize + (static_cast (outputLayout.size()) * sizeof (Vst2::VstSpeakerProperties)), 1); - - *pluginInput = cachedInArrangement. getData(); - *pluginOutput = cachedOutArrangement.getData(); - - SpeakerMappings::channelSetToVstArrangement (processor->getChannelLayoutOfBus (true, 0), **pluginInput); - SpeakerMappings::channelSetToVstArrangement (processor->getChannelLayoutOfBus (false, 0), **pluginOutput); - - return 1; - } - - pointer_sized_int handleSetNumberOfSamplesToProcess (VstOpCodeArguments args) - { - return args.value; - } - - pointer_sized_int handleSetSampleFloatType (VstOpCodeArguments args) - { - if (! isProcessing) - { - if (processor != nullptr) - { - processor->setProcessingPrecision ((args.value == Vst2::kVstProcessPrecision64 - && processor->supportsDoublePrecisionProcessing()) - ? AudioProcessor::doublePrecision - : AudioProcessor::singlePrecision); - - return 1; - } - } - - return 0; - } - - pointer_sized_int handleSetContentScaleFactor ([[maybe_unused]] float scale, [[maybe_unused]] bool force = false) - { - checkWhetherMessageThreadIsCorrect(); - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - #else - const MessageManagerLock mmLock; - #endif - - #if ! JUCE_MAC - if (force || ! approximatelyEqual (scale, editorScaleFactor)) - { - editorScaleFactor = scale; - - if (editorComp != nullptr) - editorComp->setContentScaleFactor (editorScaleFactor); - } - #endif - - return 1; - } - - pointer_sized_int handleCockosGetParameterText (pointer_sized_int paramIndex, - void* dest, - float value) - { - if (processor != nullptr && dest != nullptr) - { - if (auto* param = juceParameters.getParamForIndex ((int) paramIndex)) - { - if (! LegacyAudioParameter::isLegacy (param)) - { - String text (param->getText (value, 1024)); - memcpy (dest, text.toRawUTF8(), ((size_t) text.length()) + 1); - return 0xbeef; - } - } - } - - return 0; - } - - //============================================================================== - pointer_sized_int handleGetNumMidiInputChannels() - { - #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect - #ifdef JucePlugin_VSTNumMidiInputs - return JucePlugin_VSTNumMidiInputs; - #else - return 16; - #endif - #else - return 0; - #endif - } - - pointer_sized_int handleGetNumMidiOutputChannels() - { - #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect - #ifdef JucePlugin_VSTNumMidiOutputs - return JucePlugin_VSTNumMidiOutputs; - #else - return 16; - #endif - #else - return 0; - #endif - } - - pointer_sized_int handleEditIdle() - { - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - hostDrivenEventLoop->processPendingEvents(); - #endif - - return 0; - } - - //============================================================================== - ScopedJuceInitialiser_GUI libraryInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - Vst2::audioMasterCallback hostCallback; - std::unique_ptr processor; - double sampleRate = 44100.0; - int32 blockSize = 1024; - Vst2::AEffect vstEffect; - CriticalSection stateInformationLock; - juce::MemoryBlock chunkMemory; - uint32 chunkMemoryTime = 0; - float editorScaleFactor = 1.0f; - std::unique_ptr editorComp; - Vst2::ERect editorRect; - MidiBuffer midiEvents; - VSTMidiEventList outgoingEvents; - Optional currentPosition; - - LegacyAudioParametersWrapper juceParameters; - - bool isProcessing = false, isBypassed = false, hasShutdown = false; - bool firstProcessCallback = true, shouldDeleteEditor = false; - - #if JUCE_MAC - #if JUCE_64BIT - bool useNSView = true; - #else - bool useNSView = false; - #endif - #endif - - VstTempBuffers floatTempBuffers; - VstTempBuffers doubleTempBuffers; - int maxNumInChannels = 0, maxNumOutChannels = 0; - - HeapBlock cachedInArrangement, cachedOutArrangement; - - ThreadLocalValue inParameterChangedCallback; - - HostChangeUpdater hostChangeUpdater { *this }; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVSTWrapper) -}; - - -//============================================================================== -namespace -{ - Vst2::AEffect* pluginEntryPoint (Vst2::audioMasterCallback audioMaster) - { - JUCE_AUTORELEASEPOOL - { - ScopedJuceInitialiser_GUI libraryInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer hostDrivenEventLoop; - #endif - - try - { - if (audioMaster (nullptr, Vst2::audioMasterVersion, 0, 0, nullptr, 0) != 0) - { - std::unique_ptr processor { createPluginFilterOfType (AudioProcessor::wrapperType_VST) }; - auto* processorPtr = processor.get(); - auto* wrapper = new JuceVSTWrapper (audioMaster, std::move (processor)); - auto* aEffect = wrapper->getAEffect(); - - if (auto* callbackHandler = dynamic_cast (processorPtr)) - { - callbackHandler->handleVstHostCallbackAvailable ([audioMaster, aEffect] (int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) - { - return audioMaster (aEffect, opcode, index, value, ptr, opt); - }); - } - - return aEffect; - } - } - catch (...) - {} - } - - return nullptr; - } -} - -#if ! JUCE_WINDOWS - #define JUCE_EXPORTED_FUNCTION extern "C" __attribute__ ((visibility("default"))) -#endif - -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - -//============================================================================== -// Mac startup code.. -#if JUCE_MAC - - JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) - { - initialiseMacVST(); - return pluginEntryPoint (audioMaster); - } - - JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_macho (Vst2::audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_macho (Vst2::audioMasterCallback audioMaster) - { - initialiseMacVST(); - return pluginEntryPoint (audioMaster); - } - -//============================================================================== -// Linux startup code.. -#elif JUCE_LINUX || JUCE_BSD - - JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) - { - return pluginEntryPoint (audioMaster); - } - - JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_plugin (Vst2::audioMasterCallback audioMaster) asm ("main"); - JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_plugin (Vst2::audioMasterCallback audioMaster) - { - return VSTPluginMain (audioMaster); - } - - // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash! - __attribute__((constructor)) void myPluginInit() {} - __attribute__((destructor)) void myPluginFini() {} - -//============================================================================== -// Win32 startup code.. -#else - - extern "C" __declspec (dllexport) Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) - { - return pluginEntryPoint (audioMaster); - } - - #if ! defined (JUCE_64BIT) && JUCE_MSVC // (can't compile this on win64, but it's not needed anyway with VST2.4) - extern "C" __declspec (dllexport) int main (Vst2::audioMasterCallback audioMaster) - { - return (int) pluginEntryPoint (audioMaster); - } - #endif - - extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) - { - if (reason == DLL_PROCESS_ATTACH) - Process::setCurrentModuleInstanceHandle (instance); - - return true; - } -#endif - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -JUCE_END_IGNORE_WARNINGS_MSVC - -#endif diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm deleted file mode 100644 index 2c13881a5aff..000000000000 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm +++ /dev/null @@ -1,305 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 - -#if JUCE_MAC - -#include "../utility/juce_CheckSettingMacros.h" - -#if JucePlugin_Build_VST || JucePlugin_Build_VST3 - -#include "../utility/juce_IncludeSystemHeaders.h" -#include "../utility/juce_IncludeModuleHeaders.h" - -//============================================================================== -namespace juce -{ - -#if ! JUCE_64BIT -JUCE_API void updateEditorCompBoundsVST (Component*); -void updateEditorCompBoundsVST (Component* comp) -{ - HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - comp->getProperties() ["dummyViewRef"].toString().getHexValue64(); - - HIRect r; - HIViewGetFrame (dummyView, &r); - HIViewRef root; - HIViewFindByID (HIViewGetRoot (HIViewGetWindow (dummyView)), kHIViewWindowContentID, &root); - HIViewConvertRect (&r, HIViewGetSuperview (dummyView), root); - - Rect windowPos; - GetWindowBounds (HIViewGetWindow (dummyView), kWindowContentRgn, &windowPos); - - comp->setTopLeftPosition ((int) (windowPos.left + r.origin.x), - (int) (windowPos.top + r.origin.y)); -} - -static pascal OSStatus viewBoundsChangedEvent (EventHandlerCallRef, EventRef, void* user) -{ - updateEditorCompBoundsVST ((Component*) user); - return noErr; -} - -static bool shouldManuallyCloseHostWindow() -{ - return getHostType().isCubase7orLater() || getHostType().isRenoise() || ((SystemStats::getOperatingSystemType() & 0xff) >= 12); -} -#endif - -//============================================================================== -JUCE_API void initialiseMacVST(); -void initialiseMacVST() -{ - #if ! JUCE_64BIT - NSApplicationLoad(); - #endif -} - -JUCE_API void* attachComponentToWindowRefVST (Component* comp, void* parentWindowOrView, bool isNSView); -void* attachComponentToWindowRefVST (Component* comp, void* parentWindowOrView, [[maybe_unused]] bool isNSView) -{ - JUCE_AUTORELEASEPOOL - { - #if ! JUCE_64BIT - if (! isNSView) - { - NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: parentWindowOrView]; - - if (shouldManuallyCloseHostWindow()) - { - [hostWindow setReleasedWhenClosed: NO]; - } - else - { - [hostWindow retain]; - [hostWindow setReleasedWhenClosed: YES]; - } - - [hostWindow setCanHide: YES]; - - HIViewRef parentView = 0; - - WindowAttributes attributes; - GetWindowAttributes ((WindowRef) parentWindowOrView, &attributes); - - if ((attributes & kWindowCompositingAttribute) != 0) - { - HIViewRef root = HIViewGetRoot ((WindowRef) parentWindowOrView); - HIViewFindByID (root, kHIViewWindowContentID, &parentView); - - if (parentView == 0) - parentView = root; - } - else - { - GetRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); - - if (parentView == 0) - CreateRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); - } - - // It seems that the only way to successfully position our overlaid window is by putting a dummy - // HIView into the host's carbon window, and then catching events to see when it gets repositioned - HIViewRef dummyView = 0; - HIImageViewCreate (0, &dummyView); - HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} }; - HIViewSetFrame (dummyView, &r); - HIViewAddSubview (parentView, dummyView); - comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView)); - - EventHandlerRef ref; - const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; - InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref); - comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref)); - - updateEditorCompBoundsVST (comp); - - #if ! JucePlugin_EditorRequiresKeyboardFocus - comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); - #else - comp->addToDesktop (ComponentPeer::windowIsTemporary); - #endif - - comp->setVisible (true); - comp->toFront (false); - - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; - [pluginWindow setExcludedFromWindowsMenu: YES]; - [pluginWindow setCanHide: YES]; - - [hostWindow addChildWindow: pluginWindow - ordered: NSWindowAbove]; - [hostWindow orderFront: nil]; - [pluginWindow orderFront: nil]; - - return hostWindow; - } - #endif - - NSView* parentView = [(NSView*) parentWindowOrView retain]; - - #if JucePlugin_EditorRequiresKeyboardFocus - comp->addToDesktop (0, parentView); - #else - comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView); - #endif - - // (this workaround is because Wavelab provides a zero-size parent view..) - if ([parentView frame].size.height == 0) - [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint]; - - comp->setVisible (true); - comp->toFront (false); - - [[parentView window] setAcceptsMouseMovedEvents: YES]; - return parentView; - } -} - -JUCE_API void detachComponentFromWindowRefVST (Component* comp, void* window, bool isNSView); -void detachComponentFromWindowRefVST (Component* comp, void* window, [[maybe_unused]] bool isNSView) -{ - JUCE_AUTORELEASEPOOL - { - #if ! JUCE_64BIT - if (! isNSView) - { - EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int) - comp->getProperties() ["boundsEventRef"].toString().getHexValue64(); - RemoveEventHandler (ref); - - CFUniquePtr dummyView ((HIViewRef) (void*) (pointer_sized_int) - comp->getProperties() ["dummyViewRef"].toString().getHexValue64()); - - if (HIViewIsValid (dummyView.get())) - dummyView = nullptr; - - NSWindow* hostWindow = (NSWindow*) window; - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; - - [pluginView retain]; - [hostWindow removeChildWindow: pluginWindow]; - [pluginWindow close]; - comp->removeFromDesktop(); - [pluginView release]; - - if (shouldManuallyCloseHostWindow()) - [hostWindow close]; - else - [hostWindow release]; - - #if JUCE_MODAL_LOOPS_PERMITTED - static bool needToRunMessageLoop = ! getHostType().isReaper(); - - // The event loop needs to be run between closing the window and deleting the plugin, - // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes - // in Live when you delete the plugin with its window open. - // (Doing it this way rather than using a single longer timeout means that we can guarantee - // how many messages will be dispatched, which seems to be vital in Reaper) - if (needToRunMessageLoop) - for (int i = 20; --i >= 0;) - MessageManager::getInstance()->runDispatchLoopUntil (1); - #endif - - return; - } - #endif - - comp->removeFromDesktop(); - [(id) window release]; - } -} - -JUCE_API void setNativeHostWindowSizeVST (void* window, Component* component, int newWidth, int newHeight, bool isNSView); -void setNativeHostWindowSizeVST (void* window, Component* component, int newWidth, int newHeight, [[maybe_unused]] bool isNSView) -{ - JUCE_AUTORELEASEPOOL - { - #if ! JUCE_64BIT - if (! isNSView) - { - if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - component->getProperties() ["dummyViewRef"].toString().getHexValue64()) - { - HIRect frameRect; - HIViewGetFrame (dummyView, &frameRect); - frameRect.size.width = newWidth; - frameRect.size.height = newHeight; - HIViewSetFrame (dummyView, &frameRect); - } - - return; - } - #endif - - if (NSView* hostView = (NSView*) window) - { - const int dx = newWidth - component->getWidth(); - const int dy = newHeight - component->getHeight(); - - NSRect r = [hostView frame]; - r.size.width += dx; - r.size.height += dy; - r.origin.y -= dy; - [hostView setFrame: r]; - } - } -} - -JUCE_API void checkWindowVisibilityVST (void* window, Component* comp, bool isNSView); -void checkWindowVisibilityVST ([[maybe_unused]] void* window, - [[maybe_unused]] Component* comp, - [[maybe_unused]] bool isNSView) -{ - #if ! JUCE_64BIT - if (! isNSView) - comp->setVisible ([((NSWindow*) window) isVisible]); - #endif -} - -JUCE_API bool forwardCurrentKeyEventToHostVST (Component* comp, bool isNSView); -bool forwardCurrentKeyEventToHostVST ([[maybe_unused]] Component* comp, [[maybe_unused]] bool isNSView) -{ - #if ! JUCE_64BIT - if (! isNSView) - { - NSWindow* win = [(NSView*) comp->getWindowHandle() window]; - [[win parentWindow] makeKeyWindow]; - repostCurrentNSEvent(); - return true; - } - #endif - - return false; -} - -} // (juce namespace) - -#endif -#endif diff --git a/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp new file mode 100644 index 000000000000..04c88f154535 --- /dev/null +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp @@ -0,0 +1,73 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +// This suppresses a warning in juce_TargetPlatform.h +#ifndef JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED + #define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1 +#endif + +#include + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc++98-compat-extra-semi", + "-Wdeprecated-declarations", + "-Wexpansion-to-defined", + "-Wfloat-equal", + "-Wformat", + "-Wmissing-prototypes", + "-Wpragma-pack", + "-Wredundant-decls", + "-Wshadow", + "-Wshadow-field", + "-Wshorten-64-to-32", + "-Wsign-conversion", + "-Wzero-as-null-pointer-constant") + +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387 6031) + +#ifndef NOMINMAX + #define NOMINMAX 1 +#endif + +#if JUCE_MAC + #include +#elif JUCE_WINDOWS + #include +#elif JUCE_LINUX + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST_utils.mm b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.mm similarity index 92% rename from modules/juce_audio_plugin_client/juce_audio_plugin_client_VST_utils.mm rename to modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.mm index bff235073564..0edda27d5f14 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST_utils.mm +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.mm @@ -23,4 +23,4 @@ ============================================================================== */ -#include "VST/juce_VST_Wrapper.mm" +#include "juce_VST3ManifestHelper.cpp" diff --git a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp b/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp deleted file mode 100644 index da79dcc63ff8..000000000000 --- a/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp +++ /dev/null @@ -1,4239 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 -#include - -//============================================================================== -#if JucePlugin_Build_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD) - -JUCE_BEGIN_NO_SANITIZE ("vptr") - -#if JUCE_PLUGINHOST_VST3 - #if JUCE_MAC - #include - #endif - #undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY - #define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1 -#endif - -#include - -#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY -#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 - -#include "../utility/juce_CheckSettingMacros.h" -#include "../utility/juce_IncludeSystemHeaders.h" -#include "../utility/juce_IncludeModuleHeaders.h" -#include "../utility/juce_WindowsHooks.h" -#include "../utility/juce_LinuxMessageThread.h" -#include -#include -#include - -#ifndef JUCE_VST3_CAN_REPLACE_VST2 - #define JUCE_VST3_CAN_REPLACE_VST2 1 -#endif - -#if JUCE_VST3_CAN_REPLACE_VST2 - - #if ! JUCE_MSVC && ! defined (__cdecl) - #define __cdecl - #endif - - namespace Vst2 - { - struct AEffect; - #include "pluginterfaces/vst2.x/vstfxstore.h" - } - -#endif - -#ifndef JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS - #if JucePlugin_WantsMidiInput - #define JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS 1 - #endif -#endif - -#if JUCE_LINUX || JUCE_BSD - #include "juce_events/native/juce_linux_EventLoopInternal.h" - #include -#endif - -#if JUCE_MAC - #include -#endif - -//============================================================================== -#if JucePlugin_Enable_ARA - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wpragma-pack") - #include - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - #if ARA_SUPPORT_VERSION_1 - #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation" - #endif - - DEF_CLASS_IID(ARA::IPlugInEntryPoint) - DEF_CLASS_IID(ARA::IPlugInEntryPoint2) - DEF_CLASS_IID(ARA::IMainFactory) -#endif - -namespace juce -{ - -using namespace Steinberg; - -//============================================================================== -#if JUCE_MAC - extern void initialiseMacVST(); - - #if ! JUCE_64BIT - extern void updateEditorCompBoundsVST (Component*); - #endif - - extern JUCE_API void* attachComponentToWindowRefVST (Component*, void* parentWindowOrView, bool isNSView); - extern JUCE_API void detachComponentFromWindowRefVST (Component*, void* nsWindow, bool isNSView); -#endif - -#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - double getScaleFactorForWindow (HWND); -#endif - -//============================================================================== -#if JUCE_LINUX || JUCE_BSD - -enum class HostMessageThreadAttached { no, yes }; - -class HostMessageThreadState -{ -public: - template - void setStateWithAction (HostMessageThreadAttached stateIn, Callback&& action) - { - const std::lock_guard lock { m }; - state = stateIn; - action(); - } - - void assertHostMessageThread() - { - const std::lock_guard lock { m }; - - if (state == HostMessageThreadAttached::no) - return; - - JUCE_ASSERT_MESSAGE_THREAD - } - -private: - HostMessageThreadAttached state = HostMessageThreadAttached::no; - std::mutex m; -}; - -class EventHandler final : public Steinberg::Linux::IEventHandler, - private LinuxEventLoopInternal::Listener -{ -public: - EventHandler() - { - LinuxEventLoopInternal::registerLinuxEventLoopListener (*this); - } - - ~EventHandler() override - { - jassert (hostRunLoops.empty()); - - LinuxEventLoopInternal::deregisterLinuxEventLoopListener (*this); - - if (! messageThread->isRunning()) - hostMessageThreadState.setStateWithAction (HostMessageThreadAttached::no, - [this]() { messageThread->start(); }); - } - - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - return testFor (*this, targetIID, UniqueBase{}).extract (obj); - } - - void PLUGIN_API onFDIsSet (Steinberg::Linux::FileDescriptor fd) override - { - updateCurrentMessageThread(); - LinuxEventLoopInternal::invokeEventLoopCallbackForFd (fd); - } - - //============================================================================== - void registerHandlerForFrame (IPlugFrame* plugFrame) - { - if (auto* runLoop = getRunLoopFromFrame (plugFrame)) - { - refreshAttachedEventLoop ([this, runLoop] { hostRunLoops.insert (runLoop); }); - updateCurrentMessageThread(); - } - } - - void unregisterHandlerForFrame (IPlugFrame* plugFrame) - { - if (auto* runLoop = getRunLoopFromFrame (plugFrame)) - refreshAttachedEventLoop ([this, runLoop] { hostRunLoops.erase (runLoop); }); - } - - /* Asserts if it can be established that the calling thread is different from the host's message - thread. - - On Linux this can only be determined if the host has already registered its run loop. Until - then JUCE messages are serviced by a background thread internal to the plugin. - */ - static void assertHostMessageThread() - { - hostMessageThreadState.assertHostMessageThread(); - } - -private: - //============================================================================== - /* Connects all known FDs to a single host event loop instance. */ - class AttachedEventLoop - { - public: - AttachedEventLoop() = default; - - AttachedEventLoop (Steinberg::Linux::IRunLoop* loopIn, Steinberg::Linux::IEventHandler* handlerIn) - : loop (loopIn), handler (handlerIn) - { - for (auto& fd : LinuxEventLoopInternal::getRegisteredFds()) - loop->registerEventHandler (handler, fd); - } - - AttachedEventLoop (AttachedEventLoop&& other) noexcept - { - swap (other); - } - - AttachedEventLoop& operator= (AttachedEventLoop&& other) noexcept - { - swap (other); - return *this; - } - - AttachedEventLoop (const AttachedEventLoop&) = delete; - AttachedEventLoop& operator= (const AttachedEventLoop&) = delete; - - ~AttachedEventLoop() - { - if (loop == nullptr) - return; - - loop->unregisterEventHandler (handler); - } - - private: - void swap (AttachedEventLoop& other) - { - std::swap (other.loop, loop); - std::swap (other.handler, handler); - } - - Steinberg::Linux::IRunLoop* loop = nullptr; - Steinberg::Linux::IEventHandler* handler = nullptr; - }; - - //============================================================================== - static Steinberg::Linux::IRunLoop* getRunLoopFromFrame (IPlugFrame* plugFrame) - { - Steinberg::Linux::IRunLoop* runLoop = nullptr; - - if (plugFrame != nullptr) - plugFrame->queryInterface (Steinberg::Linux::IRunLoop::iid, (void**) &runLoop); - - jassert (runLoop != nullptr); - return runLoop; - } - - void updateCurrentMessageThread() - { - if (! MessageManager::getInstance()->isThisTheMessageThread()) - { - if (messageThread->isRunning()) - messageThread->stop(); - - hostMessageThreadState.setStateWithAction (HostMessageThreadAttached::yes, - [] { MessageManager::getInstance()->setCurrentThreadAsMessageThread(); }); - } - } - - void fdCallbacksChanged() override - { - // The set of active FDs has changed, so deregister from the current event loop and then - // re-register the current set of FDs. - refreshAttachedEventLoop ([]{}); - } - - /* Deregisters from any attached event loop, updates the set of known event loops, and then - attaches all FDs to the first known event loop. - - The same event loop instance is shared between all plugin instances. Every time an event - loop is added or removed, this function should be called to register all FDs with a - suitable event loop. - - Note that there's no API to deregister a single FD for a given event loop. Instead, we must - deregister all FDs, and then register all known FDs again. - */ - template - void refreshAttachedEventLoop (Callback&& modifyKnownRunLoops) - { - // Deregister the old event loop. - // It's important to call the destructor from the old attached loop before calling the - // constructor of the new attached loop. - attachedEventLoop = AttachedEventLoop(); - - modifyKnownRunLoops(); - - // If we still know about an extant event loop, attach to it. - if (hostRunLoops.begin() != hostRunLoops.end()) - attachedEventLoop = AttachedEventLoop (*hostRunLoops.begin(), this); - } - - SharedResourcePointer messageThread; - - std::atomic refCount { 1 }; - - std::multiset hostRunLoops; - AttachedEventLoop attachedEventLoop; - - static HostMessageThreadState hostMessageThreadState; - - //============================================================================== - JUCE_DECLARE_NON_MOVEABLE (EventHandler) - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler) -}; - -HostMessageThreadState EventHandler::hostMessageThreadState; - -#endif - -static void assertHostMessageThread() -{ - #if JUCE_LINUX || JUCE_BSD - EventHandler::assertHostMessageThread(); - #else - JUCE_ASSERT_MESSAGE_THREAD - #endif -} - -//============================================================================== -class InParameterChangedCallbackSetter -{ -public: - explicit InParameterChangedCallbackSetter (bool& ref) - : inner ([&]() -> auto& { jassert (! ref); return ref; }(), true, false) {} - -private: - ScopedValueSetter inner; -}; - -template -static QueryInterfaceResult queryAdditionalInterfaces (AudioProcessor* processor, - const TUID targetIID, - Member&& member) -{ - if (processor == nullptr) - return {}; - - void* obj = nullptr; - - if (auto* extensions = dynamic_cast (processor)) - { - const auto result = (extensions->*member) (targetIID, &obj); - return { result, obj }; - } - - return {}; -} - -static tresult extractResult (const QueryInterfaceResult& userInterface, - const InterfaceResultWithDeferredAddRef& juceInterface, - void** obj) -{ - if (userInterface.isOk() && juceInterface.isOk()) - { - // If you hit this assertion, you've provided a custom implementation of an interface - // that JUCE implements already. As a result, your plugin may not behave correctly. - // Consider removing your custom implementation. - jassertfalse; - - return userInterface.extract (obj); - } - - if (userInterface.isOk()) - return userInterface.extract (obj); - - return juceInterface.extract (obj); -} - -//============================================================================== -class JuceAudioProcessor : public Vst::IUnitInfo -{ -public: - explicit JuceAudioProcessor (AudioProcessor* source) noexcept - : audioProcessor (source) - { - setupParameters(); - } - - virtual ~JuceAudioProcessor() = default; - - AudioProcessor* get() const noexcept { return audioProcessor.get(); } - - JUCE_DECLARE_VST3_COM_QUERY_METHODS - JUCE_DECLARE_VST3_COM_REF_METHODS - - //============================================================================== - enum InternalParameters - { - paramPreset = 0x70727374, // 'prst' - paramMidiControllerOffset = 0x6d636d00, // 'mdm*' - paramBypass = 0x62797073 // 'byps' - }; - - //============================================================================== - Steinberg::int32 PLUGIN_API getUnitCount() override - { - return parameterGroups.size() + 1; - } - - tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override - { - if (unitIndex == 0) - { - info.id = Vst::kRootUnitId; - info.parentUnitId = Vst::kNoParentUnitId; - info.programListId = getProgramListCount() > 0 - ? static_cast (programParamID) - : Vst::kNoProgramListId; - - toString128 (info.name, TRANS ("Root Unit")); - - return kResultTrue; - } - - if (auto* group = parameterGroups[unitIndex - 1]) - { - info.id = JuceAudioProcessor::getUnitID (group); - info.parentUnitId = JuceAudioProcessor::getUnitID (group->getParent()); - info.programListId = Vst::kNoProgramListId; - - toString128 (info.name, group->getName()); - - return kResultTrue; - } - - return kResultFalse; - } - - Steinberg::int32 PLUGIN_API getProgramListCount() override - { - if (audioProcessor->getNumPrograms() > 0) - return 1; - - return 0; - } - - tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override - { - if (listIndex == 0) - { - info.id = static_cast (programParamID); - info.programCount = static_cast (audioProcessor->getNumPrograms()); - - toString128 (info.name, TRANS ("Factory Presets")); - - return kResultTrue; - } - - jassertfalse; - zerostruct (info); - return kResultFalse; - } - - tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override - { - if (listId == static_cast (programParamID) - && isPositiveAndBelow ((int) programIndex, audioProcessor->getNumPrograms())) - { - toString128 (name, audioProcessor->getProgramName ((int) programIndex)); - return kResultTrue; - } - - jassertfalse; - toString128 (name, juce::String()); - return kResultFalse; - } - - tresult PLUGIN_API getProgramInfo (Vst::ProgramListID, Steinberg::int32, Vst::CString, Vst::String128) override { return kNotImplemented; } - tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID, Steinberg::int32) override { return kNotImplemented; } - tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID, Steinberg::int32, Steinberg::int16, Vst::String128) override { return kNotImplemented; } - tresult PLUGIN_API selectUnit (Vst::UnitID) override { return kNotImplemented; } - tresult PLUGIN_API setUnitProgramData (Steinberg::int32, Steinberg::int32, IBStream*) override { return kNotImplemented; } - Vst::UnitID PLUGIN_API getSelectedUnit() override { return Vst::kRootUnitId; } - - tresult PLUGIN_API getUnitByBus (Vst::MediaType, Vst::BusDirection, Steinberg::int32, Steinberg::int32, Vst::UnitID& unitId) override - { - unitId = Vst::kRootUnitId; - return kResultOk; - } - - //============================================================================== - inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept - { - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - return static_cast (paramIndex); - #else - return vstParamIDs.getReference (paramIndex); - #endif - } - - AudioProcessorParameter* getParamForVSTParamID (Vst::ParamID paramID) const noexcept - { - return paramMap[static_cast (paramID)]; - } - - AudioProcessorParameter* getBypassParameter() const noexcept - { - return getParamForVSTParamID (bypassParamID); - } - - AudioProcessorParameter* getProgramParameter() const noexcept - { - return getParamForVSTParamID (programParamID); - } - - static Vst::UnitID getUnitID (const AudioProcessorParameterGroup* group) - { - if (group == nullptr || group->getParent() == nullptr) - return Vst::kRootUnitId; - - // From the VST3 docs (also applicable to unit IDs!): - // Up to 2^31 parameters can be exported with id range [0, 2147483648] - // (the range [2147483649, 429496729] is reserved for host application). - auto unitID = group->getID().hashCode() & 0x7fffffff; - - // If you hit this assertion then your group ID is hashing to a value - // reserved by the VST3 SDK. Please use a different group ID. - jassert (unitID != Vst::kRootUnitId); - - return unitID; - } - - const Array& getParamIDs() const noexcept { return vstParamIDs; } - Vst::ParamID getBypassParamID() const noexcept { return bypassParamID; } - Vst::ParamID getProgramParamID() const noexcept { return programParamID; } - bool isBypassRegularParameter() const noexcept { return bypassIsRegularParameter; } - - int findCacheIndexForParamID (Vst::ParamID paramID) const noexcept { return vstParamIDs.indexOf (paramID); } - - void setParameterValue (Steinberg::int32 paramIndex, float value) - { - cachedParamValues.set (paramIndex, value); - } - - template - void forAllChangedParameters (Callback&& callback) - { - cachedParamValues.ifSet ([&] (Steinberg::int32 index, float value) - { - callback (cachedParamValues.getParamID (index), value); - }); - } - - bool isUsingManagedParameters() const noexcept { return juceParameters.isUsingManagedParameters(); } - - //============================================================================== - static const FUID iid; - -private: - //============================================================================== - void setupParameters() - { - parameterGroups = audioProcessor->getParameterTree().getSubgroups (true); - - #if JUCE_DEBUG - auto allGroups = parameterGroups; - allGroups.add (&audioProcessor->getParameterTree()); - std::unordered_set unitIDs; - - for (auto* group : allGroups) - { - auto insertResult = unitIDs.insert (getUnitID (group)); - - // If you hit this assertion then either a group ID is not unique or - // you are very unlucky and a hashed group ID is not unique - jassert (insertResult.second); - } - #endif - - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - const bool forceLegacyParamIDs = true; - #else - const bool forceLegacyParamIDs = false; - #endif - - juceParameters.update (*audioProcessor, forceLegacyParamIDs); - auto numParameters = juceParameters.getNumParameters(); - - bool vst3WrapperProvidedBypassParam = false; - auto* bypassParameter = audioProcessor->getBypassParameter(); - - if (bypassParameter == nullptr) - { - vst3WrapperProvidedBypassParam = true; - ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false)); - bypassParameter = ownedBypassParameter.get(); - } - - // if the bypass parameter is not part of the exported parameters that the plug-in supports - // then add it to the end of the list as VST3 requires the bypass parameter to be exported! - bypassIsRegularParameter = juceParameters.contains (audioProcessor->getBypassParameter()); - - if (! bypassIsRegularParameter) - juceParameters.addNonOwning (bypassParameter); - - int i = 0; - for (auto* juceParam : juceParameters) - { - bool isBypassParameter = (juceParam == bypassParameter); - - Vst::ParamID vstParamID = forceLegacyParamIDs ? static_cast (i++) - : generateVSTParamIDForParam (juceParam); - - if (isBypassParameter) - { - // we need to remain backward compatible with the old bypass id - if (vst3WrapperProvidedBypassParam) - { - JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6240) - vstParamID = static_cast ((isUsingManagedParameters() && ! forceLegacyParamIDs) ? paramBypass : numParameters); - JUCE_END_IGNORE_WARNINGS_MSVC - } - - bypassParamID = vstParamID; - } - - vstParamIDs.add (vstParamID); - paramMap.set (static_cast (vstParamID), juceParam); - } - - auto numPrograms = audioProcessor->getNumPrograms(); - - if (numPrograms > 1) - { - ownedProgramParameter = std::make_unique ("juceProgramParameter", "Program", - 0, numPrograms - 1, - audioProcessor->getCurrentProgram()); - - juceParameters.addNonOwning (ownedProgramParameter.get()); - - if (forceLegacyParamIDs) - programParamID = static_cast (i++); - - vstParamIDs.add (programParamID); - paramMap.set (static_cast (programParamID), ownedProgramParameter.get()); - } - - cachedParamValues = CachedParamValues { { vstParamIDs.begin(), vstParamIDs.end() } }; - } - - Vst::ParamID generateVSTParamIDForParam (const AudioProcessorParameter* param) - { - auto juceParamID = LegacyAudioParameter::getParamID (param, false); - - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS - return static_cast (juceParamID.getIntValue()); - #else - auto paramHash = static_cast (juceParamID.hashCode()); - - #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS - // studio one doesn't like negative parameters - paramHash &= ~(((Vst::ParamID) 1) << (sizeof (Vst::ParamID) * 8 - 1)); - #endif - - return paramHash; - #endif - } - - //============================================================================== - Array vstParamIDs; - CachedParamValues cachedParamValues; - Vst::ParamID bypassParamID = 0, programParamID = static_cast (paramPreset); - bool bypassIsRegularParameter = false; - - //============================================================================== - std::atomic refCount { 0 }; - std::unique_ptr audioProcessor; - - //============================================================================== - LegacyAudioParametersWrapper juceParameters; - HashMap paramMap; - std::unique_ptr ownedBypassParameter, ownedProgramParameter; - Array parameterGroups; - - JuceAudioProcessor() = delete; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAudioProcessor) -}; - -class JuceVST3Component; - -static thread_local bool inParameterChangedCallback = false; - -static void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) -{ - if (param.getValue() == newValue) - return; - - const InParameterChangedCallbackSetter scopedSetter { inParameterChangedCallback }; - param.setValueNotifyingHost (newValue); -} - -//============================================================================== -class JuceVST3EditController : public Vst::EditController, - public Vst::IMidiMapping, - public Vst::IUnitInfo, - public Vst::ChannelContext::IInfoListener, - #if JucePlugin_Enable_ARA - public Presonus::IPlugInViewEmbedding, - #endif - public AudioProcessorListener, - private ComponentRestarter::Listener -{ -public: - explicit JuceVST3EditController (Vst::IHostApplication* host) - { - if (host != nullptr) - host->queryInterface (FUnknown::iid, (void**) &hostContext); - - blueCatPatchwork |= isBlueCatHost (host); - } - - //============================================================================== - static const FUID iid; - - //============================================================================== - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Winconsistent-missing-override") - - REFCOUNT_METHODS (ComponentBase) - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto userProvidedInterface = queryAdditionalInterfaces (getPluginInstance(), - targetIID, - &VST3ClientExtensions::queryIEditController); - - const auto juceProvidedInterface = queryInterfaceInternal (targetIID); - - return extractResult (userProvidedInterface, juceProvidedInterface, obj); - } - - //============================================================================== - tresult PLUGIN_API initialize (FUnknown* context) override - { - if (hostContext != context) - hostContext = context; - - blueCatPatchwork |= isBlueCatHost (context); - - return kResultTrue; - } - - tresult PLUGIN_API terminate() override - { - if (auto* pluginInstance = getPluginInstance()) - pluginInstance->removeListener (this); - - audioProcessor = nullptr; - - return EditController::terminate(); - } - - //============================================================================== - struct Param : public Vst::Parameter - { - Param (JuceVST3EditController& editController, AudioProcessorParameter& p, - Vst::ParamID vstParamID, Vst::UnitID vstUnitID, - bool isBypassParameter) - : owner (editController), param (p) - { - info.id = vstParamID; - info.unitId = vstUnitID; - - updateParameterInfo(); - - info.stepCount = (Steinberg::int32) 0; - - #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE - if (param.isDiscrete()) - #endif - { - const int numSteps = param.getNumSteps(); - info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0); - } - - info.defaultNormalizedValue = param.getDefaultValue(); - jassert (info.defaultNormalizedValue >= 0 && info.defaultNormalizedValue <= 1.0f); - - // Is this a meter? - if ((((unsigned int) param.getCategory() & 0xffff0000) >> 16) == 2) - info.flags = Vst::ParameterInfo::kIsReadOnly; - else - info.flags = param.isAutomatable() ? Vst::ParameterInfo::kCanAutomate : 0; - - if (isBypassParameter) - info.flags |= Vst::ParameterInfo::kIsBypass; - - valueNormalized = info.defaultNormalizedValue; - } - - bool updateParameterInfo() - { - auto updateParamIfChanged = [] (Vst::String128& paramToUpdate, const String& newValue) - { - if (juce::toString (paramToUpdate) == newValue) - return false; - - toString128 (paramToUpdate, newValue); - return true; - }; - - auto anyUpdated = updateParamIfChanged (info.title, param.getName (128)); - anyUpdated |= updateParamIfChanged (info.shortTitle, param.getName (8)); - anyUpdated |= updateParamIfChanged (info.units, param.getLabel()); - - return anyUpdated; - } - - bool setNormalized (Vst::ParamValue v) override - { - v = jlimit (0.0, 1.0, v); - - if (v != valueNormalized) - { - valueNormalized = v; - - // Only update the AudioProcessor here if we're not playing, - // otherwise we get parallel streams of parameter value updates - // during playback - if (! owner.vst3IsPlaying) - setValueAndNotifyIfChanged (param, (float) v); - - changed(); - return true; - } - - return false; - } - - void toString (Vst::ParamValue value, Vst::String128 result) const override - { - if (LegacyAudioParameter::isLegacy (¶m)) - // remain backward-compatible with old JUCE code - toString128 (result, param.getCurrentValueAsText()); - else - toString128 (result, param.getText ((float) value, 128)); - } - - bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override - { - if (! LegacyAudioParameter::isLegacy (¶m)) - { - outValueNormalized = param.getValueForText (getStringFromVstTChars (text)); - return true; - } - - return false; - } - - static String getStringFromVstTChars (const Vst::TChar* text) - { - return juce::String (juce::CharPointer_UTF16 (reinterpret_cast (text))); - } - - Vst::ParamValue toPlain (Vst::ParamValue v) const override { return v; } - Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v; } - - private: - JuceVST3EditController& owner; - AudioProcessorParameter& param; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Param) - }; - - //============================================================================== - struct ProgramChangeParameter : public Vst::Parameter - { - ProgramChangeParameter (AudioProcessor& p, Vst::ParamID vstParamID) - : owner (p) - { - jassert (owner.getNumPrograms() > 1); - - info.id = vstParamID; - toString128 (info.title, "Program"); - toString128 (info.shortTitle, "Program"); - toString128 (info.units, ""); - info.stepCount = owner.getNumPrograms() - 1; - info.defaultNormalizedValue = static_cast (owner.getCurrentProgram()) - / static_cast (info.stepCount); - info.unitId = Vst::kRootUnitId; - info.flags = Vst::ParameterInfo::kIsProgramChange | Vst::ParameterInfo::kCanAutomate; - } - - ~ProgramChangeParameter() override = default; - - bool setNormalized (Vst::ParamValue v) override - { - const auto programValue = getProgramValueFromNormalised (v); - - if (programValue != owner.getCurrentProgram()) - owner.setCurrentProgram (programValue); - - if (valueNormalized != v) - { - valueNormalized = v; - changed(); - - return true; - } - - return false; - } - - void toString (Vst::ParamValue value, Vst::String128 result) const override - { - toString128 (result, owner.getProgramName (roundToInt (value * info.stepCount))); - } - - bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override - { - auto paramValueString = getStringFromVstTChars (text); - auto n = owner.getNumPrograms(); - - for (int i = 0; i < n; ++i) - { - if (paramValueString == owner.getProgramName (i)) - { - outValueNormalized = static_cast (i) / info.stepCount; - return true; - } - } - - return false; - } - - static String getStringFromVstTChars (const Vst::TChar* text) - { - return String (CharPointer_UTF16 (reinterpret_cast (text))); - } - - Steinberg::int32 getProgramValueFromNormalised (Vst::ParamValue v) const - { - return jmin (info.stepCount, (Steinberg::int32) (v * (info.stepCount + 1))); - } - - Vst::ParamValue toPlain (Vst::ParamValue v) const override { return getProgramValueFromNormalised (v); } - Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v / info.stepCount; } - - private: - AudioProcessor& owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter) - }; - - //============================================================================== - tresult PLUGIN_API setChannelContextInfos (Vst::IAttributeList* list) override - { - if (auto* instance = getPluginInstance()) - { - if (list != nullptr) - { - AudioProcessor::TrackProperties trackProperties; - - { - Vst::String128 channelName; - if (list->getString (Vst::ChannelContext::kChannelNameKey, channelName, sizeof (channelName)) == kResultTrue) - trackProperties.name = toString (channelName); - } - - { - int64 colour; - if (list->getInt (Vst::ChannelContext::kChannelColorKey, colour) == kResultTrue) - trackProperties.colour = Colour (Vst::ChannelContext::GetRed ((uint32) colour), Vst::ChannelContext::GetGreen ((uint32) colour), - Vst::ChannelContext::GetBlue ((uint32) colour), Vst::ChannelContext::GetAlpha ((uint32) colour)); - } - - - - if (MessageManager::getInstance()->isThisTheMessageThread()) - instance->updateTrackProperties (trackProperties); - else - MessageManager::callAsync ([trackProperties, instance] - { instance->updateTrackProperties (trackProperties); }); - } - } - - return kResultOk; - } - - //============================================================================== - #if JucePlugin_Enable_ARA - Steinberg::TBool PLUGIN_API isViewEmbeddingSupported() override - { - if (auto* pluginInstance = getPluginInstance()) - return (Steinberg::TBool) dynamic_cast (pluginInstance)->isEditorView(); - return (Steinberg::TBool) false; - } - - Steinberg::tresult PLUGIN_API setViewIsEmbedded (Steinberg::IPlugView* /*view*/, Steinberg::TBool /*embedded*/) override - { - return kResultOk; - } - #endif - - //============================================================================== - tresult PLUGIN_API setComponentState (IBStream* stream) override - { - // As an IEditController member, the host should only call this from the message thread. - assertHostMessageThread(); - - if (auto* pluginInstance = getPluginInstance()) - { - for (auto vstParamId : audioProcessor->getParamIDs()) - { - auto paramValue = [&] - { - if (vstParamId == audioProcessor->getProgramParamID()) - return EditController::plainParamToNormalized (audioProcessor->getProgramParamID(), - pluginInstance->getCurrentProgram()); - - return (double) audioProcessor->getParamForVSTParamID (vstParamId)->getValue(); - }(); - - setParamNormalized (vstParamId, paramValue); - } - } - - if (auto* handler = getComponentHandler()) - handler->restartComponent (Vst::kParamValuesChanged); - - return Vst::EditController::setComponentState (stream); - } - - void setAudioProcessor (JuceAudioProcessor* audioProc) - { - if (audioProcessor != audioProc) - installAudioProcessor (audioProc); - } - - tresult PLUGIN_API connect (IConnectionPoint* other) override - { - if (other != nullptr && audioProcessor == nullptr) - { - auto result = ComponentBase::connect (other); - - if (! audioProcessor.loadFrom (other)) - sendIntMessage ("JuceVST3EditController", (Steinberg::int64) (pointer_sized_int) this); - else - installAudioProcessor (audioProcessor); - - return result; - } - - jassertfalse; - return kResultFalse; - } - - //============================================================================== - tresult PLUGIN_API getMidiControllerAssignment ([[maybe_unused]] Steinberg::int32 busIndex, - [[maybe_unused]] Steinberg::int16 channel, - [[maybe_unused]] Vst::CtrlNumber midiControllerNumber, - [[maybe_unused]] Vst::ParamID& resultID) override - { - #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS - resultID = midiControllerToParameter[channel][midiControllerNumber]; - return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments - #else - return kResultFalse; - #endif - } - - // Converts an incoming parameter index to a MIDI controller: - bool getMidiControllerForParameter (Vst::ParamID index, int& channel, int& ctrlNumber) - { - auto mappedIndex = static_cast (index - parameterToMidiControllerOffset); - - if (isPositiveAndBelow (mappedIndex, numElementsInArray (parameterToMidiController))) - { - auto& mc = parameterToMidiController[mappedIndex]; - - if (mc.channel != -1 && mc.ctrlNumber != -1) - { - channel = jlimit (1, 16, mc.channel + 1); - ctrlNumber = mc.ctrlNumber; - return true; - } - } - - return false; - } - - inline bool isMidiControllerParamID (Vst::ParamID paramID) const noexcept - { - return (paramID >= parameterToMidiControllerOffset - && isPositiveAndBelow (paramID - parameterToMidiControllerOffset, - static_cast (numElementsInArray (parameterToMidiController)))); - } - - //============================================================================== - Steinberg::int32 PLUGIN_API getUnitCount() override - { - if (audioProcessor != nullptr) - return audioProcessor->getUnitCount(); - - jassertfalse; - return 1; - } - - tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override - { - if (audioProcessor != nullptr) - return audioProcessor->getUnitInfo (unitIndex, info); - - jassertfalse; - if (unitIndex == 0) - { - info.id = Vst::kRootUnitId; - info.parentUnitId = Vst::kNoParentUnitId; - info.programListId = Vst::kNoProgramListId; - - toString128 (info.name, TRANS ("Root Unit")); - - return kResultTrue; - } - - zerostruct (info); - return kResultFalse; - } - - Steinberg::int32 PLUGIN_API getProgramListCount() override - { - if (audioProcessor != nullptr) - return audioProcessor->getProgramListCount(); - - jassertfalse; - return 0; - } - - tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override - { - if (audioProcessor != nullptr) - return audioProcessor->getProgramListInfo (listIndex, info); - - jassertfalse; - zerostruct (info); - return kResultFalse; - } - - tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override - { - if (audioProcessor != nullptr) - return audioProcessor->getProgramName (listId, programIndex, name); - - jassertfalse; - toString128 (name, juce::String()); - return kResultFalse; - } - - tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex, - Vst::CString attributeId, Vst::String128 attributeValue) override - { - if (audioProcessor != nullptr) - return audioProcessor->getProgramInfo (listId, programIndex, attributeId, attributeValue); - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override - { - if (audioProcessor != nullptr) - return audioProcessor->hasProgramPitchNames (listId, programIndex); - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex, - Steinberg::int16 midiPitch, Vst::String128 name) override - { - if (audioProcessor != nullptr) - return audioProcessor->getProgramPitchName (listId, programIndex, midiPitch, name); - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override - { - if (audioProcessor != nullptr) - return audioProcessor->selectUnit (unitId); - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex, - Steinberg::IBStream* data) override - { - if (audioProcessor != nullptr) - return audioProcessor->setUnitProgramData (listOrUnitId, programIndex, data); - - jassertfalse; - return kResultFalse; - } - - Vst::UnitID PLUGIN_API getSelectedUnit() override - { - if (audioProcessor != nullptr) - return audioProcessor->getSelectedUnit(); - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex, - Steinberg::int32 channel, Vst::UnitID& unitId) override - { - if (audioProcessor != nullptr) - return audioProcessor->getUnitByBus (type, dir, busIndex, channel, unitId); - - jassertfalse; - return kResultFalse; - } - - //============================================================================== - IPlugView* PLUGIN_API createView (const char* name) override - { - if (auto* pluginInstance = getPluginInstance()) - { - const auto mayCreateEditor = pluginInstance->hasEditor() - && name != nullptr - && std::strcmp (name, Vst::ViewType::kEditor) == 0 - && (pluginInstance->getActiveEditor() == nullptr - || getHostType().isAdobeAudition() - || getHostType().isPremiere()); - - if (mayCreateEditor) - return new JuceVST3Editor (*this, *audioProcessor); - } - - return nullptr; - } - - //============================================================================== - void beginGesture (Vst::ParamID vstParamId) - { - if (! inSetState && MessageManager::getInstance()->isThisTheMessageThread()) - beginEdit (vstParamId); - } - - void endGesture (Vst::ParamID vstParamId) - { - if (! inSetState && MessageManager::getInstance()->isThisTheMessageThread()) - endEdit (vstParamId); - } - - void paramChanged (Steinberg::int32 parameterIndex, Vst::ParamID vstParamId, double newValue) - { - if (inParameterChangedCallback || inSetState) - return; - - if (MessageManager::getInstance()->isThisTheMessageThread()) - { - // NB: Cubase has problems if performEdit is called without setParamNormalized - EditController::setParamNormalized (vstParamId, newValue); - performEdit (vstParamId, newValue); - } - else - { - audioProcessor->setParameterValue (parameterIndex, (float) newValue); - } - } - - //============================================================================== - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override - { - beginGesture (audioProcessor->getVSTParamIDForIndex (index)); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override - { - endGesture (audioProcessor->getVSTParamIDForIndex (index)); - } - - void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override - { - paramChanged (index, audioProcessor->getVSTParamIDForIndex (index), newValue); - } - - void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override - { - int32 flags = 0; - - if (details.parameterInfoChanged) - { - for (int32 i = 0; i < parameters.getParameterCount(); ++i) - if (auto* param = dynamic_cast (parameters.getParameterByIndex (i))) - if (param->updateParameterInfo() && (flags & Vst::kParamTitlesChanged) == 0) - flags |= Vst::kParamTitlesChanged; - } - - if (auto* pluginInstance = getPluginInstance()) - { - if (details.programChanged) - { - const auto programParameterId = audioProcessor->getProgramParamID(); - - if (audioProcessor->getParamForVSTParamID (programParameterId) != nullptr) - { - const auto currentProgram = pluginInstance->getCurrentProgram(); - const auto paramValue = roundToInt (EditController::normalizedParamToPlain (programParameterId, - EditController::getParamNormalized (programParameterId))); - - if (currentProgram != paramValue) - { - beginGesture (programParameterId); - paramChanged (audioProcessor->findCacheIndexForParamID (programParameterId), - programParameterId, - EditController::plainParamToNormalized (programParameterId, currentProgram)); - endGesture (programParameterId); - - flags |= Vst::kParamValuesChanged; - } - } - } - - auto latencySamples = pluginInstance->getLatencySamples(); - - #if JucePlugin_Enable_ARA - jassert (latencySamples == 0 || ! dynamic_cast (pluginInstance)->isBoundToARA()); - #endif - - if (details.latencyChanged && latencySamples != lastLatencySamples) - { - flags |= Vst::kLatencyChanged; - lastLatencySamples = latencySamples; - } - } - - if (details.nonParameterStateChanged) - flags |= pluginShouldBeMarkedDirtyFlag; - - if (inSetupProcessing) - flags &= Vst::kLatencyChanged; - - componentRestarter.restart (flags); - } - - //============================================================================== - AudioProcessor* getPluginInstance() const noexcept - { - if (audioProcessor != nullptr) - return audioProcessor->get(); - - return nullptr; - } - - static constexpr auto pluginShouldBeMarkedDirtyFlag = 1 << 16; - -private: - bool isBlueCatHost (FUnknown* context) const - { - // We can't use the normal PluginHostType mechanism here because that will give us the name - // of the host process. However, this plugin instance might be loaded in an instance of - // the BlueCat PatchWork host, which might itself be a plugin. - - VSTComSmartPtr host; - host.loadFrom (context); - - if (host == nullptr) - return false; - - Vst::String128 name; - - if (host->getName (name) != kResultOk) - return false; - - const auto hostName = toString (name); - return hostName.contains ("Blue Cat's VST3 Host"); - } - - friend class JuceVST3Component; - friend struct Param; - - //============================================================================== - VSTComSmartPtr audioProcessor; - - struct MidiController - { - int channel = -1, ctrlNumber = -1; - }; - - ComponentRestarter componentRestarter { *this }; - - enum { numMIDIChannels = 16 }; - Vst::ParamID parameterToMidiControllerOffset; - MidiController parameterToMidiController[(int) numMIDIChannels * (int) Vst::kCountCtrlNumber]; - Vst::ParamID midiControllerToParameter[numMIDIChannels][Vst::kCountCtrlNumber]; - - void restartComponentOnMessageThread (int32 flags) override - { - if ((flags & pluginShouldBeMarkedDirtyFlag) != 0) - setDirty (true); - - flags &= ~pluginShouldBeMarkedDirtyFlag; - - if (auto* handler = componentHandler) - handler->restartComponent (flags); - } - - //============================================================================== - struct OwnedParameterListener : public AudioProcessorParameter::Listener - { - OwnedParameterListener (JuceVST3EditController& editController, - AudioProcessorParameter& parameter, - Vst::ParamID paramID, - int cacheIndex) - : owner (editController), - vstParamID (paramID), - parameterIndex (cacheIndex) - { - // We shouldn't be using an OwnedParameterListener for parameters that have - // been added directly to the AudioProcessor. We observe those via the - // normal audioProcessorParameterChanged mechanism. - jassert (parameter.getParameterIndex() == -1); - // The parameter must have a non-negative index in the parameter cache. - jassert (parameterIndex >= 0); - parameter.addListener (this); - } - - void parameterValueChanged (int, float newValue) override - { - owner.paramChanged (parameterIndex, vstParamID, newValue); - } - - void parameterGestureChanged (int, bool gestureIsStarting) override - { - if (gestureIsStarting) - owner.beginGesture (vstParamID); - else - owner.endGesture (vstParamID); - } - - JuceVST3EditController& owner; - const Vst::ParamID vstParamID = Vst::kNoParamId; - const int parameterIndex = -1; - }; - - std::vector> ownedParameterListeners; - - //============================================================================== - bool inSetState = false; - std::atomic vst3IsPlaying { false }, - inSetupProcessing { false }; - - int lastLatencySamples = 0; - bool blueCatPatchwork = isBlueCatHost (hostContext.get()); - - #if ! JUCE_MAC - float lastScaleFactorReceived = 1.0f; - #endif - - InterfaceResultWithDeferredAddRef queryInterfaceInternal (const TUID targetIID) - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - SharedBase{}, - UniqueBase{}, - #if JucePlugin_Enable_ARA - UniqueBase{}, - #endif - SharedBase{}); - - if (result.isOk()) - return result; - - if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) - return { kResultOk, audioProcessor.get() }; - - return {}; - } - - void installAudioProcessor (const VSTComSmartPtr& newAudioProcessor) - { - audioProcessor = newAudioProcessor; - - if (auto* extensions = dynamic_cast (audioProcessor->get())) - { - extensions->setIComponentHandler (componentHandler); - extensions->setIHostApplication (hostContext.get()); - } - - if (auto* pluginInstance = getPluginInstance()) - { - lastLatencySamples = pluginInstance->getLatencySamples(); - - pluginInstance->addListener (this); - - // as the bypass is not part of the regular parameters we need to listen for it explicitly - if (! audioProcessor->isBypassRegularParameter()) - { - const auto paramID = audioProcessor->getBypassParamID(); - ownedParameterListeners.push_back (std::make_unique (*this, - *audioProcessor->getParamForVSTParamID (paramID), - paramID, - audioProcessor->findCacheIndexForParamID (paramID))); - } - - if (parameters.getParameterCount() <= 0) - { - auto n = audioProcessor->getParamIDs().size(); - - for (int i = 0; i < n; ++i) - { - auto vstParamID = audioProcessor->getVSTParamIDForIndex (i); - - if (vstParamID == audioProcessor->getProgramParamID()) - continue; - - auto* juceParam = audioProcessor->getParamForVSTParamID (vstParamID); - auto* parameterGroup = pluginInstance->getParameterTree().getGroupsForParameter (juceParam).getLast(); - auto unitID = JuceAudioProcessor::getUnitID (parameterGroup); - - parameters.addParameter (new Param (*this, *juceParam, vstParamID, unitID, - (vstParamID == audioProcessor->getBypassParamID()))); - } - - const auto programParamId = audioProcessor->getProgramParamID(); - - if (auto* programParam = audioProcessor->getParamForVSTParamID (programParamId)) - { - ownedParameterListeners.push_back (std::make_unique (*this, - *programParam, - programParamId, - audioProcessor->findCacheIndexForParamID (programParamId))); - - parameters.addParameter (new ProgramChangeParameter (*pluginInstance, audioProcessor->getProgramParamID())); - } - } - - #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS - parameterToMidiControllerOffset = static_cast (audioProcessor->isUsingManagedParameters() ? JuceAudioProcessor::paramMidiControllerOffset - : parameters.getParameterCount()); - - initialiseMidiControllerMappings(); - #endif - - audioProcessorChanged (pluginInstance, ChangeDetails().withParameterInfoChanged (true)); - } - } - - void initialiseMidiControllerMappings() - { - for (int c = 0, p = 0; c < numMIDIChannels; ++c) - { - for (int i = 0; i < Vst::kCountCtrlNumber; ++i, ++p) - { - midiControllerToParameter[c][i] = static_cast (p) + parameterToMidiControllerOffset; - parameterToMidiController[p].channel = c; - parameterToMidiController[p].ctrlNumber = i; - - parameters.addParameter (new Vst::Parameter (toString ("MIDI CC " + String (c) + "|" + String (i)), - static_cast (p) + parameterToMidiControllerOffset, nullptr, 0, 0, - 0, Vst::kRootUnitId)); - } - } - } - - void sendIntMessage (const char* idTag, const Steinberg::int64 value) - { - jassert (hostContext != nullptr); - - if (auto* message = allocateMessage()) - { - const FReleaser releaser (message); - message->setMessageID (idTag); - message->getAttributes()->setInt (idTag, value); - sendMessage (message); - } - } - - class EditorContextMenu : public HostProvidedContextMenu - { - public: - EditorContextMenu (AudioProcessorEditor& editorIn, - VSTComSmartPtr contextMenuIn) - : editor (editorIn), contextMenu (contextMenuIn) {} - - PopupMenu getEquivalentPopupMenu() const override - { - using MenuItem = Steinberg::Vst::IContextMenuItem; - using MenuTarget = Steinberg::Vst::IContextMenuTarget; - - struct Submenu - { - PopupMenu menu; - String name; - bool enabled; - }; - - std::vector menuStack (1); - - for (int32_t i = 0, end = contextMenu->getItemCount(); i < end; ++i) - { - MenuItem item{}; - MenuTarget* target = nullptr; - contextMenu->getItem (i, item, &target); - - if ((item.flags & MenuItem::kIsGroupStart) == MenuItem::kIsGroupStart) - { - menuStack.push_back ({ PopupMenu{}, - toString (item.name), - (item.flags & MenuItem::kIsDisabled) == 0 }); - } - else if ((item.flags & MenuItem::kIsGroupEnd) == MenuItem::kIsGroupEnd) - { - const auto back = menuStack.back(); - menuStack.pop_back(); - - if (menuStack.empty()) - { - // malformed menu - jassertfalse; - return {}; - } - - menuStack.back().menu.addSubMenu (back.name, back.menu, back.enabled); - } - else if ((item.flags & MenuItem::kIsSeparator) == MenuItem::kIsSeparator) - { - menuStack.back().menu.addSeparator(); - } - else - { - VSTComSmartPtr ownedTarget (target); - const auto tag = item.tag; - menuStack.back().menu.addItem (toString (item.name), - (item.flags & MenuItem::kIsDisabled) == 0, - (item.flags & MenuItem::kIsChecked) != 0, - [ownedTarget, tag] { ownedTarget->executeMenuItem (tag); }); - } - } - - if (menuStack.size() != 1) - { - // malformed menu - jassertfalse; - return {}; - } - - return menuStack.back().menu; - } - - void showNativeMenu (Point pos) const override - { - const auto scaled = pos * Component::getApproximateScaleFactorForComponent (&editor); - contextMenu->popup (scaled.x, scaled.y); - } - - private: - AudioProcessorEditor& editor; - VSTComSmartPtr contextMenu; - }; - - class EditorHostContext : public AudioProcessorEditorHostContext - { - public: - EditorHostContext (JuceAudioProcessor& processorIn, - AudioProcessorEditor& editorIn, - Steinberg::Vst::IComponentHandler* handler, - Steinberg::IPlugView* viewIn) - : processor (processorIn), editor (editorIn), componentHandler (handler), view (viewIn) {} - - std::unique_ptr getContextMenuForParameter (const AudioProcessorParameter* parameter) const override - { - if (componentHandler == nullptr || view == nullptr) - return {}; - - Steinberg::FUnknownPtr handler (componentHandler); - - if (handler == nullptr) - return {}; - - const auto idToUse = parameter != nullptr ? processor.getVSTParamIDForIndex (parameter->getParameterIndex()) : 0; - const auto menu = VSTComSmartPtr (handler->createContextMenu (view, &idToUse)); - return std::make_unique (editor, menu); - } - - private: - JuceAudioProcessor& processor; - AudioProcessorEditor& editor; - Steinberg::Vst::IComponentHandler* componentHandler = nullptr; - Steinberg::IPlugView* view = nullptr; - }; - - //============================================================================== - class JuceVST3Editor : public Vst::EditorView, - public Steinberg::IPlugViewContentScaleSupport, - private Timer - { - public: - JuceVST3Editor (JuceVST3EditController& ec, JuceAudioProcessor& p) - : EditorView (&ec, nullptr), - owner (&ec), - pluginInstance (*p.get()) - { - createContentWrapperComponentIfNeeded(); - - #if JUCE_MAC - if (getHostType().type == PluginHostType::SteinbergCubase10) - cubase10Workaround.reset (new Cubase10WindowResizeWorkaround (*this)); - #endif - } - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto result = testFor (*this, targetIID, UniqueBase{}); - - if (result.isOk()) - return result.extract (obj); - - return Vst::EditorView::queryInterface (targetIID, obj); - } - - REFCOUNT_METHODS (Vst::EditorView) - - //============================================================================== - tresult PLUGIN_API isPlatformTypeSupported (FIDString type) override - { - if (type != nullptr && pluginInstance.hasEditor()) - { - #if JUCE_WINDOWS - if (strcmp (type, kPlatformTypeHWND) == 0) - #elif JUCE_MAC - if (strcmp (type, kPlatformTypeNSView) == 0 || strcmp (type, kPlatformTypeHIView) == 0) - #elif JUCE_LINUX || JUCE_BSD - if (strcmp (type, kPlatformTypeX11EmbedWindowID) == 0) - #endif - return kResultTrue; - } - - return kResultFalse; - } - - tresult PLUGIN_API attached (void* parent, FIDString type) override - { - if (parent == nullptr || isPlatformTypeSupported (type) == kResultFalse) - return kResultFalse; - - #if JUCE_LINUX || JUCE_BSD - eventHandler->registerHandlerForFrame (plugFrame); - #endif - - systemWindow = parent; - - createContentWrapperComponentIfNeeded(); - - #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD - // If the plugin was last opened at a particular scale, try to reapply that scale here. - // Note that we do this during attach(), rather than in JuceVST3Editor(). During the - // constructor, we don't have a host plugFrame, so - // ContentWrapperComponent::resizeHostWindow() won't do anything, and the content - // wrapper component will be left at the wrong size. - applyScaleFactor (StoredScaleFactor{}.withInternal (owner->lastScaleFactorReceived)); - - // Check the host scale factor *before* calling addToDesktop, so that the initial - // window size during addToDesktop is correct for the current platform scale factor. - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - component->checkHostWindowScaleFactor(); - #endif - - component->setOpaque (true); - component->addToDesktop (0, (void*) systemWindow); - component->setVisible (true); - - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - component->startTimer (500); - #endif - - #else - isNSView = (strcmp (type, kPlatformTypeNSView) == 0); - macHostWindow = juce::attachComponentToWindowRefVST (component.get(), parent, isNSView); - #endif - - component->resizeHostWindow(); - attachedToParent(); - - // Life's too short to faff around with wave lab - if (getHostType().isWavelab()) - startTimer (200); - - return kResultTrue; - } - - tresult PLUGIN_API removed() override - { - if (component != nullptr) - { - #if JUCE_WINDOWS - component->removeFromDesktop(); - #elif JUCE_MAC - if (macHostWindow != nullptr) - { - juce::detachComponentFromWindowRefVST (component.get(), macHostWindow, isNSView); - macHostWindow = nullptr; - } - #endif - - component = nullptr; - } - - #if JUCE_LINUX || JUCE_BSD - eventHandler->unregisterHandlerForFrame (plugFrame); - #endif - - return CPluginView::removed(); - } - - tresult PLUGIN_API onSize (ViewRect* newSize) override - { - if (newSize != nullptr) - { - rect = convertFromHostBounds (*newSize); - - if (component != nullptr) - { - component->setSize (rect.getWidth(), rect.getHeight()); - - #if JUCE_MAC - if (cubase10Workaround != nullptr) - { - cubase10Workaround->triggerAsyncUpdate(); - } - else - #endif - { - if (auto* peer = component->getPeer()) - peer->updateBounds(); - } - } - - return kResultTrue; - } - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API getSize (ViewRect* size) override - { - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - if (getHostType().isAbletonLive() && systemWindow == nullptr) - return kResultFalse; - #endif - - if (size != nullptr && component != nullptr) - { - auto editorBounds = component->getSizeToContainChild(); - - *size = convertToHostBounds ({ 0, 0, editorBounds.getWidth(), editorBounds.getHeight() }); - return kResultTrue; - } - - return kResultFalse; - } - - tresult PLUGIN_API canResize() override - { - if (component != nullptr) - if (auto* editor = component->pluginEditor.get()) - if (editor->isResizable()) - return kResultTrue; - - return kResultFalse; - } - - tresult PLUGIN_API checkSizeConstraint (ViewRect* rectToCheck) override - { - if (rectToCheck != nullptr && component != nullptr) - { - if (auto* editor = component->pluginEditor.get()) - { - if (canResize() == kResultFalse) - { - // Ableton Live will call checkSizeConstraint even if the view returns false - // from canResize. Set the out param to an appropriate size for the editor - // and return. - auto constrainedRect = component->getLocalArea (editor, editor->getLocalBounds()) - .getSmallestIntegerContainer(); - - *rectToCheck = convertFromHostBounds (*rectToCheck); - rectToCheck->right = rectToCheck->left + roundToInt (constrainedRect.getWidth()); - rectToCheck->bottom = rectToCheck->top + roundToInt (constrainedRect.getHeight()); - *rectToCheck = convertToHostBounds (*rectToCheck); - } - else if (auto* constrainer = editor->getConstrainer()) - { - *rectToCheck = convertFromHostBounds (*rectToCheck); - - auto editorBounds = editor->getLocalArea (component.get(), - Rectangle::leftTopRightBottom (rectToCheck->left, rectToCheck->top, - rectToCheck->right, rectToCheck->bottom).toFloat()); - - auto minW = (float) constrainer->getMinimumWidth(); - auto maxW = (float) constrainer->getMaximumWidth(); - auto minH = (float) constrainer->getMinimumHeight(); - auto maxH = (float) constrainer->getMaximumHeight(); - - auto width = jlimit (minW, maxW, editorBounds.getWidth()); - auto height = jlimit (minH, maxH, editorBounds.getHeight()); - - auto aspectRatio = (float) constrainer->getFixedAspectRatio(); - - if (aspectRatio != 0.0) - { - bool adjustWidth = (width / height > aspectRatio); - - if (getHostType().type == PluginHostType::SteinbergCubase9) - { - auto currentEditorBounds = editor->getBounds().toFloat(); - - if (currentEditorBounds.getWidth() == width && currentEditorBounds.getHeight() != height) - adjustWidth = true; - else if (currentEditorBounds.getHeight() == height && currentEditorBounds.getWidth() != width) - adjustWidth = false; - } - - if (adjustWidth) - { - width = height * aspectRatio; - - if (width > maxW || width < minW) - { - width = jlimit (minW, maxW, width); - height = width / aspectRatio; - } - } - else - { - height = width / aspectRatio; - - if (height > maxH || height < minH) - { - height = jlimit (minH, maxH, height); - width = height * aspectRatio; - } - } - } - - auto constrainedRect = component->getLocalArea (editor, Rectangle (width, height)) - .getSmallestIntegerContainer(); - - rectToCheck->right = rectToCheck->left + roundToInt (constrainedRect.getWidth()); - rectToCheck->bottom = rectToCheck->top + roundToInt (constrainedRect.getHeight()); - - *rectToCheck = convertToHostBounds (*rectToCheck); - } - } - - return kResultTrue; - } - - jassertfalse; - return kResultFalse; - } - - tresult PLUGIN_API setContentScaleFactor ([[maybe_unused]] const Steinberg::IPlugViewContentScaleSupport::ScaleFactor factor) override - { - #if ! JUCE_MAC - const auto scaleToApply = [&] - { - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - // Cubase 10 only sends integer scale factors, so correct this for fractional scales - if (getHostType().type != PluginHostType::SteinbergCubase10) - return factor; - - const auto hostWindowScale = (Steinberg::IPlugViewContentScaleSupport::ScaleFactor) getScaleFactorForWindow (static_cast (systemWindow)); - - if (hostWindowScale <= 0.0 || approximatelyEqual (factor, hostWindowScale)) - return factor; - - return hostWindowScale; - #else - return factor; - #endif - }(); - - applyScaleFactor (scaleFactor.withHost (scaleToApply)); - - return kResultTrue; - #else - return kResultFalse; - #endif - } - - private: - void timerCallback() override - { - stopTimer(); - - ViewRect viewRect; - getSize (&viewRect); - onSize (&viewRect); - } - - static ViewRect convertToHostBounds (ViewRect pluginRect) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return pluginRect; - - return { roundToInt ((float) pluginRect.left * desktopScale), - roundToInt ((float) pluginRect.top * desktopScale), - roundToInt ((float) pluginRect.right * desktopScale), - roundToInt ((float) pluginRect.bottom * desktopScale) }; - } - - static ViewRect convertFromHostBounds (ViewRect hostRect) - { - auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); - - if (approximatelyEqual (desktopScale, 1.0f)) - return hostRect; - - return { roundToInt ((float) hostRect.left / desktopScale), - roundToInt ((float) hostRect.top / desktopScale), - roundToInt ((float) hostRect.right / desktopScale), - roundToInt ((float) hostRect.bottom / desktopScale) }; - } - - //============================================================================== - struct ContentWrapperComponent : public Component - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - , public Timer - #endif - { - ContentWrapperComponent (JuceVST3Editor& editor) : owner (editor) - { - setOpaque (true); - setBroughtToFrontOnMouseClick (true); - } - - ~ContentWrapperComponent() override - { - if (pluginEditor != nullptr) - { - PopupMenu::dismissAllActiveMenus(); - pluginEditor->processor.editorBeingDeleted (pluginEditor.get()); - } - } - - void createEditor (AudioProcessor& plugin) - { - pluginEditor.reset (plugin.createEditorIfNeeded()); - - #if JucePlugin_Enable_ARA - jassert (dynamic_cast (pluginEditor.get()) != nullptr); - // for proper view embedding, ARA plug-ins must be resizable - jassert (pluginEditor->isResizable()); - #endif - - if (pluginEditor != nullptr) - { - editorHostContext = std::make_unique (*owner.owner->audioProcessor, - *pluginEditor, - owner.owner->getComponentHandler(), - &owner); - - pluginEditor->setHostContext (editorHostContext.get()); - #if ! JUCE_MAC - pluginEditor->setScaleFactor (owner.scaleFactor.get()); - #endif - - addAndMakeVisible (pluginEditor.get()); - pluginEditor->setTopLeftPosition (0, 0); - - lastBounds = getSizeToContainChild(); - - { - const ScopedValueSetter resizingParentSetter (resizingParent, true); - setBounds (lastBounds); - } - - resizeHostWindow(); - } - else - { - // if hasEditor() returns true then createEditorIfNeeded has to return a valid editor - jassertfalse; - } - } - - void paint (Graphics& g) override - { - g.fillAll (Colours::black); - } - - juce::Rectangle getSizeToContainChild() - { - if (pluginEditor != nullptr) - return getLocalArea (pluginEditor.get(), pluginEditor->getLocalBounds()); - - return {}; - } - - void childBoundsChanged (Component*) override - { - if (resizingChild) - return; - - auto newBounds = getSizeToContainChild(); - - if (newBounds != lastBounds) - { - resizeHostWindow(); - - #if JUCE_LINUX || JUCE_BSD - if (getHostType().isBitwigStudio()) - repaint(); - #endif - - lastBounds = newBounds; - } - } - - void resized() override - { - if (pluginEditor != nullptr) - { - if (! resizingParent) - { - auto newBounds = getLocalBounds(); - - { - const ScopedValueSetter resizingChildSetter (resizingChild, true); - pluginEditor->setBounds (pluginEditor->getLocalArea (this, newBounds).withPosition (0, 0)); - } - - lastBounds = newBounds; - } - } - } - - void parentSizeChanged() override - { - if (pluginEditor != nullptr) - { - resizeHostWindow(); - pluginEditor->repaint(); - } - } - - void resizeHostWindow() - { - if (pluginEditor != nullptr) - { - if (owner.plugFrame != nullptr) - { - auto editorBounds = getSizeToContainChild(); - auto newSize = convertToHostBounds ({ 0, 0, editorBounds.getWidth(), editorBounds.getHeight() }); - - { - const ScopedValueSetter resizingParentSetter (resizingParent, true); - owner.plugFrame->resizeView (&owner, &newSize); - } - - auto host = getHostType(); - - #if JUCE_MAC - if (host.isWavelab() || host.isReaper() || owner.owner->blueCatPatchwork) - #else - if (host.isWavelab() || host.isAbletonLive() || host.isBitwigStudio() || owner.owner->blueCatPatchwork) - #endif - setBounds (editorBounds.withPosition (0, 0)); - } - } - } - - void setEditorScaleFactor (float scale) - { - if (pluginEditor != nullptr) - { - auto prevEditorBounds = pluginEditor->getLocalArea (this, lastBounds); - - { - const ScopedValueSetter resizingChildSetter (resizingChild, true); - - pluginEditor->setScaleFactor (scale); - pluginEditor->setBounds (prevEditorBounds.withPosition (0, 0)); - } - - lastBounds = getSizeToContainChild(); - - resizeHostWindow(); - repaint(); - } - } - - #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE - void checkHostWindowScaleFactor() - { - const auto estimatedScale = (float) getScaleFactorForWindow (static_cast (owner.systemWindow)); - - if (estimatedScale > 0.0) - owner.applyScaleFactor (owner.scaleFactor.withInternal (estimatedScale)); - } - - void timerCallback() override - { - checkHostWindowScaleFactor(); - } - #endif - - std::unique_ptr pluginEditor; - - private: - JuceVST3Editor& owner; - std::unique_ptr editorHostContext; - Rectangle lastBounds; - bool resizingChild = false, resizingParent = false; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) - }; - - void createContentWrapperComponentIfNeeded() - { - if (component == nullptr) - { - #if JUCE_LINUX || JUCE_BSD - const MessageManagerLock mmLock; - #endif - - component.reset (new ContentWrapperComponent (*this)); - component->createEditor (pluginInstance); - } - } - - //============================================================================== - ScopedJuceInitialiser_GUI libraryInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - SharedResourcePointer eventHandler; - #endif - - VSTComSmartPtr owner; - AudioProcessor& pluginInstance; - - #if JUCE_LINUX || JUCE_BSD - struct MessageManagerLockedDeleter - { - template - void operator() (ObjectType* object) const noexcept - { - const MessageManagerLock mmLock; - delete object; - } - }; - - std::unique_ptr component; - #else - std::unique_ptr component; - #endif - - friend struct ContentWrapperComponent; - - #if JUCE_MAC - void* macHostWindow = nullptr; - bool isNSView = false; - - // On macOS Cubase 10 resizes the host window after calling onSize() resulting in the peer - // bounds being a step behind the plug-in. Calling updateBounds() asynchronously seems to fix things... - struct Cubase10WindowResizeWorkaround : public AsyncUpdater - { - Cubase10WindowResizeWorkaround (JuceVST3Editor& o) : owner (o) {} - - void handleAsyncUpdate() override - { - if (owner.component != nullptr) - if (auto* peer = owner.component->getPeer()) - peer->updateBounds(); - } - - JuceVST3Editor& owner; - }; - - std::unique_ptr cubase10Workaround; - #else - class StoredScaleFactor - { - public: - StoredScaleFactor withHost (float x) const { return withMember (*this, &StoredScaleFactor::host, x); } - StoredScaleFactor withInternal (float x) const { return withMember (*this, &StoredScaleFactor::internal, x); } - float get() const { return host.value_or (internal); } - - private: - std::optional host; - float internal = 1.0f; - }; - - void applyScaleFactor (const StoredScaleFactor newFactor) - { - const auto previous = std::exchange (scaleFactor, newFactor).get(); - - if (previous == scaleFactor.get()) - return; - - if (owner != nullptr) - owner->lastScaleFactorReceived = scaleFactor.get(); - - if (component != nullptr) - { - #if JUCE_LINUX || JUCE_BSD - const MessageManagerLock mmLock; - #endif - component->setEditorScaleFactor (scaleFactor.get()); - } - } - - StoredScaleFactor scaleFactor; - - #if JUCE_WINDOWS - WindowsHooks hooks; - #endif - - #endif - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Editor) - }; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3EditController) -}; - - -//============================================================================== -#if JucePlugin_Enable_ARA - class JuceARAFactory : public ARA::IMainFactory - { - public: - JuceARAFactory() = default; - virtual ~JuceARAFactory() = default; - - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const ::Steinberg::TUID targetIID, void** obj) override - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}); - - if (result.isOk()) - return result.extract (obj); - - if (doUIDsMatch (targetIID, JuceARAFactory::iid)) - { - addRef(); - *obj = this; - return kResultOk; - } - - *obj = nullptr; - return kNoInterface; - } - - //---from ARA::IMainFactory------- - const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE - { - return createARAFactory(); - } - static const FUID iid; - - private: - //============================================================================== - std::atomic refCount { 1 }; - }; -#endif - -//============================================================================== -class JuceVST3Component : public Vst::IComponent, - public Vst::IAudioProcessor, - public Vst::IUnitInfo, - public Vst::IConnectionPoint, - public Vst::IProcessContextRequirements, - #if JucePlugin_Enable_ARA - public ARA::IPlugInEntryPoint, - public ARA::IPlugInEntryPoint2, - #endif - public AudioPlayHead -{ -public: - JuceVST3Component (Vst::IHostApplication* h) - : pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_VST3).release()), - host (h) - { - inParameterChangedCallback = false; - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - [[maybe_unused]] const int numConfigs = numElementsInArray (configs); - - jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); - - pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024); - #endif - - // VST-3 requires your default layout to be non-discrete! - // For example, your default layout must be mono, stereo, quadrophonic - // and not AudioChannelSet::discreteChannels (2) etc. - jassert (checkBusFormatsAreNotDiscrete()); - - comPluginInstance = VSTComSmartPtr { new JuceAudioProcessor (pluginInstance) }; - - zerostruct (processContext); - - processSetup.maxSamplesPerBlock = 1024; - processSetup.processMode = Vst::kRealtime; - processSetup.sampleRate = 44100.0; - processSetup.symbolicSampleSize = Vst::kSample32; - - pluginInstance->setPlayHead (this); - - // Constructing the underlying static object involves dynamic allocation. - // This call ensures that the construction won't happen on the audio thread. - getHostType(); - } - - ~JuceVST3Component() override - { - if (juceVST3EditController != nullptr) - juceVST3EditController->vst3IsPlaying = false; - - if (pluginInstance != nullptr) - if (pluginInstance->getPlayHead() == this) - pluginInstance->setPlayHead (nullptr); - } - - //============================================================================== - AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } - - //============================================================================== - static const FUID iid; - - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto userProvidedInterface = queryAdditionalInterfaces (&getPluginInstance(), - targetIID, - &VST3ClientExtensions::queryIAudioProcessor); - - const auto juceProvidedInterface = queryInterfaceInternal (targetIID); - - return extractResult (userProvidedInterface, juceProvidedInterface, obj); - } - - enum class CallPrepareToPlay { no, yes }; - - //============================================================================== - tresult PLUGIN_API initialize (FUnknown* hostContext) override - { - if (host != hostContext) - host.loadFrom (hostContext); - - processContext.sampleRate = processSetup.sampleRate; - preparePlugin (processSetup.sampleRate, (int) processSetup.maxSamplesPerBlock, CallPrepareToPlay::no); - - return kResultTrue; - } - - tresult PLUGIN_API terminate() override - { - getPluginInstance().releaseResources(); - return kResultTrue; - } - - //============================================================================== - tresult PLUGIN_API connect (IConnectionPoint* other) override - { - if (other != nullptr && juceVST3EditController == nullptr) - juceVST3EditController.loadFrom (other); - - return kResultTrue; - } - - tresult PLUGIN_API disconnect (IConnectionPoint*) override - { - if (juceVST3EditController != nullptr) - juceVST3EditController->vst3IsPlaying = false; - - juceVST3EditController = {}; - return kResultTrue; - } - - tresult PLUGIN_API notify (Vst::IMessage* message) override - { - if (message != nullptr && juceVST3EditController == nullptr) - { - Steinberg::int64 value = 0; - - if (message->getAttributes()->getInt ("JuceVST3EditController", value) == kResultTrue) - { - juceVST3EditController = VSTComSmartPtr { (JuceVST3EditController*) (pointer_sized_int) value }; - - if (juceVST3EditController != nullptr) - juceVST3EditController->setAudioProcessor (comPluginInstance); - else - jassertfalse; - } - } - - return kResultTrue; - } - - tresult PLUGIN_API getControllerClassId (TUID classID) override - { - memcpy (classID, JuceVST3EditController::iid, sizeof (TUID)); - return kResultTrue; - } - - //============================================================================== - tresult PLUGIN_API setActive (TBool state) override - { - const auto willBeActive = (state != 0); - - active = false; - // Some hosts may call setBusArrangements in response to calls made during prepareToPlay - // or releaseResources. Specifically, Wavelab 11.1 calls setBusArrangements in the same - // call stack when the AudioProcessor calls setLatencySamples inside prepareToPlay. - // In order for setBusArrangements to return successfully, the plugin must not be activated - // until after prepareToPlay has completely finished. - const ScopeGuard scope { [&] { active = willBeActive; } }; - - if (willBeActive) - { - const auto sampleRate = processSetup.sampleRate > 0.0 - ? processSetup.sampleRate - : getPluginInstance().getSampleRate(); - - const auto bufferSize = processSetup.maxSamplesPerBlock > 0 - ? (int) processSetup.maxSamplesPerBlock - : getPluginInstance().getBlockSize(); - - preparePlugin (sampleRate, bufferSize, CallPrepareToPlay::yes); - } - else - { - getPluginInstance().releaseResources(); - } - - return kResultOk; - } - - tresult PLUGIN_API setIoMode (Vst::IoMode) override { return kNotImplemented; } - tresult PLUGIN_API getRoutingInfo (Vst::RoutingInfo&, Vst::RoutingInfo&) override { return kNotImplemented; } - - //============================================================================== - bool isBypassed() const - { - if (auto* bypassParam = comPluginInstance->getBypassParameter()) - return bypassParam->getValue() >= 0.5f; - - return false; - } - - void setBypassed (bool shouldBeBypassed) - { - if (auto* bypassParam = comPluginInstance->getBypassParameter()) - setValueAndNotifyIfChanged (*bypassParam, shouldBeBypassed ? 1.0f : 0.0f); - } - - //============================================================================== - void writeJucePrivateStateInformation (MemoryOutputStream& out) - { - if (pluginInstance->getBypassParameter() == nullptr) - { - ValueTree privateData (kJucePrivateDataIdentifier); - - // for now we only store the bypass value - privateData.setProperty ("Bypass", var (isBypassed()), nullptr); - privateData.writeToStream (out); - } - } - - void setJucePrivateStateInformation (const void* data, int sizeInBytes) - { - if (pluginInstance->getBypassParameter() == nullptr) - { - if (comPluginInstance->getBypassParameter() != nullptr) - { - auto privateData = ValueTree::readFromData (data, static_cast (sizeInBytes)); - setBypassed (static_cast (privateData.getProperty ("Bypass", var (false)))); - } - } - } - - void getStateInformation (MemoryBlock& destData) - { - pluginInstance->getStateInformation (destData); - - // With bypass support, JUCE now needs to store private state data. - // Put this at the end of the plug-in state and add a few null characters - // so that plug-ins built with older versions of JUCE will hopefully ignore - // this data. Additionally, we need to add some sort of magic identifier - // at the very end of the private data so that JUCE has some sort of - // way to figure out if the data was stored with a newer JUCE version. - MemoryOutputStream extraData; - - extraData.writeInt64 (0); - writeJucePrivateStateInformation (extraData); - auto privateDataSize = (int64) (extraData.getDataSize() - sizeof (int64)); - extraData.writeInt64 (privateDataSize); - extraData << kJucePrivateDataIdentifier; - - // write magic string - destData.append (extraData.getData(), extraData.getDataSize()); - } - - void setStateInformation (const void* data, int sizeAsInt) - { - bool unusedState = false; - auto& flagToSet = juceVST3EditController != nullptr ? juceVST3EditController->inSetState : unusedState; - const ScopedValueSetter scope (flagToSet, true); - - auto size = (uint64) sizeAsInt; - - // Check if this data was written with a newer JUCE version - // and if it has the JUCE private data magic code at the end - auto jucePrivDataIdentifierSize = std::strlen (kJucePrivateDataIdentifier); - - if ((size_t) size >= jucePrivDataIdentifierSize + sizeof (int64)) - { - auto buffer = static_cast (data); - - String magic (CharPointer_UTF8 (buffer + size - jucePrivDataIdentifierSize), - CharPointer_UTF8 (buffer + size)); - - if (magic == kJucePrivateDataIdentifier) - { - // found a JUCE private data section - uint64 privateDataSize; - - std::memcpy (&privateDataSize, - buffer + ((size_t) size - jucePrivDataIdentifierSize - sizeof (uint64)), - sizeof (uint64)); - - privateDataSize = ByteOrder::swapIfBigEndian (privateDataSize); - size -= privateDataSize + jucePrivDataIdentifierSize + sizeof (uint64); - - if (privateDataSize > 0) - setJucePrivateStateInformation (buffer + size, static_cast (privateDataSize)); - - size -= sizeof (uint64); - } - } - - if (size > 0) - pluginInstance->setStateInformation (data, static_cast (size)); - } - - //============================================================================== - #if JUCE_VST3_CAN_REPLACE_VST2 - bool loadVST2VstWBlock (const char* data, int size) - { - jassert (ByteOrder::bigEndianInt ("VstW") == htonl ((uint32) readUnaligned (data))); - jassert (1 == htonl ((uint32) readUnaligned (data + 8))); // version should be 1 according to Steinberg's docs - - auto headerLen = (int) htonl ((uint32) readUnaligned (data + 4)) + 8; - return loadVST2CcnKBlock (data + headerLen, size - headerLen); - } - - bool loadVST2CcnKBlock (const char* data, int size) - { - auto* bank = reinterpret_cast (data); - - jassert (ByteOrder::bigEndianInt ("CcnK") == htonl ((uint32) bank->chunkMagic)); - jassert (ByteOrder::bigEndianInt ("FBCh") == htonl ((uint32) bank->fxMagic)); - jassert (htonl ((uint32) bank->version) == 1 || htonl ((uint32) bank->version) == 2); - jassert (JucePlugin_VSTUniqueID == htonl ((uint32) bank->fxID)); - - setStateInformation (bank->content.data.chunk, - jmin ((int) (size - (bank->content.data.chunk - data)), - (int) htonl ((uint32) bank->content.data.size))); - return true; - } - - bool loadVST3PresetFile (const char* data, int size) - { - if (size < 48) - return false; - - // At offset 4 there's a little-endian version number which seems to typically be 1 - // At offset 8 there's 32 bytes the SDK calls "ASCII-encoded class id" - auto chunkListOffset = (int) ByteOrder::littleEndianInt (data + 40); - jassert (memcmp (data + chunkListOffset, "List", 4) == 0); - auto entryCount = (int) ByteOrder::littleEndianInt (data + chunkListOffset + 4); - jassert (entryCount > 0); - - for (int i = 0; i < entryCount; ++i) - { - auto entryOffset = chunkListOffset + 8 + 20 * i; - - if (entryOffset + 20 > size) - return false; - - if (memcmp (data + entryOffset, "Comp", 4) == 0) - { - // "Comp" entries seem to contain the data. - auto chunkOffset = ByteOrder::littleEndianInt64 (data + entryOffset + 4); - auto chunkSize = ByteOrder::littleEndianInt64 (data + entryOffset + 12); - - if (static_cast (chunkOffset + chunkSize) > static_cast (size)) - { - jassertfalse; - return false; - } - - loadVST2VstWBlock (data + chunkOffset, (int) chunkSize); - } - } - - return true; - } - - bool loadVST2CompatibleState (const char* data, int size) - { - if (size < 4) - return false; - - auto header = htonl ((uint32) readUnaligned (data)); - - if (header == ByteOrder::bigEndianInt ("VstW")) - return loadVST2VstWBlock (data, size); - - if (header == ByteOrder::bigEndianInt ("CcnK")) - return loadVST2CcnKBlock (data, size); - - if (memcmp (data, "VST3", 4) == 0) - { - // In Cubase 5, when loading VST3 .vstpreset files, - // we get the whole content of the files to load. - // In Cubase 7 we get just the contents within and - // we go directly to the loadVST2VstW codepath instead. - return loadVST3PresetFile (data, size); - } - - return false; - } - #endif - - void loadStateData (const void* data, int size) - { - #if JUCE_VST3_CAN_REPLACE_VST2 - if (loadVST2CompatibleState ((const char*) data, size)) - return; - #endif - setStateInformation (data, size); - } - - bool readFromMemoryStream (IBStream* state) - { - FUnknownPtr s (state); - Steinberg::int64 size = 0; - - if (s != nullptr - && s->getStreamSize (size) == kResultOk - && size > 0 - && size < 1024 * 1024 * 100) // (some hosts seem to return junk for the size) - { - MemoryBlock block (static_cast (size)); - - // turns out that Cubase 9 might give you the incorrect stream size :-( - Steinberg::int32 bytesRead = 1; - int len; - - for (len = 0; bytesRead > 0 && len < static_cast (block.getSize()); len += bytesRead) - if (state->read (block.getData(), static_cast (block.getSize()), &bytesRead) != kResultOk) - break; - - if (len == 0) - return false; - - block.setSize (static_cast (len)); - - // Adobe Audition CS6 hack to avoid trying to use corrupted streams: - if (getHostType().isAdobeAudition()) - if (block.getSize() >= 5 && memcmp (block.getData(), "VC2!E", 5) == 0) - return false; - - loadStateData (block.getData(), (int) block.getSize()); - return true; - } - - return false; - } - - bool readFromUnknownStream (IBStream* state) - { - MemoryOutputStream allData; - - { - const size_t bytesPerBlock = 4096; - HeapBlock buffer (bytesPerBlock); - - for (;;) - { - Steinberg::int32 bytesRead = 0; - auto status = state->read (buffer, (Steinberg::int32) bytesPerBlock, &bytesRead); - - if (bytesRead <= 0 || (status != kResultTrue && ! getHostType().isWavelab())) - break; - - allData.write (buffer, static_cast (bytesRead)); - } - } - - const size_t dataSize = allData.getDataSize(); - - if (dataSize <= 0 || dataSize >= 0x7fffffff) - return false; - - loadStateData (allData.getData(), (int) dataSize); - return true; - } - - tresult PLUGIN_API setState (IBStream* state) override - { - // The VST3 spec requires that this function is called from the UI thread. - // If this assertion fires, your host is misbehaving! - assertHostMessageThread(); - - if (state == nullptr) - return kInvalidArgument; - - FUnknownPtr stateRefHolder (state); // just in case the caller hasn't properly ref-counted the stream object - - if (state->seek (0, IBStream::kIBSeekSet, nullptr) == kResultTrue) - { - if (! getHostType().isFruityLoops() && readFromMemoryStream (state)) - return kResultTrue; - - if (readFromUnknownStream (state)) - return kResultTrue; - } - - return kResultFalse; - } - - #if JUCE_VST3_CAN_REPLACE_VST2 - static tresult writeVST2Header (IBStream* state, bool bypassed) - { - auto writeVST2IntToState = [state] (uint32 n) - { - auto t = (int32) htonl (n); - return state->write (&t, 4); - }; - - auto status = writeVST2IntToState (ByteOrder::bigEndianInt ("VstW")); - - if (status == kResultOk) status = writeVST2IntToState (8); // header size - if (status == kResultOk) status = writeVST2IntToState (1); // version - if (status == kResultOk) status = writeVST2IntToState (bypassed ? 1 : 0); // bypass - - return status; - } - #endif - - tresult PLUGIN_API getState (IBStream* state) override - { - if (state == nullptr) - return kInvalidArgument; - - MemoryBlock mem; - getStateInformation (mem); - - #if JUCE_VST3_CAN_REPLACE_VST2 - tresult status = writeVST2Header (state, isBypassed()); - - if (status != kResultOk) - return status; - - const int bankBlockSize = 160; - Vst2::fxBank bank; - - zerostruct (bank); - bank.chunkMagic = (int32) htonl (ByteOrder::bigEndianInt ("CcnK")); - bank.byteSize = (int32) htonl (bankBlockSize - 8 + (unsigned int) mem.getSize()); - bank.fxMagic = (int32) htonl (ByteOrder::bigEndianInt ("FBCh")); - bank.version = (int32) htonl (2); - bank.fxID = (int32) htonl (JucePlugin_VSTUniqueID); - bank.fxVersion = (int32) htonl (JucePlugin_VersionCode); - bank.content.data.size = (int32) htonl ((unsigned int) mem.getSize()); - - status = state->write (&bank, bankBlockSize); - - if (status != kResultOk) - return status; - #endif - - return state->write (mem.getData(), (Steinberg::int32) mem.getSize()); - } - - //============================================================================== - Steinberg::int32 PLUGIN_API getUnitCount() override { return comPluginInstance->getUnitCount(); } - tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override { return comPluginInstance->getUnitInfo (unitIndex, info); } - Steinberg::int32 PLUGIN_API getProgramListCount() override { return comPluginInstance->getProgramListCount(); } - tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override { return comPluginInstance->getProgramListInfo (listIndex, info); } - tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override { return comPluginInstance->getProgramName (listId, programIndex, name); } - tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex, - Vst::CString attributeId, Vst::String128 attributeValue) override { return comPluginInstance->getProgramInfo (listId, programIndex, attributeId, attributeValue); } - tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override { return comPluginInstance->hasProgramPitchNames (listId, programIndex); } - tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex, - Steinberg::int16 midiPitch, Vst::String128 name) override { return comPluginInstance->getProgramPitchName (listId, programIndex, midiPitch, name); } - tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override { return comPluginInstance->selectUnit (unitId); } - tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex, - Steinberg::IBStream* data) override { return comPluginInstance->setUnitProgramData (listOrUnitId, programIndex, data); } - Vst::UnitID PLUGIN_API getSelectedUnit() override { return comPluginInstance->getSelectedUnit(); } - tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex, - Steinberg::int32 channel, Vst::UnitID& unitId) override { return comPluginInstance->getUnitByBus (type, dir, busIndex, channel, unitId); } - - //============================================================================== - Optional getPosition() const override - { - PositionInfo info; - info.setTimeInSamples (jmax ((juce::int64) 0, processContext.projectTimeSamples)); - info.setTimeInSeconds (static_cast (*info.getTimeInSamples()) / processContext.sampleRate); - info.setIsRecording ((processContext.state & Vst::ProcessContext::kRecording) != 0); - info.setIsPlaying ((processContext.state & Vst::ProcessContext::kPlaying) != 0); - info.setIsLooping ((processContext.state & Vst::ProcessContext::kCycleActive) != 0); - - info.setBpm ((processContext.state & Vst::ProcessContext::kTempoValid) != 0 - ? makeOptional (processContext.tempo) - : nullopt); - - info.setTimeSignature ((processContext.state & Vst::ProcessContext::kTimeSigValid) != 0 - ? makeOptional (TimeSignature { processContext.timeSigNumerator, processContext.timeSigDenominator }) - : nullopt); - - info.setLoopPoints ((processContext.state & Vst::ProcessContext::kCycleValid) != 0 - ? makeOptional (LoopPoints { processContext.cycleStartMusic, processContext.cycleEndMusic }) - : nullopt); - - info.setPpqPosition ((processContext.state & Vst::ProcessContext::kProjectTimeMusicValid) != 0 - ? makeOptional (processContext.projectTimeMusic) - : nullopt); - - info.setPpqPositionOfLastBarStart ((processContext.state & Vst::ProcessContext::kBarPositionValid) != 0 - ? makeOptional (processContext.barPositionMusic) - : nullopt); - - info.setFrameRate ((processContext.state & Vst::ProcessContext::kSmpteValid) != 0 - ? makeOptional (FrameRate().withBaseRate ((int) processContext.frameRate.framesPerSecond) - .withDrop ((processContext.frameRate.flags & Vst::FrameRate::kDropRate) != 0) - .withPullDown ((processContext.frameRate.flags & Vst::FrameRate::kPullDownRate) != 0)) - : nullopt); - - info.setEditOriginTime (info.getFrameRate().hasValue() - ? makeOptional ((double) processContext.smpteOffsetSubframes / (80.0 * info.getFrameRate()->getEffectiveRate())) - : nullopt); - - info.setHostTimeNs ((processContext.state & Vst::ProcessContext::kSystemTimeValid) != 0 - ? makeOptional ((uint64_t) processContext.systemTime) - : nullopt); - - return info; - } - - //============================================================================== - int getNumAudioBuses (bool isInput) const - { - int busCount = pluginInstance->getBusCount (isInput); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; - const int numConfigs = numElementsInArray (configs); - - bool hasOnlyZeroChannels = true; - - for (int i = 0; i < numConfigs && hasOnlyZeroChannels == true; ++i) - if (configs[i][isInput ? 0 : 1] != 0) - hasOnlyZeroChannels = false; - - busCount = jmin (busCount, hasOnlyZeroChannels ? 0 : 1); - #endif - - return busCount; - } - - //============================================================================== - Steinberg::int32 PLUGIN_API getBusCount (Vst::MediaType type, Vst::BusDirection dir) override - { - if (type == Vst::kAudio) - return getNumAudioBuses (dir == Vst::kInput); - - if (type == Vst::kEvent) - { - #if JucePlugin_WantsMidiInput - if (dir == Vst::kInput) - return 1; - #endif - - #if JucePlugin_ProducesMidiOutput - if (dir == Vst::kOutput) - return 1; - #endif - } - - return 0; - } - - tresult PLUGIN_API getBusInfo (Vst::MediaType type, Vst::BusDirection dir, - Steinberg::int32 index, Vst::BusInfo& info) override - { - if (type == Vst::kAudio) - { - if (index < 0 || index >= getNumAudioBuses (dir == Vst::kInput)) - return kResultFalse; - - if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index)) - { - info.mediaType = Vst::kAudio; - info.direction = dir; - info.channelCount = bus->getLastEnabledLayout().size(); - jassert (info.channelCount == Steinberg::Vst::SpeakerArr::getChannelCount (getVst3SpeakerArrangement (bus->getLastEnabledLayout()))); - toString128 (info.name, bus->getName()); - - info.busType = [&] - { - const auto isFirstBus = (index == 0); - - if (dir == Vst::kInput) - { - if (isFirstBus) - { - if (auto* extensions = dynamic_cast (pluginInstance)) - return extensions->getPluginHasMainInput() ? Vst::kMain : Vst::kAux; - - return Vst::kMain; - } - - return Vst::kAux; - } - - #if JucePlugin_IsSynth - return Vst::kMain; - #else - return isFirstBus ? Vst::kMain : Vst::kAux; - #endif - }(); - - #ifdef JucePlugin_PreferredChannelConfigurations - info.flags = Vst::BusInfo::kDefaultActive; - #else - info.flags = (bus->isEnabledByDefault()) ? Vst::BusInfo::kDefaultActive : 0; - #endif - - return kResultTrue; - } - } - - if (type == Vst::kEvent) - { - info.flags = Vst::BusInfo::kDefaultActive; - - #if JucePlugin_WantsMidiInput - if (dir == Vst::kInput && index == 0) - { - info.mediaType = Vst::kEvent; - info.direction = dir; - - #ifdef JucePlugin_VSTNumMidiInputs - info.channelCount = JucePlugin_VSTNumMidiInputs; - #else - info.channelCount = 16; - #endif - - toString128 (info.name, TRANS("MIDI Input")); - info.busType = Vst::kMain; - return kResultTrue; - } - #endif - - #if JucePlugin_ProducesMidiOutput - if (dir == Vst::kOutput && index == 0) - { - info.mediaType = Vst::kEvent; - info.direction = dir; - - #ifdef JucePlugin_VSTNumMidiOutputs - info.channelCount = JucePlugin_VSTNumMidiOutputs; - #else - info.channelCount = 16; - #endif - - toString128 (info.name, TRANS("MIDI Output")); - info.busType = Vst::kMain; - return kResultTrue; - } - #endif - } - - zerostruct (info); - return kResultFalse; - } - - tresult PLUGIN_API activateBus (Vst::MediaType type, - Vst::BusDirection dir, - Steinberg::int32 index, - TBool state) override - { - // The host is misbehaving! The plugin must be deactivated before setting new arrangements. - jassert (! active); - - if (type == Vst::kEvent) - { - #if JucePlugin_WantsMidiInput - if (index == 0 && dir == Vst::kInput) - { - isMidiInputBusEnabled = (state != 0); - return kResultTrue; - } - #endif - - #if JucePlugin_ProducesMidiOutput - if (index == 0 && dir == Vst::kOutput) - { - isMidiOutputBusEnabled = (state != 0); - return kResultTrue; - } - #endif - - return kResultFalse; - } - - if (type == Vst::kAudio) - { - const auto numInputBuses = getNumAudioBuses (true); - const auto numOutputBuses = getNumAudioBuses (false); - - if (! isPositiveAndBelow (index, dir == Vst::kInput ? numInputBuses : numOutputBuses)) - return kResultFalse; - - // The host is allowed to enable/disable buses as it sees fit, so the plugin needs to be - // able to handle any set of enabled/disabled buses, including layouts for which - // AudioProcessor::isBusesLayoutSupported would return false. - // Our strategy is to keep track of the layout that the host last requested, and to - // attempt to apply that layout directly. - // If the layout isn't supported by the processor, we'll try enabling all the buses - // instead. - // If the host enables a bus that the processor refused to enable, then we'll ignore - // that bus (and return silence for output buses). If the host disables a bus that the - // processor refuses to disable, the wrapper will provide the processor with silence for - // input buses, and ignore the contents of output buses. - // Note that some hosts (old bitwig and cakewalk) may incorrectly call this function - // when the plugin is in an activated state. - if (dir == Vst::kInput) - bufferMapper.setInputBusHostActive ((size_t) index, state != 0); - else - bufferMapper.setOutputBusHostActive ((size_t) index, state != 0); - - AudioProcessor::BusesLayout desiredLayout; - - for (auto i = 0; i < numInputBuses; ++i) - desiredLayout.inputBuses.add (bufferMapper.getRequestedLayoutForInputBus ((size_t) i)); - - for (auto i = 0; i < numOutputBuses; ++i) - desiredLayout.outputBuses.add (bufferMapper.getRequestedLayoutForOutputBus ((size_t) i)); - - const auto prev = pluginInstance->getBusesLayout(); - - const auto busesLayoutSupported = [&] - { - #ifdef JucePlugin_PreferredChannelConfigurations - struct ChannelPair - { - short ins, outs; - - auto tie() const { return std::tie (ins, outs); } - bool operator== (ChannelPair x) const { return tie() == x.tie(); } - }; - - const auto countChannels = [] (auto& range) - { - return std::accumulate (range.begin(), range.end(), 0, [] (auto acc, auto set) - { - return acc + set.size(); - }); - }; - - const auto toShort = [] (int x) - { - jassert (0 <= x && x <= std::numeric_limits::max()); - return (short) x; - }; - - const ChannelPair requested { toShort (countChannels (desiredLayout.inputBuses)), - toShort (countChannels (desiredLayout.outputBuses)) }; - const ChannelPair configs[] = { JucePlugin_PreferredChannelConfigurations }; - return std::find (std::begin (configs), std::end (configs), requested) != std::end (configs); - #else - return pluginInstance->checkBusesLayoutSupported (desiredLayout); - #endif - }(); - - if (busesLayoutSupported) - pluginInstance->setBusesLayout (desiredLayout); - else - pluginInstance->enableAllBuses(); - - bufferMapper.updateActiveClientBuses (pluginInstance->getBusesLayout()); - - return kResultTrue; - } - - return kResultFalse; - } - - bool checkBusFormatsAreNotDiscrete() - { - auto numInputBuses = pluginInstance->getBusCount (true); - auto numOutputBuses = pluginInstance->getBusCount (false); - - for (int i = 0; i < numInputBuses; ++i) - { - auto layout = pluginInstance->getChannelLayoutOfBus (true, i); - - if (layout.isDiscreteLayout() && ! layout.isDisabled()) - return false; - } - - for (int i = 0; i < numOutputBuses; ++i) - { - auto layout = pluginInstance->getChannelLayoutOfBus (false, i); - - if (layout.isDiscreteLayout() && ! layout.isDisabled()) - return false; - } - - return true; - } - - tresult PLUGIN_API setBusArrangements (Vst::SpeakerArrangement* inputs, Steinberg::int32 numIns, - Vst::SpeakerArrangement* outputs, Steinberg::int32 numOuts) override - { - if (active) - { - // The host is misbehaving! The plugin must be deactivated before setting new arrangements. - jassertfalse; - return kResultFalse; - } - - auto numInputBuses = pluginInstance->getBusCount (true); - auto numOutputBuses = pluginInstance->getBusCount (false); - - if (numIns > numInputBuses || numOuts > numOutputBuses) - return false; - - // see the following documentation to understand the correct way to react to this callback - // https://steinbergmedia.github.io/vst3_doc/vstinterfaces/classSteinberg_1_1Vst_1_1IAudioProcessor.html#ad3bc7bac3fd3b194122669be2a1ecc42 - - const auto requestedLayout = [&] - { - auto result = pluginInstance->getBusesLayout(); - - for (int i = 0; i < numIns; ++i) - result.getChannelSet (true, i) = getChannelSetForSpeakerArrangement (inputs[i]); - - for (int i = 0; i < numOuts; ++i) - result.getChannelSet (false, i) = getChannelSetForSpeakerArrangement (outputs[i]); - - return result; - }(); - - #ifdef JucePlugin_PreferredChannelConfigurations - short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; - if (! AudioProcessor::containsLayout (requestedLayout, configs)) - return kResultFalse; - #endif - - if (pluginInstance->checkBusesLayoutSupported (requestedLayout)) - { - if (! pluginInstance->setBusesLayoutWithoutEnabling (requestedLayout)) - return kResultFalse; - - bufferMapper.updateFromProcessor (*pluginInstance); - return kResultTrue; - } - - // apply layout changes in reverse order as Steinberg says we should prioritize main buses - const auto nextBest = [this, numInputBuses, numOutputBuses, &requestedLayout] - { - auto layout = pluginInstance->getBusesLayout(); - - for (auto busIdx = jmax (numInputBuses, numOutputBuses) - 1; busIdx >= 0; --busIdx) - for (const auto isInput : { true, false }) - if (auto* bus = pluginInstance->getBus (isInput, busIdx)) - bus->isLayoutSupported (requestedLayout.getChannelSet (isInput, busIdx), &layout); - - return layout; - }(); - - if (pluginInstance->setBusesLayoutWithoutEnabling (nextBest)) - bufferMapper.updateFromProcessor (*pluginInstance); - - return kResultFalse; - } - - tresult PLUGIN_API getBusArrangement (Vst::BusDirection dir, Steinberg::int32 index, Vst::SpeakerArrangement& arr) override - { - if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index)) - { - arr = getVst3SpeakerArrangement (bus->getLastEnabledLayout()); - return kResultTrue; - } - - return kResultFalse; - } - - //============================================================================== - tresult PLUGIN_API canProcessSampleSize (Steinberg::int32 symbolicSampleSize) override - { - return (symbolicSampleSize == Vst::kSample32 - || (getPluginInstance().supportsDoublePrecisionProcessing() - && symbolicSampleSize == Vst::kSample64)) ? kResultTrue : kResultFalse; - } - - Steinberg::uint32 PLUGIN_API getLatencySamples() override - { - return (Steinberg::uint32) jmax (0, getPluginInstance().getLatencySamples()); - } - - tresult PLUGIN_API setupProcessing (Vst::ProcessSetup& newSetup) override - { - ScopedInSetupProcessingSetter inSetupProcessingSetter (juceVST3EditController); - - if (canProcessSampleSize (newSetup.symbolicSampleSize) != kResultTrue) - return kResultFalse; - - processSetup = newSetup; - processContext.sampleRate = processSetup.sampleRate; - - getPluginInstance().setProcessingPrecision (newSetup.symbolicSampleSize == Vst::kSample64 - ? AudioProcessor::doublePrecision - : AudioProcessor::singlePrecision); - getPluginInstance().setNonRealtime (newSetup.processMode == Vst::kOffline); - - preparePlugin (processSetup.sampleRate, processSetup.maxSamplesPerBlock, CallPrepareToPlay::no); - - return kResultTrue; - } - - tresult PLUGIN_API setProcessing (TBool state) override - { - if (! state) - getPluginInstance().reset(); - - return kResultTrue; - } - - Steinberg::uint32 PLUGIN_API getTailSamples() override - { - auto tailLengthSeconds = getPluginInstance().getTailLengthSeconds(); - - if (tailLengthSeconds <= 0.0 || processSetup.sampleRate <= 0.0) - return Vst::kNoTail; - - if (tailLengthSeconds == std::numeric_limits::infinity()) - return Vst::kInfiniteTail; - - return (Steinberg::uint32) roundToIntAccurate (tailLengthSeconds * processSetup.sampleRate); - } - - //============================================================================== - void processParameterChanges (Vst::IParameterChanges& paramChanges) - { - jassert (pluginInstance != nullptr); - - struct ParamChangeInfo - { - Steinberg::int32 offsetSamples = 0; - double value = 0.0; - }; - - const auto getPointFromQueue = [] (Steinberg::Vst::IParamValueQueue* queue, Steinberg::int32 index) - { - ParamChangeInfo result; - return queue->getPoint (index, result.offsetSamples, result.value) == kResultTrue - ? makeOptional (result) - : nullopt; - }; - - const auto numParamsChanged = paramChanges.getParameterCount(); - - for (Steinberg::int32 i = 0; i < numParamsChanged; ++i) - { - if (auto* paramQueue = paramChanges.getParameterData (i)) - { - const auto vstParamID = paramQueue->getParameterId(); - const auto numPoints = paramQueue->getPointCount(); - - #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS - if (juceVST3EditController != nullptr && juceVST3EditController->isMidiControllerParamID (vstParamID)) - { - for (Steinberg::int32 point = 0; point < numPoints; ++point) - { - if (const auto change = getPointFromQueue (paramQueue, point)) - addParameterChangeToMidiBuffer (change->offsetSamples, vstParamID, change->value); - } - } - else - #endif - if (const auto change = getPointFromQueue (paramQueue, numPoints - 1)) - { - if (auto* param = comPluginInstance->getParamForVSTParamID (vstParamID)) - setValueAndNotifyIfChanged (*param, (float) change->value); - } - } - } - } - - void addParameterChangeToMidiBuffer (const Steinberg::int32 offsetSamples, const Vst::ParamID id, const double value) - { - // If the parameter is mapped to a MIDI CC message then insert it into the midiBuffer. - int channel, ctrlNumber; - - if (juceVST3EditController->getMidiControllerForParameter (id, channel, ctrlNumber)) - { - if (ctrlNumber == Vst::kAfterTouch) - midiBuffer.addEvent (MidiMessage::channelPressureChange (channel, - jlimit (0, 127, (int) (value * 128.0))), offsetSamples); - else if (ctrlNumber == Vst::kPitchBend) - midiBuffer.addEvent (MidiMessage::pitchWheel (channel, - jlimit (0, 0x3fff, (int) (value * 0x4000))), offsetSamples); - else - midiBuffer.addEvent (MidiMessage::controllerEvent (channel, - jlimit (0, 127, ctrlNumber), - jlimit (0, 127, (int) (value * 128.0))), offsetSamples); - } - } - - tresult PLUGIN_API process (Vst::ProcessData& data) override - { - if (pluginInstance == nullptr) - return kResultFalse; - - if ((processSetup.symbolicSampleSize == Vst::kSample64) != pluginInstance->isUsingDoublePrecision()) - return kResultFalse; - - if (data.processContext != nullptr) - { - processContext = *data.processContext; - - if (juceVST3EditController != nullptr) - juceVST3EditController->vst3IsPlaying = (processContext.state & Vst::ProcessContext::kPlaying) != 0; - } - else - { - zerostruct (processContext); - - if (juceVST3EditController != nullptr) - juceVST3EditController->vst3IsPlaying = false; - } - - midiBuffer.clear(); - - if (data.inputParameterChanges != nullptr) - processParameterChanges (*data.inputParameterChanges); - - #if JucePlugin_WantsMidiInput - if (isMidiInputBusEnabled && data.inputEvents != nullptr) - MidiEventList::toMidiBuffer (midiBuffer, *data.inputEvents); - #endif - - if (getHostType().isWavelab()) - { - const int numInputChans = (data.inputs != nullptr && data.inputs[0].channelBuffers32 != nullptr) ? (int) data.inputs[0].numChannels : 0; - const int numOutputChans = (data.outputs != nullptr && data.outputs[0].channelBuffers32 != nullptr) ? (int) data.outputs[0].numChannels : 0; - - if ((pluginInstance->getTotalNumInputChannels() + pluginInstance->getTotalNumOutputChannels()) > 0 - && (numInputChans + numOutputChans) == 0) - return kResultFalse; - } - - // If all of these are zero, the host is attempting to flush parameters without processing audio. - if (data.numSamples != 0 || data.numInputs != 0 || data.numOutputs != 0) - { - if (processSetup.symbolicSampleSize == Vst::kSample32) processAudio (data); - else if (processSetup.symbolicSampleSize == Vst::kSample64) processAudio (data); - else jassertfalse; - } - - if (auto* changes = data.outputParameterChanges) - { - comPluginInstance->forAllChangedParameters ([&] (Vst::ParamID paramID, float value) - { - Steinberg::int32 queueIndex = 0; - - if (auto* queue = changes->addParameterData (paramID, queueIndex)) - { - Steinberg::int32 pointIndex = 0; - queue->addPoint (0, value, pointIndex); - } - }); - } - - #if JucePlugin_ProducesMidiOutput - if (isMidiOutputBusEnabled && data.outputEvents != nullptr) - MidiEventList::pluginToHostEventList (*data.outputEvents, midiBuffer); - #endif - - return kResultTrue; - } - -private: - InterfaceResultWithDeferredAddRef queryInterfaceInternal (const TUID targetIID) - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - #if JucePlugin_Enable_ARA - UniqueBase{}, - UniqueBase{}, - #endif - SharedBase{}); - - if (result.isOk()) - return result; - - if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) - return { kResultOk, comPluginInstance.get() }; - - return {}; - } - - //============================================================================== - struct ScopedInSetupProcessingSetter - { - ScopedInSetupProcessingSetter (JuceVST3EditController* c) - : controller (c) - { - if (controller != nullptr) - controller->inSetupProcessing = true; - } - - ~ScopedInSetupProcessingSetter() - { - if (controller != nullptr) - controller->inSetupProcessing = false; - } - - private: - JuceVST3EditController* controller = nullptr; - }; - - //============================================================================== - template - void processAudio (Vst::ProcessData& data) - { - ClientRemappedBuffer remappedBuffer { bufferMapper, data }; - auto& buffer = remappedBuffer.buffer; - - jassert ((int) buffer.getNumChannels() == jmax (pluginInstance->getTotalNumInputChannels(), - pluginInstance->getTotalNumOutputChannels())); - - { - const ScopedLock sl (pluginInstance->getCallbackLock()); - - pluginInstance->setNonRealtime (data.processMode == Vst::kOffline); - - #if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput - const int numMidiEventsComingIn = midiBuffer.getNumEvents(); - #endif - - if (pluginInstance->isSuspended()) - { - buffer.clear(); - } - else - { - // processBlockBypassed should only ever be called if the AudioProcessor doesn't - // return a valid parameter from getBypassParameter - if (pluginInstance->getBypassParameter() == nullptr && comPluginInstance->getBypassParameter()->getValue() >= 0.5f) - pluginInstance->processBlockBypassed (buffer, midiBuffer); - else - pluginInstance->processBlock (buffer, midiBuffer); - } - - #if JUCE_DEBUG && (! JucePlugin_ProducesMidiOutput) - /* This assertion is caused when you've added some events to the - midiMessages array in your processBlock() method, which usually means - that you're trying to send them somewhere. But in this case they're - getting thrown away. - - If your plugin does want to send MIDI messages, you'll need to set - the JucePlugin_ProducesMidiOutput macro to 1 in your - JucePluginCharacteristics.h file. - - If you don't want to produce any MIDI output, then you should clear the - midiMessages array at the end of your processBlock() method, to - indicate that you don't want any of the events to be passed through - to the output. - */ - jassert (midiBuffer.getNumEvents() <= numMidiEventsComingIn); - #endif - } - } - - //============================================================================== - Steinberg::uint32 PLUGIN_API getProcessContextRequirements() override - { - return kNeedSystemTime - | kNeedContinousTimeSamples - | kNeedProjectTimeMusic - | kNeedBarPositionMusic - | kNeedCycleMusic - | kNeedSamplesToNextClock - | kNeedTempo - | kNeedTimeSignature - | kNeedChord - | kNeedFrameRate - | kNeedTransportState; - } - - void preparePlugin (double sampleRate, int bufferSize, CallPrepareToPlay callPrepareToPlay) - { - auto& p = getPluginInstance(); - - p.setRateAndBufferSizeDetails (sampleRate, bufferSize); - - if (callPrepareToPlay == CallPrepareToPlay::yes) - p.prepareToPlay (sampleRate, bufferSize); - - midiBuffer.ensureSize (2048); - midiBuffer.clear(); - - bufferMapper.updateFromProcessor (p); - bufferMapper.prepare (bufferSize); - } - - //============================================================================== - #if JucePlugin_Enable_ARA - const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE - { - return createARAFactory(); - } - - const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentController (ARA::ARADocumentControllerRef /*controllerRef*/) SMTG_OVERRIDE - { - ARA_VALIDATE_API_STATE (false && "call is deprecated in ARA 2, host must not call this"); - return nullptr; - } - - const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentControllerWithRoles (ARA::ARADocumentControllerRef documentControllerRef, - ARA::ARAPlugInInstanceRoleFlags knownRoles, ARA::ARAPlugInInstanceRoleFlags assignedRoles) SMTG_OVERRIDE - { - AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast (pluginInstance); - return araAudioProcessorExtension->bindToARA (documentControllerRef, knownRoles, assignedRoles); - } - #endif - - //============================================================================== - ScopedJuceInitialiser_GUI libraryInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - std::atomic refCount { 1 }; - AudioProcessor* pluginInstance = nullptr; - - #if JUCE_LINUX || JUCE_BSD - template - struct LockedVSTComSmartPtr - { - LockedVSTComSmartPtr() = default; - LockedVSTComSmartPtr (const VSTComSmartPtr& ptrIn) : ptr (ptrIn) {} - LockedVSTComSmartPtr (const LockedVSTComSmartPtr&) = default; - LockedVSTComSmartPtr& operator= (const LockedVSTComSmartPtr&) = default; - - ~LockedVSTComSmartPtr() - { - const MessageManagerLock mmLock; - ptr = {}; - } - - T* operator->() const { return ptr.operator->(); } - T* get() const noexcept { return ptr.get(); } - operator T*() const noexcept { return ptr.get(); } - - template - bool loadFrom (Args&&... args) { return ptr.loadFrom (std::forward (args)...); } - - private: - VSTComSmartPtr ptr; - }; - - LockedVSTComSmartPtr host; - LockedVSTComSmartPtr comPluginInstance; - LockedVSTComSmartPtr juceVST3EditController; - #else - VSTComSmartPtr host; - VSTComSmartPtr comPluginInstance; - VSTComSmartPtr juceVST3EditController; - #endif - - /** - Since VST3 does not provide a way of knowing the buffer size and sample rate at any point, - this object needs to be copied on every call to process() to be up-to-date... - */ - Vst::ProcessContext processContext; - Vst::ProcessSetup processSetup; - - MidiBuffer midiBuffer; - ClientBufferMapper bufferMapper; - - bool active = false; - - #if JucePlugin_WantsMidiInput - std::atomic isMidiInputBusEnabled { true }; - #endif - #if JucePlugin_ProducesMidiOutput - std::atomic isMidiOutputBusEnabled { true }; - #endif - - static const char* kJucePrivateDataIdentifier; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Component) -}; - -const char* JuceVST3Component::kJucePrivateDataIdentifier = "JUCEPrivateData"; - -//============================================================================== -JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4310) -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wall") - -DECLARE_CLASS_IID (JuceAudioProcessor, 0x0101ABAB, 0xABCDEF01, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) -DEF_CLASS_IID (JuceAudioProcessor) - -#if JUCE_VST3_CAN_REPLACE_VST2 - // Defined in PluginUtilities.cpp - void getUUIDForVST2ID (bool, uint8[16]); - - static FUID getFUIDForVST2ID (bool forControllerUID) - { - TUID uuid; - getUUIDForVST2ID (forControllerUID, (uint8*) uuid); - return FUID (uuid); - } - const Steinberg::FUID JuceVST3Component ::iid (getFUIDForVST2ID (false)); - const Steinberg::FUID JuceVST3EditController::iid (getFUIDForVST2ID (true)); -#else - DECLARE_CLASS_IID (JuceVST3EditController, 0xABCDEF01, 0x1234ABCD, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) - DEF_CLASS_IID (JuceVST3EditController) - - DECLARE_CLASS_IID (JuceVST3Component, 0xABCDEF01, 0x9182FAEB, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) - DEF_CLASS_IID (JuceVST3Component) -#endif - -#if JucePlugin_Enable_ARA - DECLARE_CLASS_IID (JuceARAFactory, 0xABCDEF01, 0xA1B2C3D4, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) - DEF_CLASS_IID (JuceARAFactory) -#endif - -JUCE_END_IGNORE_WARNINGS_MSVC -JUCE_END_IGNORE_WARNINGS_GCC_LIKE - -//============================================================================== -bool initModule(); -bool initModule() -{ - #if JUCE_MAC - initialiseMacVST(); - #endif - - return true; -} - -bool shutdownModule(); -bool shutdownModule() -{ - return true; -} - -#undef JUCE_EXPORTED_FUNCTION - -#if JUCE_WINDOWS - #define JUCE_EXPORTED_FUNCTION -#else - #define JUCE_EXPORTED_FUNCTION extern "C" __attribute__ ((visibility("default"))) -#endif - -#if JUCE_WINDOWS - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - - extern "C" __declspec (dllexport) bool InitDll() { return initModule(); } - extern "C" __declspec (dllexport) bool ExitDll() { return shutdownModule(); } - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#elif JUCE_LINUX || JUCE_BSD - void* moduleHandle = nullptr; - int moduleEntryCounter = 0; - - JUCE_EXPORTED_FUNCTION bool ModuleEntry (void* sharedLibraryHandle); - JUCE_EXPORTED_FUNCTION bool ModuleEntry (void* sharedLibraryHandle) - { - if (++moduleEntryCounter == 1) - { - moduleHandle = sharedLibraryHandle; - return initModule(); - } - - return true; - } - - JUCE_EXPORTED_FUNCTION bool ModuleExit(); - JUCE_EXPORTED_FUNCTION bool ModuleExit() - { - if (--moduleEntryCounter == 0) - { - moduleHandle = nullptr; - return shutdownModule(); - } - - return true; - } -#elif JUCE_MAC - CFBundleRef globalBundleInstance = nullptr; - juce::uint32 numBundleRefs = 0; - juce::Array bundleRefs; - - enum { MaxPathLength = 2048 }; - char modulePath[MaxPathLength] = { 0 }; - void* moduleHandle = nullptr; - - JUCE_EXPORTED_FUNCTION bool bundleEntry (CFBundleRef ref); - JUCE_EXPORTED_FUNCTION bool bundleEntry (CFBundleRef ref) - { - if (ref != nullptr) - { - ++numBundleRefs; - CFRetain (ref); - - bundleRefs.add (ref); - - if (moduleHandle == nullptr) - { - globalBundleInstance = ref; - moduleHandle = ref; - - CFUniquePtr tempURL (CFBundleCopyBundleURL (ref)); - CFURLGetFileSystemRepresentation (tempURL.get(), true, (UInt8*) modulePath, MaxPathLength); - } - } - - return initModule(); - } - - JUCE_EXPORTED_FUNCTION bool bundleExit(); - JUCE_EXPORTED_FUNCTION bool bundleExit() - { - if (shutdownModule()) - { - if (--numBundleRefs == 0) - { - for (int i = 0; i < bundleRefs.size(); ++i) - CFRelease (bundleRefs.getUnchecked (i)); - - bundleRefs.clear(); - } - - return true; - } - - return false; - } -#endif - -//============================================================================== -/** This typedef represents VST3's createInstance() function signature */ -using CreateFunction = FUnknown* (*)(Vst::IHostApplication*); - -static FUnknown* createComponentInstance (Vst::IHostApplication* host) -{ - return static_cast (new JuceVST3Component (host)); -} - -static FUnknown* createControllerInstance (Vst::IHostApplication* host) -{ - return static_cast (new JuceVST3EditController (host)); -} - -#if JucePlugin_Enable_ARA - static FUnknown* createARAFactoryInstance (Vst::IHostApplication* /*host*/) - { - return static_cast (new JuceARAFactory()); - } -#endif - -//============================================================================== -struct JucePluginFactory; -static JucePluginFactory* globalFactory = nullptr; - -//============================================================================== -struct JucePluginFactory : public IPluginFactory3 -{ - JucePluginFactory() - : factoryInfo (JucePlugin_Manufacturer, JucePlugin_ManufacturerWebsite, - JucePlugin_ManufacturerEmail, Vst::kDefaultFactoryFlags) - { - } - - virtual ~JucePluginFactory() - { - if (globalFactory == this) - globalFactory = nullptr; - } - - //============================================================================== - bool registerClass (const PClassInfo2& info, CreateFunction createFunction) - { - if (createFunction == nullptr) - { - jassertfalse; - return false; - } - - auto entry = std::make_unique (info, createFunction); - entry->infoW.fromAscii (info); - - classes.push_back (std::move (entry)); - - return true; - } - - //============================================================================== - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}); - - if (result.isOk()) - return result.extract (obj); - - jassertfalse; // Something new? - *obj = nullptr; - return kNotImplemented; - } - - //============================================================================== - Steinberg::int32 PLUGIN_API countClasses() override - { - return (Steinberg::int32) classes.size(); - } - - tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) override - { - if (info == nullptr) - return kInvalidArgument; - - memcpy (info, &factoryInfo, sizeof (PFactoryInfo)); - return kResultOk; - } - - tresult PLUGIN_API getClassInfo (Steinberg::int32 index, PClassInfo* info) override - { - return getPClassInfo (index, info); - } - - tresult PLUGIN_API getClassInfo2 (Steinberg::int32 index, PClassInfo2* info) override - { - return getPClassInfo (index, info); - } - - tresult PLUGIN_API getClassInfoUnicode (Steinberg::int32 index, PClassInfoW* info) override - { - if (info != nullptr) - { - if (auto& entry = classes[(size_t) index]) - { - memcpy (info, &entry->infoW, sizeof (PClassInfoW)); - return kResultOk; - } - } - - return kInvalidArgument; - } - - tresult PLUGIN_API createInstance (FIDString cid, FIDString sourceIid, void** obj) override - { - ScopedJuceInitialiser_GUI libraryInitialiser; - - #if JUCE_LINUX || JUCE_BSD - SharedResourcePointer messageThread; - #endif - - *obj = nullptr; - - TUID tuid; - memcpy (tuid, sourceIid, sizeof (TUID)); - - #if VST_VERSION >= 0x030608 - auto sourceFuid = FUID::fromTUID (tuid); - #else - FUID sourceFuid; - sourceFuid = tuid; - #endif - - if (cid == nullptr || sourceIid == nullptr || ! sourceFuid.isValid()) - { - jassertfalse; // The host you're running in has severe implementation issues! - return kInvalidArgument; - } - - TUID iidToQuery; - sourceFuid.toTUID (iidToQuery); - - for (auto& entry : classes) - { - if (doUIDsMatch (entry->infoW.cid, cid)) - { - if (auto* instance = entry->createFunction (host)) - { - const FReleaser releaser (instance); - - if (instance->queryInterface (iidToQuery, obj) == kResultOk) - return kResultOk; - } - - break; - } - } - - return kNoInterface; - } - - tresult PLUGIN_API setHostContext (FUnknown* context) override - { - host.loadFrom (context); - - if (host != nullptr) - { - Vst::String128 name; - host->getName (name); - - return kResultTrue; - } - - return kNotImplemented; - } - -private: - //============================================================================== - std::atomic refCount { 1 }; - const PFactoryInfo factoryInfo; - VSTComSmartPtr host; - - //============================================================================== - struct ClassEntry - { - ClassEntry() noexcept {} - - ClassEntry (const PClassInfo2& info, CreateFunction fn) noexcept - : info2 (info), createFunction (fn) {} - - PClassInfo2 info2; - PClassInfoW infoW; - CreateFunction createFunction = {}; - bool isUnicode = false; - - private: - JUCE_DECLARE_NON_COPYABLE (ClassEntry) - }; - - std::vector> classes; - - //============================================================================== - template - tresult PLUGIN_API getPClassInfo (Steinberg::int32 index, PClassInfoType* info) - { - if (info != nullptr) - { - zerostruct (*info); - - if (auto& entry = classes[(size_t) index]) - { - if (entry->isUnicode) - return kResultFalse; - - memcpy (info, (PClassInfoType*) &entry->info2, sizeof (PClassInfoType)); - return kResultOk; - } - } - - jassertfalse; - return kInvalidArgument; - } - - //============================================================================== - // no leak detector here to prevent it firing on shutdown when running in hosts that - // don't release the factory object correctly... - JUCE_DECLARE_NON_COPYABLE (JucePluginFactory) -}; - -} // namespace juce - -//============================================================================== -#ifndef JucePlugin_Vst3ComponentFlags - #if JucePlugin_IsSynth - #define JucePlugin_Vst3ComponentFlags Vst::kSimpleModeSupported - #else - #define JucePlugin_Vst3ComponentFlags 0 - #endif -#endif - -#ifndef JucePlugin_Vst3Category - #if JucePlugin_IsSynth - #define JucePlugin_Vst3Category Vst::PlugType::kInstrumentSynth - #else - #define JucePlugin_Vst3Category Vst::PlugType::kFx - #endif -#endif - -using namespace juce; - -//============================================================================== -// The VST3 plugin entry point. -extern "C" SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API GetPluginFactory() -{ - #if (JUCE_MSVC || (JUCE_WINDOWS && JUCE_CLANG)) && JUCE_32BIT - // Cunning trick to force this function to be exported. Life's too short to - // faff around creating .def files for this kind of thing. - // Unnecessary for 64-bit builds because those don't use decorated function names. - #pragma comment(linker, "/EXPORT:GetPluginFactory=_GetPluginFactory@0") - #endif - - if (globalFactory == nullptr) - { - globalFactory = new JucePluginFactory(); - - static const PClassInfo2 componentClass (JuceVST3Component::iid, - PClassInfo::kManyInstances, - kVstAudioEffectClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString); - - globalFactory->registerClass (componentClass, createComponentInstance); - - static const PClassInfo2 controllerClass (JuceVST3EditController::iid, - PClassInfo::kManyInstances, - kVstComponentControllerClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString); - - globalFactory->registerClass (controllerClass, createControllerInstance); - - #if JucePlugin_Enable_ARA - static const PClassInfo2 araFactoryClass (JuceARAFactory::iid, - PClassInfo::kManyInstances, - kARAMainFactoryClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString); - - globalFactory->registerClass (araFactoryClass, createARAFactoryInstance); - #endif - } - else - { - globalFactory->addRef(); - } - - return dynamic_cast (globalFactory); -} - -//============================================================================== -#if JUCE_WINDOWS -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") - -extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) Process::setCurrentModuleInstanceHandle (instance); return true; } - -JUCE_END_IGNORE_WARNINGS_GCC_LIKE -#endif - -JUCE_END_NO_SANITIZE - -#endif //JucePlugin_Build_VST3 diff --git a/modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h b/modules/juce_audio_plugin_client/detail/juce_CheckSettingMacros.h similarity index 100% rename from modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h rename to modules/juce_audio_plugin_client/detail/juce_CheckSettingMacros.h diff --git a/modules/juce_audio_plugin_client/utility/juce_CreatePluginFilter.h b/modules/juce_audio_plugin_client/detail/juce_CreatePluginFilter.h similarity index 100% rename from modules/juce_audio_plugin_client/utility/juce_CreatePluginFilter.h rename to modules/juce_audio_plugin_client/detail/juce_CreatePluginFilter.h diff --git a/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h b/modules/juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h similarity index 67% rename from modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h rename to modules/juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h index 70547cbe5e6a..2388d651ceec 100644 --- a/modules/juce_audio_plugin_client/utility/juce_IncludeModuleHeaders.h +++ b/modules/juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h @@ -23,22 +23,12 @@ ============================================================================== */ +#pragma once + #include -#include "juce_CreatePluginFilter.h" - -namespace juce -{ - #define Component juce::Component - - #if JUCE_MAC - #define Point juce::Point - void repostCurrentNSEvent(); - #endif - - //============================================================================== - inline const PluginHostType& getHostType() - { - static PluginHostType hostType; - return hostType; - } -} + +#define Component juce::Component + +#if JUCE_MAC + #define Point juce::Point +#endif diff --git a/modules/juce_audio_plugin_client/utility/juce_IncludeSystemHeaders.h b/modules/juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h similarity index 100% rename from modules/juce_audio_plugin_client/utility/juce_IncludeSystemHeaders.h rename to modules/juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h diff --git a/modules/juce_audio_plugin_client/utility/juce_LinuxMessageThread.h b/modules/juce_audio_plugin_client/detail/juce_LinuxMessageThread.h similarity index 92% rename from modules/juce_audio_plugin_client/utility/juce_LinuxMessageThread.h rename to modules/juce_audio_plugin_client/detail/juce_LinuxMessageThread.h index 267a86fe1134..ed3ff7f3c09e 100644 --- a/modules/juce_audio_plugin_client/utility/juce_LinuxMessageThread.h +++ b/modules/juce_audio_plugin_client/detail/juce_LinuxMessageThread.h @@ -25,10 +25,10 @@ #if JUCE_LINUX || JUCE_BSD -namespace juce +namespace juce::detail { -// Implemented in juce_linux_Messaging.cpp +// Implemented in juce_Messaging_linux.cpp bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages); /** @internal */ @@ -112,6 +112,6 @@ class HostDrivenEventLoop SharedResourcePointer messageThread; }; -} // namespace juce +} // namespace juce::detail #endif diff --git a/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h new file mode 100644 index 000000000000..de2f5f6d7b22 --- /dev/null +++ b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h @@ -0,0 +1,167 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 + +#include + +namespace juce::detail +{ + +struct PluginUtilities +{ + PluginUtilities() = delete; + + static int getDesktopFlags (const AudioProcessorEditor& editor) + { + return editor.wantsLayerBackedView() + ? 0 + : ComponentPeer::windowRequiresSynchronousCoreGraphicsRendering; + } + + static int getDesktopFlags (const AudioProcessorEditor* editor) + { + return editor != nullptr ? getDesktopFlags (*editor) : 0; + } + + static void addToDesktop (AudioProcessorEditor& editor, void* parent) + { + editor.addToDesktop (getDesktopFlags (editor), parent); + } + + static const PluginHostType& getHostType() + { + static PluginHostType hostType; + return hostType; + } + + #ifndef JUCE_VST3_CAN_REPLACE_VST2 + #define JUCE_VST3_CAN_REPLACE_VST2 1 + #endif + + // NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code. + static void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16]) + { + #if JUCE_WINDOWS && ! JUCE_MINGW + const auto juce_sprintf = [] (auto&& head, auto&&... tail) { sprintf_s (head, (size_t) numElementsInArray (head), tail...); }; + const auto juce_strcpy = [] (auto&& head, auto&&... tail) { strcpy_s (head, (size_t) numElementsInArray (head), tail...); }; + const auto juce_strcat = [] (auto&& head, auto&&... tail) { strcat_s (head, (size_t) numElementsInArray (head), tail...); }; + const auto juce_sscanf = [] (auto&&... args) { sscanf_s (args...); }; + #else + const auto juce_sprintf = [] (auto&& head, auto&&... tail) { snprintf (head, (size_t) numElementsInArray (head), tail...); }; + const auto juce_strcpy = [] (auto&&... args) { strcpy (args...); }; + const auto juce_strcat = [] (auto&&... args) { strcat (args...); }; + const auto juce_sscanf = [] (auto&&... args) { sscanf (args...); }; + #endif + + char uidString[33]; + + const int vstfxid = (('V' << 16) | ('S' << 8) | (forControllerUID ? 'E' : 'T')); + char vstfxidStr[7] = { 0 }; + juce_sprintf (vstfxidStr, "%06X", vstfxid); + + juce_strcpy (uidString, vstfxidStr); + + char uidStr[9] = { 0 }; + juce_sprintf (uidStr, "%08X", JucePlugin_VSTUniqueID); + juce_strcat (uidString, uidStr); + + char nameidStr[3] = { 0 }; + const size_t len = strlen (JucePlugin_Name); + + for (size_t i = 0; i <= 8; ++i) + { + juce::uint8 c = i < len ? static_cast (JucePlugin_Name[i]) : 0; + + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + + juce_sprintf (nameidStr, "%02X", c); + juce_strcat (uidString, nameidStr); + } + + unsigned long p0; + unsigned int p1, p2; + unsigned int p3[8]; + + juce_sscanf (uidString, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", + &p0, &p1, &p2, &p3[0], &p3[1], &p3[2], &p3[3], &p3[4], &p3[5], &p3[6], &p3[7]); + + union q0_u { + uint32 word; + uint8 bytes[4]; + } q0; + + union q1_u { + uint16 half; + uint8 bytes[2]; + } q1, q2; + + q0.word = static_cast (p0); + q1.half = static_cast (p1); + q2.half = static_cast (p2); + + // VST3 doesn't use COM compatible UUIDs on non windows platforms + #if ! JUCE_WINDOWS + q0.word = ByteOrder::swap (q0.word); + q1.half = ByteOrder::swap (q1.half); + q2.half = ByteOrder::swap (q2.half); + #endif + + for (int i = 0; i < 4; ++i) + uuid[i+0] = q0.bytes[i]; + + for (int i = 0; i < 2; ++i) + uuid[i+4] = q1.bytes[i]; + + for (int i = 0; i < 2; ++i) + uuid[i+6] = q2.bytes[i]; + + for (int i = 0; i < 8; ++i) + uuid[i+8] = static_cast (p3[i]); + } + + #if JucePlugin_Build_VST + static bool handleManufacturerSpecificVST2Opcode ([[maybe_unused]] int32 index, + [[maybe_unused]] pointer_sized_int value, + [[maybe_unused]] void* ptr, + float) + { + #if JUCE_VST3_CAN_REPLACE_VST2 + if ((index == (int32) ByteOrder::bigEndianInt ("stCA") || index == (int32) ByteOrder::bigEndianInt ("stCa")) + && value == (int32) ByteOrder::bigEndianInt ("FUID") && ptr != nullptr) + { + uint8 fuid[16]; + getUUIDForVST2ID (false, fuid); + ::memcpy (ptr, fuid, 16); + return true; + } + #endif + return false; + } + #endif +}; + +} // namespace juce::detail diff --git a/modules/juce_audio_plugin_client/detail/juce_VSTWindowUtilities.h b/modules/juce_audio_plugin_client/detail/juce_VSTWindowUtilities.h new file mode 100644 index 000000000000..38e800695ec7 --- /dev/null +++ b/modules/juce_audio_plugin_client/detail/juce_VSTWindowUtilities.h @@ -0,0 +1,98 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 + +#if JUCE_MAC + +#include + +namespace juce::detail +{ + +struct VSTWindowUtilities +{ + VSTWindowUtilities() = delete; + + static void* attachComponentToWindowRefVST (Component* comp, + int desktopFlags, + void* parentWindowOrView) + { + JUCE_AUTORELEASEPOOL + { + NSView* parentView = [(NSView*) parentWindowOrView retain]; + + const auto defaultFlags = JucePlugin_EditorRequiresKeyboardFocus + ? 0 + : ComponentPeer::windowIgnoresKeyPresses; + comp->addToDesktop (desktopFlags | defaultFlags, parentView); + + // (this workaround is because Wavelab provides a zero-size parent view..) + if (approximatelyEqual ([parentView frame].size.height, 0.0)) + [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint]; + + comp->setVisible (true); + comp->toFront (false); + + [[parentView window] setAcceptsMouseMovedEvents: YES]; + return parentView; + } + } + + static void detachComponentFromWindowRefVST (Component* comp, + void* window) + { + JUCE_AUTORELEASEPOOL + { + comp->removeFromDesktop(); + [(id) window release]; + } + } + + static void setNativeHostWindowSizeVST (void* window, + Component* component, + int newWidth, + int newHeight) + { + JUCE_AUTORELEASEPOOL + { + if (NSView* hostView = (NSView*) window) + { + const int dx = newWidth - component->getWidth(); + const int dy = newHeight - component->getHeight(); + + NSRect r = [hostView frame]; + r.size.width += dx; + r.size.height += dy; + r.origin.y -= dy; + [hostView setFrame: r]; + } + } + } +}; + +} // namespace juce::detail + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h index ae55ffd3e601..d3de46ef4fc8 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h @@ -35,9 +35,9 @@ ID: juce_audio_plugin_client vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE audio plugin wrapper classes - description: Classes for building VST, VST3, AU, AUv3 and AAX plugins. + description: Classes for building VST, VST3, AU, AUv3, LV2 and AAX plugins. website: http://www.juce.com/juce license: GPL/Commercial minimumCppStandard: 17 @@ -127,4 +127,4 @@ #define JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE (JUCE_IOS || JUCE_ANDROID) #endif -#include "utility/juce_CreatePluginFilter.h" +#include "detail/juce_CreatePluginFilter.h" diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp index dab46ad5ff36..55cf1dbcf47a 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp @@ -23,4 +23,2683 @@ ============================================================================== */ -#include "AAX/juce_AAX_Wrapper.cpp" +#include +#include + +#if JucePlugin_Build_AAX + +#include +#include +#include + +#include + +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127 4512 4996) +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations", + "-Wextra-semi", + "-Wfloat-equal", + "-Wfour-char-constants", + "-Winconsistent-missing-destructor-override", + "-Wnon-virtual-dtor", + "-Wpragma-pack", + "-Wshift-sign-overflow", + "-Wsign-conversion", + "-Wtautological-overlap-compare", + "-Wzero-as-null-pointer-constant", + "-Wdeprecated-copy-with-user-provided-dtor", + "-Wdeprecated") + +#include + +static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p4p0_REVISION, "JUCE requires AAX SDK version 2.4.0 or higher"); + +#if defined (AAX_SDK_2p5p0_REVISION) && AAX_SDK_2p5p0_REVISION <= AAX_SDK_CURRENT_REVISION + #define JUCE_AAX_SDK_2p5p0 1 +#else + #define JUCE_AAX_SDK_2p5p0 0 +#endif + +#define INITACFIDS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfour-char-constants") + +#undef check + +#include + +using namespace juce; + +#ifndef JucePlugin_AAX_Chunk_Identifier + #define JucePlugin_AAX_Chunk_Identifier 'juce' +#endif + +const int32_t juceChunkType = JucePlugin_AAX_Chunk_Identifier; + +//============================================================================== +namespace AAXClasses +{ + static int32 getAAXParamHash (AAX_CParamID paramID) noexcept + { + int32 result = 0; + + while (*paramID != 0) + result = (31 * result) + (*paramID++); + + return result; + } + + static void check (AAX_Result result) + { + jassertquiet (result == AAX_SUCCESS); + } + + // maps a channel index of an AAX format to an index of a juce format + struct AAXChannelStreamOrder + { + AAX_EStemFormat aaxStemFormat; + std::initializer_list speakerOrder; + }; + + static AAX_EStemFormat stemFormatForAmbisonicOrder (int order) + { + switch (order) + { + case 1: return AAX_eStemFormat_Ambi_1_ACN; + case 2: return AAX_eStemFormat_Ambi_2_ACN; + case 3: return AAX_eStemFormat_Ambi_3_ACN; + #if JUCE_AAX_SDK_2p5p0 + case 4: return AAX_eStemFormat_Ambi_4_ACN; + case 5: return AAX_eStemFormat_Ambi_5_ACN; + case 6: return AAX_eStemFormat_Ambi_6_ACN; + case 7: return AAX_eStemFormat_Ambi_7_ACN; + #endif + default: break; + } + + return AAX_eStemFormat_INT32_MAX; + } + + static AAXChannelStreamOrder aaxChannelOrder[] = + { + { AAX_eStemFormat_Mono, { AudioChannelSet::centre } }, + + { AAX_eStemFormat_Stereo, { AudioChannelSet::left, AudioChannelSet::right } }, + + { AAX_eStemFormat_LCR, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right } }, + + { AAX_eStemFormat_LCRS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::centreSurround } }, + + { AAX_eStemFormat_Quad, { AudioChannelSet::left, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround } }, + + { AAX_eStemFormat_5_0, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround } }, + + { AAX_eStemFormat_5_1, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, + AudioChannelSet::LFE } }, + + { AAX_eStemFormat_6_0, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, + AudioChannelSet::rightSurround } }, + + { AAX_eStemFormat_6_1, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::centreSurround, + AudioChannelSet::rightSurround, AudioChannelSet::LFE } }, + + { AAX_eStemFormat_7_0_SDDS, { AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, + AudioChannelSet::leftSurround, AudioChannelSet::rightSurround } }, + + { AAX_eStemFormat_7_0_DTS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear } }, + + { AAX_eStemFormat_7_1_SDDS, { AudioChannelSet::left, AudioChannelSet::leftCentre, AudioChannelSet::centre, AudioChannelSet::rightCentre, AudioChannelSet::right, + AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, AudioChannelSet::LFE } }, + + { AAX_eStemFormat_7_1_DTS, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE } }, + + { AAX_eStemFormat_7_0_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight } }, + + { AAX_eStemFormat_7_1_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight } }, + + #if JUCE_AAX_SDK_2p5p0 + { AAX_eStemFormat_5_0_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, + AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight } }, + + { AAX_eStemFormat_5_1_2, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, + AudioChannelSet::LFE, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight } }, + + { AAX_eStemFormat_5_0_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, + AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_5_1_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurround, AudioChannelSet::rightSurround, + AudioChannelSet::LFE, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_7_0_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, + AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_7_1_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::topFrontLeft, + AudioChannelSet::topFrontRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_7_0_6, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, + AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_7_1_6, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, + AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, AudioChannelSet::LFE, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, + AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_9_0_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::wideLeft, AudioChannelSet::wideRight, + AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, + AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_9_1_4, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::wideLeft, AudioChannelSet::wideRight, + AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, + AudioChannelSet::LFE, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_9_0_6, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::wideLeft, AudioChannelSet::wideRight, + AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, + AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, AudioChannelSet::topRearLeft, + AudioChannelSet::topRearRight } }, + + { AAX_eStemFormat_9_1_6, { AudioChannelSet::left, AudioChannelSet::centre, AudioChannelSet::right, AudioChannelSet::wideLeft, AudioChannelSet::wideRight, + AudioChannelSet::leftSurroundSide, AudioChannelSet::rightSurroundSide, AudioChannelSet::leftSurroundRear, AudioChannelSet::rightSurroundRear, + AudioChannelSet::LFE, AudioChannelSet::topFrontLeft, AudioChannelSet::topFrontRight, AudioChannelSet::topSideLeft, AudioChannelSet::topSideRight, + AudioChannelSet::topRearLeft, AudioChannelSet::topRearRight } }, + #endif + + { AAX_eStemFormat_None, {} }, + }; + + static AAX_EStemFormat aaxFormats[] = + { + AAX_eStemFormat_Mono, + AAX_eStemFormat_Stereo, + AAX_eStemFormat_LCR, + AAX_eStemFormat_LCRS, + AAX_eStemFormat_Quad, + AAX_eStemFormat_5_0, + AAX_eStemFormat_5_1, + AAX_eStemFormat_6_0, + AAX_eStemFormat_6_1, + AAX_eStemFormat_7_0_SDDS, + AAX_eStemFormat_7_1_SDDS, + AAX_eStemFormat_7_0_DTS, + AAX_eStemFormat_7_1_DTS, + AAX_eStemFormat_7_0_2, + AAX_eStemFormat_7_1_2, + AAX_eStemFormat_Ambi_1_ACN, + AAX_eStemFormat_Ambi_2_ACN, + AAX_eStemFormat_Ambi_3_ACN, + #if JUCE_AAX_SDK_2p5p0 + AAX_eStemFormat_5_0_2, + AAX_eStemFormat_5_1_2, + AAX_eStemFormat_5_0_4, + AAX_eStemFormat_5_1_4, + AAX_eStemFormat_7_0_4, + AAX_eStemFormat_7_1_4, + AAX_eStemFormat_7_0_6, + AAX_eStemFormat_7_1_6, + AAX_eStemFormat_9_0_4, + AAX_eStemFormat_9_1_4, + AAX_eStemFormat_9_0_6, + AAX_eStemFormat_9_1_6, + AAX_eStemFormat_Ambi_4_ACN, + AAX_eStemFormat_Ambi_5_ACN, + AAX_eStemFormat_Ambi_6_ACN, + AAX_eStemFormat_Ambi_7_ACN, + #endif + }; + + static AAX_EStemFormat getFormatForAudioChannelSet (const AudioChannelSet& set, bool ignoreLayout) noexcept + { + // if the plug-in ignores layout, it is ok to convert between formats only by their numchannnels + if (ignoreLayout) + { + auto numChannels = set.size(); + + switch (numChannels) + { + case 0: return AAX_eStemFormat_None; + case 1: return AAX_eStemFormat_Mono; + case 2: return AAX_eStemFormat_Stereo; + case 3: return AAX_eStemFormat_LCR; + case 4: return AAX_eStemFormat_Quad; + case 5: return AAX_eStemFormat_5_0; + case 6: return AAX_eStemFormat_5_1; + case 7: return AAX_eStemFormat_7_0_DTS; + case 8: return AAX_eStemFormat_7_1_DTS; + case 9: return AAX_eStemFormat_7_0_2; + case 10: return AAX_eStemFormat_7_1_2; + #if JUCE_AAX_SDK_2p5p0 + case 11: return AAX_eStemFormat_7_0_4; + case 12: return AAX_eStemFormat_7_1_4; + case 13: return AAX_eStemFormat_9_0_4; + case 14: return AAX_eStemFormat_9_1_4; + case 15: return AAX_eStemFormat_9_0_6; + case 16: return AAX_eStemFormat_9_1_6; + #endif + default: break; + } + + const auto maybeAmbisonicOrder = AudioChannelSet::getAmbisonicOrderForNumChannels (numChannels); + + if (maybeAmbisonicOrder != -1) + return stemFormatForAmbisonicOrder (maybeAmbisonicOrder); + + return AAX_eStemFormat_INT32_MAX; + } + + if (set == AudioChannelSet::disabled()) return AAX_eStemFormat_None; + if (set == AudioChannelSet::mono()) return AAX_eStemFormat_Mono; + if (set == AudioChannelSet::stereo()) return AAX_eStemFormat_Stereo; + if (set == AudioChannelSet::createLCR()) return AAX_eStemFormat_LCR; + if (set == AudioChannelSet::createLCRS()) return AAX_eStemFormat_LCRS; + if (set == AudioChannelSet::quadraphonic()) return AAX_eStemFormat_Quad; + if (set == AudioChannelSet::create5point0()) return AAX_eStemFormat_5_0; + if (set == AudioChannelSet::create5point1()) return AAX_eStemFormat_5_1; + if (set == AudioChannelSet::create6point0()) return AAX_eStemFormat_6_0; + if (set == AudioChannelSet::create6point1()) return AAX_eStemFormat_6_1; + if (set == AudioChannelSet::create7point0()) return AAX_eStemFormat_7_0_DTS; + if (set == AudioChannelSet::create7point1()) return AAX_eStemFormat_7_1_DTS; + if (set == AudioChannelSet::create7point0SDDS()) return AAX_eStemFormat_7_0_SDDS; + if (set == AudioChannelSet::create7point1SDDS()) return AAX_eStemFormat_7_1_SDDS; + if (set == AudioChannelSet::create7point0point2()) return AAX_eStemFormat_7_0_2; + if (set == AudioChannelSet::create7point1point2()) return AAX_eStemFormat_7_1_2; + + #if JUCE_AAX_SDK_2p5p0 + if (set == AudioChannelSet::create5point0point2()) return AAX_eStemFormat_5_0_2; + if (set == AudioChannelSet::create5point1point2()) return AAX_eStemFormat_5_1_2; + if (set == AudioChannelSet::create5point0point4()) return AAX_eStemFormat_5_0_4; + if (set == AudioChannelSet::create5point1point4()) return AAX_eStemFormat_5_1_4; + if (set == AudioChannelSet::create7point0point4()) return AAX_eStemFormat_7_0_4; + if (set == AudioChannelSet::create7point1point4()) return AAX_eStemFormat_7_1_4; + if (set == AudioChannelSet::create7point0point6()) return AAX_eStemFormat_7_0_6; + if (set == AudioChannelSet::create7point1point6()) return AAX_eStemFormat_7_1_6; + if (set == AudioChannelSet::create9point0point4()) return AAX_eStemFormat_9_0_4; + if (set == AudioChannelSet::create9point1point4()) return AAX_eStemFormat_9_1_4; + if (set == AudioChannelSet::create9point0point6()) return AAX_eStemFormat_9_0_6; + if (set == AudioChannelSet::create9point1point6()) return AAX_eStemFormat_9_1_6; + #endif + + auto order = set.getAmbisonicOrder(); + if (order >= 0) + return stemFormatForAmbisonicOrder (order); + + return AAX_eStemFormat_INT32_MAX; + } + + static inline AudioChannelSet channelSetFromStemFormat (AAX_EStemFormat format, bool ignoreLayout) noexcept + { + if (! ignoreLayout) + { + switch (format) + { + case AAX_eStemFormat_None: return AudioChannelSet::disabled(); + case AAX_eStemFormat_Mono: return AudioChannelSet::mono(); + case AAX_eStemFormat_Stereo: return AudioChannelSet::stereo(); + case AAX_eStemFormat_LCR: return AudioChannelSet::createLCR(); + case AAX_eStemFormat_LCRS: return AudioChannelSet::createLCRS(); + case AAX_eStemFormat_Quad: return AudioChannelSet::quadraphonic(); + case AAX_eStemFormat_5_0: return AudioChannelSet::create5point0(); + case AAX_eStemFormat_5_1: return AudioChannelSet::create5point1(); + case AAX_eStemFormat_6_0: return AudioChannelSet::create6point0(); + case AAX_eStemFormat_6_1: return AudioChannelSet::create6point1(); + case AAX_eStemFormat_7_0_SDDS: return AudioChannelSet::create7point0SDDS(); + case AAX_eStemFormat_7_0_DTS: return AudioChannelSet::create7point0(); + case AAX_eStemFormat_7_1_SDDS: return AudioChannelSet::create7point1SDDS(); + case AAX_eStemFormat_7_1_DTS: return AudioChannelSet::create7point1(); + case AAX_eStemFormat_7_0_2: return AudioChannelSet::create7point0point2(); + case AAX_eStemFormat_7_1_2: return AudioChannelSet::create7point1point2(); + case AAX_eStemFormat_Ambi_1_ACN: return AudioChannelSet::ambisonic (1); + case AAX_eStemFormat_Ambi_2_ACN: return AudioChannelSet::ambisonic (2); + case AAX_eStemFormat_Ambi_3_ACN: return AudioChannelSet::ambisonic (3); + + #if JUCE_AAX_SDK_2p5p0 + case AAX_eStemFormat_5_0_2: return AudioChannelSet::create5point0point2(); + case AAX_eStemFormat_5_1_2: return AudioChannelSet::create5point1point2(); + case AAX_eStemFormat_5_0_4: return AudioChannelSet::create5point0point4(); + case AAX_eStemFormat_5_1_4: return AudioChannelSet::create5point1point4(); + case AAX_eStemFormat_7_0_4: return AudioChannelSet::create7point0point4(); + case AAX_eStemFormat_7_1_4: return AudioChannelSet::create7point1point4(); + case AAX_eStemFormat_7_0_6: return AudioChannelSet::create7point0point6(); + case AAX_eStemFormat_7_1_6: return AudioChannelSet::create7point1point6(); + case AAX_eStemFormat_9_0_4: return AudioChannelSet::create9point0point4(); + case AAX_eStemFormat_9_1_4: return AudioChannelSet::create9point1point4(); + case AAX_eStemFormat_9_0_6: return AudioChannelSet::create9point0point6(); + case AAX_eStemFormat_9_1_6: return AudioChannelSet::create9point1point6(); + case AAX_eStemFormat_Ambi_4_ACN: return AudioChannelSet::ambisonic (4); + case AAX_eStemFormat_Ambi_5_ACN: return AudioChannelSet::ambisonic (5); + case AAX_eStemFormat_Ambi_6_ACN: return AudioChannelSet::ambisonic (6); + case AAX_eStemFormat_Ambi_7_ACN: return AudioChannelSet::ambisonic (7); + #else + case AAX_eStemFormat_Reserved_1: + case AAX_eStemFormat_Reserved_2: + case AAX_eStemFormat_Reserved_3: + #endif + + case AAX_eStemFormatNum: + case AAX_eStemFormat_Any: + case AAX_eStemFormat_INT32_MAX: + default: return AudioChannelSet::disabled(); + } + } + + return AudioChannelSet::discreteChannels (jmax (0, static_cast (AAX_STEM_FORMAT_CHANNEL_COUNT (format)))); + } + + static AAX_EMeterType getMeterTypeForCategory (AudioProcessorParameter::Category category) + { + switch (category) + { + case AudioProcessorParameter::inputMeter: return AAX_eMeterType_Input; + case AudioProcessorParameter::outputMeter: return AAX_eMeterType_Output; + case AudioProcessorParameter::compressorLimiterGainReductionMeter: return AAX_eMeterType_CLGain; + case AudioProcessorParameter::expanderGateGainReductionMeter: return AAX_eMeterType_EGGain; + case AudioProcessorParameter::analysisMeter: return AAX_eMeterType_Analysis; + case AudioProcessorParameter::genericParameter: + case AudioProcessorParameter::inputGain: + case AudioProcessorParameter::outputGain: + case AudioProcessorParameter::otherMeter: + default: return AAX_eMeterType_Other; + } + } + + static Colour getColourFromHighlightEnum (AAX_EHighlightColor colour) noexcept + { + switch (colour) + { + case AAX_eHighlightColor_Red: return Colours::red; + case AAX_eHighlightColor_Blue: return Colours::blue; + case AAX_eHighlightColor_Green: return Colours::green; + case AAX_eHighlightColor_Yellow: return Colours::yellow; + case AAX_eHighlightColor_Num: + default: jassertfalse; break; + } + + return Colours::black; + } + + static int juceChannelIndexToAax (int juceIndex, const AudioChannelSet& channelSet) + { + auto isAmbisonic = (channelSet.getAmbisonicOrder() >= 0); + auto currentLayout = getFormatForAudioChannelSet (channelSet, false); + int layoutIndex; + + if (isAmbisonic && currentLayout != AAX_eStemFormat_INT32_MAX) + return juceIndex; + + for (layoutIndex = 0; aaxChannelOrder[layoutIndex].aaxStemFormat != currentLayout; ++layoutIndex) + if (aaxChannelOrder[layoutIndex].aaxStemFormat == 0) return juceIndex; + + auto& channelOrder = aaxChannelOrder[layoutIndex]; + auto channelType = channelSet.getTypeOfChannel (static_cast (juceIndex)); + const auto& speakerOrder = channelOrder.speakerOrder; + + const auto it = std::find (std::cbegin (speakerOrder), std::cend (speakerOrder), channelType); + + if (it != std::cend (speakerOrder)) + return (int) std::distance (std::cbegin (speakerOrder), it); + + return juceIndex; + } + + //============================================================================== + class JuceAAX_Processor; + + struct PluginInstanceInfo + { + PluginInstanceInfo (JuceAAX_Processor& p) : parameters (p) {} + + JuceAAX_Processor& parameters; + + JUCE_DECLARE_NON_COPYABLE (PluginInstanceInfo) + }; + + //============================================================================== + struct JUCEAlgorithmContext + { + float** inputChannels; + float** outputChannels; + int32_t* bufferSize; + int32_t* bypass; + + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + AAX_IMIDINode* midiNodeIn; + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect + AAX_IMIDINode* midiNodeOut; + #endif + + PluginInstanceInfo* pluginInstance; + int32_t* isPrepared; + float* const* meterTapBuffers; + int32_t* sideChainBuffers; + }; + + struct JUCEAlgorithmIDs + { + enum + { + inputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, inputChannels), + outputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, outputChannels), + bufferSize = AAX_FIELD_INDEX (JUCEAlgorithmContext, bufferSize), + bypass = AAX_FIELD_INDEX (JUCEAlgorithmContext, bypass), + + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + midiNodeIn = AAX_FIELD_INDEX (JUCEAlgorithmContext, midiNodeIn), + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect + midiNodeOut = AAX_FIELD_INDEX (JUCEAlgorithmContext, midiNodeOut), + #endif + + pluginInstance = AAX_FIELD_INDEX (JUCEAlgorithmContext, pluginInstance), + preparedFlag = AAX_FIELD_INDEX (JUCEAlgorithmContext, isPrepared), + + meterTapBuffers = AAX_FIELD_INDEX (JUCEAlgorithmContext, meterTapBuffers), + + sideChainBuffers = AAX_FIELD_INDEX (JUCEAlgorithmContext, sideChainBuffers) + }; + }; + + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + static AAX_IMIDINode* getMidiNodeIn (const JUCEAlgorithmContext& c) noexcept { return c.midiNodeIn; } + #else + static AAX_IMIDINode* getMidiNodeIn (const JUCEAlgorithmContext&) noexcept { return nullptr; } + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect + AAX_IMIDINode* midiNodeOut; + static AAX_IMIDINode* getMidiNodeOut (const JUCEAlgorithmContext& c) noexcept { return c.midiNodeOut; } + #else + static AAX_IMIDINode* getMidiNodeOut (const JUCEAlgorithmContext&) noexcept { return nullptr; } + #endif + + //============================================================================== + class JuceAAX_Processor; + + class JuceAAX_GUI : public AAX_CEffectGUI, + public ModifierKeyProvider + { + public: + JuceAAX_GUI() = default; + ~JuceAAX_GUI() override { DeleteViewContainer(); } + + static AAX_IEffectGUI* AAX_CALLBACK Create() { return new JuceAAX_GUI(); } + + void CreateViewContents() override; + + void CreateViewContainer() override + { + CreateViewContents(); + + if (void* nativeViewToAttachTo = GetViewContainerPtr()) + { + #if JUCE_MAC + if (GetViewContainerType() == AAX_eViewContainer_Type_NSView) + #else + if (GetViewContainerType() == AAX_eViewContainer_Type_HWND) + #endif + { + component->setVisible (true); + component->addToDesktop (detail::PluginUtilities::getDesktopFlags (component->pluginEditor.get()), nativeViewToAttachTo); + + if (ModifierKeyReceiver* modReceiver = dynamic_cast (component->getPeer())) + modReceiver->setModifierKeyProvider (this); + } + } + } + + void DeleteViewContainer() override + { + if (component != nullptr) + { + JUCE_AUTORELEASEPOOL + { + if (auto* modReceiver = dynamic_cast (component->getPeer())) + modReceiver->removeModifierKeyProvider(); + + component->removeFromDesktop(); + component = nullptr; + } + } + } + + AAX_Result GetViewSize (AAX_Point* viewSize) const override + { + if (component != nullptr) + { + *viewSize = convertToHostBounds ({ (float) component->getHeight(), + (float) component->getWidth() }); + + return AAX_SUCCESS; + } + + return AAX_ERROR_NULL_OBJECT; + } + + AAX_Result ParameterUpdated (AAX_CParamID) override + { + return AAX_SUCCESS; + } + + AAX_Result SetControlHighlightInfo (AAX_CParamID paramID, AAX_CBoolean isHighlighted, AAX_EHighlightColor colour) override + { + if (component != nullptr && component->pluginEditor != nullptr) + { + auto index = getParamIndexFromID (paramID); + + if (index >= 0) + { + AudioProcessorEditor::ParameterControlHighlightInfo info; + info.parameterIndex = index; + info.isHighlighted = (isHighlighted != 0); + info.suggestedColour = getColourFromHighlightEnum (colour); + + component->pluginEditor->setControlHighlight (info); + } + + return AAX_SUCCESS; + } + + return AAX_ERROR_NULL_OBJECT; + } + + int getWin32Modifiers() const override + { + int modifierFlags = 0; + + if (auto* viewContainer = GetViewContainer()) + { + uint32 aaxViewMods = 0; + const_cast (viewContainer)->GetModifiers (&aaxViewMods); + + if ((aaxViewMods & AAX_eModifiers_Shift) != 0) modifierFlags |= ModifierKeys::shiftModifier; + if ((aaxViewMods & AAX_eModifiers_Alt ) != 0) modifierFlags |= ModifierKeys::altModifier; + } + + return modifierFlags; + } + + private: + //============================================================================== + int getParamIndexFromID (AAX_CParamID paramID) const noexcept; + AAX_CParamID getAAXParamIDFromJuceIndex (int index) const noexcept; + + //============================================================================== + static AAX_Point convertToHostBounds (AAX_Point pluginSize) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return pluginSize; + + return { pluginSize.vert * desktopScale, + pluginSize.horz * desktopScale }; + } + + //============================================================================== + struct ContentWrapperComponent : public Component + { + ContentWrapperComponent (JuceAAX_GUI& gui, AudioProcessor& plugin) + : owner (gui) + { + setOpaque (true); + setBroughtToFrontOnMouseClick (true); + + pluginEditor.reset (plugin.createEditorIfNeeded()); + addAndMakeVisible (pluginEditor.get()); + + if (pluginEditor != nullptr) + { + lastValidSize = pluginEditor->getLocalBounds(); + setBounds (lastValidSize); + pluginEditor->addMouseListener (this, true); + } + } + + ~ContentWrapperComponent() override + { + if (pluginEditor != nullptr) + { + PopupMenu::dismissAllActiveMenus(); + pluginEditor->removeMouseListener (this); + pluginEditor->processor.editorBeingDeleted (pluginEditor.get()); + } + } + + void paint (Graphics& g) override + { + g.fillAll (Colours::black); + } + + template + void callMouseMethod (const MouseEvent& e, MethodType method) + { + if (auto* vc = owner.GetViewContainer()) + { + auto parameterIndex = pluginEditor->getControlParameterIndex (*e.eventComponent); + + if (auto aaxParamID = owner.getAAXParamIDFromJuceIndex (parameterIndex)) + { + uint32_t mods = 0; + vc->GetModifiers (&mods); + + (vc->*method) (aaxParamID, mods); + } + } + } + + void mouseDown (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDown); } + void mouseUp (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseUp); } + void mouseDrag (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDrag); } + + void parentSizeChanged() override + { + resizeHostWindow(); + + if (pluginEditor != nullptr) + pluginEditor->repaint(); + } + + void childBoundsChanged (Component*) override + { + if (resizeHostWindow()) + { + setSize (pluginEditor->getWidth(), pluginEditor->getHeight()); + lastValidSize = getBounds(); + } + else + { + pluginEditor->setBoundsConstrained (pluginEditor->getBounds().withSize (lastValidSize.getWidth(), + lastValidSize.getHeight())); + } + } + + bool resizeHostWindow() + { + if (pluginEditor != nullptr) + { + auto newSize = convertToHostBounds ({ (float) pluginEditor->getHeight(), + (float) pluginEditor->getWidth() }); + + return owner.GetViewContainer()->SetViewSize (newSize) == AAX_SUCCESS; + } + + return false; + } + + std::unique_ptr pluginEditor; + JuceAAX_GUI& owner; + + #if JUCE_WINDOWS + detail::WindowsHooks hooks; + #endif + juce::Rectangle lastValidSize; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) + }; + + std::unique_ptr component; + ScopedJuceInitialiser_GUI libraryInitialiser; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAAX_GUI) + }; + + // Copied here, because not all versions of the AAX SDK define all of these values + enum JUCE_AAX_EFrameRate : std::underlying_type_t + { + JUCE_AAX_eFrameRate_Undeclared = 0, + JUCE_AAX_eFrameRate_24Frame = 1, + JUCE_AAX_eFrameRate_25Frame = 2, + JUCE_AAX_eFrameRate_2997NonDrop = 3, + JUCE_AAX_eFrameRate_2997DropFrame = 4, + JUCE_AAX_eFrameRate_30NonDrop = 5, + JUCE_AAX_eFrameRate_30DropFrame = 6, + JUCE_AAX_eFrameRate_23976 = 7, + JUCE_AAX_eFrameRate_47952 = 8, + JUCE_AAX_eFrameRate_48Frame = 9, + JUCE_AAX_eFrameRate_50Frame = 10, + JUCE_AAX_eFrameRate_5994NonDrop = 11, + JUCE_AAX_eFrameRate_5994DropFrame = 12, + JUCE_AAX_eFrameRate_60NonDrop = 13, + JUCE_AAX_eFrameRate_60DropFrame = 14, + JUCE_AAX_eFrameRate_100Frame = 15, + JUCE_AAX_eFrameRate_11988NonDrop = 16, + JUCE_AAX_eFrameRate_11988DropFrame = 17, + JUCE_AAX_eFrameRate_120NonDrop = 18, + JUCE_AAX_eFrameRate_120DropFrame = 19 + }; + + static void AAX_CALLBACK algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd); + + static Array activeProcessors; + + //============================================================================== + class JuceAAX_Processor : public AAX_CEffectParameters, + public juce::AudioPlayHead, + public AudioProcessorListener, + private AsyncUpdater + { + public: + JuceAAX_Processor() + : pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_AAX)) + { + inParameterChangedCallback = false; + + pluginInstance->setPlayHead (this); + pluginInstance->addListener (this); + + rebuildChannelMapArrays(); + + AAX_CEffectParameters::GetNumberOfChunks (&juceChunkIndex); + activeProcessors.add (this); + } + + ~JuceAAX_Processor() override + { + activeProcessors.removeAllInstancesOf (this); + } + + static AAX_CEffectParameters* AAX_CALLBACK Create() + { + if (PluginHostType::jucePlugInIsRunningInAudioSuiteFn == nullptr) + { + PluginHostType::jucePlugInIsRunningInAudioSuiteFn = [] (AudioProcessor& processor) + { + for (auto* p : activeProcessors) + if (&p->getPluginInstance() == &processor) + return p->isInAudioSuite(); + + return false; + }; + } + + return new JuceAAX_Processor(); + } + + AAX_Result Uninitialize() override + { + cancelPendingUpdate(); + juceParameters.clear(); + + if (isPrepared && pluginInstance != nullptr) + { + isPrepared = false; + processingSidechainChange = false; + + pluginInstance->releaseResources(); + } + + return AAX_CEffectParameters::Uninitialize(); + } + + AAX_Result EffectInit() override + { + cancelPendingUpdate(); + check (Controller()->GetSampleRate (&sampleRate)); + processingSidechainChange = false; + auto err = preparePlugin(); + + if (err != AAX_SUCCESS) + return err; + + addAudioProcessorParameters(); + + return AAX_SUCCESS; + } + + AAX_Result GetNumberOfChunks (int32_t* numChunks) const override + { + // The juceChunk is the last chunk. + *numChunks = juceChunkIndex + 1; + return AAX_SUCCESS; + } + + AAX_Result GetChunkIDFromIndex (int32_t index, AAX_CTypeID* chunkID) const override + { + if (index != juceChunkIndex) + return AAX_CEffectParameters::GetChunkIDFromIndex (index, chunkID); + + *chunkID = juceChunkType; + return AAX_SUCCESS; + } + + AAX_Result GetChunkSize (AAX_CTypeID chunkID, uint32_t* oSize) const override + { + if (chunkID != juceChunkType) + return AAX_CEffectParameters::GetChunkSize (chunkID, oSize); + + auto& chunkMemoryBlock = perThreadFilterData.get(); + + chunkMemoryBlock.data.reset(); + pluginInstance->getStateInformation (chunkMemoryBlock.data); + chunkMemoryBlock.isValid = true; + + *oSize = (uint32_t) chunkMemoryBlock.data.getSize(); + return AAX_SUCCESS; + } + + AAX_Result GetChunk (AAX_CTypeID chunkID, AAX_SPlugInChunk* oChunk) const override + { + if (chunkID != juceChunkType) + return AAX_CEffectParameters::GetChunk (chunkID, oChunk); + + auto& chunkMemoryBlock = perThreadFilterData.get(); + + if (! chunkMemoryBlock.isValid) + return 20700; // AAX_ERROR_PLUGIN_API_INVALID_THREAD + + oChunk->fSize = (int32_t) chunkMemoryBlock.data.getSize(); + chunkMemoryBlock.data.copyTo (oChunk->fData, 0, chunkMemoryBlock.data.getSize()); + chunkMemoryBlock.isValid = false; + + return AAX_SUCCESS; + } + + AAX_Result SetChunk (AAX_CTypeID chunkID, const AAX_SPlugInChunk* chunk) override + { + if (chunkID != juceChunkType) + return AAX_CEffectParameters::SetChunk (chunkID, chunk); + + pluginInstance->setStateInformation ((void*) chunk->fData, chunk->fSize); + + // Notify Pro Tools that the parameters were updated. + // Without it a bug happens in these circumstances: + // * A preset is saved with the RTAS version of the plugin (".tfx" preset format). + // * The preset is loaded in PT 10 using the AAX version. + // * The session is then saved, and closed. + // * The saved session is loaded, but acting as if the preset was never loaded. + // IMPORTANT! If the plugin doesn't manage its own bypass parameter, don't try + // to overwrite the bypass parameter value. + auto numParameters = juceParameters.getNumParameters(); + + for (int i = 0; i < numParameters; ++i) + if (auto* juceParam = juceParameters.getParamForIndex (i)) + if (juceParam != ownedBypassParameter.get()) + if (auto paramID = getAAXParamIDFromJuceIndex (i)) + SetParameterNormalizedValue (paramID, juceParam->getValue()); + + return AAX_SUCCESS; + } + + AAX_Result ResetFieldData (AAX_CFieldIndex fieldIndex, void* data, uint32_t dataSize) const override + { + switch (fieldIndex) + { + case JUCEAlgorithmIDs::pluginInstance: + { + auto numObjects = dataSize / sizeof (PluginInstanceInfo); + auto* objects = static_cast (data); + + jassert (numObjects == 1); // not sure how to handle more than one.. + + for (size_t i = 0; i < numObjects; ++i) + new (objects + i) PluginInstanceInfo (const_cast (*this)); + + break; + } + + case JUCEAlgorithmIDs::preparedFlag: + { + const_cast (this)->preparePlugin(); + + auto numObjects = dataSize / sizeof (uint32_t); + auto* objects = static_cast (data); + + for (size_t i = 0; i < numObjects; ++i) + objects[i] = 1; + + break; + } + + case JUCEAlgorithmIDs::meterTapBuffers: + { + // this is a dummy field only when there are no aaxMeters + jassert (aaxMeters.size() == 0); + + { + auto numObjects = dataSize / sizeof (float*); + auto* objects = static_cast (data); + + for (size_t i = 0; i < numObjects; ++i) + objects[i] = nullptr; + } + break; + } + } + + return AAX_SUCCESS; + } + + void setAudioProcessorParameter (AAX_CParamID paramID, double value) + { + if (auto* param = getParameterFromID (paramID)) + { + auto newValue = static_cast (value); + + if (! approximatelyEqual (newValue, param->getValue())) + { + param->setValue (newValue); + + inParameterChangedCallback = true; + param->sendValueChangedMessageToListeners (newValue); + } + } + } + + AAX_Result GetNumberOfChanges (int32_t* numChanges) const override + { + const auto result = AAX_CEffectParameters::GetNumberOfChanges (numChanges); + *numChanges += numSetDirtyCalls; + return result; + } + + AAX_Result UpdateParameterNormalizedValue (AAX_CParamID paramID, double value, AAX_EUpdateSource source) override + { + auto result = AAX_CEffectParameters::UpdateParameterNormalizedValue (paramID, value, source); + setAudioProcessorParameter (paramID, value); + + return result; + } + + AAX_Result GetParameterValueFromString (AAX_CParamID paramID, double* result, const AAX_IString& text) const override + { + if (auto* param = getParameterFromID (paramID)) + { + if (! LegacyAudioParameter::isLegacy (param)) + { + *result = param->getValueForText (text.Get()); + return AAX_SUCCESS; + } + } + + return AAX_CEffectParameters::GetParameterValueFromString (paramID, result, text); + } + + AAX_Result GetParameterStringFromValue (AAX_CParamID paramID, double value, AAX_IString* result, int32_t maxLen) const override + { + if (auto* param = getParameterFromID (paramID)) + result->Set (param->getText ((float) value, maxLen).toRawUTF8()); + + return AAX_SUCCESS; + } + + AAX_Result GetParameterNumberofSteps (AAX_CParamID paramID, int32_t* result) const + { + if (auto* param = getParameterFromID (paramID)) + *result = getSafeNumberOfParameterSteps (*param); + + return AAX_SUCCESS; + } + + AAX_Result GetParameterNormalizedValue (AAX_CParamID paramID, double* result) const override + { + if (auto* param = getParameterFromID (paramID)) + *result = (double) param->getValue(); + else + *result = 0.0; + + return AAX_SUCCESS; + } + + AAX_Result SetParameterNormalizedValue (AAX_CParamID paramID, double newValue) override + { + if (auto* p = mParameterManager.GetParameterByID (paramID)) + p->SetValueWithFloat ((float) newValue); + + setAudioProcessorParameter (paramID, (float) newValue); + + return AAX_SUCCESS; + } + + AAX_Result SetParameterNormalizedRelative (AAX_CParamID paramID, double newDeltaValue) override + { + if (auto* param = getParameterFromID (paramID)) + { + auto newValue = param->getValue() + (float) newDeltaValue; + + setAudioProcessorParameter (paramID, jlimit (0.0f, 1.0f, newValue)); + + if (auto* p = mParameterManager.GetParameterByID (paramID)) + p->SetValueWithFloat (newValue); + } + + return AAX_SUCCESS; + } + + AAX_Result GetParameterNameOfLength (AAX_CParamID paramID, AAX_IString* result, int32_t maxLen) const override + { + if (auto* param = getParameterFromID (paramID)) + result->Set (param->getName (maxLen).toRawUTF8()); + + return AAX_SUCCESS; + } + + AAX_Result GetParameterName (AAX_CParamID paramID, AAX_IString* result) const override + { + if (auto* param = getParameterFromID (paramID)) + result->Set (param->getName (31).toRawUTF8()); + + return AAX_SUCCESS; + } + + AAX_Result GetParameterDefaultNormalizedValue (AAX_CParamID paramID, double* result) const override + { + if (auto* param = getParameterFromID (paramID)) + *result = (double) param->getDefaultValue(); + else + *result = 0.0; + + jassert (*result >= 0 && *result <= 1.0f); + + return AAX_SUCCESS; + } + + AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } + + Optional getPosition() const override + { + PositionInfo info; + + const AAX_ITransport& transport = *Transport(); + + info.setBpm ([&] + { + double bpm = 0.0; + + return transport.GetCurrentTempo (&bpm) == AAX_SUCCESS ? makeOptional (bpm) : nullopt; + }()); + + const auto signature = [&] + { + int32_t num = 4, den = 4; + + return transport.GetCurrentMeter (&num, &den) == AAX_SUCCESS + ? makeOptional (TimeSignature { (int) num, (int) den }) + : nullopt; + }(); + + info.setTimeSignature (signature); + + info.setIsPlaying ([&] + { + bool isPlaying = false; + + return transport.IsTransportPlaying (&isPlaying) == AAX_SUCCESS && isPlaying; + }()); + + info.setIsRecording (recordingState.get().orFallback (false)); + + const auto optionalTimeInSamples = [&info, &transport] + { + int64_t timeInSamples = 0; + return ((! info.getIsPlaying() && transport.GetTimelineSelectionStartPosition (&timeInSamples) == AAX_SUCCESS) + || transport.GetCurrentNativeSampleLocation (&timeInSamples) == AAX_SUCCESS) + ? makeOptional (timeInSamples) + : nullopt; + }(); + + info.setTimeInSamples (optionalTimeInSamples); + info.setTimeInSeconds ((float) optionalTimeInSamples.orFallback (0) / sampleRate); + + const auto tickPosition = [&] + { + int64_t ticks = 0; + + return ((info.getIsPlaying() && transport.GetCustomTickPosition (&ticks, optionalTimeInSamples.orFallback (0))) == AAX_SUCCESS) + || transport.GetCurrentTickPosition (&ticks) == AAX_SUCCESS + ? makeOptional (ticks) + : nullopt; + }(); + + info.setPpqPosition (tickPosition.hasValue() ? makeOptional (static_cast (*tickPosition) / 960'000.0) : nullopt); + + bool isLooping = false; + int64_t loopStartTick = 0, loopEndTick = 0; + + if (transport.GetCurrentLoopPosition (&isLooping, &loopStartTick, &loopEndTick) == AAX_SUCCESS) + { + info.setIsLooping (isLooping); + info.setLoopPoints (LoopPoints { (double) loopStartTick / 960000.0, (double) loopEndTick / 960000.0 }); + } + + struct RateAndOffset + { + AAX_EFrameRate frameRate{}; + int64_t offset{}; + }; + + const auto timeCodeIfAvailable = [&]() -> std::optional + { + RateAndOffset result{}; + + if (transport.GetHDTimeCodeInfo (&result.frameRate, &result.offset) == AAX_SUCCESS) + return result; + + int32_t offset32{}; + + if (transport.GetTimeCodeInfo (&result.frameRate, &offset32) == AAX_SUCCESS) + { + result.offset = offset32; + return result; + } + + return {}; + }(); + + if (timeCodeIfAvailable.has_value()) + { + info.setFrameRate ([&]() -> Optional + { + switch ((JUCE_AAX_EFrameRate) timeCodeIfAvailable->frameRate) + { + case JUCE_AAX_eFrameRate_24Frame: return FrameRate().withBaseRate (24); + case JUCE_AAX_eFrameRate_23976: return FrameRate().withBaseRate (24).withPullDown(); + + case JUCE_AAX_eFrameRate_25Frame: return FrameRate().withBaseRate (25); + + case JUCE_AAX_eFrameRate_30NonDrop: return FrameRate().withBaseRate (30); + case JUCE_AAX_eFrameRate_30DropFrame: return FrameRate().withBaseRate (30).withDrop(); + case JUCE_AAX_eFrameRate_2997NonDrop: return FrameRate().withBaseRate (30).withPullDown(); + case JUCE_AAX_eFrameRate_2997DropFrame: return FrameRate().withBaseRate (30).withPullDown().withDrop(); + + case JUCE_AAX_eFrameRate_48Frame: return FrameRate().withBaseRate (48); + case JUCE_AAX_eFrameRate_47952: return FrameRate().withBaseRate (48).withPullDown(); + + case JUCE_AAX_eFrameRate_50Frame: return FrameRate().withBaseRate (50); + + case JUCE_AAX_eFrameRate_60NonDrop: return FrameRate().withBaseRate (60); + case JUCE_AAX_eFrameRate_60DropFrame: return FrameRate().withBaseRate (60).withDrop(); + case JUCE_AAX_eFrameRate_5994NonDrop: return FrameRate().withBaseRate (60).withPullDown(); + case JUCE_AAX_eFrameRate_5994DropFrame: return FrameRate().withBaseRate (60).withPullDown().withDrop(); + + case JUCE_AAX_eFrameRate_100Frame: return FrameRate().withBaseRate (100); + + case JUCE_AAX_eFrameRate_120NonDrop: return FrameRate().withBaseRate (120); + case JUCE_AAX_eFrameRate_120DropFrame: return FrameRate().withBaseRate (120).withDrop(); + case JUCE_AAX_eFrameRate_11988NonDrop: return FrameRate().withBaseRate (120).withPullDown(); + case JUCE_AAX_eFrameRate_11988DropFrame: return FrameRate().withBaseRate (120).withPullDown().withDrop(); + + case JUCE_AAX_eFrameRate_Undeclared: break; + } + + return {}; + }()); + } + + const auto offset = timeCodeIfAvailable.has_value() ? timeCodeIfAvailable->offset : int64_t{}; + const auto effectiveRate = info.getFrameRate().hasValue() ? info.getFrameRate()->getEffectiveRate() : 0.0; + info.setEditOriginTime (makeOptional (effectiveRate != 0.0 ? offset / effectiveRate : offset)); + + { + int32_t bars{}, beats{}; + int64_t displayTicks{}; + + if (optionalTimeInSamples.hasValue() + && transport.GetBarBeatPosition (&bars, &beats, &displayTicks, *optionalTimeInSamples) == AAX_SUCCESS) + { + info.setBarCount (bars); + + if (signature.hasValue()) + { + const auto ticksSinceBar = static_cast (((beats - 1) * 4 * 960'000) / signature->denominator) + displayTicks; + + if (tickPosition.hasValue() && ticksSinceBar <= tickPosition) + { + const auto barStartInTicks = static_cast (*tickPosition - ticksSinceBar); + info.setPpqPositionOfLastBarStart (barStartInTicks / 960'000.0); + } + } + } + } + + return info; + } + + void audioProcessorParameterChanged (AudioProcessor* /*processor*/, int parameterIndex, float newValue) override + { + if (inParameterChangedCallback.get()) + { + inParameterChangedCallback = false; + return; + } + + if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) + SetParameterNormalizedValue (paramID, (double) newValue); + } + + void audioProcessorChanged (AudioProcessor* processor, const ChangeDetails& details) override + { + ++mNumPlugInChanges; + + if (details.parameterInfoChanged) + { + for (const auto* param : juceParameters) + if (auto* aaxParam = mParameterManager.GetParameterByID (getAAXParamIDFromJuceIndex (param->getParameterIndex()))) + syncParameterAttributes (aaxParam, param); + } + + if (details.latencyChanged) + check (Controller()->SetSignalLatency (processor->getLatencySamples())); + + if (details.nonParameterStateChanged) + ++numSetDirtyCalls; + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int parameterIndex) override + { + if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) + TouchParameter (paramID); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int parameterIndex) override + { + if (auto paramID = getAAXParamIDFromJuceIndex (parameterIndex)) + ReleaseParameter (paramID); + } + + AAX_Result NotificationReceived (AAX_CTypeID type, const void* data, uint32_t size) override + { + switch (type) + { + case AAX_eNotificationEvent_EnteringOfflineMode: pluginInstance->setNonRealtime (true); break; + case AAX_eNotificationEvent_ExitingOfflineMode: pluginInstance->setNonRealtime (false); break; + + case AAX_eNotificationEvent_ASProcessingState: + { + if (data != nullptr && size == sizeof (AAX_EProcessingState)) + { + const auto state = *static_cast (data); + const auto nonRealtime = state == AAX_eProcessingState_StartPass + || state == AAX_eProcessingState_BeginPassGroup; + pluginInstance->setNonRealtime (nonRealtime); + } + + break; + } + + case AAX_eNotificationEvent_TrackNameChanged: + if (data != nullptr) + { + AudioProcessor::TrackProperties props; + props.name = String::fromUTF8 (static_cast (data)->Get()); + + pluginInstance->updateTrackProperties (props); + } + break; + + case AAX_eNotificationEvent_SideChainBeingConnected: + case AAX_eNotificationEvent_SideChainBeingDisconnected: + { + processingSidechainChange = true; + sidechainDesired = (type == AAX_eNotificationEvent_SideChainBeingConnected); + updateSidechainState(); + break; + } + + case AAX_eNotificationEvent_TransportStateChanged: + if (data != nullptr) + { + const auto& info = *static_cast (data); + recordingState.set (info.mIsRecording); + } + break; + } + + return AAX_CEffectParameters::NotificationReceived (type, data, size); + } + + const float* getAudioBufferForInput (const float* const* inputs, int sidechain, int mainNumIns, int idx) const noexcept + { + jassert (idx < (mainNumIns + 1)); + + if (idx < mainNumIns) + return inputs[inputLayoutMap[idx]]; + + return (sidechain != -1 ? inputs[sidechain] : sideChainBuffer.data()); + } + + void process (const float* const* inputs, float* const* outputs, const int sideChainBufferIdx, + const int bufferSize, const bool bypass, + AAX_IMIDINode* midiNodeIn, AAX_IMIDINode* midiNodesOut, + float* const meterBuffers) + { + auto numIns = pluginInstance->getTotalNumInputChannels(); + auto numOuts = pluginInstance->getTotalNumOutputChannels(); + auto numMeters = aaxMeters.size(); + + const ScopedLock sl (pluginInstance->getCallbackLock()); + + bool isSuspended = [this, sideChainBufferIdx] + { + if (processingSidechainChange) + return true; + + bool processWantsSidechain = (sideChainBufferIdx != -1); + + if (hasSidechain && canDisableSidechain && (sidechainDesired != processWantsSidechain)) + { + sidechainDesired = processWantsSidechain; + processingSidechainChange = true; + triggerAsyncUpdate(); + return true; + } + + return pluginInstance->isSuspended(); + }(); + + if (isSuspended) + { + for (int i = 0; i < numOuts; ++i) + FloatVectorOperations::clear (outputs[i], bufferSize); + + if (meterBuffers != nullptr) + FloatVectorOperations::clear (meterBuffers, numMeters); + } + else + { + auto mainNumIns = pluginInstance->getMainBusNumInputChannels(); + auto sidechain = (pluginInstance->getChannelCountOfBus (true, 1) > 0 ? sideChainBufferIdx : -1); + auto numChans = jmax (numIns, numOuts); + + if (numChans == 0) + return; + + if (channelList.size() <= numChans) + channelList.insertMultiple (-1, nullptr, 1 + numChans - channelList.size()); + + float** channels = channelList.getRawDataPointer(); + + if (numOuts >= numIns) + { + for (int i = 0; i < numOuts; ++i) + channels[i] = outputs[outputLayoutMap[i]]; + + for (int i = 0; i < numIns; ++i) + memcpy (channels[i], getAudioBufferForInput (inputs, sidechain, mainNumIns, i), (size_t) bufferSize * sizeof (float)); + + for (int i = numIns; i < numOuts; ++i) + zeromem (channels[i], (size_t) bufferSize * sizeof (float)); + + process (channels, numOuts, bufferSize, bypass, midiNodeIn, midiNodesOut); + } + else + { + for (int i = 0; i < numOuts; ++i) + channels[i] = outputs[outputLayoutMap[i]]; + + for (int i = 0; i < numOuts; ++i) + memcpy (channels[i], getAudioBufferForInput (inputs, sidechain, mainNumIns, i), (size_t) bufferSize * sizeof (float)); + + for (int i = numOuts; i < numIns; ++i) + channels[i] = const_cast (getAudioBufferForInput (inputs, sidechain, mainNumIns, i)); + + process (channels, numIns, bufferSize, bypass, midiNodeIn, midiNodesOut); + } + + if (meterBuffers != nullptr) + for (int i = 0; i < numMeters; ++i) + meterBuffers[i] = aaxMeters[i]->getValue(); + } + } + + //============================================================================== + // In aax, the format of the aux and sidechain buses need to be fully determined + // by the format on the main buses. This function tried to provide such a mapping. + // Returns false if the in/out main layout is not supported + static bool fullBusesLayoutFromMainLayout (const AudioProcessor& p, + const AudioChannelSet& mainInput, const AudioChannelSet& mainOutput, + AudioProcessor::BusesLayout& fullLayout) + { + auto currentLayout = getDefaultLayout (p, true); + bool success = p.checkBusesLayoutSupported (currentLayout); + jassertquiet (success); + + auto numInputBuses = p.getBusCount (true); + auto numOutputBuses = p.getBusCount (false); + + if (auto* bus = p.getBus (true, 0)) + if (! bus->isLayoutSupported (mainInput, ¤tLayout)) + return false; + + if (auto* bus = p.getBus (false, 0)) + if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) + return false; + + // did this change the input again + if (numInputBuses > 0 && currentLayout.inputBuses.getReference (0) != mainInput) + return false; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + + if (! AudioProcessor::containsLayout (currentLayout, configs)) + return false; + #endif + + bool foundValid = false; + { + auto onlyMains = currentLayout; + + for (int i = 1; i < numInputBuses; ++i) + onlyMains.inputBuses.getReference (i) = AudioChannelSet::disabled(); + + for (int i = 1; i < numOutputBuses; ++i) + onlyMains.outputBuses.getReference (i) = AudioChannelSet::disabled(); + + if (p.checkBusesLayoutSupported (onlyMains)) + { + foundValid = true; + fullLayout = onlyMains; + } + } + + if (numInputBuses > 1) + { + // can the first bus be a sidechain or disabled, if not then we can't use this layout combination + if (auto* bus = p.getBus (true, 1)) + if (! bus->isLayoutSupported (AudioChannelSet::mono(), ¤tLayout) && ! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) + return foundValid; + + // can all the other inputs be disabled, if not then we can't use this layout combination + for (int i = 2; i < numInputBuses; ++i) + if (auto* bus = p.getBus (true, i)) + if (! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) + return foundValid; + + if (auto* bus = p.getBus (true, 0)) + if (! bus->isLayoutSupported (mainInput, ¤tLayout)) + return foundValid; + + if (auto* bus = p.getBus (false, 0)) + if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) + return foundValid; + + // recheck if the format is correct + if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput) + || (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput)) + return foundValid; + + auto& sidechainBus = currentLayout.inputBuses.getReference (1); + + if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) + return foundValid; + + for (int i = 2; i < numInputBuses; ++i) + if (! currentLayout.inputBuses.getReference (i).isDisabled()) + return foundValid; + } + + const bool hasSidechain = (numInputBuses > 1 && currentLayout.inputBuses.getReference (1) == AudioChannelSet::mono()); + + if (hasSidechain) + { + auto onlyMainsAndSidechain = currentLayout; + + for (int i = 1; i < numOutputBuses; ++i) + onlyMainsAndSidechain.outputBuses.getReference (i) = AudioChannelSet::disabled(); + + if (p.checkBusesLayoutSupported (onlyMainsAndSidechain)) + { + foundValid = true; + fullLayout = onlyMainsAndSidechain; + } + } + + if (numOutputBuses > 1) + { + auto copy = currentLayout; + int maxAuxBuses = jmin (16, numOutputBuses); + + for (int i = 1; i < maxAuxBuses; ++i) + copy.outputBuses.getReference (i) = mainOutput; + + for (int i = maxAuxBuses; i < numOutputBuses; ++i) + copy.outputBuses.getReference (i) = AudioChannelSet::disabled(); + + if (p.checkBusesLayoutSupported (copy)) + { + fullLayout = copy; + foundValid = true; + } + else + { + for (int i = 1; i < maxAuxBuses; ++i) + if (currentLayout.outputBuses.getReference (i).isDisabled()) + return foundValid; + + for (int i = maxAuxBuses; i < numOutputBuses; ++i) + if (auto* bus = p.getBus (false, i)) + if (! bus->isLayoutSupported (AudioChannelSet::disabled(), ¤tLayout)) + return foundValid; + + if (auto* bus = p.getBus (true, 0)) + if (! bus->isLayoutSupported (mainInput, ¤tLayout)) + return foundValid; + + if (auto* bus = p.getBus (false, 0)) + if (! bus->isLayoutSupported (mainOutput, ¤tLayout)) + return foundValid; + + if ((numInputBuses > 0 && currentLayout.inputBuses .getReference (0) != mainInput) + || (numOutputBuses > 0 && currentLayout.outputBuses.getReference (0) != mainOutput)) + return foundValid; + + if (numInputBuses > 1) + { + auto& sidechainBus = currentLayout.inputBuses.getReference (1); + + if (sidechainBus != AudioChannelSet::mono() && sidechainBus != AudioChannelSet::disabled()) + return foundValid; + } + + for (int i = maxAuxBuses; i < numOutputBuses; ++i) + if (! currentLayout.outputBuses.getReference (i).isDisabled()) + return foundValid; + + fullLayout = currentLayout; + foundValid = true; + } + } + + return foundValid; + } + + bool isInAudioSuite() + { + AAX_CBoolean res; + Controller()->GetIsAudioSuite (&res); + + return res > 0; + } + + private: + friend class JuceAAX_GUI; + friend void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd); + + void process (float* const* channels, const int numChans, const int bufferSize, + const bool bypass, [[maybe_unused]] AAX_IMIDINode* midiNodeIn, [[maybe_unused]] AAX_IMIDINode* midiNodesOut) + { + AudioBuffer buffer (channels, numChans, bufferSize); + midiBuffer.clear(); + + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + { + auto* midiStream = midiNodeIn->GetNodeBuffer(); + auto numMidiEvents = midiStream->mBufferSize; + + for (uint32_t i = 0; i < numMidiEvents; ++i) + { + auto& m = midiStream->mBuffer[i]; + jassert ((int) m.mTimestamp < bufferSize); + + midiBuffer.addEvent (m.mData, (int) m.mLength, + jlimit (0, (int) bufferSize - 1, (int) m.mTimestamp)); + } + } + #endif + + { + if (lastBufferSize != bufferSize) + { + lastBufferSize = bufferSize; + pluginInstance->setRateAndBufferSizeDetails (sampleRate, lastBufferSize); + + // we only call prepareToPlay here if the new buffer size is larger than + // the one used last time prepareToPlay was called. + // currently, this should never actually happen, because as of Pro Tools 12, + // the maximum possible value is 1024, and we call prepareToPlay with that + // value during initialisation. + if (bufferSize > maxBufferSize) + prepareProcessorWithSampleRateAndBufferSize (sampleRate, bufferSize); + } + + if (bypass && pluginInstance->getBypassParameter() == nullptr) + pluginInstance->processBlockBypassed (buffer, midiBuffer); + else + pluginInstance->processBlock (buffer, midiBuffer); + } + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + { + AAX_CMidiPacket packet; + packet.mIsImmediate = false; + + for (const auto metadata : midiBuffer) + { + jassert (isPositiveAndBelow (metadata.samplePosition, bufferSize)); + + if (metadata.numBytes <= 4) + { + packet.mTimestamp = (uint32_t) metadata.samplePosition; + packet.mLength = (uint32_t) metadata.numBytes; + memcpy (packet.mData, metadata.data, (size_t) metadata.numBytes); + + check (midiNodesOut->PostMIDIPacket (&packet)); + } + } + } + #endif + } + + bool isBypassPartOfRegularParemeters() const + { + auto& audioProcessor = getPluginInstance(); + + int n = juceParameters.getNumParameters(); + + if (auto* bypassParam = audioProcessor.getBypassParameter()) + for (int i = 0; i < n; ++i) + if (juceParameters.getParamForIndex (i) == bypassParam) + return true; + + return false; + } + + // Some older Pro Tools control surfaces (EUCON [PT version 12.4] and + // Avid S6 before version 2.1) cannot cope with a large number of + // parameter steps. + static int32_t getSafeNumberOfParameterSteps (const AudioProcessorParameter& param) + { + return jmin (param.getNumSteps(), 2048); + } + + void addAudioProcessorParameters() + { + auto& audioProcessor = getPluginInstance(); + + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + const bool forceLegacyParamIDs = true; + #else + const bool forceLegacyParamIDs = false; + #endif + + auto bypassPartOfRegularParams = isBypassPartOfRegularParemeters(); + + juceParameters.update (audioProcessor, forceLegacyParamIDs); + + auto* bypassParameter = pluginInstance->getBypassParameter(); + + if (bypassParameter == nullptr) + { + ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false)); + bypassParameter = ownedBypassParameter.get(); + } + + if (! bypassPartOfRegularParams) + juceParameters.addNonOwning (bypassParameter); + + int parameterIndex = 0; + + for (auto* juceParam : juceParameters) + { + auto isBypassParameter = (juceParam == bypassParameter); + + auto category = juceParam->getCategory(); + auto paramID = isBypassParameter ? String (cDefaultMasterBypassID) + : juceParameters.getParamID (audioProcessor, parameterIndex); + + aaxParamIDs.add (paramID); + auto* aaxParamID = aaxParamIDs.getReference (parameterIndex++).toRawUTF8(); + + paramMap.set (AAXClasses::getAAXParamHash (aaxParamID), juceParam); + + // is this a meter? + if (((category & 0xffff0000) >> 16) == 2) + { + aaxMeters.add (juceParam); + continue; + } + + auto parameter = new AAX_CParameter (aaxParamID, + AAX_CString (juceParam->getName (31).toRawUTF8()), + juceParam->getDefaultValue(), + AAX_CLinearTaperDelegate(), + AAX_CNumberDisplayDelegate(), + juceParam->isAutomatable()); + + parameter->AddShortenedName (juceParam->getName (4).toRawUTF8()); + + auto parameterNumSteps = getSafeNumberOfParameterSteps (*juceParam); + parameter->SetNumberOfSteps ((uint32_t) parameterNumSteps); + + #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + parameter->SetType (parameterNumSteps > 1000 ? AAX_eParameterType_Continuous + : AAX_eParameterType_Discrete); + #else + parameter->SetType (juceParam->isDiscrete() ? AAX_eParameterType_Discrete + : AAX_eParameterType_Continuous); + #endif + + parameter->SetOrientation (juceParam->isOrientationInverted() + ? (AAX_eParameterOrientation_RightMinLeftMax | AAX_eParameterOrientation_TopMinBottomMax + | AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryRightMinLeftMax) + : (AAX_eParameterOrientation_LeftMinRightMax | AAX_eParameterOrientation_BottomMinTopMax + | AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryLeftMinRightMax)); + + mParameterManager.AddParameter (parameter); + + if (isBypassParameter) + mPacketDispatcher.RegisterPacket (aaxParamID, JUCEAlgorithmIDs::bypass); + } + } + + bool getMainBusFormats (AudioChannelSet& inputSet, AudioChannelSet& outputSet) + { + auto& audioProcessor = getPluginInstance(); + + #if JucePlugin_IsMidiEffect + // MIDI effect plug-ins do not support any audio channels + jassert (audioProcessor.getTotalNumInputChannels() == 0 + && audioProcessor.getTotalNumOutputChannels() == 0); + + inputSet = outputSet = AudioChannelSet(); + return true; + #else + auto inputBuses = audioProcessor.getBusCount (true); + auto outputBuses = audioProcessor.getBusCount (false); + + AAX_EStemFormat inputStemFormat = AAX_eStemFormat_None; + check (Controller()->GetInputStemFormat (&inputStemFormat)); + + AAX_EStemFormat outputStemFormat = AAX_eStemFormat_None; + check (Controller()->GetOutputStemFormat (&outputStemFormat)); + + #if JucePlugin_IsSynth + if (inputBuses == 0) + inputStemFormat = AAX_eStemFormat_None; + #endif + + inputSet = (inputBuses > 0 ? channelSetFromStemFormat (inputStemFormat, false) : AudioChannelSet()); + outputSet = (outputBuses > 0 ? channelSetFromStemFormat (outputStemFormat, false) : AudioChannelSet()); + + if ((inputSet == AudioChannelSet::disabled() && inputStemFormat != AAX_eStemFormat_None) || (outputSet == AudioChannelSet::disabled() && outputStemFormat != AAX_eStemFormat_None) + || (inputSet != AudioChannelSet::disabled() && inputBuses == 0) || (outputSet != AudioChannelSet::disabled() && outputBuses == 0)) + return false; + + return true; + #endif + } + + AAX_Result preparePlugin() + { + auto& audioProcessor = getPluginInstance(); + auto oldLayout = audioProcessor.getBusesLayout(); + AudioChannelSet inputSet, outputSet; + + if (! getMainBusFormats (inputSet, outputSet)) + { + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + AudioProcessor::BusesLayout newLayout; + + if (! fullBusesLayoutFromMainLayout (audioProcessor, inputSet, outputSet, newLayout)) + { + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + hasSidechain = (newLayout.getNumChannels (true, 1) == 1); + + if (hasSidechain) + { + sidechainDesired = true; + + auto disabledSidechainLayout = newLayout; + disabledSidechainLayout.inputBuses.getReference (1) = AudioChannelSet::disabled(); + + canDisableSidechain = audioProcessor.checkBusesLayoutSupported (disabledSidechainLayout); + + if (canDisableSidechain && ! lastSideChainState) + { + sidechainDesired = false; + newLayout = disabledSidechainLayout; + } + } + + if (isInAudioSuite()) + { + // AudioSuite doesn't support multiple output buses + for (int i = 1; i < newLayout.outputBuses.size(); ++i) + newLayout.outputBuses.getReference (i) = AudioChannelSet::disabled(); + + if (! audioProcessor.checkBusesLayoutSupported (newLayout)) + { + // your plug-in needs to support a single output bus if running in AudioSuite + jassertfalse; + + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + return AAX_ERROR_UNIMPLEMENTED; + } + } + + const bool layoutChanged = (oldLayout != newLayout); + + if (layoutChanged) + { + if (! audioProcessor.setBusesLayout (newLayout)) + { + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + rebuildChannelMapArrays(); + } + + if (layoutChanged || (! isPrepared)) + { + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + prepareProcessorWithSampleRateAndBufferSize (sampleRate, lastBufferSize); + + midiBuffer.ensureSize (2048); + midiBuffer.clear(); + } + + check (Controller()->SetSignalLatency (audioProcessor.getLatencySamples())); + isPrepared = true; + + return AAX_SUCCESS; + } + + void rebuildChannelMapArrays() + { + auto& audioProcessor = getPluginInstance(); + + for (int dir = 0; dir < 2; ++dir) + { + bool isInput = (dir == 0); + auto& layoutMap = isInput ? inputLayoutMap : outputLayoutMap; + layoutMap.clear(); + + auto numBuses = audioProcessor.getBusCount (isInput); + int chOffset = 0; + + for (int busIdx = 0; busIdx < numBuses; ++busIdx) + { + auto channelFormat = audioProcessor.getChannelLayoutOfBus (isInput, busIdx); + + if (channelFormat != AudioChannelSet::disabled()) + { + auto numChannels = channelFormat.size(); + + for (int ch = 0; ch < numChannels; ++ch) + layoutMap.add (juceChannelIndexToAax (ch, channelFormat) + chOffset); + + chOffset += numChannels; + } + } + } + } + + static void algorithmCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd) + { + for (auto iter = instancesBegin; iter < instancesEnd; ++iter) + { + auto& i = **iter; + + int sideChainBufferIdx = i.pluginInstance->parameters.hasSidechain && i.sideChainBuffers != nullptr + ? static_cast (*i.sideChainBuffers) : -1; + + // sidechain index of zero is an invalid index + if (sideChainBufferIdx <= 0) + sideChainBufferIdx = -1; + + auto numMeters = i.pluginInstance->parameters.aaxMeters.size(); + float* const meterTapBuffers = (i.meterTapBuffers != nullptr && numMeters > 0 ? *i.meterTapBuffers : nullptr); + + i.pluginInstance->parameters.process (i.inputChannels, i.outputChannels, sideChainBufferIdx, + *(i.bufferSize), *(i.bypass) != 0, + getMidiNodeIn(i), getMidiNodeOut(i), + meterTapBuffers); + } + } + + void prepareProcessorWithSampleRateAndBufferSize (double sr, int bs) + { + maxBufferSize = jmax (maxBufferSize, bs); + + auto& audioProcessor = getPluginInstance(); + audioProcessor.setRateAndBufferSizeDetails (sr, maxBufferSize); + audioProcessor.prepareToPlay (sr, maxBufferSize); + sideChainBuffer.resize (static_cast (maxBufferSize)); + } + + //============================================================================== + void updateSidechainState() + { + if (! processingSidechainChange) + return; + + auto& audioProcessor = getPluginInstance(); + const auto sidechainActual = audioProcessor.getChannelCountOfBus (true, 1) > 0; + + if (hasSidechain && canDisableSidechain && sidechainDesired != sidechainActual) + { + lastSideChainState = sidechainDesired; + + if (isPrepared) + { + isPrepared = false; + audioProcessor.releaseResources(); + } + + if (auto* bus = audioProcessor.getBus (true, 1)) + bus->setCurrentLayout (lastSideChainState ? AudioChannelSet::mono() + : AudioChannelSet::disabled()); + + prepareProcessorWithSampleRateAndBufferSize (audioProcessor.getSampleRate(), maxBufferSize); + isPrepared = true; + } + + processingSidechainChange = false; + } + + void handleAsyncUpdate() override + { + updateSidechainState(); + } + + //============================================================================== + static AudioProcessor::CurveData::Type aaxCurveTypeToJUCE (AAX_CTypeID type) noexcept + { + switch (type) + { + case AAX_eCurveType_EQ: return AudioProcessor::CurveData::Type::EQ; + case AAX_eCurveType_Dynamics: return AudioProcessor::CurveData::Type::Dynamics; + case AAX_eCurveType_Reduction: return AudioProcessor::CurveData::Type::GainReduction; + default: break; + } + + return AudioProcessor::CurveData::Type::Unknown; + } + + uint32_t getAAXMeterIdForParamId (const String& paramID) const noexcept + { + int idx; + + for (idx = 0; idx < aaxMeters.size(); ++idx) + if (LegacyAudioParameter::getParamID (aaxMeters[idx], false) == paramID) + break; + + // you specified a parameter id in your curve but the parameter does not have the meter + // category + jassert (idx < aaxMeters.size()); + return 'Metr' + static_cast (idx); + } + + //============================================================================== + AAX_Result GetCurveData (AAX_CTypeID iCurveType, const float * iValues, uint32_t iNumValues, float * oValues ) const override + { + auto curveType = aaxCurveTypeToJUCE (iCurveType); + + if (curveType != AudioProcessor::CurveData::Type::Unknown) + { + auto& audioProcessor = getPluginInstance(); + auto curve = audioProcessor.getResponseCurve (curveType); + + if (curve.curve) + { + if (oValues != nullptr && iValues != nullptr) + { + for (uint32_t i = 0; i < iNumValues; ++i) + oValues[i] = curve.curve (iValues[i]); + } + + return AAX_SUCCESS; + } + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + AAX_Result GetCurveDataMeterIds (AAX_CTypeID iCurveType, uint32_t *oXMeterId, uint32_t *oYMeterId) const override + { + auto curveType = aaxCurveTypeToJUCE (iCurveType); + + if (curveType != AudioProcessor::CurveData::Type::Unknown) + { + auto& audioProcessor = getPluginInstance(); + auto curve = audioProcessor.getResponseCurve (curveType); + + if (curve.curve && curve.xMeterID.isNotEmpty() && curve.yMeterID.isNotEmpty()) + { + if (oXMeterId != nullptr) *oXMeterId = getAAXMeterIdForParamId (curve.xMeterID); + if (oYMeterId != nullptr) *oYMeterId = getAAXMeterIdForParamId (curve.yMeterID); + + return AAX_SUCCESS; + } + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + AAX_Result GetCurveDataDisplayRange (AAX_CTypeID iCurveType, float *oXMin, float *oXMax, float *oYMin, float *oYMax) const override + { + auto curveType = aaxCurveTypeToJUCE (iCurveType); + + if (curveType != AudioProcessor::CurveData::Type::Unknown) + { + auto& audioProcessor = getPluginInstance(); + auto curve = audioProcessor.getResponseCurve (curveType); + + if (curve.curve) + { + if (oXMin != nullptr) *oXMin = curve.xRange.getStart(); + if (oXMax != nullptr) *oXMax = curve.xRange.getEnd(); + if (oYMin != nullptr) *oYMin = curve.yRange.getStart(); + if (oYMax != nullptr) *oYMax = curve.yRange.getEnd(); + + return AAX_SUCCESS; + } + } + + return AAX_ERROR_UNIMPLEMENTED; + } + + //============================================================================== + inline int getParamIndexFromID (AAX_CParamID paramID) const noexcept + { + if (auto* param = getParameterFromID (paramID)) + return LegacyAudioParameter::getParamIndex (getPluginInstance(), param); + + return -1; + } + + inline AAX_CParamID getAAXParamIDFromJuceIndex (int index) const noexcept + { + if (isPositiveAndBelow (index, aaxParamIDs.size())) + return aaxParamIDs.getReference (index).toRawUTF8(); + + return nullptr; + } + + AudioProcessorParameter* getParameterFromID (AAX_CParamID paramID) const noexcept + { + return paramMap [AAXClasses::getAAXParamHash (paramID)]; + } + + //============================================================================== + static AudioProcessor::BusesLayout getDefaultLayout (const AudioProcessor& p, bool enableAll) + { + AudioProcessor::BusesLayout defaultLayout; + + for (int dir = 0; dir < 2; ++dir) + { + bool isInput = (dir == 0); + auto numBuses = p.getBusCount (isInput); + auto& layouts = (isInput ? defaultLayout.inputBuses : defaultLayout.outputBuses); + + for (int i = 0; i < numBuses; ++i) + if (auto* bus = p.getBus (isInput, i)) + layouts.add (enableAll || bus->isEnabledByDefault() ? bus->getDefaultLayout() : AudioChannelSet()); + } + + return defaultLayout; + } + + static AudioProcessor::BusesLayout getDefaultLayout (AudioProcessor& p) + { + auto defaultLayout = getDefaultLayout (p, true); + + if (! p.checkBusesLayoutSupported (defaultLayout)) + defaultLayout = getDefaultLayout (p, false); + + // Your processor must support the default layout + jassert (p.checkBusesLayoutSupported (defaultLayout)); + return defaultLayout; + } + + void syncParameterAttributes (AAX_IParameter* aaxParam, const AudioProcessorParameter* juceParam) + { + if (juceParam == nullptr) + return; + + { + auto newName = juceParam->getName (31); + + if (aaxParam->Name() != newName.toRawUTF8()) + aaxParam->SetName (AAX_CString (newName.toRawUTF8())); + } + + { + auto newType = juceParam->isDiscrete() ? AAX_eParameterType_Discrete : AAX_eParameterType_Continuous; + + if (aaxParam->GetType() != newType) + aaxParam->SetType (newType); + } + + { + auto newNumSteps = static_cast (juceParam->getNumSteps()); + + if (aaxParam->GetNumberOfSteps() != newNumSteps) + aaxParam->SetNumberOfSteps (newNumSteps); + } + + { + auto defaultValue = juceParam->getDefaultValue(); + + if (! approximatelyEqual (static_cast (aaxParam->GetNormalizedDefaultValue()), defaultValue)) + aaxParam->SetNormalizedDefaultValue (defaultValue); + } + } + + //============================================================================== + ScopedJuceInitialiser_GUI libraryInitialiser; + + std::unique_ptr pluginInstance; + + static constexpr auto maxSamplesPerBlock = 1 << AAX_eAudioBufferLength_Max; + + bool isPrepared = false; + MidiBuffer midiBuffer; + Array channelList; + int32_t juceChunkIndex = 0, numSetDirtyCalls = 0; + AAX_CSampleRate sampleRate = 0; + int lastBufferSize = maxSamplesPerBlock, maxBufferSize = maxSamplesPerBlock; + bool hasSidechain = false, canDisableSidechain = false, lastSideChainState = false; + + /* Pro Tools 2021 sends TransportStateChanged on the main thread, but we read + the recording state on the audio thread. + I'm not sure whether Pro Tools ensures that these calls are mutually + exclusive, so to ensure there are no data races, we store the recording + state in an atomic int and convert it to/from an Optional as necessary. + */ + class RecordingState + { + public: + /* This uses Optional rather than std::optional for consistency with get() */ + void set (const Optional newState) + { + state.store (newState.hasValue() ? (flagValid | (*newState ? flagActive : 0)) + : 0, + std::memory_order_relaxed); + } + + /* PositionInfo::setIsRecording takes an Optional, so we use that type rather + than std::optional to avoid having to convert. + */ + Optional get() const + { + const auto loaded = state.load (std::memory_order_relaxed); + return ((loaded & flagValid) != 0) ? makeOptional ((loaded & flagActive) != 0) + : nullopt; + } + + private: + enum RecordingFlags + { + flagValid = 1 << 0, + flagActive = 1 << 1 + }; + + std::atomic state { 0 }; + }; + + RecordingState recordingState; + + std::atomic processingSidechainChange, sidechainDesired; + + std::vector sideChainBuffer; + Array inputLayoutMap, outputLayoutMap; + + Array aaxParamIDs; + HashMap paramMap; + LegacyAudioParametersWrapper juceParameters; + std::unique_ptr ownedBypassParameter; + + Array aaxMeters; + + struct ChunkMemoryBlock + { + juce::MemoryBlock data; + bool isValid; + }; + + // temporary filter data is generated in GetChunkSize + // and the size of the data returned. To avoid generating + // it again in GetChunk, we need to store it somewhere. + // However, as GetChunkSize and GetChunk can be called + // on different threads, we store it in thread dependent storage + // in a hash map with the thread id as a key. + mutable ThreadLocalValue perThreadFilterData; + CriticalSection perThreadDataLock; + + ThreadLocalValue inParameterChangedCallback; + + JUCE_DECLARE_NON_COPYABLE (JuceAAX_Processor) + }; + + //============================================================================== + void JuceAAX_GUI::CreateViewContents() + { + if (component == nullptr) + { + if (auto* params = dynamic_cast (GetEffectParameters())) + component.reset (new ContentWrapperComponent (*this, params->getPluginInstance())); + else + jassertfalse; + } + } + + int JuceAAX_GUI::getParamIndexFromID (AAX_CParamID paramID) const noexcept + { + if (auto* params = dynamic_cast (GetEffectParameters())) + return params->getParamIndexFromID (paramID); + + return -1; + } + + AAX_CParamID JuceAAX_GUI::getAAXParamIDFromJuceIndex (int index) const noexcept + { + if (auto* params = dynamic_cast (GetEffectParameters())) + return params->getAAXParamIDFromJuceIndex (index); + + return nullptr; + } + + //============================================================================== + struct AAXFormatConfiguration + { + AAXFormatConfiguration() noexcept {} + + AAXFormatConfiguration (AAX_EStemFormat inFormat, AAX_EStemFormat outFormat) noexcept + : inputFormat (inFormat), outputFormat (outFormat) {} + + AAX_EStemFormat inputFormat = AAX_eStemFormat_None, + outputFormat = AAX_eStemFormat_None; + + bool operator== (const AAXFormatConfiguration other) const noexcept + { + return inputFormat == other.inputFormat && outputFormat == other.outputFormat; + } + + bool operator< (const AAXFormatConfiguration other) const noexcept + { + return inputFormat == other.inputFormat ? (outputFormat < other.outputFormat) + : (inputFormat < other.inputFormat); + } + }; + + //============================================================================== + static int addAAXMeters (AudioProcessor& p, AAX_IEffectDescriptor& descriptor) + { + LegacyAudioParametersWrapper params; + + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + const bool forceLegacyParamIDs = true; + #else + const bool forceLegacyParamIDs = false; + #endif + + params.update (p, forceLegacyParamIDs); + + int meterIdx = 0; + + for (auto* param : params) + { + auto category = param->getCategory(); + + // is this a meter? + if (((category & 0xffff0000) >> 16) == 2) + { + if (auto* meterProperties = descriptor.NewPropertyMap()) + { + meterProperties->AddProperty (AAX_eProperty_Meter_Type, getMeterTypeForCategory (category)); + meterProperties->AddProperty (AAX_eProperty_Meter_Orientation, AAX_eMeterOrientation_TopRight); + + descriptor.AddMeterDescription ('Metr' + static_cast (meterIdx++), + param->getName (1024).toRawUTF8(), meterProperties); + } + } + } + + return meterIdx; + } + + static void createDescriptor (AAX_IComponentDescriptor& desc, + const AudioProcessor::BusesLayout& fullLayout, + AudioProcessor& processor, + Array& pluginIds, + const int numMeters) + { + auto aaxInputFormat = getFormatForAudioChannelSet (fullLayout.getMainInputChannelSet(), false); + auto aaxOutputFormat = getFormatForAudioChannelSet (fullLayout.getMainOutputChannelSet(), false); + + #if JucePlugin_IsSynth + if (aaxInputFormat == AAX_eStemFormat_None) + aaxInputFormat = aaxOutputFormat; + #endif + + #if JucePlugin_IsMidiEffect + aaxInputFormat = aaxOutputFormat = AAX_eStemFormat_Mono; + #endif + + check (desc.AddAudioIn (JUCEAlgorithmIDs::inputChannels)); + check (desc.AddAudioOut (JUCEAlgorithmIDs::outputChannels)); + + check (desc.AddAudioBufferLength (JUCEAlgorithmIDs::bufferSize)); + check (desc.AddDataInPort (JUCEAlgorithmIDs::bypass, sizeof (int32_t))); + + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + check (desc.AddMIDINode (JUCEAlgorithmIDs::midiNodeIn, AAX_eMIDINodeType_LocalInput, + JucePlugin_Name, 0xffff)); + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsSynth || JucePlugin_IsMidiEffect + check (desc.AddMIDINode (JUCEAlgorithmIDs::midiNodeOut, AAX_eMIDINodeType_LocalOutput, + JucePlugin_Name " Out", 0xffff)); + #endif + + check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo))); + check (desc.AddPrivateData (JUCEAlgorithmIDs::preparedFlag, sizeof (int32_t))); + + if (numMeters > 0) + { + HeapBlock meterIDs (static_cast (numMeters)); + + for (int i = 0; i < numMeters; ++i) + meterIDs[i] = 'Metr' + static_cast (i); + + check (desc.AddMeters (JUCEAlgorithmIDs::meterTapBuffers, meterIDs.getData(), static_cast (numMeters))); + } + else + { + // AAX does not allow there to be any gaps in the fields of the algorithm context structure + // so just add a dummy one here if there aren't any meters + check (desc.AddPrivateData (JUCEAlgorithmIDs::meterTapBuffers, sizeof (uintptr_t))); + } + + // Create a property map + AAX_IPropertyMap* const properties = desc.NewPropertyMap(); + jassert (properties != nullptr); + + properties->AddProperty (AAX_eProperty_ManufacturerID, JucePlugin_AAXManufacturerCode); + properties->AddProperty (AAX_eProperty_ProductID, JucePlugin_AAXProductId); + + #if JucePlugin_AAXDisableBypass + properties->AddProperty (AAX_eProperty_CanBypass, false); + #else + properties->AddProperty (AAX_eProperty_CanBypass, true); + #endif + + properties->AddProperty (AAX_eProperty_InputStemFormat, static_cast (aaxInputFormat)); + properties->AddProperty (AAX_eProperty_OutputStemFormat, static_cast (aaxOutputFormat)); + + const auto& extensions = processor.getAAXClientExtensions(); + + // This value needs to match the RTAS wrapper's Type ID, so that + // the host knows that the RTAS/AAX plugins are equivalent. + const auto pluginID = extensions.getPluginIDForMainBusConfig (fullLayout.getMainInputChannelSet(), + fullLayout.getMainOutputChannelSet(), + false); + + // The plugin id generated from your AudioProcessor's getAAXPluginIDForMainBusConfig callback + // it not unique. Please fix your implementation! + jassert (! pluginIds.contains (pluginID)); + pluginIds.add (pluginID); + + properties->AddProperty (AAX_eProperty_PlugInID_Native, pluginID); + + #if ! JucePlugin_AAXDisableAudioSuite + properties->AddProperty (AAX_eProperty_PlugInID_AudioSuite, + extensions.getPluginIDForMainBusConfig (fullLayout.getMainInputChannelSet(), + fullLayout.getMainOutputChannelSet(), + true)); + #endif + + #if JucePlugin_AAXDisableMultiMono + properties->AddProperty (AAX_eProperty_Constraint_MultiMonoSupport, false); + #else + properties->AddProperty (AAX_eProperty_Constraint_MultiMonoSupport, true); + #endif + + #if JucePlugin_AAXDisableDynamicProcessing + properties->AddProperty (AAX_eProperty_Constraint_AlwaysProcess, true); + #endif + + #if JucePlugin_AAXDisableDefaultSettingsChunks + properties->AddProperty (AAX_eProperty_Constraint_DoNotApplyDefaultSettings, true); + #endif + + #if JucePlugin_AAXDisableSaveRestore + properties->AddProperty (AAX_eProperty_SupportsSaveRestore, false); + #endif + + properties->AddProperty (AAX_eProperty_ObservesTransportState, true); + + if (fullLayout.getChannelSet (true, 1) == AudioChannelSet::mono()) + { + check (desc.AddSideChainIn (JUCEAlgorithmIDs::sideChainBuffers)); + properties->AddProperty (AAX_eProperty_SupportsSideChainInput, true); + } + else + { + // AAX does not allow there to be any gaps in the fields of the algorithm context structure + // so just add a dummy one here if there aren't any side chains + check (desc.AddPrivateData (JUCEAlgorithmIDs::sideChainBuffers, sizeof (uintptr_t))); + } + + auto maxAuxBuses = jmax (0, jmin (15, fullLayout.outputBuses.size() - 1)); + + // add the output buses + // This is incredibly dumb: the output bus format must be well defined + // for every main bus in/out format pair. This means that there cannot + // be two configurations with different aux formats but + // identical main bus in/out formats. + for (int busIdx = 1; busIdx < maxAuxBuses + 1; ++busIdx) + { + auto set = fullLayout.getChannelSet (false, busIdx); + + if (set.isDisabled()) + break; + + auto auxFormat = getFormatForAudioChannelSet (set, true); + + if (auxFormat != AAX_eStemFormat_INT32_MAX && auxFormat != AAX_eStemFormat_None) + { + auto& name = processor.getBus (false, busIdx)->getName(); + check (desc.AddAuxOutputStem (0, static_cast (auxFormat), name.toRawUTF8())); + } + } + + check (desc.AddProcessProc_Native (algorithmProcessCallback, properties)); + } + + static inline bool hostSupportsStemFormat (AAX_EStemFormat stemFormat, const AAX_IFeatureInfo* featureInfo) + { + if (featureInfo != nullptr) + { + AAX_ESupportLevel supportLevel; + + if (featureInfo->SupportLevel (supportLevel) == AAX_SUCCESS && supportLevel == AAX_eSupportLevel_ByProperty) + { + std::unique_ptr props (featureInfo->AcquireProperties()); + + // Due to a bug in ProTools 12.8, ProTools thinks that AAX_eStemFormat_Ambi_1_ACN is not supported + // To workaround this bug, check if ProTools supports AAX_eStemFormat_Ambi_2_ACN, and, if yes, + // we can safely assume that it will also support AAX_eStemFormat_Ambi_1_ACN + if (stemFormat == AAX_eStemFormat_Ambi_1_ACN) + stemFormat = AAX_eStemFormat_Ambi_2_ACN; + + if (props != nullptr && props->GetProperty ((AAX_EProperty) stemFormat, (AAX_CPropertyValue*) &supportLevel) != 0) + return (supportLevel == AAX_eSupportLevel_Supported); + } + } + + return (AAX_STEM_FORMAT_INDEX (stemFormat) <= 12); + } + + static void getPlugInDescription (AAX_IEffectDescriptor& descriptor, [[maybe_unused]] const AAX_IFeatureInfo* featureInfo) + { + auto plugin = createPluginFilterOfType (AudioProcessor::wrapperType_AAX); + auto numInputBuses = plugin->getBusCount (true); + auto numOutputBuses = plugin->getBusCount (false); + + auto pluginNames = plugin->getAlternateDisplayNames(); + + pluginNames.insert (0, JucePlugin_Name); + + pluginNames.removeDuplicates (false); + + for (auto name : pluginNames) + descriptor.AddName (name.toRawUTF8()); + + descriptor.AddCategory (JucePlugin_AAXCategory); + + const int numMeters = addAAXMeters (*plugin, descriptor); + + const auto& extensions = plugin->getAAXClientExtensions(); + + if (const auto searchPath = extensions.getPageFileSearchPath().getFullPathName(); searchPath.isNotEmpty()) + descriptor.AddResourceInfo (AAX_eResourceType_PageTableDir, searchPath.toRawUTF8()); + + if (const auto filename = extensions.getPageFileName(); filename.isNotEmpty()) + descriptor.AddResourceInfo (AAX_eResourceType_PageTable, filename.toRawUTF8()); + + check (descriptor.AddProcPtr ((void*) JuceAAX_GUI::Create, kAAX_ProcPtrID_Create_EffectGUI)); + check (descriptor.AddProcPtr ((void*) JuceAAX_Processor::Create, kAAX_ProcPtrID_Create_EffectParameters)); + + Array pluginIds; + #if JucePlugin_IsMidiEffect + // MIDI effect plug-ins do not support any audio channels + jassert (numInputBuses == 0 && numOutputBuses == 0); + + if (auto* desc = descriptor.NewComponentDescriptor()) + { + createDescriptor (*desc, plugin->getBusesLayout(), *plugin, pluginIds, numMeters); + check (descriptor.AddComponent (desc)); + } + #else + const int numIns = numInputBuses > 0 ? numElementsInArray (aaxFormats) : 0; + const int numOuts = numOutputBuses > 0 ? numElementsInArray (aaxFormats) : 0; + + for (int inIdx = 0; inIdx < jmax (numIns, 1); ++inIdx) + { + auto aaxInFormat = numIns > 0 ? aaxFormats[inIdx] : AAX_eStemFormat_None; + auto inLayout = channelSetFromStemFormat (aaxInFormat, false); + + for (int outIdx = 0; outIdx < jmax (numOuts, 1); ++outIdx) + { + auto aaxOutFormat = numOuts > 0 ? aaxFormats[outIdx] : AAX_eStemFormat_None; + auto outLayout = channelSetFromStemFormat (aaxOutFormat, false); + + if (hostSupportsStemFormat (aaxInFormat, featureInfo) + && hostSupportsStemFormat (aaxOutFormat, featureInfo)) + { + AudioProcessor::BusesLayout fullLayout; + + if (! JuceAAX_Processor::fullBusesLayoutFromMainLayout (*plugin, inLayout, outLayout, fullLayout)) + continue; + + if (auto* desc = descriptor.NewComponentDescriptor()) + { + createDescriptor (*desc, fullLayout, *plugin, pluginIds, numMeters); + check (descriptor.AddComponent (desc)); + } + } + } + } + + // You don't have any supported layouts + jassert (pluginIds.size() > 0); + #endif + } +} // namespace AAXClasses + +void AAX_CALLBACK AAXClasses::algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[], const void* const instancesEnd) +{ + AAXClasses::JuceAAX_Processor::algorithmCallback (instancesBegin, instancesEnd); +} + +//============================================================================== +AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*); +AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection) +{ + ScopedJuceInitialiser_GUI libraryInitialiser; + + std::unique_ptr stemFormatFeatureInfo; + + if (const auto* hostDescription = collection->DescriptionHost()) + stemFormatFeatureInfo.reset (hostDescription->AcquireFeatureProperties (AAXATTR_ClientFeature_StemFormat)); + + if (auto* descriptor = collection->NewDescriptor()) + { + AAXClasses::getPlugInDescription (*descriptor, stemFormatFeatureInfo.get()); + collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor); + + collection->SetManufacturerName (JucePlugin_Manufacturer); + collection->AddPackageName (JucePlugin_Desc); + collection->AddPackageName (JucePlugin_Name); + collection->SetPackageVersion (JucePlugin_VersionCode); + + return AAX_SUCCESS; + } + + return AAX_ERROR_NULL_OBJECT; +} + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +//============================================================================== +#if _MSC_VER || JUCE_MINGW +extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) Process::setCurrentModuleInstanceHandle (instance); return true; } +#endif + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.mm index 58f3b0d95efd..fddac2e440e8 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.mm +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.mm @@ -24,4 +24,4 @@ */ #define JUCE_INCLUDED_AAX_IN_MM 1 -#include "AAX/juce_AAX_Wrapper.cpp" +#include "juce_audio_plugin_client_AAX.cpp" diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX_utils.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX_utils.cpp new file mode 100644 index 000000000000..cea4daf7d912 --- /dev/null +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX_utils.cpp @@ -0,0 +1,107 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 + +#if JucePlugin_Build_AAX + +#include + +static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p4p0_REVISION, "JUCE requires AAX SDK version 2.4.0 or higher"); + +#if JUCE_INTEL || (JUCE_MAC && JUCE_ARM) + +#include + +// Utilities +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant") +#include +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations", + "-Wextra-semi", + "-Wfloat-equal", + "-Winconsistent-missing-destructor-override", + "-Wshift-sign-overflow", + "-Wunused-parameter", + "-Wzero-as-null-pointer-constant", + "-Wfour-char-constants", + "-Wdeprecated-copy-with-user-provided-dtor", + "-Wdeprecated") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001 6053 4996 5033 4068 4996) + +#include +#include + +#if defined(_WIN32) && ! defined(WIN32) + #define WIN32 +#endif +#include + +#include +#include +#include + +// Versioned Interfaces +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +#else + #error "This version of the AAX SDK does not support the current platform." +#endif +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp index ec83d19af999..1692ee52469f 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_ARA.cpp @@ -23,4 +23,26 @@ ============================================================================== */ -#include "ARA/juce_ARA_Wrapper.cpp" +#include +#include + +#if JucePlugin_Enable_ARA + +#include +#include + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunused-parameter", + "-Wgnu-zero-variadic-macro-arguments", + "-Wmissing-prototypes", + "-Wfloat-equal") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4100) + +#include +#include +#include +#include + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_1.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_1.mm index edb490a8a0d3..a781b0f60c22 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_1.mm +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_1.mm @@ -23,4 +23,2599 @@ ============================================================================== */ -#include "AU/juce_AU_Wrapper.mm" +#include +#include +#include + +#if JucePlugin_Build_AU + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", + "-Wconversion", + "-Wdeprecated-anon-enum-enum-conversion", + "-Wdeprecated-declarations", + "-Wextra-semi", + "-Wfloat-equal", + "-Wformat-pedantic", + "-Wgnu-zero-variadic-macro-arguments", + "-Wnullable-to-nonnull-conversion", + "-Woverloaded-virtual", + "-Wshadow", + "-Wshorten-64-to-32", + "-Wsign-conversion", + "-Wswitch-enum", + "-Wunused-parameter", + "-Wzero-as-null-pointer-constant") + +#include + +#include +#include +#include +#include +#include +#include "AudioUnitSDK/MusicDeviceBase.h" + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 + +#include + +#include +#include +#include +#include + +#if JucePlugin_Enable_ARA + #include + #include + #if ARA_SUPPORT_VERSION_1 + #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current JUCE ARA implementation" + #endif +#endif + +#include + +//============================================================================== +using namespace juce; + +static Array activePlugins, activeUIs; + +static const AudioUnitPropertyID juceFilterObjectPropertyID = 0x1a45ffe9; + +template <> struct ContainerDeletePolicy { static void destroy (const __CFString* o) { if (o != nullptr) CFRelease (o); } }; + +// make sure the audio processor is initialized before the AUBase class +struct AudioProcessorHolder +{ + AudioProcessorHolder (bool initialiseGUI) + { + if (initialiseGUI) + initialiseJuce_GUI(); + + juceFilter = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnit); + + // audio units do not have a notion of enabled or un-enabled buses + juceFilter->enableAllBuses(); + } + + std::unique_ptr juceFilter; +}; + +//============================================================================== +class JuceAU : public AudioProcessorHolder, + public ausdk::MusicDeviceBase, + public AudioProcessorListener, + public AudioProcessorParameter::Listener +{ +public: + JuceAU (AudioUnit component) + : AudioProcessorHolder (activePlugins.size() + activeUIs.size() == 0), + MusicDeviceBase (component, + (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true), + (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false)) + { + inParameterChangedCallback = false; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + const int numConfigs = sizeof (configs) / sizeof (short[2]); + + jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); + juceFilter->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024); + + for (int i = 0; i < numConfigs; ++i) + { + AUChannelInfo info; + + info.inChannels = configs[i][0]; + info.outChannels = configs[i][1]; + + channelInfo.add (info); + } + #else + channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter); + #endif + + AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this); + + totalInChannels = juceFilter->getTotalNumInputChannels(); + totalOutChannels = juceFilter->getTotalNumOutputChannels(); + + juceFilter->addListener (this); + + addParameters(); + + activePlugins.add (this); + + zerostruct (auEvent); + auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance(); + auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global; + auEvent.mArgument.mParameter.mElement = 0; + + zerostruct (midiCallback); + + CreateElements(); + + if (syncAudioUnitWithProcessor() != noErr) + jassertfalse; + } + + ~JuceAU() override + { + if (bypassParam != nullptr) + bypassParam->removeListener (this); + + deleteActiveEditors(); + juceFilter = nullptr; + clearPresetsArray(); + + jassert (activePlugins.contains (this)); + activePlugins.removeFirstMatchingValue (this); + + if (activePlugins.size() + activeUIs.size() == 0) + shutdownJuce_GUI(); + } + + //============================================================================== + ComponentResult Initialize() override + { + ComponentResult err; + + if ((err = syncProcessorWithAudioUnit()) != noErr) + return err; + + if ((err = MusicDeviceBase::Initialize()) != noErr) + return err; + + mapper.alloc (*juceFilter); + pulledSucceeded.calloc (static_cast (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true))); + + prepareToPlay(); + + return noErr; + } + + void Cleanup() override + { + MusicDeviceBase::Cleanup(); + + pulledSucceeded.free(); + mapper.release(); + + if (juceFilter != nullptr) + juceFilter->releaseResources(); + + audioBuffer.release(); + midiEvents.clear(); + incomingEvents.clear(); + prepared = false; + } + + ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) override + { + if (! prepared) + prepareToPlay(); + + if (juceFilter != nullptr) + juceFilter->reset(); + + return MusicDeviceBase::Reset (inScope, inElement); + } + + //============================================================================== + void prepareToPlay() + { + if (juceFilter != nullptr) + { + juceFilter->setRateAndBufferSizeDetails (getSampleRate(), (int) GetMaxFramesPerSlice()); + + audioBuffer.prepare (AudioUnitHelpers::getBusesLayout (juceFilter.get()), (int) GetMaxFramesPerSlice() + 32); + juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice()); + + midiEvents.ensureSize (2048); + midiEvents.clear(); + incomingEvents.ensureSize (2048); + incomingEvents.clear(); + + prepared = true; + } + } + + //============================================================================== + bool BusCountWritable ([[maybe_unused]] AudioUnitScope scope) override + { + #ifdef JucePlugin_PreferredChannelConfigurations + return false; + #else + bool isInput; + + if (scopeToDirection (scope, isInput) != noErr) + return false; + + #if JucePlugin_IsMidiEffect + return false; + #elif JucePlugin_IsSynth + if (isInput) return false; + #endif + + const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); + return (juceFilter->canAddBus (isInput) || (busCount > 0 && juceFilter->canRemoveBus (isInput))); + #endif + } + + OSStatus SetBusCount (AudioUnitScope scope, UInt32 count) override + { + OSStatus err = noErr; + bool isInput; + + if ((err = scopeToDirection (scope, isInput)) != noErr) + return err; + + if (count != (UInt32) AudioUnitHelpers::getBusCount (*juceFilter, isInput)) + { + #ifdef JucePlugin_PreferredChannelConfigurations + return kAudioUnitErr_PropertyNotWritable; + #else + const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); + + if ((! juceFilter->canAddBus (isInput)) && ((busCount == 0) || (! juceFilter->canRemoveBus (isInput)))) + return kAudioUnitErr_PropertyNotWritable; + + // we need to already create the underlying elements so that we can change their formats + err = MusicDeviceBase::SetBusCount (scope, count); + + if (err != noErr) + return err; + + // however we do need to update the format tag: we need to do the same thing in SetFormat, for example + const int requestedNumBus = static_cast (count); + { + (isInput ? currentInputLayout : currentOutputLayout).resize (requestedNumBus); + + int busNr; + + for (busNr = (busCount - 1); busNr != (requestedNumBus - 1); busNr += (requestedNumBus > busCount ? 1 : -1)) + { + if (requestedNumBus > busCount) + { + if (! juceFilter->addBus (isInput)) + break; + + err = syncAudioUnitWithChannelSet (isInput, busNr, + juceFilter->getBus (isInput, busNr + 1)->getDefaultLayout()); + if (err != noErr) + break; + } + else + { + if (! juceFilter->removeBus (isInput)) + break; + } + } + + err = (busNr == (requestedNumBus - 1) ? (OSStatus) noErr : (OSStatus) kAudioUnitErr_FormatNotSupported); + } + + // was there an error? + if (err != noErr) + { + // restore bus state + const int newBusCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput); + for (int i = newBusCount; i != busCount; i += (busCount > newBusCount ? 1 : -1)) + { + if (busCount > newBusCount) + juceFilter->addBus (isInput); + else + juceFilter->removeBus (isInput); + } + + (isInput ? currentInputLayout : currentOutputLayout).resize (busCount); + MusicDeviceBase::SetBusCount (scope, static_cast (busCount)); + + return kAudioUnitErr_FormatNotSupported; + } + + // update total channel count + totalInChannels = juceFilter->getTotalNumInputChannels(); + totalOutChannels = juceFilter->getTotalNumOutputChannels(); + + addSupportedLayoutTagsForDirection (isInput); + + if (err != noErr) + return err; + #endif + } + + return noErr; + } + + UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) override + { + if (outInfo != nullptr) + *outInfo = channelInfo.getRawDataPointer(); + + return (UInt32) channelInfo.size(); + } + + //============================================================================== + ComponentResult GetPropertyInfo (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + UInt32& outDataSize, + bool& outWritable) override + { + if (inScope == kAudioUnitScope_Global) + { + switch (inID) + { + case juceFilterObjectPropertyID: + outWritable = false; + outDataSize = sizeof (void*) * 2; + return noErr; + + case kAudioUnitProperty_OfflineRender: + outWritable = true; + outDataSize = sizeof (UInt32); + return noErr; + + case kMusicDeviceProperty_InstrumentCount: + outDataSize = sizeof (UInt32); + outWritable = false; + return noErr; + + case kAudioUnitProperty_CocoaUI: + outDataSize = sizeof (AudioUnitCocoaViewInfo); + outWritable = true; + return noErr; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case kAudioUnitProperty_AudioUnitMIDIProtocol: + outDataSize = sizeof (SInt32); + outWritable = false; + return noErr; + + case kAudioUnitProperty_HostMIDIProtocol: + outDataSize = sizeof (SInt32); + outWritable = true; + return noErr; + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + case kAudioUnitProperty_MIDIOutputCallbackInfo: + outDataSize = sizeof (CFArrayRef); + outWritable = false; + return noErr; + + case kAudioUnitProperty_MIDIOutputCallback: + outDataSize = sizeof (AUMIDIOutputCallbackStruct); + outWritable = true; + return noErr; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case kAudioUnitProperty_MIDIOutputEventListCallback: + outDataSize = sizeof (AUMIDIEventListBlock); + outWritable = true; + return noErr; + #endif + #endif + + case kAudioUnitProperty_ParameterStringFromValue: + outDataSize = sizeof (AudioUnitParameterStringFromValue); + outWritable = false; + return noErr; + + case kAudioUnitProperty_ParameterValueFromString: + outDataSize = sizeof (AudioUnitParameterValueFromString); + outWritable = false; + return noErr; + + case kAudioUnitProperty_BypassEffect: + outDataSize = sizeof (UInt32); + outWritable = true; + return noErr; + + case kAudioUnitProperty_SupportsMPE: + outDataSize = sizeof (UInt32); + outWritable = false; + return noErr; + + #if JucePlugin_Enable_ARA + case ARA::kAudioUnitProperty_ARAFactory: + outWritable = false; + outDataSize = sizeof (ARA::ARAAudioUnitFactory); + return noErr; + case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles: + outWritable = false; + outDataSize = sizeof (ARA::ARAAudioUnitPlugInExtensionBinding); + return noErr; + #endif + + default: break; + } + } + + return MusicDeviceBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); + } + + ComponentResult GetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + void* outData) override + { + if (inScope == kAudioUnitScope_Global) + { + switch (inID) + { + case kAudioUnitProperty_ParameterClumpName: + + if (auto* clumpNameInfo = (AudioUnitParameterNameInfo*) outData) + { + if (juceFilter != nullptr) + { + auto clumpIndex = clumpNameInfo->inID - 1; + const auto* group = parameterGroups[(int) clumpIndex]; + auto name = group->getName(); + + while (group->getParent() != &juceFilter->getParameterTree()) + { + group = group->getParent(); + name = group->getName() + group->getSeparator() + name; + } + + clumpNameInfo->outName = name.toCFString(); + return noErr; + } + } + + // Failed to find a group corresponding to the clump ID. + jassertfalse; + break; + + //============================================================================== + #if JucePlugin_Enable_ARA + case ARA::kAudioUnitProperty_ARAFactory: + { + auto auFactory = static_cast (outData); + if (auFactory->inOutMagicNumber != ARA::kARAAudioUnitMagic) + return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics + + auFactory->outFactory = createARAFactory(); + return noErr; + } + + case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles: + { + auto binding = static_cast (outData); + if (binding->inOutMagicNumber != ARA::kARAAudioUnitMagic) + return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics + + AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast (juceFilter.get()); + binding->outPlugInExtension = araAudioProcessorExtension->bindToARA (binding->inDocumentControllerRef, binding->knownRoles, binding->assignedRoles); + if (binding->outPlugInExtension == nullptr) + return kAudioUnitErr_CannotDoInCurrentContext; // bindToARA() returns null if binding is already established + + return noErr; + } + #endif + + case juceFilterObjectPropertyID: + ((void**) outData)[0] = (void*) static_cast (juceFilter.get()); + ((void**) outData)[1] = (void*) this; + return noErr; + + case kAudioUnitProperty_OfflineRender: + *(UInt32*) outData = (juceFilter != nullptr && juceFilter->isNonRealtime()) ? 1 : 0; + return noErr; + + case kMusicDeviceProperty_InstrumentCount: + *(UInt32*) outData = 1; + return noErr; + + case kAudioUnitProperty_BypassEffect: + if (bypassParam != nullptr) + *(UInt32*) outData = (bypassParam->getValue() != 0.0f ? 1 : 0); + else + *(UInt32*) outData = isBypassed ? 1 : 0; + return noErr; + + case kAudioUnitProperty_SupportsMPE: + *(UInt32*) outData = (juceFilter != nullptr && juceFilter->supportsMPE()) ? 1 : 0; + return noErr; + + case kAudioUnitProperty_CocoaUI: + { + JUCE_AUTORELEASEPOOL + { + static JuceUICreationClass cls; + + // (NB: this may be the host's bundle, not necessarily the component's) + NSBundle* bundle = [NSBundle bundleForClass: cls.cls]; + + AudioUnitCocoaViewInfo* info = static_cast (outData); + info->mCocoaAUViewClass[0] = (CFStringRef) [juceStringToNS (class_getName (cls.cls)) retain]; + info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [bundle bundlePath]] retain]; + } + + return noErr; + } + + break; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case kAudioUnitProperty_AudioUnitMIDIProtocol: + { + // This will become configurable in the future + *static_cast (outData) = kMIDIProtocol_1_0; + return noErr; + } + #endif + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + case kAudioUnitProperty_MIDIOutputCallbackInfo: + { + CFStringRef strs[1]; + strs[0] = CFSTR ("MIDI Callback"); + + CFArrayRef callbackArray = CFArrayCreate (nullptr, (const void**) strs, 1, &kCFTypeArrayCallBacks); + *(CFArrayRef*) outData = callbackArray; + return noErr; + } + #endif + + case kAudioUnitProperty_ParameterValueFromString: + { + if (AudioUnitParameterValueFromString* pv = (AudioUnitParameterValueFromString*) outData) + { + if (juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (pv->inParamID)) + { + const String text (String::fromCFString (pv->inString)); + + if (LegacyAudioParameter::isLegacy (param)) + pv->outValue = text.getFloatValue(); + else + pv->outValue = param->getValueForText (text) * getMaximumParameterValue (param); + + + return noErr; + } + } + } + } + break; + + case kAudioUnitProperty_ParameterStringFromValue: + { + if (AudioUnitParameterStringFromValue* pv = (AudioUnitParameterStringFromValue*) outData) + { + if (juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (pv->inParamID)) + { + const float value = (float) *(pv->inValue); + String text; + + if (LegacyAudioParameter::isLegacy (param)) + text = String (value); + else + text = param->getText (value / getMaximumParameterValue (param), 0); + + pv->outString = text.toCFString(); + + return noErr; + } + } + } + } + break; + + default: + break; + } + } + + return MusicDeviceBase::GetProperty (inID, inScope, inElement, outData); + } + + ComponentResult SetProperty (AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const void* inData, + UInt32 inDataSize) override + { + if (inScope == kAudioUnitScope_Global) + { + switch (inID) + { + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + case kAudioUnitProperty_MIDIOutputCallback: + if (inDataSize < sizeof (AUMIDIOutputCallbackStruct)) + return kAudioUnitErr_InvalidPropertyValue; + + if (AUMIDIOutputCallbackStruct* callbackStruct = (AUMIDIOutputCallbackStruct*) inData) + midiCallback = *callbackStruct; + + return noErr; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case kAudioUnitProperty_MIDIOutputEventListCallback: + { + if (inDataSize != sizeof (AUMIDIEventListBlock)) + return kAudioUnitErr_InvalidPropertyValue; + + midiEventListBlock = ScopedMIDIEventListBlock::copy (*static_cast (inData)); + return noErr; + } + #endif + #endif + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case kAudioUnitProperty_HostMIDIProtocol: + { + if (inDataSize != sizeof (SInt32)) + return kAudioUnitErr_InvalidPropertyValue; + + hostProtocol = *static_cast (inData); + return noErr; + } + #endif + + case kAudioUnitProperty_BypassEffect: + { + if (inDataSize < sizeof (UInt32)) + return kAudioUnitErr_InvalidPropertyValue; + + const bool newBypass = *((UInt32*) inData) != 0; + const bool currentlyBypassed = (bypassParam != nullptr ? (bypassParam->getValue() != 0.0f) : isBypassed); + + if (newBypass != currentlyBypassed) + { + if (bypassParam != nullptr) + bypassParam->setValueNotifyingHost (newBypass ? 1.0f : 0.0f); + else + isBypassed = newBypass; + + if (! currentlyBypassed && IsInitialized()) // turning bypass off and we're initialized + Reset (0, 0); + } + + return noErr; + } + + case kAudioUnitProperty_OfflineRender: + { + const auto shouldBeOffline = (*reinterpret_cast (inData) != 0); + + if (juceFilter != nullptr) + { + const auto isOffline = juceFilter->isNonRealtime(); + + if (isOffline != shouldBeOffline) + { + const ScopedLock sl (juceFilter->getCallbackLock()); + + juceFilter->setNonRealtime (shouldBeOffline); + + if (prepared) + juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice()); + } + } + + return noErr; + } + + case kAudioUnitProperty_AUHostIdentifier: + { + if (inDataSize < sizeof (AUHostVersionIdentifier)) + return kAudioUnitErr_InvalidPropertyValue; + + const auto* identifier = static_cast (inData); + PluginHostType::hostIdReportedByWrapper = String::fromCFString (identifier->hostName); + + return noErr; + } + + default: break; + } + } + + return MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize); + } + + //============================================================================== + ComponentResult SaveState (CFPropertyListRef* outData) override + { + ComponentResult err = MusicDeviceBase::SaveState (outData); + + if (err != noErr) + return err; + + jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID()); + + CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData; + + if (juceFilter != nullptr) + { + juce::MemoryBlock state; + + #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + juceFilter->getCurrentProgramStateInformation (state); + #else + juceFilter->getStateInformation (state); + #endif + + if (state.getSize() > 0) + { + CFUniquePtr ourState (CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), (CFIndex) state.getSize())); + CFUniquePtr key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8)); + CFDictionarySetValue (dict, key.get(), ourState.get()); + } + } + + return noErr; + } + + ComponentResult RestoreState (CFPropertyListRef inData) override + { + const ScopedValueSetter scope { restoringState, true }; + + { + // Remove the data entry from the state to prevent the superclass loading the parameters + CFUniquePtr copyWithoutData (CFDictionaryCreateMutableCopy (nullptr, 0, (CFDictionaryRef) inData)); + CFDictionaryRemoveValue (copyWithoutData.get(), CFSTR (kAUPresetDataKey)); + ComponentResult err = MusicDeviceBase::RestoreState (copyWithoutData.get()); + + if (err != noErr) + return err; + } + + if (juceFilter != nullptr) + { + CFDictionaryRef dict = (CFDictionaryRef) inData; + CFDataRef data = nullptr; + + CFUniquePtr key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8)); + + bool valuePresent = CFDictionaryGetValueIfPresent (dict, key.get(), (const void**) &data); + + if (valuePresent) + { + if (data != nullptr) + { + const int numBytes = (int) CFDataGetLength (data); + const juce::uint8* const rawBytes = CFDataGetBytePtr (data); + + if (numBytes > 0) + { + #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + juceFilter->setCurrentProgramStateInformation (rawBytes, numBytes); + #else + juceFilter->setStateInformation (rawBytes, numBytes); + #endif + } + } + } + } + + return noErr; + } + + //============================================================================== + bool busIgnoresLayout ([[maybe_unused]] bool isInput, [[maybe_unused]] int busNr) const + { + #ifdef JucePlugin_PreferredChannelConfigurations + return true; + #else + if (const AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNr)) + { + AudioChannelSet discreteRangeSet; + const int n = bus->getDefaultLayout().size(); + for (int i = 0; i < n; ++i) + discreteRangeSet.addChannel ((AudioChannelSet::ChannelType) (256 + i)); + + // if the audioprocessor supports this it cannot + // really be interested in the bus layouts + return bus->isLayoutSupported (discreteRangeSet); + } + + return true; + #endif + } + + UInt32 GetAudioChannelLayout (AudioUnitScope scope, + AudioUnitElement element, + AudioChannelLayout* outLayoutPtr, + bool& outWritable) override + { + outWritable = false; + + const auto info = getElementInfo (scope, element); + + if (info.error != noErr) + return 0; + + if (busIgnoresLayout (info.isInput, info.busNr)) + return 0; + + outWritable = true; + + const size_t sizeInBytes = sizeof (AudioChannelLayout) - sizeof (AudioChannelDescription); + + if (outLayoutPtr != nullptr) + { + zeromem (outLayoutPtr, sizeInBytes); + outLayoutPtr->mChannelLayoutTag = getCurrentLayout (info.isInput, info.busNr); + } + + return sizeInBytes; + } + + std::vector GetChannelLayoutTags (AudioUnitScope inScope, AudioUnitElement inElement) override + { + const auto info = getElementInfo (inScope, inElement); + + if (info.error != noErr) + return {}; + + if (busIgnoresLayout (info.isInput, info.busNr)) + return {}; + + return getSupportedBusLayouts (info.isInput, info.busNr); + } + + OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override + { + const auto info = getElementInfo (scope, element); + + if (info.error != noErr) + return info.error; + + if (busIgnoresLayout (info.isInput, info.busNr)) + return kAudioUnitErr_PropertyNotWritable; + + if (inLayout == nullptr) + return kAudioUnitErr_InvalidPropertyValue; + + auto& ioElement = IOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element); + + const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout); + const int currentNumChannels = static_cast (ioElement.NumberChannels()); + const int newChannelNum = newChannelSet.size(); + + if (currentNumChannels != newChannelNum) + return kAudioUnitErr_InvalidPropertyValue; + + // check if the new layout could be potentially set + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs)) + return kAudioUnitErr_FormatNotSupported; + #else + if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet)) + return kAudioUnitErr_FormatNotSupported; + #endif + + getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet); + + return noErr; + } + + //============================================================================== + // When parameters are discrete we need to use integer values. + float getMaximumParameterValue ([[maybe_unused]] AudioProcessorParameter* juceParam) + { + #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + return 1.0f; + #else + return juceParam->isDiscrete() ? (float) (juceParam->getNumSteps() - 1) : 1.0f; + #endif + } + + ComponentResult GetParameterInfo (AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + AudioUnitParameterInfo& outParameterInfo) override + { + if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (inParameterID)) + { + outParameterInfo.unit = kAudioUnitParameterUnit_Generic; + outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable + | kAudioUnitParameterFlag_IsReadable + | kAudioUnitParameterFlag_HasCFNameString + | kAudioUnitParameterFlag_ValuesHaveStrings); + + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution; + #endif + + const String name = param->getName (1024); + + // Set whether the param is automatable (unnamed parameters aren't allowed to be automated) + if (name.isEmpty() || ! param->isAutomatable()) + outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime; + + const bool isParameterDiscrete = param->isDiscrete(); + + if (! isParameterDiscrete) + outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp; + + if (param->isMetaParameter()) + outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta; + + auto parameterGroupHierarchy = juceFilter->getParameterTree().getGroupsForParameter (param); + + if (! parameterGroupHierarchy.isEmpty()) + { + outParameterInfo.flags |= kAudioUnitParameterFlag_HasClump; + outParameterInfo.clumpID = (UInt32) parameterGroups.indexOf (parameterGroupHierarchy.getLast()) + 1; + } + + // Is this a meter? + if ((((unsigned int) param->getCategory() & 0xffff0000) >> 16) == 2) + { + outParameterInfo.flags &= ~kAudioUnitParameterFlag_IsWritable; + outParameterInfo.flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic; + outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain; + } + else + { + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + if (isParameterDiscrete) + outParameterInfo.unit = param->isBoolean() ? kAudioUnitParameterUnit_Boolean + : kAudioUnitParameterUnit_Indexed; + #endif + } + + MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true); + + outParameterInfo.minValue = 0.0f; + outParameterInfo.maxValue = getMaximumParameterValue (param); + outParameterInfo.defaultValue = param->getDefaultValue() * getMaximumParameterValue (param); + jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue + && outParameterInfo.defaultValue <= outParameterInfo.maxValue); + + return noErr; + } + } + + return kAudioUnitErr_InvalidParameter; + } + + ComponentResult GetParameterValueStrings (AudioUnitScope inScope, + AudioUnitParameterID inParameterID, + CFArrayRef *outStrings) override + { + if (outStrings == nullptr) + return noErr; + + if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (inParameterID)) + { + if (param->isDiscrete()) + { + auto index = LegacyAudioParameter::getParamIndex (*juceFilter, param); + + if (auto* valueStrings = parameterValueStringArrays[index]) + { + *outStrings = CFArrayCreate (nullptr, + (const void **) valueStrings->getRawDataPointer(), + valueStrings->size(), + nullptr); + + return noErr; + } + } + } + } + + return kAudioUnitErr_InvalidParameter; + } + + ComponentResult GetParameter (AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32& outValue) override + { + if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (inID)) + { + const auto normValue = param->getValue(); + + outValue = normValue * getMaximumParameterValue (param); + return noErr; + } + } + + return MusicDeviceBase::GetParameter (inID, inScope, inElement, outValue); + } + + ComponentResult SetParameter (AudioUnitParameterID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + Float32 inValue, + UInt32 inBufferOffsetInFrames) override + { + if (inScope == kAudioUnitScope_Global && juceFilter != nullptr) + { + if (auto* param = getParameterForAUParameterID (inID)) + { + auto value = inValue / getMaximumParameterValue (param); + + if (! approximatelyEqual (value, param->getValue())) + { + inParameterChangedCallback = true; + param->setValueNotifyingHost (value); + } + + return noErr; + } + } + + return MusicDeviceBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames); + } + + // No idea what this method actually does or what it should return. Current Apple docs say nothing about it. + // (Note that this isn't marked 'override' in case older versions of the SDK don't include it) + bool CanScheduleParameters() const override { return false; } + + //============================================================================== + bool SupportsTail() override { return true; } + Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); } + + double getSampleRate() + { + if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0) + return Output (0).GetStreamFormat().mSampleRate; + + return 44100.0; + } + + Float64 GetLatency() override + { + const double rate = getSampleRate(); + jassert (rate > 0); + #if JucePlugin_Enable_ARA + jassert (juceFilter->getLatencySamples() == 0 || ! dynamic_cast (juceFilter.get())->isBoundToARA()); + #endif + return rate > 0 ? juceFilter->getLatencySamples() / rate : 0; + } + + class ScopedPlayHead : private AudioPlayHead + { + public: + explicit ScopedPlayHead (JuceAU& juceAudioUnit) + : audioUnit (juceAudioUnit) + { + audioUnit.juceFilter->setPlayHead (this); + } + + ~ScopedPlayHead() override + { + audioUnit.juceFilter->setPlayHead (nullptr); + } + + private: + Optional getPosition() const override + { + PositionInfo info; + + info.setFrameRate ([this]() -> Optional + { + switch (audioUnit.lastTimeStamp.mSMPTETime.mType) + { + case kSMPTETimeType2398: return FrameRate().withBaseRate (24).withPullDown(); + case kSMPTETimeType24: return FrameRate().withBaseRate (24); + case kSMPTETimeType25: return FrameRate().withBaseRate (25); + case kSMPTETimeType30Drop: return FrameRate().withBaseRate (30).withDrop(); + case kSMPTETimeType30: return FrameRate().withBaseRate (30); + case kSMPTETimeType2997: return FrameRate().withBaseRate (30).withPullDown(); + case kSMPTETimeType2997Drop: return FrameRate().withBaseRate (30).withPullDown().withDrop(); + case kSMPTETimeType60: return FrameRate().withBaseRate (60); + case kSMPTETimeType60Drop: return FrameRate().withBaseRate (60).withDrop(); + case kSMPTETimeType5994: return FrameRate().withBaseRate (60).withPullDown(); + case kSMPTETimeType5994Drop: return FrameRate().withBaseRate (60).withPullDown().withDrop(); + case kSMPTETimeType50: return FrameRate().withBaseRate (50); + default: break; + } + + return {}; + }()); + + double ppqPosition = 0.0; + double bpm = 0.0; + + if (audioUnit.CallHostBeatAndTempo (&ppqPosition, &bpm) == noErr) + { + info.setPpqPosition (ppqPosition); + info.setBpm (bpm); + } + + UInt32 outDeltaSampleOffsetToNextBeat; + double outCurrentMeasureDownBeat; + float num; + UInt32 den; + + if (audioUnit.CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, + &num, + &den, + &outCurrentMeasureDownBeat) == noErr) + { + info.setTimeSignature (TimeSignature { (int) num, (int) den }); + info.setPpqPositionOfLastBarStart (outCurrentMeasureDownBeat); + } + + double outCurrentSampleInTimeLine = 0, outCycleStartBeat = 0, outCycleEndBeat = 0; + Boolean playing = false, looping = false, playchanged; + + const auto setTimeInSamples = [&] (auto timeInSamples) + { + info.setTimeInSamples ((int64) (timeInSamples + 0.5)); + info.setTimeInSeconds (*info.getTimeInSamples() / audioUnit.getSampleRate()); + }; + + if (audioUnit.CallHostTransportState (&playing, + &playchanged, + &outCurrentSampleInTimeLine, + &looping, + &outCycleStartBeat, + &outCycleEndBeat) == noErr) + { + info.setIsPlaying (playing); + info.setIsLooping (looping); + info.setLoopPoints (LoopPoints { outCycleStartBeat, outCycleEndBeat }); + setTimeInSamples (outCurrentSampleInTimeLine); + } + else + { + // If the host doesn't support this callback, then use the sample time from lastTimeStamp + setTimeInSamples (audioUnit.lastTimeStamp.mSampleTime); + } + + info.setHostTimeNs ((audioUnit.lastTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0 + ? makeOptional (audioUnit.timeConversions.hostTimeToNanos (audioUnit.lastTimeStamp.mHostTime)) + : nullopt); + + return info; + } + + JuceAU& audioUnit; + }; + + //============================================================================== + void sendAUEvent (const AudioUnitEventType type, const int juceParamIndex) + { + if (restoringState) + return; + + auEvent.mEventType = type; + auEvent.mArgument.mParameter.mParameterID = getAUParameterIDForIndex (juceParamIndex); + AUEventListenerNotify (nullptr, nullptr, &auEvent); + } + + void audioProcessorParameterChanged (AudioProcessor*, int index, float /*newValue*/) override + { + if (inParameterChangedCallback.get()) + { + inParameterChangedCallback = false; + return; + } + + sendAUEvent (kAudioUnitEvent_ParameterValueChange, index); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override + { + sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override + { + sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index); + } + + void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override + { + audioProcessorChangedUpdater.update (details); + } + + //============================================================================== + // this will only ever be called by the bypass parameter + void parameterValueChanged (int, float) override + { + if (! restoringState) + PropertyChanged (kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); + } + + void parameterGestureChanged (int, bool) override {} + + //============================================================================== + bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) override + { + const auto info = getElementInfo (scope, element); + + return ((! IsInitialized()) && (info.error == noErr)); + } + + bool ValidFormat (AudioUnitScope inScope, + AudioUnitElement inElement, + const AudioStreamBasicDescription& inNewFormat) override + { + // DSP Quattro incorrectly uses global scope for the ValidFormat call + if (inScope == kAudioUnitScope_Global) + return ValidFormat (kAudioUnitScope_Input, inElement, inNewFormat) + || ValidFormat (kAudioUnitScope_Output, inElement, inNewFormat); + + const auto info = getElementInfo (inScope, inElement); + + if (info.error != noErr) + return false; + + if (info.kind == BusKind::wrapperOnly) + return true; + + const auto newNumChannels = static_cast (inNewFormat.mChannelsPerFrame); + const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); + + if (newNumChannels == oldNumChannels) + return true; + + if ([[maybe_unused]] AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr)) + { + if (! MusicDeviceBase::ValidFormat (inScope, inElement, inNewFormat)) + return false; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + return AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs); + #else + return bus->isNumberOfChannelsSupported (newNumChannels); + #endif + } + + return false; + } + + // AU requires us to override this for the sole reason that we need to find a default layout tag if the number of channels have changed + OSStatus ChangeStreamFormat (AudioUnitScope inScope, + AudioUnitElement inElement, + const AudioStreamBasicDescription& inPrevFormat, + const AudioStreamBasicDescription& inNewFormat) override + { + const auto info = getElementInfo (inScope, inElement); + + if (info.error != noErr) + return info.error; + + AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr); + + const auto newNumChannels = static_cast (inNewFormat.mChannelsPerFrame); + const auto oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr); + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs)) + return kAudioUnitErr_FormatNotSupported; + #endif + + // predict channel layout + const auto set = [&] + { + if (info.kind == BusKind::wrapperOnly) + return AudioChannelSet::discreteChannels (newNumChannels); + + if (newNumChannels != oldNumChannels) + return juceFilter->getBus (info.isInput, info.busNr)->supportedLayoutWithChannels (newNumChannels); + + return juceFilter->getChannelLayoutOfBus (info.isInput, info.busNr); + }(); + + if (set == AudioChannelSet()) + return kAudioUnitErr_FormatNotSupported; + + const auto err = MusicDeviceBase::ChangeStreamFormat (inScope, inElement, inPrevFormat, inNewFormat); + + if (err == noErr) + currentTag = CoreAudioLayouts::toCoreAudio (set); + + return err; + } + + //============================================================================== + ComponentResult Render (AudioUnitRenderActionFlags& ioActionFlags, + const AudioTimeStamp& inTimeStamp, + const UInt32 nFrames) override + { + lastTimeStamp = inTimeStamp; + + // prepare buffers + { + pullInputAudio (ioActionFlags, inTimeStamp, nFrames); + prepareOutputBuffers (nFrames); + audioBuffer.reset(); + } + + ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence; + + const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); + const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); + + // set buffer pointers to minimize copying + { + int chIdx = 0, numChannels = 0; + bool interleaved = false; + AudioBufferList* buffer = nullptr; + + // use output pointers + for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) + { + GetAudioBufferList (false, busIdx, buffer, interleaved, numChannels); + const int* outLayoutMap = mapper.get (false, busIdx); + + for (int ch = 0; ch < numChannels; ++ch) + audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast (buffer->mBuffers[outLayoutMap[ch]].mData)); + } + + // use input pointers on remaining channels + for (int busIdx = 0; chIdx < totalInChannels;) + { + int channelIndexInBus = juceFilter->getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx); + const bool badData = ! pulledSucceeded[busIdx]; + + if (! badData) + GetAudioBufferList (true, busIdx, buffer, interleaved, numChannels); + + const int* inLayoutMap = mapper.get (true, busIdx); + + const int n = juceFilter->getChannelCountOfBus (true, busIdx); + for (int ch = channelIndexInBus; ch < n; ++ch) + audioBuffer.setBuffer (chIdx++, interleaved || badData ? nullptr : static_cast (buffer->mBuffers[inLayoutMap[ch]].mData)); + } + } + + // copy input + { + for (int busIdx = 0; busIdx < numInputBuses; ++busIdx) + { + if (pulledSucceeded[busIdx]) + audioBuffer.set (busIdx, Input ((UInt32) busIdx).GetBufferList(), mapper.get (true, busIdx)); + else + audioBuffer.clearInputBus (busIdx, (int) nFrames); + } + + audioBuffer.clearUnusedChannels ((int) nFrames); + } + + // swap midi buffers + { + const ScopedLock sl (incomingMidiLock); + midiEvents.clear(); + incomingEvents.swapWith (midiEvents); + } + + // process audio + processBlock (audioBuffer.getBuffer (nFrames), midiEvents); + + // copy back + { + for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx) + audioBuffer.get (busIdx, Output ((UInt32) busIdx).GetBufferList(), mapper.get (false, busIdx)); + } + + // process midi output + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + pushMidiOutput (nFrames); + #endif + + midiEvents.clear(); + + return noErr; + } + + //============================================================================== + ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID*, UInt32, const MusicDeviceNoteParams&) override { return noErr; } + ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; } + + //============================================================================== + OSStatus HandleMIDIEvent ([[maybe_unused]] UInt8 inStatus, + [[maybe_unused]] UInt8 inChannel, + [[maybe_unused]] UInt8 inData1, + [[maybe_unused]] UInt8 inData2, + [[maybe_unused]] UInt32 inStartFrame) override + { + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + const juce::uint8 data[] = { (juce::uint8) (inStatus | inChannel), + (juce::uint8) inData1, + (juce::uint8) inData2 }; + + const ScopedLock sl (incomingMidiLock); + incomingEvents.addEvent (data, 3, (int) inStartFrame); + return noErr; + #else + return kAudioUnitErr_PropertyNotInUse; + #endif + } + + OSStatus HandleSysEx ([[maybe_unused]] const UInt8* inData, [[maybe_unused]] UInt32 inLength) override + { + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + const ScopedLock sl (incomingMidiLock); + incomingEvents.addEvent (inData, (int) inLength, 0); + return noErr; + #else + return kAudioUnitErr_PropertyNotInUse; + #endif + } + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + OSStatus MIDIEventList (UInt32 inOffsetSampleFrame, const struct MIDIEventList* list) override + { + const ScopedLock sl (incomingMidiLock); + + auto* packet = &list->packet[0]; + + for (uint32_t i = 0; i < list->numPackets; ++i) + { + toBytestreamDispatcher.dispatch (reinterpret_cast (packet->words), + reinterpret_cast (packet->words + packet->wordCount), + static_cast (packet->timeStamp + inOffsetSampleFrame), + [this] (const ump::BytestreamMidiView& message) + { + incomingEvents.addEvent (message.getMessage(), (int) message.timestamp); + }); + + packet = MIDIEventPacketNext (packet); + } + + return noErr; + } + #endif + + //============================================================================== + ComponentResult GetPresets (CFArrayRef* outData) const override + { + if (outData != nullptr) + { + const int numPrograms = juceFilter->getNumPrograms(); + + clearPresetsArray(); + presetsArray.insertMultiple (0, AUPreset(), numPrograms); + + CFMutableArrayRef presetsArrayRef = CFArrayCreateMutable (nullptr, numPrograms, nullptr); + + for (int i = 0; i < numPrograms; ++i) + { + String name (juceFilter->getProgramName(i)); + if (name.isEmpty()) + name = "Untitled"; + + AUPreset& p = presetsArray.getReference(i); + p.presetNumber = i; + p.presetName = name.toCFString(); + + CFArrayAppendValue (presetsArrayRef, &p); + } + + *outData = (CFArrayRef) presetsArrayRef; + } + + return noErr; + } + + OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override + { + const int numPrograms = juceFilter->getNumPrograms(); + const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber; + + if (chosenPresetNumber >= numPrograms) + return kAudioUnitErr_InvalidProperty; + + AUPreset chosenPreset; + chosenPreset.presetNumber = chosenPresetNumber; + chosenPreset.presetName = juceFilter->getProgramName (chosenPresetNumber).toCFString(); + + juceFilter->setCurrentProgram (chosenPresetNumber); + SetAFactoryPresetAsCurrent (chosenPreset); + + return noErr; + } + + //============================================================================== + class EditorCompHolder : public Component + { + public: + EditorCompHolder (AudioProcessorEditor* const editor) + { + addAndMakeVisible (editor); + + #if ! JucePlugin_EditorRequiresKeyboardFocus + setWantsKeyboardFocus (false); + #else + setWantsKeyboardFocus (true); + #endif + + setBounds (getSizeToContainChild()); + + lastBounds = getBounds(); + } + + ~EditorCompHolder() override + { + deleteAllChildren(); // note that we can't use a std::unique_ptr because the editor may + // have been transferred to another parent which takes over ownership. + } + + Rectangle getSizeToContainChild() + { + if (auto* editor = getChildComponent (0)) + return getLocalArea (editor, editor->getLocalBounds()); + + return {}; + } + + static NSView* createViewFor (AudioProcessor* filter, JuceAU* au, AudioProcessorEditor* const editor) + { + auto* editorCompHolder = new EditorCompHolder (editor); + auto r = convertToHostBounds (makeNSRect (editorCompHolder->getSizeToContainChild())); + + static JuceUIViewClass cls; + auto* view = [[cls.createInstance() initWithFrame: r] autorelease]; + + JuceUIViewClass::setFilter (view, filter); + JuceUIViewClass::setAU (view, au); + JuceUIViewClass::setEditor (view, editorCompHolder); + + [view setHidden: NO]; + [view setPostsFrameChangedNotifications: YES]; + + [[NSNotificationCenter defaultCenter] addObserver: view + selector: @selector (applicationWillTerminate:) + name: NSApplicationWillTerminateNotification + object: nil]; + activeUIs.add (view); + + editorCompHolder->addToDesktop (detail::PluginUtilities::getDesktopFlags (editor), view); + editorCompHolder->setVisible (true); + + return view; + } + + void parentSizeChanged() override + { + resizeHostWindow(); + + if (auto* editor = getChildComponent (0)) + editor->repaint(); + } + + void childBoundsChanged (Component*) override + { + auto b = getSizeToContainChild(); + + if (lastBounds != b) + { + lastBounds = b; + setSize (jmax (32, b.getWidth()), jmax (32, b.getHeight())); + + resizeHostWindow(); + } + } + + bool keyPressed (const KeyPress&) override + { + if (detail::PluginUtilities::getHostType().isAbletonLive()) + { + static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event + NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; + + if (! approximatelyEqual (lastEventTime, eventTime)) + { + lastEventTime = eventTime; + + NSView* view = (NSView*) getWindowHandle(); + NSView* hostView = [view superview]; + NSWindow* hostWindow = [hostView window]; + + [hostWindow makeFirstResponder: hostView]; + [hostView keyDown: (NSEvent*) [NSApp currentEvent]]; + [hostWindow makeFirstResponder: view]; + } + } + + return false; + } + + void resizeHostWindow() + { + [CATransaction begin]; + [CATransaction setValue:(id) kCFBooleanTrue forKey:kCATransactionDisableActions]; + + auto rect = convertToHostBounds (makeNSRect (lastBounds)); + auto* view = (NSView*) getWindowHandle(); + + auto superRect = [[view superview] frame]; + superRect.size.width = rect.size.width; + superRect.size.height = rect.size.height; + + [[view superview] setFrame: superRect]; + [view setFrame: rect]; + [CATransaction commit]; + + [view setNeedsDisplay: YES]; + } + + private: + Rectangle lastBounds; + + JUCE_DECLARE_NON_COPYABLE (EditorCompHolder) + }; + + void deleteActiveEditors() + { + for (int i = activeUIs.size(); --i >= 0;) + { + id ui = (id) activeUIs.getUnchecked(i); + + if (JuceUIViewClass::getAU (ui) == this) + JuceUIViewClass::deleteEditor (ui); + } + } + + //============================================================================== + struct JuceUIViewClass : public ObjCClass + { + JuceUIViewClass() : ObjCClass ("JUCEAUView_") + { + addIvar ("filter"); + addIvar ("au"); + addIvar ("editor"); + + addMethod (@selector (dealloc), dealloc); + addMethod (@selector (applicationWillTerminate:), applicationWillTerminate); + addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow); + addMethod (@selector (mouseDownCanMoveWindow), mouseDownCanMoveWindow); + + registerClass(); + } + + static void deleteEditor (id self) + { + std::unique_ptr editorComp (getEditor (self)); + + if (editorComp != nullptr) + { + if (editorComp->getChildComponent(0) != nullptr + && activePlugins.contains (getAU (self))) // plugin may have been deleted before the UI + { + AudioProcessor* const filter = getIvar (self, "filter"); + filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0)); + } + + editorComp = nullptr; + setEditor (self, nullptr); + } + } + + static JuceAU* getAU (id self) { return getIvar (self, "au"); } + static EditorCompHolder* getEditor (id self) { return getIvar (self, "editor"); } + + static void setFilter (id self, AudioProcessor* filter) { object_setInstanceVariable (self, "filter", filter); } + static void setAU (id self, JuceAU* au) { object_setInstanceVariable (self, "au", au); } + static void setEditor (id self, EditorCompHolder* e) { object_setInstanceVariable (self, "editor", e); } + + private: + static void dealloc (id self, SEL) + { + if (activeUIs.contains (self)) + shutdown (self); + + sendSuperclassMessage (self, @selector (dealloc)); + } + + static void applicationWillTerminate (id self, SEL, NSNotification*) + { + shutdown (self); + } + + static void shutdown (id self) + { + [[NSNotificationCenter defaultCenter] removeObserver: self]; + deleteEditor (self); + + jassert (activeUIs.contains (self)); + activeUIs.removeFirstMatchingValue (self); + + if (activePlugins.size() + activeUIs.size() == 0) + { + // there's some kind of component currently modal, but the host + // is trying to delete our plugin.. + jassert (Component::getCurrentlyModalComponent() == nullptr); + + shutdownJuce_GUI(); + } + } + + static void viewDidMoveToWindow (id self, SEL) + { + if (NSWindow* w = [(NSView*) self window]) + { + [w setAcceptsMouseMovedEvents: YES]; + + if (EditorCompHolder* const editorComp = getEditor (self)) + [w makeFirstResponder: (NSView*) editorComp->getWindowHandle()]; + } + } + + static BOOL mouseDownCanMoveWindow (id, SEL) + { + return NO; + } + }; + + //============================================================================== + struct JuceUICreationClass : public ObjCClass + { + JuceUICreationClass() : ObjCClass ("JUCE_AUCocoaViewClass_") + { + addMethod (@selector (interfaceVersion), interfaceVersion); + addMethod (@selector (description), description); + addMethod (@selector (uiViewForAudioUnit:withSize:), uiViewForAudioUnit); + + addProtocol (@protocol (AUCocoaUIBase)); + + registerClass(); + } + + private: + static unsigned int interfaceVersion (id, SEL) { return 0; } + + static NSString* description (id, SEL) + { + return [NSString stringWithString: nsStringLiteral (JucePlugin_Name)]; + } + + static NSView* uiViewForAudioUnit (id, SEL, AudioUnit inAudioUnit, NSSize) + { + void* pointers[2]; + UInt32 propertySize = sizeof (pointers); + + if (AudioUnitGetProperty (inAudioUnit, juceFilterObjectPropertyID, + kAudioUnitScope_Global, 0, pointers, &propertySize) == noErr) + { + if (AudioProcessor* filter = static_cast (pointers[0])) + if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded()) + { + #if JucePlugin_Enable_ARA + jassert (dynamic_cast (editorComp) != nullptr); + // for proper view embedding, ARA plug-ins must be resizable + jassert (editorComp->isResizable()); + #endif + return EditorCompHolder::createViewFor (filter, static_cast (pointers[1]), editorComp); + } + } + + return nil; + } + }; + +private: + //============================================================================== + /* The call to AUBase::PropertyChanged may allocate hence the need for this class */ + class AudioProcessorChangedUpdater final : private AsyncUpdater + { + public: + explicit AudioProcessorChangedUpdater (JuceAU& o) : owner (o) {} + ~AudioProcessorChangedUpdater() override { cancelPendingUpdate(); } + + void update (const ChangeDetails& details) + { + int flags = 0; + + if (details.latencyChanged) + flags |= latencyChangedFlag; + + if (details.parameterInfoChanged) + flags |= parameterInfoChangedFlag; + + if (details.programChanged) + flags |= programChangedFlag; + + if (flags != 0) + { + callbackFlags.fetch_or (flags); + + if (MessageManager::getInstance()->isThisTheMessageThread()) + handleAsyncUpdate(); + else + triggerAsyncUpdate(); + } + } + + private: + void handleAsyncUpdate() override + { + const auto flags = callbackFlags.exchange (0); + + if ((flags & latencyChangedFlag) != 0) + owner.PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0); + + if ((flags & parameterInfoChangedFlag) != 0) + { + owner.PropertyChanged (kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0); + owner.PropertyChanged (kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, 0); + } + + owner.PropertyChanged (kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0); + + if ((flags & programChangedFlag) != 0) + { + owner.refreshCurrentPreset(); + owner.PropertyChanged (kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0); + } + } + + JuceAU& owner; + + static constexpr int latencyChangedFlag = 1 << 0, + parameterInfoChangedFlag = 1 << 1, + programChangedFlag = 1 << 2; + + std::atomic callbackFlags { 0 }; + }; + + //============================================================================== + AudioUnitHelpers::CoreAudioBufferList audioBuffer; + MidiBuffer midiEvents, incomingEvents; + bool prepared = false, isBypassed = false, restoringState = false; + + //============================================================================== + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + static constexpr bool forceUseLegacyParamIDs = true; + #else + static constexpr bool forceUseLegacyParamIDs = false; + #endif + + //============================================================================== + LegacyAudioParametersWrapper juceParameters; + std::unordered_map paramMap; + Array auParamIDs; + Array parameterGroups; + + // Stores the parameter IDs in the order that they will be reported to the host. + std::vector cachedParameterList; + + //============================================================================== + // According to the docs, this is the maximum size of a MIDIPacketList. + static constexpr UInt32 packetListBytes = 65536; + + CoreAudioTimeConversions timeConversions; + AudioUnitEvent auEvent; + mutable Array presetsArray; + CriticalSection incomingMidiLock; + AUMIDIOutputCallbackStruct midiCallback; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + class ScopedMIDIEventListBlock + { + public: + ScopedMIDIEventListBlock() = default; + + ScopedMIDIEventListBlock (ScopedMIDIEventListBlock&& other) noexcept + : midiEventListBlock (std::exchange (other.midiEventListBlock, nil)) {} + + ScopedMIDIEventListBlock& operator= (ScopedMIDIEventListBlock&& other) noexcept + { + ScopedMIDIEventListBlock { std::move (other) }.swap (*this); + return *this; + } + + ~ScopedMIDIEventListBlock() + { + if (midiEventListBlock != nil) + [midiEventListBlock release]; + } + + static ScopedMIDIEventListBlock copy (AUMIDIEventListBlock b) + { + return ScopedMIDIEventListBlock { b }; + } + + explicit operator bool() const { return midiEventListBlock != nil; } + + void operator() (AUEventSampleTime eventSampleTime, uint8_t cable, const struct MIDIEventList * eventList) const + { + jassert (midiEventListBlock != nil); + midiEventListBlock (eventSampleTime, cable, eventList); + } + + private: + void swap (ScopedMIDIEventListBlock& other) noexcept + { + std::swap (other.midiEventListBlock, midiEventListBlock); + } + + explicit ScopedMIDIEventListBlock (AUMIDIEventListBlock b) : midiEventListBlock ([b copy]) {} + + AUMIDIEventListBlock midiEventListBlock = nil; + }; + + ScopedMIDIEventListBlock midiEventListBlock; + std::optional hostProtocol; + ump::ToUMP1Converter toUmp1Converter; + ump::ToBytestreamDispatcher toBytestreamDispatcher { 2048 }; + #endif + + AudioTimeStamp lastTimeStamp; + int totalInChannels, totalOutChannels; + HeapBlock pulledSucceeded; + HeapBlock packetList { packetListBytes, 1 }; + + ThreadLocalValue inParameterChangedCallback; + + AudioProcessorChangedUpdater audioProcessorChangedUpdater { *this }; + + //============================================================================== + Array channelInfo; + Array> supportedInputLayouts, supportedOutputLayouts; + Array currentInputLayout, currentOutputLayout; + + //============================================================================== + AudioUnitHelpers::ChannelRemapper mapper; + + //============================================================================== + OwnedArray> parameterValueStringArrays; + + //============================================================================== + AudioProcessorParameter* bypassParam = nullptr; + + //============================================================================== + static NSRect convertToHostBounds (NSRect pluginRect) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return pluginRect; + + return NSMakeRect (static_cast (pluginRect.origin.x * desktopScale), + static_cast (pluginRect.origin.y * desktopScale), + static_cast (pluginRect.size.width * desktopScale), + static_cast (pluginRect.size.height * desktopScale)); + } + + static NSRect convertFromHostBounds (NSRect hostRect) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return hostRect; + + return NSMakeRect (static_cast (hostRect.origin.x / desktopScale), + static_cast (hostRect.origin.y / desktopScale), + static_cast (hostRect.size.width / desktopScale), + static_cast (hostRect.size.height / desktopScale)); + } + + //============================================================================== + void pullInputAudio (AudioUnitRenderActionFlags& flags, const AudioTimeStamp& timestamp, const UInt32 nFrames) noexcept + { + const unsigned int numInputBuses = GetScope (kAudioUnitScope_Input).GetNumberOfElements(); + + for (unsigned int i = 0; i < numInputBuses; ++i) + { + auto& input = Input (i); + + const bool succeeded = (input.PullInput (flags, timestamp, i, nFrames) == noErr); + + if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded) + AudioUnitHelpers::clearAudioBuffer (input.GetBufferList()); + + pulledSucceeded[i] = succeeded; + } + } + + void prepareOutputBuffers (const UInt32 nFrames) noexcept + { + const auto numProcessorBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); + const auto numWrapperBuses = GetScope (kAudioUnitScope_Output).GetNumberOfElements(); + + for (UInt32 busIdx = 0; busIdx < numWrapperBuses; ++busIdx) + { + auto& output = Output (busIdx); + + if (output.WillAllocateBuffer()) + output.PrepareBuffer (nFrames); + + if (busIdx >= (UInt32) numProcessorBuses) + AudioUnitHelpers::clearAudioBuffer (output.GetBufferList()); + } + } + + void processBlock (juce::AudioBuffer& buffer, MidiBuffer& midiBuffer) noexcept + { + const ScopedLock sl (juceFilter->getCallbackLock()); + const ScopedPlayHead playhead { *this }; + + if (juceFilter->isSuspended()) + { + buffer.clear(); + } + else if (bypassParam == nullptr && isBypassed) + { + juceFilter->processBlockBypassed (buffer, midiBuffer); + } + else + { + juceFilter->processBlock (buffer, midiBuffer); + } + } + + void pushMidiOutput ([[maybe_unused]] UInt32 nFrames) noexcept + { + if (midiEvents.isEmpty()) + return; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + if (@available (macOS 12.0, iOS 15.0, *)) + { + if (midiEventListBlock) + { + struct MIDIEventList stackList = {}; + MIDIEventPacket* end = nullptr; + + const auto init = [&] + { + end = MIDIEventListInit (&stackList, kMIDIProtocol_1_0); + }; + + const auto send = [&] + { + midiEventListBlock (static_cast (lastTimeStamp.mSampleTime), 0, &stackList); + }; + + const auto add = [&] (const ump::View& view, int timeStamp) + { + static_assert (sizeof (uint32_t) == sizeof (UInt32) + && alignof (uint32_t) == alignof (UInt32), + "If this fails, the cast below will be broken too!"); + using List = struct MIDIEventList; + end = MIDIEventListAdd (&stackList, + sizeof (List::packet), + end, + (MIDITimeStamp) timeStamp, + view.size(), + reinterpret_cast (view.data())); + }; + + init(); + + for (const auto metadata : midiEvents) + { + toUmp1Converter.convert (ump::BytestreamMidiView (metadata), [&] (const ump::View& view) + { + add (view, metadata.samplePosition); + + if (end != nullptr) + return; + + send(); + init(); + add (view, metadata.samplePosition); + }); + + } + + send(); + + return; + } + } + #endif + + if (midiCallback.midiOutputCallback) + { + MIDIPacket* end = nullptr; + + const auto init = [&] + { + end = MIDIPacketListInit (packetList); + }; + + const auto send = [&] + { + midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList); + }; + + const auto add = [&] (const MidiMessageMetadata& metadata) + { + end = MIDIPacketListAdd (packetList, + packetListBytes, + end, + static_cast (metadata.samplePosition), + static_cast (metadata.numBytes), + metadata.data); + }; + + init(); + + for (const auto metadata : midiEvents) + { + jassert (isPositiveAndBelow (metadata.samplePosition, nFrames)); + + add (metadata); + + if (end == nullptr) + { + send(); + init(); + add (metadata); + + if (end == nullptr) + { + // If this is hit, the size of this midi packet exceeds the maximum size of + // a MIDIPacketList. Large SysEx messages should be broken up into smaller + // chunks. + jassertfalse; + init(); + } + } + } + + send(); + } + } + + void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels) + { + auto* element = Element (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast (busIdx)).AsIOElement(); + jassert (element != nullptr); + + bufferList = &element->GetBufferList(); + + jassert (bufferList->mNumberBuffers > 0); + + interleaved = AudioUnitHelpers::isAudioBufferInterleaved (*bufferList); + numChannels = static_cast (interleaved ? bufferList->mBuffers[0].mNumberChannels : bufferList->mNumberBuffers); + } + + //============================================================================== + static OSStatus scopeToDirection (AudioUnitScope scope, bool& isInput) noexcept + { + isInput = (scope == kAudioUnitScope_Input); + + return (scope != kAudioUnitScope_Input + && scope != kAudioUnitScope_Output) + ? (OSStatus) kAudioUnitErr_InvalidScope : (OSStatus) noErr; + } + + enum class BusKind + { + processor, + wrapperOnly, + }; + + struct ElementInfo + { + int busNr; + BusKind kind; + bool isInput; + OSStatus error; + }; + + ElementInfo getElementInfo (AudioUnitScope scope, AudioUnitElement element) noexcept + { + bool isInput = false; + OSStatus err; + + if ((err = scopeToDirection (scope, isInput)) != noErr) + return { {}, {}, {}, err }; + + const auto busIdx = static_cast (element); + + if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCount (*juceFilter, isInput))) + return { busIdx, BusKind::processor, isInput, noErr }; + + if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCountForWrapper (*juceFilter, isInput))) + return { busIdx, BusKind::wrapperOnly, isInput, noErr }; + + return { {}, {}, {}, kAudioUnitErr_InvalidElement }; + } + + OSStatus GetParameterList (AudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters) override + { + if (forceUseLegacyParamIDs || inScope != kAudioUnitScope_Global) + return MusicDeviceBase::GetParameterList (inScope, outParameterList, outNumParameters); + + outNumParameters = (UInt32) juceParameters.size(); + + if (outParameterList == nullptr) + return noErr; + + if (cachedParameterList.empty()) + { + struct ParamInfo + { + AudioUnitParameterID identifier; + int versionHint; + }; + + std::vector vec; + vec.reserve (juceParameters.size()); + + for (const auto* param : juceParameters) + vec.push_back ({ generateAUParameterID (*param), param->getVersionHint() }); + + std::sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.identifier < b.identifier; }); + std::stable_sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.versionHint < b.versionHint; }); + std::transform (vec.begin(), vec.end(), std::back_inserter (cachedParameterList), [] (auto x) { return x.identifier; }); + } + + std::copy (cachedParameterList.begin(), cachedParameterList.end(), outParameterList); + + return noErr; + } + + //============================================================================== + void addParameters() + { + parameterGroups = juceFilter->getParameterTree().getSubgroups (true); + + juceParameters.update (*juceFilter, forceUseLegacyParamIDs); + const int numParams = juceParameters.getNumParameters(); + + if (forceUseLegacyParamIDs) + { + Globals()->UseIndexedParameters (static_cast (numParams)); + } + else + { + for (auto* param : juceParameters) + { + const AudioUnitParameterID auParamID = generateAUParameterID (*param); + + // Consider yourself very unlucky if you hit this assertion. The hash codes of your + // parameter ids are not unique. + jassert (paramMap.find (static_cast (auParamID)) == paramMap.end()); + + auParamIDs.add (auParamID); + paramMap.emplace (static_cast (auParamID), param); + Globals()->SetParameter (auParamID, param->getValue()); + } + } + + #if JUCE_DEBUG + // Some hosts can't handle the huge numbers of discrete parameter values created when + // using the default number of steps. + for (auto* param : juceParameters) + if (param->isDiscrete()) + jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps()); + #endif + + parameterValueStringArrays.ensureStorageAllocated (numParams); + + for (auto* param : juceParameters) + { + OwnedArray* stringValues = nullptr; + + auto initialValue = param->getValue(); + bool paramIsLegacy = dynamic_cast (param) != nullptr; + + if (param->isDiscrete() && (! forceUseLegacyParamIDs)) + { + const auto numSteps = param->getNumSteps(); + stringValues = new OwnedArray(); + stringValues->ensureStorageAllocated (numSteps); + + const auto maxValue = getMaximumParameterValue (param); + + auto getTextValue = [param, paramIsLegacy] (float value) + { + if (paramIsLegacy) + { + param->setValue (value); + return param->getCurrentValueAsText(); + } + + return param->getText (value, 256); + }; + + for (int i = 0; i < numSteps; ++i) + { + auto value = (float) i / maxValue; + stringValues->add (CFStringCreateCopy (nullptr, (getTextValue (value).toCFString()))); + } + } + + if (paramIsLegacy) + param->setValue (initialValue); + + parameterValueStringArrays.add (stringValues); + } + + if ((bypassParam = juceFilter->getBypassParameter()) != nullptr) + bypassParam->addListener (this); + } + + //============================================================================== + static AudioUnitParameterID generateAUParameterID (const AudioProcessorParameter& param) + { + const String& juceParamID = LegacyAudioParameter::getParamID (¶m, forceUseLegacyParamIDs); + AudioUnitParameterID paramHash = static_cast (juceParamID.hashCode()); + + #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS + // studio one doesn't like negative parameters + paramHash &= ~(((AudioUnitParameterID) 1) << (sizeof (AudioUnitParameterID) * 8 - 1)); + #endif + + return forceUseLegacyParamIDs ? static_cast (juceParamID.getIntValue()) + : paramHash; + } + + inline AudioUnitParameterID getAUParameterIDForIndex (int paramIndex) const noexcept + { + return forceUseLegacyParamIDs ? static_cast (paramIndex) + : auParamIDs.getReference (paramIndex); + } + + AudioProcessorParameter* getParameterForAUParameterID (AudioUnitParameterID address) const noexcept + { + const auto index = static_cast (address); + + if (forceUseLegacyParamIDs) + return juceParameters.getParamForIndex (index); + + const auto iter = paramMap.find (index); + return iter != paramMap.end() ? iter->second : nullptr; + } + + //============================================================================== + OSStatus syncAudioUnitWithProcessor() + { + OSStatus err = noErr; + const auto numWrapperInputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true); + const auto numWrapperOutputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false); + + if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Input, static_cast (numWrapperInputs))) != noErr) + return err; + + if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Output, static_cast (numWrapperOutputs))) != noErr) + return err; + + addSupportedLayoutTags(); + + const auto numProcessorInputs = AudioUnitHelpers::getBusCount (*juceFilter, true); + const auto numProcessorOutputs = AudioUnitHelpers::getBusCount (*juceFilter, false); + + for (int i = 0; i < numProcessorInputs; ++i) + if ((err = syncAudioUnitWithChannelSet (true, i, juceFilter->getChannelLayoutOfBus (true, i))) != noErr) + return err; + + for (int i = 0; i < numProcessorOutputs; ++i) + if ((err = syncAudioUnitWithChannelSet (false, i, juceFilter->getChannelLayoutOfBus (false, i))) != noErr) + return err; + + return noErr; + } + + OSStatus syncProcessorWithAudioUnit() + { + const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true); + const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false); + + const int numInputElements = static_cast (GetScope (kAudioUnitScope_Input). GetNumberOfElements()); + const int numOutputElements = static_cast (GetScope (kAudioUnitScope_Output).GetNumberOfElements()); + + AudioProcessor::BusesLayout requestedLayouts; + for (int dir = 0; dir < 2; ++dir) + { + const bool isInput = (dir == 0); + const int n = (isInput ? numInputBuses : numOutputBuses); + const int numAUElements = (isInput ? numInputElements : numOutputElements); + Array& requestedBuses = (isInput ? requestedLayouts.inputBuses : requestedLayouts.outputBuses); + + for (int busIdx = 0; busIdx < n; ++busIdx) + { + const auto* element = (busIdx < numAUElements ? &IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr); + const int numChannels = (element != nullptr ? static_cast (element->NumberChannels()) : 0); + + AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx]; + const int tagNumChannels = currentLayoutTag & 0xffff; + + if (numChannels != tagNumChannels) + return kAudioUnitErr_FormatNotSupported; + + requestedBuses.add (CoreAudioLayouts::fromCoreAudio (currentLayoutTag)); + } + } + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + if (! AudioProcessor::containsLayout (requestedLayouts, configs)) + return kAudioUnitErr_FormatNotSupported; + #endif + + if (! AudioUnitHelpers::setBusesLayout (juceFilter.get(), requestedLayouts)) + return kAudioUnitErr_FormatNotSupported; + + // update total channel count + totalInChannels = juceFilter->getTotalNumInputChannels(); + totalOutChannels = juceFilter->getTotalNumOutputChannels(); + + return noErr; + } + + OSStatus syncAudioUnitWithChannelSet (bool isInput, int busNr, const AudioChannelSet& channelSet) + { + const int numChannels = channelSet.size(); + + getCurrentLayout (isInput, busNr) = CoreAudioLayouts::toCoreAudio (channelSet); + + // is this bus activated? + if (numChannels == 0) + return noErr; + + auto& element = IOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr); + + element.SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName())); + + const auto streamDescription = ausdk::ASBD::CreateCommonFloat32 (getSampleRate(), (UInt32) numChannels); + return element.SetStreamFormat (streamDescription); + } + + //============================================================================== + void clearPresetsArray() const + { + for (int i = presetsArray.size(); --i >= 0;) + CFRelease (presetsArray.getReference(i).presetName); + + presetsArray.clear(); + } + + void refreshCurrentPreset() + { + // this will make the AU host re-read and update the current preset name + // in case it was changed here in the plug-in: + + const int currentProgramNumber = juceFilter->getCurrentProgram(); + const String currentProgramName = juceFilter->getProgramName (currentProgramNumber); + + AUPreset currentPreset; + currentPreset.presetNumber = currentProgramNumber; + currentPreset.presetName = currentProgramName.toCFString(); + + SetAFactoryPresetAsCurrent (currentPreset); + } + + //============================================================================== + std::vector& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } + const std::vector& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); } + AudioChannelLayoutTag& getCurrentLayout (bool isInput, int bus) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); } + AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[bus]; } + + //============================================================================== + std::vector getSupportedLayoutTagsForBus (bool isInput, int busNum) const + { + std::set tags; + + if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum)) + { + #ifndef JucePlugin_PreferredChannelConfigurations + auto& knownTags = CoreAudioLayouts::getKnownCoreAudioTags(); + + for (auto tag : knownTags) + if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag))) + tags.insert (tag); + #endif + + // add discrete layout tags + int n = bus->getMaxSupportedChannels (maxChannelsToProbeFor()); + + for (int ch = 0; ch < n; ++ch) + { + #ifdef JucePlugin_PreferredChannelConfigurations + const short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + if (AudioUnitHelpers::isLayoutSupported (*juceFilter, isInput, busNum, ch, configs)) + tags.insert (static_cast ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); + #else + if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch))) + tags.insert (static_cast ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch)); + #endif + } + } + + return std::vector (tags.begin(), tags.end()); + } + + void addSupportedLayoutTagsForDirection (bool isInput) + { + auto& layouts = isInput ? supportedInputLayouts : supportedOutputLayouts; + layouts.clearQuick(); + auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput); + + for (int busNr = 0; busNr < numBuses; ++busNr) + layouts.add (getSupportedLayoutTagsForBus (isInput, busNr)); + } + + void addSupportedLayoutTags() + { + currentInputLayout.clear(); currentOutputLayout.clear(); + + currentInputLayout. resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true)); + currentOutputLayout.resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false)); + + addSupportedLayoutTagsForDirection (true); + addSupportedLayoutTagsForDirection (false); + } + + static int maxChannelsToProbeFor() + { + return (detail::PluginUtilities::getHostType().isLogic() ? 8 : 64); + } + + //============================================================================== + void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement) + { + if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName + && juceFilter != nullptr && GetContextName() != nullptr) + { + AudioProcessor::TrackProperties props; + props.name = String::fromCFString (GetContextName()); + + juceFilter->updateTrackProperties (props); + } + } + + static void auPropertyListenerDispatcher (void* inRefCon, AudioUnit, AudioUnitPropertyID propId, + AudioUnitScope scope, AudioUnitElement element) + { + static_cast (inRefCon)->auPropertyListener (propId, scope, element); + } + + JUCE_DECLARE_NON_COPYABLE (JuceAU) +}; + +//============================================================================== +#if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + #define FACTORY_BASE_CLASS ausdk::AUMusicDeviceFactory +#else + #define FACTORY_BASE_CLASS ausdk::AUBaseFactory +#endif + +AUSDK_COMPONENT_ENTRY (FACTORY_BASE_CLASS, JuceAU) + +#define JUCE_AU_ENTRY_POINT_NAME JUCE_CONCAT (JucePlugin_AUExportPrefix, Factory) + + extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc); +AUSDK_EXPORT extern "C" void* JUCE_AU_ENTRY_POINT_NAME (const AudioComponentDescription* inDesc) +{ + return JuceAUFactory (inDesc); +} + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm index ed10cded95f4..bf11de1ae215 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm @@ -29,26 +29,29 @@ #include -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wparentheses", - "-Wextra-tokens", +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wambiguous-reversed-operator", + "-Wc99-extensions", + "-Wcast-align", "-Wcomment", "-Wconversion", - "-Wunused-parameter", - "-Wunused", + "-Wdeprecated-anon-enum-enum-conversion", "-Wextra-semi", + "-Wextra-tokens", + "-Wfloat-equal", "-Wformat-pedantic", + "-Wfour-char-constants", "-Wgnu-zero-variadic-macro-arguments", - "-Wshadow-all", - "-Wcast-align", - "-Wswitch-enum", - "-Wimplicit-fallthrough", - "-Wzero-as-null-pointer-constant", - "-Wnullable-to-nonnull-conversion", "-Wignored-qualifiers", - "-Wfour-char-constants", + "-Wimplicit-fallthrough", "-Wmissing-prototypes", - "-Wdeprecated-anon-enum-enum-conversion", - "-Wambiguous-reversed-operator") + "-Wnullable-to-nonnull-conversion", + "-Wparentheses", + "-Wshadow-all", + "-Wswitch-enum", + "-Wunknown-attributes", + "-Wunused", + "-Wunused-parameter", + "-Wzero-as-null-pointer-constant") // From MacOS 10.13 and iOS 11 Apple has (sensibly!) stopped defining a whole // set of functions with rather generic names. However, we still need a couple @@ -84,18 +87,18 @@ #endif -#include "AU/AudioUnitSDK/AUBase.cpp" -#include "AU/AudioUnitSDK/AUBuffer.cpp" -#include "AU/AudioUnitSDK/AUBufferAllocator.cpp" -#include "AU/AudioUnitSDK/AUEffectBase.cpp" -#include "AU/AudioUnitSDK/AUInputElement.cpp" -#include "AU/AudioUnitSDK/AUMIDIBase.cpp" -#include "AU/AudioUnitSDK/AUMIDIEffectBase.cpp" -#include "AU/AudioUnitSDK/AUOutputElement.cpp" -#include "AU/AudioUnitSDK/AUPlugInDispatch.cpp" -#include "AU/AudioUnitSDK/AUScopeElement.cpp" -#include "AU/AudioUnitSDK/ComponentBase.cpp" -#include "AU/AudioUnitSDK/MusicDeviceBase.cpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #undef verify #undef verify_noerr diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm index ec742fff7f92..03992548c3b1 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm @@ -23,4 +23,1970 @@ ============================================================================== */ -#include "AU/juce_AUv3_Wrapper.mm" +#include +#include + +#if JucePlugin_Build_AUv3 + +#if JUCE_MAC && ! (defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) + #error AUv3 needs Deployment Target OS X 10.11 or higher to compile +#endif + +#ifndef __OBJC2__ + #error AUv3 needs Objective-C 2 support (compile with 64-bit) +#endif + +#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 + +#include +#include + +#import +#import +#import + +#include +#include +#include +#include +#include + +#define JUCE_VIEWCONTROLLER_OBJC_NAME(x) JUCE_JOIN_MACRO (x, FactoryAUv3) + +#if JUCE_IOS + #define JUCE_IOS_MAC_VIEW UIView +#else + #define JUCE_IOS_MAC_VIEW NSView +#endif + +#define JUCE_AUDIOUNIT_OBJC_NAME(x) JUCE_JOIN_MACRO (x, AUv3) + +#include + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullability-completeness") + +using namespace juce; + +struct AudioProcessorHolder : public ReferenceCountedObject +{ + AudioProcessorHolder() = default; + explicit AudioProcessorHolder (std::unique_ptr p) : processor (std::move (p)) {} + AudioProcessor& operator*() noexcept { return *processor; } + AudioProcessor* operator->() noexcept { return processor.get(); } + AudioProcessor* get() noexcept { return processor.get(); } + + struct ViewConfig + { + double width; + double height; + bool hostHasMIDIController; + }; + + std::unique_ptr viewConfiguration; + + using Ptr = ReferenceCountedObjectPtr; + +private: + std::unique_ptr processor; + + AudioProcessorHolder& operator= (AudioProcessor*) = delete; + AudioProcessorHolder (AudioProcessorHolder&) = delete; + AudioProcessorHolder& operator= (AudioProcessorHolder&) = delete; +}; + +//============================================================================== +//=========================== The actual AudioUnit ============================= +//============================================================================== +class JuceAudioUnitv3 : public AudioProcessorListener, + public AudioPlayHead, + private AudioProcessorParameter::Listener +{ +public: + JuceAudioUnitv3 (const AudioProcessorHolder::Ptr& processor, + const AudioComponentDescription& descr, + AudioComponentInstantiationOptions options, + NSError** error) + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wobjc-method-access") + : au ([getClass().createInstance() initWithComponentDescription: descr + options: options + error: error + juceClass: this]), + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + processorHolder (processor) + { + init(); + } + + JuceAudioUnitv3 (AUAudioUnit* audioUnit, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**) + : au (audioUnit), + processorHolder (new AudioProcessorHolder (createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))) + { + jassert (MessageManager::getInstance()->isThisTheMessageThread()); + initialiseJuce_GUI(); + + init(); + } + + ~JuceAudioUnitv3() override + { + auto& processor = getAudioProcessor(); + processor.removeListener (this); + + if (bypassParam != nullptr) + bypassParam->removeListener (this); + + removeEditor (processor); + } + + //============================================================================== + void init() + { + inParameterChangedCallback = false; + + AudioProcessor& processor = getAudioProcessor(); + const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + const int numConfigs = sizeof (configs) / sizeof (short[2]); + + jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); + processor.setPlayConfigDetails (configs[0][0], configs[0][1], kDefaultSampleRate, static_cast (maxFrames)); + + Array channelInfos; + + for (int i = 0; i < numConfigs; ++i) + { + AUChannelInfo channelInfo; + + channelInfo.inChannels = configs[i][0]; + channelInfo.outChannels = configs[i][1]; + + channelInfos.add (channelInfo); + } + #else + Array channelInfos = AudioUnitHelpers::getAUChannelInfo (processor); + #endif + + processor.setPlayHead (this); + + totalInChannels = processor.getTotalNumInputChannels(); + totalOutChannels = processor.getTotalNumOutputChannels(); + + { + channelCapabilities.reset ([[NSMutableArray alloc] init]); + + for (int i = 0; i < channelInfos.size(); ++i) + { + AUChannelInfo& info = channelInfos.getReference (i); + + [channelCapabilities.get() addObject: [NSNumber numberWithInteger: info.inChannels]]; + [channelCapabilities.get() addObject: [NSNumber numberWithInteger: info.outChannels]]; + } + } + + internalRenderBlock = CreateObjCBlock (this, &JuceAudioUnitv3::renderCallback); + + processor.setRateAndBufferSizeDetails (kDefaultSampleRate, static_cast (maxFrames)); + processor.prepareToPlay (kDefaultSampleRate, static_cast (maxFrames)); + processor.addListener (this); + + addParameters(); + addPresets(); + + addAudioUnitBusses (true); + addAudioUnitBusses (false); + } + + AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; } + + //============================================================================== + void reset() + { + midiMessages.clear(); + lastTimeStamp.mSampleTime = std::numeric_limits::max(); + lastTimeStamp.mFlags = 0; + } + + //============================================================================== + AUAudioUnitPreset* getCurrentPreset() const + { + return factoryPresets.getAtIndex (getAudioProcessor().getCurrentProgram()); + } + + void setCurrentPreset (AUAudioUnitPreset* preset) + { + getAudioProcessor().setCurrentProgram (static_cast ([preset number])); + } + + NSArray* getFactoryPresets() const + { + return factoryPresets.get(); + } + + NSDictionary* getFullState() const + { + NSMutableDictionary* retval = [[NSMutableDictionary alloc] init]; + + { + auto* superRetval = ObjCMsgSendSuper*> (au, @selector (fullState)); + + if (superRetval != nullptr) + [retval addEntriesFromDictionary:superRetval]; + } + + juce::MemoryBlock state; + + #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + getAudioProcessor().getCurrentProgramStateInformation (state); + #else + getAudioProcessor().getStateInformation (state); + #endif + + if (state.getSize() > 0) + { + [retval setObject: [[NSData alloc] initWithBytes: state.getData() length: state.getSize()] + forKey: @JUCE_STATE_DICTIONARY_KEY]; + } + + return [retval autorelease]; + } + + void setFullState (NSDictionary* state) + { + if (state == nullptr) + return; + + NSObject* obj = [state objectForKey: @JUCE_STATE_DICTIONARY_KEY]; + + if (obj == nullptr || ! [obj isKindOfClass: [NSData class]]) + return; + + auto* data = reinterpret_cast (obj); + const auto numBytes = static_cast ([data length]); + + if (numBytes <= 0) + return; + + auto* rawBytes = reinterpret_cast ([data bytes]); + + ScopedKeyChange scope (au, @"allParameterValues"); + + #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES + getAudioProcessor().setCurrentProgramStateInformation (rawBytes, numBytes); + #else + getAudioProcessor().setStateInformation (rawBytes, numBytes); + #endif + } + + AUParameterTree* getParameterTree() const + { + return paramTree.get(); + } + + NSArray* parametersForOverviewWithCount (int count) const + { + auto* retval = [[[NSMutableArray alloc] init] autorelease]; + + for (const auto& address : addressForIndex) + { + if (static_cast (count) <= [retval count]) + break; + + [retval addObject: [NSNumber numberWithUnsignedLongLong: address]]; + } + + return retval; + } + + //============================================================================== + NSTimeInterval getLatency() const + { + auto& p = getAudioProcessor(); + return p.getLatencySamples() / p.getSampleRate(); + } + + NSTimeInterval getTailTime() const + { + return getAudioProcessor().getTailLengthSeconds(); + } + + //============================================================================== + AUAudioUnitBusArray* getInputBusses() const { return inputBusses.get(); } + AUAudioUnitBusArray* getOutputBusses() const { return outputBusses.get(); } + NSArray* getChannelCapabilities() const { return channelCapabilities.get(); } + + bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* auBus) + { + const bool isInput = ([auBus busType] == AUAudioUnitBusTypeInput); + const int busIdx = static_cast ([auBus index]); + const int newNumChannels = static_cast ([format channelCount]); + + AudioProcessor& processor = getAudioProcessor(); + + if ([[maybe_unused]] AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx)) + { + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + if (! AudioUnitHelpers::isLayoutSupported (processor, isInput, busIdx, newNumChannels, configs)) + return false; + #else + const AVAudioChannelLayout* layout = [format channelLayout]; + const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0); + + if (layoutTag != 0) + { + AudioChannelSet newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag); + + if (newLayout.size() != newNumChannels) + return false; + + if (! bus->isLayoutSupported (newLayout)) + return false; + } + else + { + if (! bus->isNumberOfChannelsSupported (newNumChannels)) + return false; + } + #endif + + return true; + } + + return false; + } + + //============================================================================== + int getVirtualMIDICableCount() const + { + #if JucePlugin_WantsMidiInput + return 1; + #else + return 0; + #endif + } + + bool getSupportsMPE() const + { + return getAudioProcessor().supportsMPE(); + } + + NSArray* getMIDIOutputNames() const + { + #if JucePlugin_ProducesMidiOutput + return @[@"MIDI Out"]; + #else + return @[]; + #endif + } + + //============================================================================== + AUInternalRenderBlock getInternalRenderBlock() const { return internalRenderBlock; } + bool getRenderingOffline() const { return getAudioProcessor().isNonRealtime(); } + void setRenderingOffline (bool offline) + { + auto& processor = getAudioProcessor(); + auto isCurrentlyNonRealtime = processor.isNonRealtime(); + + if (isCurrentlyNonRealtime != offline) + { + ScopedLock callbackLock (processor.getCallbackLock()); + + processor.setNonRealtime (offline); + processor.prepareToPlay (processor.getSampleRate(), processor.getBlockSize()); + } + } + + bool getShouldBypassEffect() const + { + if (bypassParam != nullptr) + return (bypassParam->getValue() != 0.0f); + + return (ObjCMsgSendSuper (au, @selector (shouldBypassEffect)) == YES); + } + + void setShouldBypassEffect (bool shouldBypass) + { + if (bypassParam != nullptr) + bypassParam->setValue (shouldBypass ? 1.0f : 0.0f); + + ObjCMsgSendSuper (au, @selector (setShouldBypassEffect:), shouldBypass ? YES : NO); + } + + //============================================================================== + NSString* getContextName() const { return juceStringToNS (contextName); } + void setContextName (NSString* str) + { + if (str != nullptr) + { + AudioProcessor::TrackProperties props; + props.name = nsStringToJuce (str); + + getAudioProcessor().updateTrackProperties (props); + } + } + + //============================================================================== + bool allocateRenderResourcesAndReturnError (NSError **outError) + { + AudioProcessor& processor = getAudioProcessor(); + const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; + + if (ObjCMsgSendSuper (au, @selector (allocateRenderResourcesAndReturnError:), outError) == NO) + return false; + + if (outError != nullptr) + *outError = nullptr; + + AudioProcessor::BusesLayout layouts; + for (int dir = 0; dir < 2; ++dir) + { + const bool isInput = (dir == 0); + const int n = AudioUnitHelpers::getBusCountForWrapper (processor, isInput); + Array& channelSets = (isInput ? layouts.inputBuses : layouts.outputBuses); + + AUAudioUnitBusArray* auBuses = (isInput ? [au inputBusses] : [au outputBusses]); + jassert ([auBuses count] == static_cast (n)); + + for (int busIdx = 0; busIdx < n; ++busIdx) + { + if (AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx)) + { + AVAudioFormat* format = [[auBuses objectAtIndexedSubscript:static_cast (busIdx)] format]; + + AudioChannelSet newLayout; + const AVAudioChannelLayout* layout = [format channelLayout]; + const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0); + + if (layoutTag != 0) + newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag); + else + newLayout = bus->supportedLayoutWithChannels (static_cast ([format channelCount])); + + if (newLayout.isDisabled()) + return false; + + channelSets.add (newLayout); + } + } + } + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + + if (! AudioProcessor::containsLayout (layouts, configs)) + { + if (outError != nullptr) + *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr]; + + return false; + } + #endif + + if (! AudioUnitHelpers::setBusesLayout (&getAudioProcessor(), layouts)) + { + if (outError != nullptr) + *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr]; + + return false; + } + + totalInChannels = processor.getTotalNumInputChannels(); + totalOutChannels = processor.getTotalNumOutputChannels(); + + allocateBusBuffer (true); + allocateBusBuffer (false); + + mapper.alloc (processor); + + audioBuffer.prepare (AudioUnitHelpers::getBusesLayout (&processor), static_cast (maxFrames)); + + auto sampleRate = [&] + { + for (auto* buffer : { inputBusses.get(), outputBusses.get() }) + if ([buffer count] > 0) + return [[[buffer objectAtIndexedSubscript: 0] format] sampleRate]; + + return 44100.0; + }(); + + processor.setRateAndBufferSizeDetails (sampleRate, static_cast (maxFrames)); + processor.prepareToPlay (sampleRate, static_cast (maxFrames)); + + midiMessages.ensureSize (2048); + midiMessages.clear(); + + hostMusicalContextCallback = [au musicalContextBlock]; + hostTransportStateCallback = [au transportStateBlock]; + + if (@available (macOS 10.13, iOS 11.0, *)) + midiOutputEventBlock = [au MIDIOutputEventBlock]; + + reset(); + + return true; + } + + void deallocateRenderResources() + { + midiOutputEventBlock = nullptr; + + hostMusicalContextCallback = nullptr; + hostTransportStateCallback = nullptr; + + getAudioProcessor().releaseResources(); + audioBuffer.release(); + + inBusBuffers. clear(); + outBusBuffers.clear(); + + mapper.release(); + + ObjCMsgSendSuper (au, @selector (deallocateRenderResources)); + } + + //============================================================================== + struct ScopedKeyChange + { + ScopedKeyChange (AUAudioUnit* a, NSString* k) + : au (a), key (k) + { + [au willChangeValueForKey: key]; + } + + ~ScopedKeyChange() + { + [au didChangeValueForKey: key]; + } + + AUAudioUnit* au; + NSString* key; + }; + + //============================================================================== + void audioProcessorChanged ([[maybe_unused]] AudioProcessor* processor, const ChangeDetails& details) override + { + if (details.programChanged) + { + { + ScopedKeyChange scope (au, @"allParameterValues"); + addPresets(); + } + + { + ScopedKeyChange scope (au, @"currentPreset"); + } + } + + if (details.latencyChanged) + { + ScopedKeyChange scope (au, @"latency"); + } + + if (details.parameterInfoChanged) + { + ScopedKeyChange scope (au, @"parameterTree"); + auto nodes = createParameterNodes (processor->getParameterTree()); + installNewParameterTree (std::move (nodes.nodeArray)); + } + } + + void sendParameterEvent (int idx, const float* newValue, AUParameterAutomationEventType type) + { + if (inParameterChangedCallback.get()) + { + inParameterChangedCallback = false; + return; + } + + if (auto* juceParam = juceParameters.getParamForIndex (idx)) + { + if (auto* param = [paramTree.get() parameterWithAddress: getAUParameterAddressForIndex (idx)]) + { + const auto value = (newValue != nullptr ? *newValue : juceParam->getValue()) * getMaximumParameterValue (*juceParam); + + if (@available (macOS 10.12, iOS 10.0, *)) + { + [param setValue: value + originator: editorObserverToken.get() + atHostTime: lastTimeStamp.mHostTime + eventType: type]; + } + else if (type == AUParameterAutomationEventTypeValue) + { + [param setValue: value originator: editorObserverToken.get()]; + } + } + } + } + + void audioProcessorParameterChanged (AudioProcessor*, int idx, float newValue) override + { + sendParameterEvent (idx, &newValue, AUParameterAutomationEventTypeValue); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int idx) override + { + sendParameterEvent (idx, nullptr, AUParameterAutomationEventTypeTouch); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int idx) override + { + sendParameterEvent (idx, nullptr, AUParameterAutomationEventTypeRelease); + } + + //============================================================================== + Optional getPosition() const override + { + PositionInfo info; + info.setTimeInSamples ((int64) (lastTimeStamp.mSampleTime + 0.5)); + info.setTimeInSeconds (*info.getTimeInSamples() / getAudioProcessor().getSampleRate()); + + info.setFrameRate ([this] + { + switch (lastTimeStamp.mSMPTETime.mType) + { + case kSMPTETimeType2398: return FrameRate().withBaseRate (24).withPullDown(); + case kSMPTETimeType24: return FrameRate().withBaseRate (24); + case kSMPTETimeType25: return FrameRate().withBaseRate (25); + case kSMPTETimeType30Drop: return FrameRate().withBaseRate (30).withDrop(); + case kSMPTETimeType30: return FrameRate().withBaseRate (30); + case kSMPTETimeType2997: return FrameRate().withBaseRate (30).withPullDown(); + case kSMPTETimeType2997Drop: return FrameRate().withBaseRate (30).withPullDown().withDrop(); + case kSMPTETimeType60: return FrameRate().withBaseRate (60); + case kSMPTETimeType60Drop: return FrameRate().withBaseRate (60).withDrop(); + case kSMPTETimeType5994: return FrameRate().withBaseRate (60).withPullDown(); + case kSMPTETimeType5994Drop: return FrameRate().withBaseRate (60).withPullDown().withDrop(); + case kSMPTETimeType50: return FrameRate().withBaseRate (50); + default: break; + } + + return FrameRate(); + }()); + + double num; + NSInteger den; + NSInteger outDeltaSampleOffsetToNextBeat; + double outCurrentMeasureDownBeat, bpm; + double ppqPosition; + + if (hostMusicalContextCallback != nullptr) + { + AUHostMusicalContextBlock musicalContextCallback = hostMusicalContextCallback; + + if (musicalContextCallback (&bpm, &num, &den, &ppqPosition, &outDeltaSampleOffsetToNextBeat, &outCurrentMeasureDownBeat)) + { + info.setTimeSignature (TimeSignature { (int) num, (int) den }); + info.setPpqPositionOfLastBarStart (outCurrentMeasureDownBeat); + info.setBpm (bpm); + info.setPpqPosition (ppqPosition); + } + } + + double outCurrentSampleInTimeLine = 0, outCycleStartBeat = 0, outCycleEndBeat = 0; + AUHostTransportStateFlags flags; + + if (hostTransportStateCallback != nullptr) + { + AUHostTransportStateBlock transportStateCallback = hostTransportStateCallback; + + if (transportStateCallback (&flags, &outCurrentSampleInTimeLine, &outCycleStartBeat, &outCycleEndBeat)) + { + info.setTimeInSamples ((int64) (outCurrentSampleInTimeLine + 0.5)); + info.setTimeInSeconds (*info.getTimeInSamples() / getAudioProcessor().getSampleRate()); + info.setIsPlaying ((flags & AUHostTransportStateMoving) != 0); + info.setIsLooping ((flags & AUHostTransportStateCycling) != 0); + info.setIsRecording ((flags & AUHostTransportStateRecording) != 0); + info.setLoopPoints (LoopPoints { outCycleStartBeat, outCycleEndBeat }); + } + } + + if ((lastTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0) + info.setHostTimeNs (timeConversions.hostTimeToNanos (lastTimeStamp.mHostTime)); + + return info; + } + + //============================================================================== + static void removeEditor (AudioProcessor& processor) + { + ScopedLock editorLock (processor.getCallbackLock()); + + if (AudioProcessorEditor* editor = processor.getActiveEditor()) + { + processor.editorBeingDeleted (editor); + delete editor; + } + } + + AUAudioUnit* getAudioUnit() const { return au; } + +private: + struct Class : public ObjCClass + { + Class() : ObjCClass ("AUAudioUnit_") + { + addIvar ("cppObject"); + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") + addMethod (@selector (initWithComponentDescription:options:error:juceClass:), [] (id _self, + SEL, + AudioComponentDescription descr, + AudioComponentInstantiationOptions options, + NSError** error, + JuceAudioUnitv3* juceAU) + { + AUAudioUnit* self = _self; + + self = ObjCMsgSendSuper (self, @selector(initWithComponentDescription:options:error:), descr, options, error); + + setThis (self, juceAU); + return self; + }); + + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + addMethod (@selector (initWithComponentDescription:options:error:), [] (id _self, + SEL, + AudioComponentDescription descr, + AudioComponentInstantiationOptions options, + NSError** error) + { + AUAudioUnit* self = _self; + + self = ObjCMsgSendSuper (self, @selector (initWithComponentDescription:options:error:), descr, options, error); + + auto* juceAU = JuceAudioUnitv3::create (self, descr, options, error); + + setThis (self, juceAU); + return self; + }); + + addMethod (@selector (dealloc), [] (id self, SEL) + { + if (! MessageManager::getInstance()->isThisTheMessageThread()) + { + WaitableEvent deletionEvent; + + struct AUDeleter : public CallbackMessage + { + AUDeleter (id selfToDelete, WaitableEvent& event) + : parentSelf (selfToDelete), parentDeletionEvent (event) + { + } + + void messageCallback() override + { + delete _this (parentSelf); + parentDeletionEvent.signal(); + } + + id parentSelf; + WaitableEvent& parentDeletionEvent; + }; + + (new AUDeleter (self, deletionEvent))->post(); + deletionEvent.wait (-1); + } + else + { + delete _this (self); + } + }); + + //============================================================================== + addMethod (@selector (reset), [] (id self, SEL) { return _this (self)->reset(); }); + + //============================================================================== + addMethod (@selector (currentPreset), [] (id self, SEL) { return _this (self)->getCurrentPreset(); }); + addMethod (@selector (setCurrentPreset:), [] (id self, SEL, AUAudioUnitPreset* preset) { return _this (self)->setCurrentPreset (preset); }); + addMethod (@selector (factoryPresets), [] (id self, SEL) { return _this (self)->getFactoryPresets(); }); + addMethod (@selector (fullState), [] (id self, SEL) { return _this (self)->getFullState(); }); + addMethod (@selector (setFullState:), [] (id self, SEL, NSDictionary* state) { return _this (self)->setFullState (state); }); + addMethod (@selector (parameterTree), [] (id self, SEL) { return _this (self)->getParameterTree(); }); + addMethod (@selector (parametersForOverviewWithCount:), [] (id self, SEL, NSInteger count) { return _this (self)->parametersForOverviewWithCount (static_cast (count)); }); + + //============================================================================== + addMethod (@selector (latency), [] (id self, SEL) { return _this (self)->getLatency(); }); + addMethod (@selector (tailTime), [] (id self, SEL) { return _this (self)->getTailTime(); }); + + //============================================================================== + addMethod (@selector (inputBusses), [] (id self, SEL) { return _this (self)->getInputBusses(); }); + addMethod (@selector (outputBusses), [] (id self, SEL) { return _this (self)->getOutputBusses(); }); + addMethod (@selector (channelCapabilities), [] (id self, SEL) { return _this (self)->getChannelCapabilities(); }); + addMethod (@selector (shouldChangeToFormat:forBus:), [] (id self, SEL, AVAudioFormat* format, AUAudioUnitBus* bus) { return _this (self)->shouldChangeToFormat (format, bus) ? YES : NO; }); + + //============================================================================== + addMethod (@selector (virtualMIDICableCount), [] (id self, SEL) { return _this (self)->getVirtualMIDICableCount(); }); + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") + addMethod (@selector (supportsMPE), [] (id self, SEL) { return _this (self)->getSupportsMPE() ? YES : NO; }); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + if (@available (macOS 10.13, iOS 11.0, *)) + addMethod (@selector (MIDIOutputNames), [] (id self, SEL) { return _this (self)->getMIDIOutputNames(); }); + + //============================================================================== + addMethod (@selector (internalRenderBlock), [] (id self, SEL) { return _this (self)->getInternalRenderBlock(); }); + addMethod (@selector (canProcessInPlace), [] (id, SEL) { return NO; }); + addMethod (@selector (isRenderingOffline), [] (id self, SEL) { return _this (self)->getRenderingOffline() ? YES : NO; }); + addMethod (@selector (setRenderingOffline:), [] (id self, SEL, BOOL renderingOffline) { return _this (self)->setRenderingOffline (renderingOffline); }); + addMethod (@selector (shouldBypassEffect), [] (id self, SEL) { return _this (self)->getShouldBypassEffect() ? YES : NO; }); + addMethod (@selector (setShouldBypassEffect:), [] (id self, SEL, BOOL shouldBypass) { return _this (self)->setShouldBypassEffect (shouldBypass); }); + addMethod (@selector (allocateRenderResourcesAndReturnError:), [] (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }); + addMethod (@selector (deallocateRenderResources), [] (id self, SEL) { return _this (self)->deallocateRenderResources(); }); + + //============================================================================== + addMethod (@selector (contextName), [] (id self, SEL) { return _this (self)->getContextName(); }); + addMethod (@selector (setContextName:), [](id self, SEL, NSString* str) { return _this (self)->setContextName (str); }); + + //============================================================================== + if (@available (macOS 10.13, iOS 11.0, *)) + { + addMethod (@selector (supportedViewConfigurations:), [] (id self, SEL, NSArray* configs) + { + auto supportedViewIndices = [[NSMutableIndexSet alloc] init]; + auto n = [configs count]; + + if (auto* editor = _this (self)->getAudioProcessor().createEditorIfNeeded()) + { + // If you hit this assertion then your plug-in's editor is reporting that it doesn't support + // any host MIDI controller configurations! + jassert (editor->supportsHostMIDIControllerPresence (true) || editor->supportsHostMIDIControllerPresence (false)); + + for (auto i = 0u; i < n; ++i) + { + if (auto viewConfiguration = [configs objectAtIndex: i]) + { + if (editor->supportsHostMIDIControllerPresence ([viewConfiguration hostHasController] == YES)) + { + auto* constrainer = editor->getConstrainer(); + auto height = (int) [viewConfiguration height]; + auto width = (int) [viewConfiguration width]; + + const auto maxLimits = std::numeric_limits::max() / 2; + const Rectangle requestedBounds { width, height }; + auto modifiedBounds = requestedBounds; + constrainer->checkBounds (modifiedBounds, editor->getBounds().withZeroOrigin(), { maxLimits, maxLimits }, false, false, false, false); + + if (modifiedBounds == requestedBounds) + [supportedViewIndices addIndex: i]; + } + } + } + } + + return [supportedViewIndices autorelease]; + }); + + addMethod (@selector (selectViewConfiguration:), [] (id self, SEL, AUAudioUnitViewConfiguration* config) + { + _this (self)->processorHolder->viewConfiguration.reset (new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES }); + }); + } + + registerClass(); + } + + //============================================================================== + static JuceAudioUnitv3* _this (id self) { return getIvar (self, "cppObject"); } + static void setThis (id self, JuceAudioUnitv3* cpp) { object_setInstanceVariable (self, "cppObject", cpp); } + }; + + static JuceAudioUnitv3* create (AUAudioUnit* audioUnit, AudioComponentDescription descr, AudioComponentInstantiationOptions options, NSError** error) + { + return new JuceAudioUnitv3 (audioUnit, descr, options, error); + } + + //============================================================================== + static Class& getClass() + { + static Class result; + return result; + } + + //============================================================================== + struct BusBuffer + { + BusBuffer (AUAudioUnitBus* bus, int maxFramesPerBuffer) + : auBus (bus), + maxFrames (maxFramesPerBuffer), + numberOfChannels (static_cast ([[auBus format] channelCount])), + isInterleaved ([[auBus format] isInterleaved]) + { + alloc(); + } + + //============================================================================== + void alloc() + { + const int numBuffers = isInterleaved ? 1 : numberOfChannels; + int bytes = static_cast (sizeof (AudioBufferList)) + + ((numBuffers - 1) * static_cast (sizeof (::AudioBuffer))); + jassert (bytes > 0); + + bufferListStorage.calloc (static_cast (bytes)); + bufferList = reinterpret_cast (bufferListStorage.getData()); + + const int bufferChannels = isInterleaved ? numberOfChannels : 1; + scratchBuffer.setSize (numBuffers, bufferChannels * maxFrames); + } + + void dealloc() + { + bufferList = nullptr; + bufferListStorage.free(); + scratchBuffer.setSize (0, 0); + } + + //============================================================================== + int numChannels() const noexcept { return numberOfChannels; } + bool interleaved() const noexcept { return isInterleaved; } + AudioBufferList* get() const noexcept { return bufferList; } + + //============================================================================== + void prepare (UInt32 nFrames, const AudioBufferList* other = nullptr) noexcept + { + const int numBuffers = isInterleaved ? 1 : numberOfChannels; + const bool isCompatible = isCompatibleWith (other); + + bufferList->mNumberBuffers = static_cast (numBuffers); + + for (int i = 0; i < numBuffers; ++i) + { + const UInt32 bufferChannels = static_cast (isInterleaved ? numberOfChannels : 1); + bufferList->mBuffers[i].mNumberChannels = bufferChannels; + bufferList->mBuffers[i].mData = (isCompatible ? other->mBuffers[i].mData + : scratchBuffer.getWritePointer (i)); + bufferList->mBuffers[i].mDataByteSize = nFrames * bufferChannels * sizeof (float); + } + } + + //============================================================================== + bool isCompatibleWith (const AudioBufferList* other) const noexcept + { + if (other == nullptr) + return false; + + if (other->mNumberBuffers > 0) + { + const bool otherInterleaved = AudioUnitHelpers::isAudioBufferInterleaved (*other); + const int otherChannels = static_cast (otherInterleaved ? other->mBuffers[0].mNumberChannels + : other->mNumberBuffers); + + return otherInterleaved == isInterleaved + && numberOfChannels == otherChannels; + } + + return numberOfChannels == 0; + } + + private: + AUAudioUnitBus* auBus; + HeapBlock bufferListStorage; + AudioBufferList* bufferList = nullptr; + int maxFrames, numberOfChannels; + bool isInterleaved; + juce::AudioBuffer scratchBuffer; + }; + + class FactoryPresets + { + public: + using Presets = std::unique_ptr, NSObjectDeleter>; + + void set (Presets newPresets) + { + std::lock_guard lock (mutex); + std::swap (presets, newPresets); + } + + NSArray* get() const + { + std::lock_guard lock (mutex); + return presets.get(); + } + + AUAudioUnitPreset* getAtIndex (int index) const + { + std::lock_guard lock (mutex); + + if (index < (int) [presets.get() count]) + return [presets.get() objectAtIndex: (unsigned int) index]; + + return nullptr; + } + + private: + Presets presets; + mutable std::mutex mutex; + }; + + //============================================================================== + void addAudioUnitBusses (bool isInput) + { + std::unique_ptr, NSObjectDeleter> array ([[NSMutableArray alloc] init]); + AudioProcessor& processor = getAudioProcessor(); + const auto numWrapperBuses = AudioUnitHelpers::getBusCountForWrapper (processor, isInput); + const auto numProcessorBuses = AudioUnitHelpers::getBusCount (processor, isInput); + + for (int i = 0; i < numWrapperBuses; ++i) + { + using AVAudioFormatPtr = std::unique_ptr; + + const auto audioFormat = [&]() -> AVAudioFormatPtr + { + const auto tag = i < numProcessorBuses ? CoreAudioLayouts::toCoreAudio (processor.getChannelLayoutOfBus (isInput, i)) + : kAudioChannelLayoutTag_Stereo; + const std::unique_ptr layout { [[AVAudioChannelLayout alloc] initWithLayoutTag: tag] }; + + if (auto format = AVAudioFormatPtr { [[AVAudioFormat alloc] initStandardFormatWithSampleRate: kDefaultSampleRate + channelLayout: layout.get()] }) + return format; + + const auto channels = i < numProcessorBuses ? processor.getChannelCountOfBus (isInput, i) + : 2; + + // According to the docs, this will fail if the number of channels is greater than 2. + if (auto format = AVAudioFormatPtr { [[AVAudioFormat alloc] initStandardFormatWithSampleRate: kDefaultSampleRate + channels: static_cast (channels)] }) + return format; + + jassertfalse; + return nullptr; + }(); + + using AUAudioUnitBusPtr = std::unique_ptr; + + const auto audioUnitBus = [&]() -> AUAudioUnitBusPtr + { + if (audioFormat != nullptr) + return AUAudioUnitBusPtr { [[AUAudioUnitBus alloc] initWithFormat: audioFormat.get() error: nullptr] }; + + jassertfalse; + return nullptr; + }(); + + if (audioUnitBus != nullptr) + [array.get() addObject: audioUnitBus.get()]; + } + + (isInput ? inputBusses : outputBusses).reset ([[AUAudioUnitBusArray alloc] initWithAudioUnit: au + busType: (isInput ? AUAudioUnitBusTypeInput : AUAudioUnitBusTypeOutput) + busses: array.get()]); + } + + // When parameters are discrete we need to use integer values. + static float getMaximumParameterValue ([[maybe_unused]] const AudioProcessorParameter& juceParam) + { + #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + return 1.0f; + #else + return juceParam.isDiscrete() ? (float) (juceParam.getNumSteps() - 1) : 1.0f; + #endif + } + + static auto createParameter (const AudioProcessorParameter& parameter) + { + const String name (parameter.getName (512)); + + AudioUnitParameterUnit unit = kAudioUnitParameterUnit_Generic; + AudioUnitParameterOptions flags = (UInt32) (kAudioUnitParameterFlag_IsWritable + | kAudioUnitParameterFlag_IsReadable + | kAudioUnitParameterFlag_HasCFNameString + | kAudioUnitParameterFlag_ValuesHaveStrings); + + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution; + #endif + + // Set whether the param is automatable (unnamed parameters aren't allowed to be automated). + if (name.isEmpty() || ! parameter.isAutomatable()) + flags |= kAudioUnitParameterFlag_NonRealTime; + + const bool isParameterDiscrete = parameter.isDiscrete(); + + if (! isParameterDiscrete) + flags |= kAudioUnitParameterFlag_CanRamp; + + if (parameter.isMetaParameter()) + flags |= kAudioUnitParameterFlag_IsGlobalMeta; + + std::unique_ptr valueStrings; + + // Is this a meter? + if (((parameter.getCategory() & 0xffff0000) >> 16) == 2) + { + flags &= ~kAudioUnitParameterFlag_IsWritable; + flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic; + unit = kAudioUnitParameterUnit_LinearGain; + } + else + { + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + if (parameter.isDiscrete()) + { + unit = parameter.isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed; + auto maxValue = getMaximumParameterValue (parameter); + auto numSteps = parameter.getNumSteps(); + + // Some hosts can't handle the huge numbers of discrete parameter values created when + // using the default number of steps. + jassert (numSteps != AudioProcessor::getDefaultNumParameterSteps()); + + valueStrings.reset ([NSMutableArray new]); + + for (int i = 0; i < numSteps; ++i) + [valueStrings.get() addObject: juceStringToNS (parameter.getText ((float) i / maxValue, 0))]; + } + #endif + } + + const auto address = generateAUParameterAddress (parameter); + + auto getParameterIdentifier = [¶meter] + { + if (const auto* paramWithID = dynamic_cast (¶meter)) + return paramWithID->getParameterID(); + + // This could clash if any groups have been given integer IDs! + return String (parameter.getParameterIndex()); + }; + + std::unique_ptr param; + + @try + { + // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h + param.reset([[AUParameterTree createParameterWithIdentifier: juceStringToNS (getParameterIdentifier()) + name: juceStringToNS (name) + address: address + min: 0.0f + max: getMaximumParameterValue (parameter) + unit: unit + unitName: nullptr + flags: flags + valueStrings: valueStrings.get() + dependentParameters: nullptr] + retain]); + } + + @catch (NSException* exception) + { + // Do you have duplicate identifiers in any of your groups or parameters, + // or do your identifiers have unusual characters in them? + jassertfalse; + } + + [param.get() setValue: parameter.getDefaultValue()]; + return param; + } + + struct NodeArrayResult + { + std::unique_ptr, NSObjectDeleter> nodeArray { [NSMutableArray new] }; + + void addParameter (const AudioProcessorParameter&, std::unique_ptr auParam) + { + [nodeArray.get() addObject: [auParam.get() retain]]; + } + + void addGroup (const AudioProcessorParameterGroup& group, const NodeArrayResult& r) + { + @try + { + // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h + [nodeArray.get() addObject: [[AUParameterTree createGroupWithIdentifier: juceStringToNS (group.getID()) + name: juceStringToNS (group.getName()) + children: r.nodeArray.get()] retain]]; + } + @catch (NSException* exception) + { + // Do you have duplicate identifiers in any of your groups or parameters, + // or do your identifiers have unusual characters in them? + jassertfalse; + } + } + }; + + struct AddressedNodeArrayResult + { + NodeArrayResult nodeArray; + std::map addressForIndex; + + void addParameter (const AudioProcessorParameter& juceParam, std::unique_ptr auParam) + { + const auto index = juceParam.getParameterIndex(); + const auto address = [auParam.get() address]; + + if (const auto iter = addressForIndex.find (index); iter == addressForIndex.cend()) + addressForIndex.emplace (index, address); + else + jassertfalse; // If you hit this assertion then you have put a parameter in two groups. + + nodeArray.addParameter (juceParam, std::move (auParam)); + } + + void addGroup (const AudioProcessorParameterGroup& group, const AddressedNodeArrayResult& r) + { + nodeArray.addGroup (group, r.nodeArray); + + [[maybe_unused]] const auto initialSize = addressForIndex.size(); + addressForIndex.insert (r.addressForIndex.begin(), r.addressForIndex.end()); + [[maybe_unused]] const auto finalSize = addressForIndex.size(); + + // If this is hit, the same parameter index exists in multiple groups. + jassert (finalSize == initialSize + r.addressForIndex.size()); + } + }; + + template + static Result createParameterNodes (const AudioProcessorParameterGroup& group) + { + Result result; + + for (auto* node : group) + { + if (auto* childGroup = node->getGroup()) + { + result.addGroup (*childGroup, createParameterNodes (*childGroup)); + } + else if (auto* juceParam = node->getParameter()) + { + result.addParameter (*juceParam, createParameter (*juceParam)); + } + else + { + // No group or parameter at this node! + jassertfalse; + } + } + + return result; + } + + void addParameters() + { + auto& processor = getAudioProcessor(); + juceParameters.update (processor, forceLegacyParamIDs); + + if ((bypassParam = processor.getBypassParameter()) != nullptr) + bypassParam->addListener (this); + + auto nodes = createParameterNodes (processor.getParameterTree()); + installNewParameterTree (std::move (nodes.nodeArray.nodeArray)); + + // When we first create the parameter tree, we also create structures to allow lookup by index/address. + // These structures are not rebuilt, i.e. we assume that the parameter addresses and indices are stable. + // These structures aren't modified after creation, so there should be no need to synchronize access to them. + + addressForIndex = [&] + { + std::vector addresses (static_cast (processor.getParameters().size())); + + for (size_t i = 0; i < addresses.size(); ++i) + { + if (const auto iter = nodes.addressForIndex.find (static_cast (i)); iter != nodes.addressForIndex.cend()) + addresses[i] = iter->second; + else + jassertfalse; // Somehow, there's a parameter missing... + } + + return addresses; + }(); + + #if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS + indexForAddress = [&] + { + std::map indices; + + for (const auto& [index, address] : nodes.addressForIndex) + { + if (const auto iter = indices.find (address); iter == indices.cend()) + indices.emplace (address, index); + else + jassertfalse; // The parameter at index 'iter->first' has the same address as the parameter at index 'index' + } + + return indices; + }(); + #endif + } + + void installNewParameterTree (std::unique_ptr, NSObjectDeleter> topLevelNodes) + { + editorObserverToken.reset(); + + @try + { + // Create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h + paramTree.reset ([[AUParameterTree createTreeWithChildren: topLevelNodes.get()] retain]); + } + @catch (NSException* exception) + { + // Do you have duplicate identifiers in any of your groups or parameters, + // or do your identifiers have unusual characters in them? + jassertfalse; + } + + [paramTree.get() setImplementorValueObserver: ^(AUParameter* param, AUValue value) { this->valueChangedFromHost (param, value); }]; + [paramTree.get() setImplementorValueProvider: ^(AUParameter* param) { return this->getValue (param); }]; + [paramTree.get() setImplementorStringFromValueCallback: ^(AUParameter* param, const AUValue* value) { return this->stringFromValue (param, value); }]; + [paramTree.get() setImplementorValueFromStringCallback: ^(AUParameter* param, NSString* str) { return this->valueFromString (param, str); }]; + + if (getAudioProcessor().hasEditor()) + { + editorObserverToken = ObserverPtr ([paramTree.get() tokenByAddingParameterObserver: ^(AUParameterAddress, AUValue) + { + // this will have already been handled by valueChangedFromHost + }], + ObserverDestructor { paramTree.get() }); + } + } + + void setAudioProcessorParameter (AudioProcessorParameter* juceParam, float value) + { + if (! approximatelyEqual (value, juceParam->getValue())) + { + juceParam->setValue (value); + + inParameterChangedCallback = true; + juceParam->sendValueChangedMessageToListeners (value); + } + } + + void addPresets() + { + FactoryPresets::Presets newPresets { [[NSMutableArray alloc] init] }; + + const int n = getAudioProcessor().getNumPrograms(); + + for (int idx = 0; idx < n; ++idx) + { + String name = getAudioProcessor().getProgramName (idx); + + std::unique_ptr preset ([[AUAudioUnitPreset alloc] init]); + [preset.get() setName: juceStringToNS (name)]; + [preset.get() setNumber: static_cast (idx)]; + + [newPresets.get() addObject: preset.get()]; + } + + factoryPresets.set (std::move (newPresets)); + } + + //============================================================================== + void allocateBusBuffer (bool isInput) + { + OwnedArray& busBuffers = isInput ? inBusBuffers : outBusBuffers; + busBuffers.clear(); + + const int n = AudioUnitHelpers::getBusCountForWrapper (getAudioProcessor(), isInput); + const AUAudioFrameCount maxFrames = [au maximumFramesToRender]; + + for (int busIdx = 0; busIdx < n; ++busIdx) + busBuffers.add (new BusBuffer ([(isInput ? inputBusses.get() : outputBusses.get()) objectAtIndexedSubscript: static_cast (busIdx)], + static_cast (maxFrames))); + } + + //============================================================================== + void processEvents (const AURenderEvent *__nullable realtimeEventListHead, [[maybe_unused]] int numParams, AUEventSampleTime startTime) + { + for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; event = event->head.next) + { + switch (event->head.eventType) + { + case AURenderEventMIDI: + { + const AUMIDIEvent& midiEvent = event->MIDI; + midiMessages.addEvent (midiEvent.data, midiEvent.length, static_cast (midiEvent.eventSampleTime - startTime)); + } + break; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + case AURenderEventMIDIEventList: + { + const auto& list = event->MIDIEventsList.eventList; + auto* packet = &list.packet[0]; + + for (uint32_t i = 0; i < list.numPackets; ++i) + { + converter.dispatch (reinterpret_cast (packet->words), + reinterpret_cast (packet->words + packet->wordCount), + static_cast (packet->timeStamp - (MIDITimeStamp) startTime), + [this] (const ump::BytestreamMidiView& message) + { + midiMessages.addEvent (message.getMessage(), (int) message.timestamp); + }); + + packet = MIDIEventPacketNext (packet); + } + } + break; + #endif + + case AURenderEventParameter: + case AURenderEventParameterRamp: + { + const AUParameterEvent& paramEvent = event->parameter; + + if (auto* p = getJuceParameterForAUAddress (paramEvent.parameterAddress)) + { + auto normalisedValue = paramEvent.value / getMaximumParameterValue (*p); + setAudioProcessorParameter (p, normalisedValue); + } + } + break; + + case AURenderEventMIDISysEx: + default: + break; + } + } + } + + AUAudioUnitStatus renderCallback (AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp, AUAudioFrameCount frameCount, + NSInteger outputBusNumber, AudioBufferList* outputData, const AURenderEvent *__nullable realtimeEventListHead, + AURenderPullInputBlock __nullable pullInputBlock) + { + auto& processor = getAudioProcessor(); + jassert (static_cast (frameCount) <= getAudioProcessor().getBlockSize()); + + const auto numProcessorBusesOut = AudioUnitHelpers::getBusCount (processor, false); + + if (! approximatelyEqual (lastTimeStamp.mSampleTime, timestamp->mSampleTime)) + { + // process params and incoming midi (only once for a given timestamp) + midiMessages.clear(); + + const int numParams = juceParameters.getNumParameters(); + processEvents (realtimeEventListHead, numParams, static_cast (timestamp->mSampleTime)); + + lastTimeStamp = *timestamp; + + const auto numWrapperBusesIn = AudioUnitHelpers::getBusCountForWrapper (processor, true); + const auto numWrapperBusesOut = AudioUnitHelpers::getBusCountForWrapper (processor, false); + const auto numProcessorBusesIn = AudioUnitHelpers::getBusCount (processor, true); + + // prepare buffers + { + for (int busIdx = 0; busIdx < numWrapperBusesOut; ++busIdx) + { + BusBuffer& busBuffer = *outBusBuffers[busIdx]; + const bool canUseDirectOutput = + (busIdx == outputBusNumber && outputData != nullptr && outputData->mNumberBuffers > 0); + + busBuffer.prepare (frameCount, canUseDirectOutput ? outputData : nullptr); + + if (numProcessorBusesOut <= busIdx) + AudioUnitHelpers::clearAudioBuffer (*busBuffer.get()); + } + + for (int busIdx = 0; busIdx < numWrapperBusesIn; ++busIdx) + { + BusBuffer& busBuffer = *inBusBuffers[busIdx]; + busBuffer.prepare (frameCount, busIdx < numWrapperBusesOut ? outBusBuffers[busIdx]->get() : nullptr); + } + + audioBuffer.reset(); + } + + // pull inputs + { + for (int busIdx = 0; busIdx < numProcessorBusesIn; ++busIdx) + { + BusBuffer& busBuffer = *inBusBuffers[busIdx]; + AudioBufferList* buffer = busBuffer.get(); + + if (pullInputBlock == nullptr || pullInputBlock (actionFlags, timestamp, frameCount, busIdx, buffer) != noErr) + AudioUnitHelpers::clearAudioBuffer (*buffer); + + if (actionFlags != nullptr && (*actionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0) + AudioUnitHelpers::clearAudioBuffer (*buffer); + } + } + + // set buffer pointer to minimize copying + { + int chIdx = 0; + + for (int busIdx = 0; busIdx < numProcessorBusesOut; ++busIdx) + { + BusBuffer& busBuffer = *outBusBuffers[busIdx]; + AudioBufferList* buffer = busBuffer.get(); + + const bool interleaved = busBuffer.interleaved(); + const int numChannels = busBuffer.numChannels(); + + const int* outLayoutMap = mapper.get (false, busIdx); + + for (int ch = 0; ch < numChannels; ++ch) + audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast (buffer->mBuffers[outLayoutMap[ch]].mData)); + } + + // use input pointers on remaining channels + + for (int busIdx = 0; chIdx < totalInChannels;) + { + const int channelOffset = processor.getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx); + + BusBuffer& busBuffer = *inBusBuffers[busIdx]; + AudioBufferList* buffer = busBuffer.get(); + + const int* inLayoutMap = mapper.get (true, busIdx); + audioBuffer.setBuffer (chIdx++, busBuffer.interleaved() ? nullptr : static_cast (buffer->mBuffers[inLayoutMap[channelOffset]].mData)); + } + } + + // copy input + { + for (int busIdx = 0; busIdx < numProcessorBusesIn; ++busIdx) + audioBuffer.set (busIdx, *inBusBuffers[busIdx]->get(), mapper.get (true, busIdx)); + + audioBuffer.clearUnusedChannels ((int) frameCount); + } + + // process audio + processBlock (audioBuffer.getBuffer (frameCount), midiMessages); + + // send MIDI + #if JucePlugin_ProducesMidiOutput + if (@available (macOS 10.13, iOS 11.0, *)) + { + if (auto midiOut = midiOutputEventBlock) + for (const auto metadata : midiMessages) + if (isPositiveAndBelow (metadata.samplePosition, frameCount)) + midiOut ((int64_t) metadata.samplePosition + (int64_t) (timestamp->mSampleTime + 0.5), + 0, + metadata.numBytes, + metadata.data); + } + #endif + } + + // copy back + if (outputBusNumber < numProcessorBusesOut && outputData != nullptr) + audioBuffer.get ((int) outputBusNumber, *outputData, mapper.get (false, (int) outputBusNumber)); + + return noErr; + } + + void processBlock (juce::AudioBuffer& buffer, MidiBuffer& midiBuffer) noexcept + { + auto& processor = getAudioProcessor(); + const ScopedLock sl (processor.getCallbackLock()); + + if (processor.isSuspended()) + buffer.clear(); + else if (bypassParam == nullptr && [au shouldBypassEffect]) + processor.processBlockBypassed (buffer, midiBuffer); + else + processor.processBlock (buffer, midiBuffer); + } + + //============================================================================== + void valueChangedFromHost (AUParameter* param, AUValue value) + { + if (param != nullptr) + { + if (auto* p = getJuceParameterForAUAddress ([param address])) + { + auto normalisedValue = value / getMaximumParameterValue (*p); + setAudioProcessorParameter (p, normalisedValue); + } + } + } + + AUValue getValue (AUParameter* param) const + { + if (param != nullptr) + { + if (auto* p = getJuceParameterForAUAddress ([param address])) + return p->getValue() * getMaximumParameterValue (*p); + } + + return 0; + } + + NSString* stringFromValue (AUParameter* param, const AUValue* value) + { + String text; + + if (param != nullptr && value != nullptr) + { + if (auto* p = getJuceParameterForAUAddress ([param address])) + { + if (LegacyAudioParameter::isLegacy (p)) + text = String (*value); + else + text = p->getText (*value / getMaximumParameterValue (*p), 0); + } + } + + return juceStringToNS (text); + } + + AUValue valueFromString (AUParameter* param, NSString* str) + { + if (param != nullptr && str != nullptr) + { + if (auto* p = getJuceParameterForAUAddress ([param address])) + { + const String text (nsStringToJuce (str)); + + if (LegacyAudioParameter::isLegacy (p)) + return text.getFloatValue(); + + return p->getValueForText (text) * getMaximumParameterValue (*p); + } + } + + return 0; + } + + //============================================================================== + // this is only ever called for the bypass parameter + void parameterValueChanged (int, float newValue) override + { + JuceAudioUnitv3::setShouldBypassEffect (newValue != 0.0f); + } + + void parameterGestureChanged (int, bool) override {} + + //============================================================================== + inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept + { + if (isPositiveAndBelow (paramIndex, addressForIndex.size())) + return addressForIndex[static_cast (paramIndex)]; + + return {}; + } + + inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept + { + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + return static_cast (address); + #else + if (const auto iter = indexForAddress.find (address); iter != indexForAddress.cend()) + return iter->second; + + return {}; + #endif + } + + static AUParameterAddress generateAUParameterAddress (const AudioProcessorParameter& param) + { + const String& juceParamID = LegacyAudioParameter::getParamID (¶m, forceLegacyParamIDs); + + return static_cast (forceLegacyParamIDs ? juceParamID.getIntValue() + : juceParamID.hashCode64()); + } + + AudioProcessorParameter* getJuceParameterForAUAddress (AUParameterAddress address) const noexcept + { + return juceParameters.getParamForIndex (getJuceParameterIndexForAUAddress (address)); + } + + //============================================================================== + static constexpr double kDefaultSampleRate = 44100.0; + + struct ObserverDestructor + { + void operator() (AUParameterObserverToken ptr) const + { + if (ptr != nullptr) + [tree removeParameterObserver: ptr]; + } + + AUParameterTree* tree; + }; + + using ObserverPtr = std::unique_ptr, ObserverDestructor>; + + AUAudioUnit* au; + AudioProcessorHolder::Ptr processorHolder; + + int totalInChannels, totalOutChannels; + + CoreAudioTimeConversions timeConversions; + std::unique_ptr inputBusses, outputBusses; + + #if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS + std::map indexForAddress; + #endif + std::vector addressForIndex; + LegacyAudioParametersWrapper juceParameters; + + // to avoid recursion on parameter changes, we need to add an + // editor observer to do the parameter changes + std::unique_ptr paramTree; + ObserverPtr editorObserverToken; + + std::unique_ptr, NSObjectDeleter> channelCapabilities; + + FactoryPresets factoryPresets; + + ObjCBlock internalRenderBlock; + + AudioUnitHelpers::CoreAudioBufferList audioBuffer; + AudioUnitHelpers::ChannelRemapper mapper; + + OwnedArray inBusBuffers, outBusBuffers; + MidiBuffer midiMessages; + AUMIDIOutputEventBlock midiOutputEventBlock = nullptr; + + #if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + ump::ToBytestreamDispatcher converter { 2048 }; + #endif + + ObjCBlock hostMusicalContextCallback; + ObjCBlock hostTransportStateCallback; + + AudioTimeStamp lastTimeStamp; + + String contextName; + + ThreadLocalValue inParameterChangedCallback; + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + static constexpr bool forceLegacyParamIDs = true; + #else + static constexpr bool forceLegacyParamIDs = false; + #endif + AudioProcessorParameter* bypassParam = nullptr; +}; + +#if JUCE_IOS +namespace juce +{ +struct UIViewPeerControllerReceiver +{ + virtual ~UIViewPeerControllerReceiver(); + virtual void setViewController (UIViewController*) = 0; +}; +} +#endif + +//============================================================================== +class JuceAUViewController +{ +public: + JuceAUViewController (AUViewController* p) + : myself (p) + { + initialiseJuce_GUI(); + } + + ~JuceAUViewController() + { + JUCE_ASSERT_MESSAGE_THREAD + + if (processorHolder.get() != nullptr) + JuceAudioUnitv3::removeEditor (getAudioProcessor()); + } + + //============================================================================== + void loadView() + { + JUCE_ASSERT_MESSAGE_THREAD + + if (auto p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3)) + { + processorHolder = new AudioProcessorHolder (std::move (p)); + auto& processor = getAudioProcessor(); + + if (processor.hasEditor()) + { + if (AudioProcessorEditor* editor = processor.createEditorIfNeeded()) + { + preferredSize = editor->getBounds(); + + JUCE_IOS_MAC_VIEW* view = [[[JUCE_IOS_MAC_VIEW alloc] initWithFrame: convertToCGRect (editor->getBounds())] autorelease]; + [myself setView: view]; + + #if JUCE_IOS + editor->setVisible (false); + #else + editor->setVisible (true); + #endif + + detail::PluginUtilities::addToDesktop (*editor, view); + + #if JUCE_IOS + if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0]) + [peerView setContentMode: UIViewContentModeTop]; + + if (auto* peer = dynamic_cast (editor->getPeer())) + peer->setViewController (myself); + #endif + } + } + } + } + + void viewDidLayoutSubviews() + { + if (auto holder = processorHolder.get()) + { + if ([myself view] != nullptr) + { + if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) + { + if (holder->viewConfiguration != nullptr) + editor->hostMIDIControllerIsAvailable (holder->viewConfiguration->hostHasMIDIController); + + editor->setBounds (convertToRectInt ([[myself view] bounds])); + + if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0]) + { + #if JUCE_IOS + [peerView setNeedsDisplay]; + #else + [peerView setNeedsDisplay: YES]; + #endif + } + } + } + } + } + + void didReceiveMemoryWarning() + { + if (auto ptr = processorHolder.get()) + if (auto* processor = ptr->get()) + processor->memoryWarningReceived(); + } + + void viewDidAppear (bool) + { + if (processorHolder.get() != nullptr) + if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) + editor->setVisible (true); + } + + void viewDidDisappear (bool) + { + if (processorHolder.get() != nullptr) + if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) + editor->setVisible (false); + } + + CGSize getPreferredContentSize() const + { + return CGSizeMake (static_cast (preferredSize.getWidth()), + static_cast (preferredSize.getHeight())); + } + + //============================================================================== + AUAudioUnit* createAudioUnit (const AudioComponentDescription& descr, NSError** error) + { + const auto holder = [&] + { + if (auto initialisedHolder = processorHolder.get()) + return initialisedHolder; + + waitForExecutionOnMainThread ([this] { [myself view]; }); + return processorHolder.get(); + }(); + + if (holder == nullptr) + return nullptr; + + return [(new JuceAudioUnitv3 (holder, descr, 0, error))->getAudioUnit() autorelease]; + } + +private: + template + static void waitForExecutionOnMainThread (Callback&& callback) + { + if (MessageManager::getInstance()->isThisTheMessageThread()) + { + callback(); + return; + } + + std::promise promise; + + MessageManager::callAsync ([&] + { + callback(); + promise.set_value(); + }); + + promise.get_future().get(); + } + + // There's a chance that createAudioUnit will be called from a background + // thread while the processorHolder is being updated on the main thread. + class LockedProcessorHolder + { + public: + AudioProcessorHolder::Ptr get() const + { + const ScopedLock lock (mutex); + return holder; + } + + LockedProcessorHolder& operator= (const AudioProcessorHolder::Ptr& other) + { + const ScopedLock lock (mutex); + holder = other; + return *this; + } + + private: + mutable CriticalSection mutex; + AudioProcessorHolder::Ptr holder; + }; + + //============================================================================== + AUViewController* myself; + LockedProcessorHolder processorHolder; + Rectangle preferredSize { 1, 1 }; + + //============================================================================== + AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder.get(); } +}; + +//============================================================================== +// necessary glue code +@interface JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix) : AUViewController +@end + +@implementation JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix) +{ + std::unique_ptr cpp; +} + +- (instancetype) initWithNibName: (nullable NSString*) nib bundle: (nullable NSBundle*) bndl { self = [super initWithNibName: nib bundle: bndl]; cpp.reset (new JuceAUViewController (self)); return self; } +- (void) loadView { cpp->loadView(); } +- (AUAudioUnit *) createAudioUnitWithComponentDescription: (AudioComponentDescription) desc error: (NSError **) error { return cpp->createAudioUnit (desc, error); } +- (CGSize) preferredContentSize { return cpp->getPreferredContentSize(); } + +// NSViewController and UIViewController have slightly different names for this function +- (void) viewDidLayoutSubviews { cpp->viewDidLayoutSubviews(); } +- (void) viewDidLayout { cpp->viewDidLayoutSubviews(); } + +- (void) didReceiveMemoryWarning { cpp->didReceiveMemoryWarning(); } +#if JUCE_IOS +- (void) viewDidAppear: (BOOL) animated { cpp->viewDidAppear (animated); [super viewDidAppear:animated]; } +- (void) viewDidDisappear: (BOOL) animated { cpp->viewDidDisappear (animated); [super viewDidDisappear:animated]; } +#endif +@end + +//============================================================================== +#if JUCE_IOS +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + +bool JUCE_CALLTYPE juce_isInterAppAudioConnected() { return false; } +void JUCE_CALLTYPE juce_switchToHostApplication() {} +Image JUCE_CALLTYPE juce_getIAAHostIcon (int) { return {}; } + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp index 717bb795d928..9bc4b0be1aa2 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_LV2.cpp @@ -23,4 +23,1793 @@ ============================================================================== */ -#include "LV2/juce_LV2_Client.cpp" +#if JucePlugin_Build_LV2 + +#ifndef _SCL_SECURE_NO_WARNINGS + #define _SCL_SECURE_NO_WARNINGS +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS +#endif + +#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 +#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 +#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 + +#include +#include +#include +#include + +#include +#include + +#include "JuceLV2Defines.h" +#include + +#include + +#define JUCE_TURTLE_RECALL_URI "https://lv2-extensions.juce.com/turtle_recall" + +#ifndef JucePlugin_LV2URI + #error "You need to define the JucePlugin_LV2URI value! If you're using the Projucer/CMake, the definition will be written into JuceLV2Defines.h automatically." +#endif + +namespace juce +{ +namespace lv2_client +{ + +constexpr auto uriSeparator = ":"; +const auto JucePluginLV2UriUi = String (JucePlugin_LV2URI) + uriSeparator + "UI"; +const auto JucePluginLV2UriState = String (JucePlugin_LV2URI) + uriSeparator + "StateString"; +const auto JucePluginLV2UriProgram = String (JucePlugin_LV2URI) + uriSeparator + "Program"; + +static const LV2_Feature* findMatchingFeature (const LV2_Feature* const* features, const char* uri) +{ + for (auto feature = features; *feature != nullptr; ++feature) + if (std::strcmp ((*feature)->URI, uri) == 0) + return *feature; + + return nullptr; +} + +static bool hasFeature (const LV2_Feature* const* features, const char* uri) +{ + return findMatchingFeature (features, uri) != nullptr; +} + +template +Data findMatchingFeatureData (const LV2_Feature* const* features, const char* uri) +{ + if (const auto* feature = findMatchingFeature (features, uri)) + return static_cast (feature->data); + + return {}; +} + +static const LV2_Options_Option* findMatchingOption (const LV2_Options_Option* options, LV2_URID urid) +{ + for (auto option = options; option->value != nullptr; ++option) + if (option->key == urid) + return option; + + return nullptr; +} + +class ParameterStorage : private AudioProcessorListener +{ +public: + ParameterStorage (AudioProcessor& proc, LV2_URID_Map map) + : processor (proc), + mapFeature (map), + legacyParameters (proc, false) + { + processor.addListener (this); + } + + ~ParameterStorage() override + { + processor.removeListener (this); + } + + /* This is the string that will be used to uniquely identify the parameter. + + This string will be written into the plugin's manifest as an IRI, so it must be + syntactically valid. + + We escape this string rather than writing the user-defined parameter ID directly to avoid + writing a malformed manifest in the case that user IDs contain spaces or other reserved + characters. This should allow users to keep the same param IDs for all plugin formats. + */ + static String getIri (const AudioProcessorParameter& param) + { + const auto urlSanitised = URL::addEscapeChars (LegacyAudioParameter::getParamID (¶m, false), true); + const auto ttlSanitised = lv2_shared::sanitiseStringAsTtlName (urlSanitised); + + // If this is hit, the parameter ID could not be represented directly in the plugin ttl. + // We'll replace offending characters with '_'. + jassert (urlSanitised == ttlSanitised); + + return ttlSanitised; + } + + void setValueFromHost (LV2_URID urid, float value) noexcept + { + const auto it = uridToIndexMap.find (urid); + + if (it == uridToIndexMap.end()) + { + // No such parameter. + jassertfalse; + return; + } + + if (auto* param = legacyParameters.getParamForIndex ((int) it->second)) + { + const auto scaledValue = [&] + { + if (auto* rangedParam = dynamic_cast (param)) + return rangedParam->convertTo0to1 (value); + + return value; + }(); + + if (! approximatelyEqual (scaledValue, param->getValue())) + { + ScopedValueSetter scope (ignoreCallbacks, true); + param->setValueNotifyingHost (scaledValue); + } + } + } + + struct Options + { + bool parameterValue, gestureBegin, gestureEnd; + }; + + static constexpr auto newClientValue = 1 << 0, + gestureBegan = 1 << 1, + gestureEnded = 1 << 2; + + template + void forEachChangedParameter (Callback&& callback) + { + stateCache.ifSet ([this, &callback] (size_t parameterIndex, float, uint32_t bits) + { + const Options options { (bits & newClientValue) != 0, + (bits & gestureBegan) != 0, + (bits & gestureEnded) != 0 }; + + callback (*legacyParameters.getParamForIndex ((int) parameterIndex), + indexToUridMap[parameterIndex], + options); + }); + } + +private: + void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float value) override + { + if (! ignoreCallbacks) + stateCache.setValueAndBits ((size_t) parameterIndex, value, newClientValue); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int parameterIndex) override + { + if (! ignoreCallbacks) + stateCache.setBits ((size_t) parameterIndex, gestureBegan); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int parameterIndex) override + { + if (! ignoreCallbacks) + stateCache.setBits ((size_t) parameterIndex, gestureEnded); + } + + void audioProcessorChanged (AudioProcessor*, const ChangeDetails&) override {} + + AudioProcessor& processor; + const LV2_URID_Map mapFeature; + const LegacyAudioParametersWrapper legacyParameters; + const std::vector indexToUridMap = [&] + { + std::vector result; + + for (auto* param : legacyParameters) + { + jassert ((size_t) param->getParameterIndex() == result.size()); + + const auto uri = JucePlugin_LV2URI + String (uriSeparator) + getIri (*param); + const auto urid = mapFeature.map (mapFeature.handle, uri.toRawUTF8()); + result.push_back (urid); + } + + // If this is hit, some parameters have duplicate IDs. + // This may be because the IDs resolve to the same string when removing characters that + // are invalid in a TTL name. + jassert (std::set (result.begin(), result.end()).size() == result.size()); + + return result; + }(); + const std::map uridToIndexMap = [&] + { + std::map result; + size_t index = 0; + + for (const auto& urid : indexToUridMap) + result.emplace (urid, index++); + + return result; + }(); + FlaggedFloatCache<3> stateCache { (size_t) legacyParameters.getNumParameters() }; + bool ignoreCallbacks = false; + + JUCE_LEAK_DETECTOR (ParameterStorage) +}; + +enum class PortKind { seqInput, seqOutput, latencyOutput, freeWheelingInput, enabledInput }; + +struct PortIndices +{ + PortIndices (int numInputsIn, int numOutputsIn) + : numInputs (numInputsIn), numOutputs (numOutputsIn) {} + + int getPortIndexForAudioInput (int audioIndex) const noexcept + { + return audioIndex; + } + + int getPortIndexForAudioOutput (int audioIndex) const noexcept + { + return audioIndex + numInputs; + } + + int getPortIndexFor (PortKind p) const noexcept { return getMaxAudioPortIndex() + (int) p; } + + // Audio ports are numbered from 0 to numInputs + numOutputs + int getMaxAudioPortIndex() const noexcept { return numInputs + numOutputs; } + + int numInputs, numOutputs; +}; + +//============================================================================== +class PlayHead : public AudioPlayHead +{ +public: + PlayHead (LV2_URID_Map mapFeatureIn, double sampleRateIn) + : parser (mapFeatureIn), sampleRate (sampleRateIn) + { + } + + void invalidate() { info = nullopt; } + + void readNewInfo (const LV2_Atom_Event* event) + { + if (event->body.type != mLV2_ATOM__Object && event->body.type != mLV2_ATOM__Blank) + return; + + const auto* object = reinterpret_cast (&event->body); + + if (object->body.otype != mLV2_TIME__Position) + return; + + const LV2_Atom* atomFrame = nullptr; + const LV2_Atom* atomSpeed = nullptr; + const LV2_Atom* atomBar = nullptr; + const LV2_Atom* atomBeat = nullptr; + const LV2_Atom* atomBeatUnit = nullptr; + const LV2_Atom* atomBeatsPerBar = nullptr; + const LV2_Atom* atomBeatsPerMinute = nullptr; + + LV2_Atom_Object_Query query[] { { mLV2_TIME__frame, &atomFrame }, + { mLV2_TIME__speed, &atomSpeed }, + { mLV2_TIME__bar, &atomBar }, + { mLV2_TIME__beat, &atomBeat }, + { mLV2_TIME__beatUnit, &atomBeatUnit }, + { mLV2_TIME__beatsPerBar, &atomBeatsPerBar }, + { mLV2_TIME__beatsPerMinute, &atomBeatsPerMinute }, + LV2_ATOM_OBJECT_QUERY_END }; + + lv2_atom_object_query (object, query); + + info.emplace(); + + // Carla always seems to give us an integral 'beat' even though I'd expect + // it to be a floating-point value + + const auto numerator = parser.parseNumericAtom (atomBeatsPerBar); + const auto denominator = parser.parseNumericAtom (atomBeatUnit); + + if (numerator.hasValue() && denominator.hasValue()) + info->setTimeSignature (TimeSignature { (int) *numerator, (int) *denominator }); + + info->setBpm (parser.parseNumericAtom (atomBeatsPerMinute)); + info->setPpqPosition (parser.parseNumericAtom (atomBeat)); + info->setIsPlaying (! approximatelyEqual (parser.parseNumericAtom (atomSpeed).orFallback (0.0f), 0.0f)); + info->setBarCount (parser.parseNumericAtom (atomBar)); + + if (const auto parsed = parser.parseNumericAtom (atomFrame)) + { + info->setTimeInSamples (*parsed); + info->setTimeInSeconds ((double) *parsed / sampleRate); + } + } + + Optional getPosition() const override + { + return info; + } + +private: + lv2_shared::NumericAtomParser parser; + Optional info; + double sampleRate; + + #define X(str) const LV2_URID m##str = parser.map (str); + X (LV2_ATOM__Blank) + X (LV2_ATOM__Object) + X (LV2_TIME__Position) + X (LV2_TIME__beat) + X (LV2_TIME__beatUnit) + X (LV2_TIME__beatsPerBar) + X (LV2_TIME__beatsPerMinute) + X (LV2_TIME__frame) + X (LV2_TIME__speed) + X (LV2_TIME__bar) + #undef X + + JUCE_LEAK_DETECTOR (PlayHead) +}; + +//============================================================================== +class Ports +{ +public: + Ports (LV2_URID_Map map, int numInputsIn, int numOutputsIn) + : forge (map), + indices (numInputsIn, numOutputsIn), + mLV2_ATOM__Sequence (map.map (map.handle, LV2_ATOM__Sequence)) + { + audioBuffers.resize (static_cast (numInputsIn + numOutputsIn), nullptr); + } + + void connect (int port, void* data) + { + // The following is not UB _if_ data really points to an object with the expected type. + + if (port == indices.getPortIndexFor (PortKind::seqInput)) + { + inputData = static_cast (data); + } + else if (port == indices.getPortIndexFor (PortKind::seqOutput)) + { + outputData = static_cast (data); + } + else if (port == indices.getPortIndexFor (PortKind::latencyOutput)) + { + latency = static_cast (data); + } + else if (port == indices.getPortIndexFor (PortKind::freeWheelingInput)) + { + freeWheeling = static_cast (data); + } + else if (port == indices.getPortIndexFor (PortKind::enabledInput)) + { + enabled = static_cast (data); + } + else if (isPositiveAndBelow (port, indices.getMaxAudioPortIndex())) + { + audioBuffers[(size_t) port] = static_cast (data); + } + else + { + // This port was not declared! + jassertfalse; + } + } + + template + void forEachInputEvent (Callback&& callback) + { + if (inputData != nullptr && inputData->atom.type == mLV2_ATOM__Sequence) + for (const auto* event : lv2_shared::SequenceIterator { lv2_shared::SequenceWithSize { inputData } }) + callback (event); + } + + void prepareToWrite() + { + // Note: Carla seems to have a bug (verified with the eg-fifths plugin) where + // the output buffer size is incorrect on alternate calls. + forge.setBuffer (reinterpret_cast (outputData), outputData->atom.size); + } + + void writeLatency (int value) + { + if (latency != nullptr) + *latency = (float) value; + } + + const float* getBufferForAudioInput (int index) const noexcept + { + return audioBuffers[(size_t) indices.getPortIndexForAudioInput (index)]; + } + + float* getBufferForAudioOutput (int index) const noexcept + { + return audioBuffers[(size_t) indices.getPortIndexForAudioOutput (index)]; + } + + bool isFreeWheeling() const noexcept + { + if (freeWheeling != nullptr) + return *freeWheeling > 0.5f; + + return false; + } + + bool isEnabled() const noexcept + { + if (enabled != nullptr) + return *enabled > 0.5f; + + return true; + } + + lv2_shared::AtomForge forge; + PortIndices indices; + +private: + static constexpr auto numParamPorts = 3; + const LV2_Atom_Sequence* inputData = nullptr; + LV2_Atom_Sequence* outputData = nullptr; + float* latency = nullptr; + float* freeWheeling = nullptr; + float* enabled = nullptr; + std::vector audioBuffers; + const LV2_URID mLV2_ATOM__Sequence; + + JUCE_LEAK_DETECTOR (Ports) +}; + +class LV2PluginInstance : private AudioProcessorListener +{ +public: + LV2PluginInstance (double sampleRate, + int64_t maxBlockSize, + const char*, + LV2_URID_Map mapFeatureIn) + : mapFeature (mapFeatureIn), + playHead (mapFeature, sampleRate) + { + processor->addListener (this); + processor->setPlayHead (&playHead); + prepare (sampleRate, (int) maxBlockSize); + } + + void connect (uint32_t port, void* data) + { + ports.connect ((int) port, data); + } + + void activate() {} + + template + static void iterateAudioBuffer (AudioBuffer& ab, UnaryFunction fn) + { + float* const* sampleData = ab.getArrayOfWritePointers(); + + for (int c = ab.getNumChannels(); --c >= 0;) + for (int s = ab.getNumSamples(); --s >= 0;) + fn (sampleData[c][s]); + } + + static int countNaNs (AudioBuffer& ab) noexcept + { + int count = 0; + iterateAudioBuffer (ab, [&count] (float s) + { + if (std::isnan (s)) + ++count; + }); + + return count; + } + + void run (uint32_t numSteps) + { + // If this is hit, the host is trying to process more samples than it told us to prepare + jassert (static_cast (numSteps) <= processor->getBlockSize()); + + midi.clear(); + playHead.invalidate(); + audio.setSize (audio.getNumChannels(), static_cast (numSteps), true, false, true); + + ports.forEachInputEvent ([&] (const LV2_Atom_Event* event) + { + struct Callback + { + explicit Callback (LV2PluginInstance& s) : self (s) {} + + void setParameter (LV2_URID property, float value) const noexcept + { + self.parameters.setValueFromHost (property, value); + } + + // The host probably shouldn't send us 'touched' messages. + void gesture (LV2_URID, bool) const noexcept {} + + LV2PluginInstance& self; + }; + + patchSetHelper.processPatchSet (event, Callback { *this }); + + playHead.readNewInfo (event); + + if (event->body.type == mLV2_MIDI__MidiEvent) + midi.addEvent (event + 1, static_cast (event->body.size), static_cast (event->time.frames)); + }); + + processor->setNonRealtime (ports.isFreeWheeling()); + + for (auto i = 0, end = processor->getTotalNumInputChannels(); i < end; ++i) + audio.copyFrom (i, 0, ports.getBufferForAudioInput (i), audio.getNumSamples()); + + jassert (countNaNs (audio) == 0); + + { + const ScopedLock lock { processor->getCallbackLock() }; + + if (processor->isSuspended()) + { + for (auto i = 0, end = processor->getTotalNumOutputChannels(); i < end; ++i) + { + const auto ptr = ports.getBufferForAudioOutput (i); + std::fill (ptr, ptr + numSteps, 0.0f); + } + } + else + { + const auto isEnabled = ports.isEnabled(); + + if (auto* param = processor->getBypassParameter()) + { + param->setValueNotifyingHost (isEnabled ? 0.0f : 1.0f); + processor->processBlock (audio, midi); + } + else if (isEnabled) + { + processor->processBlock (audio, midi); + } + else + { + processor->processBlockBypassed (audio, midi); + } + } + } + + for (auto i = 0, end = processor->getTotalNumOutputChannels(); i < end; ++i) + { + const auto src = audio.getReadPointer (i); + const auto dst = ports.getBufferForAudioOutput (i); + + if (dst != nullptr) + std::copy (src, src + numSteps, dst); + } + + ports.prepareToWrite(); + auto* forge = ports.forge.get(); + lv2_shared::SequenceFrame sequence { forge, (uint32_t) 0 }; + + parameters.forEachChangedParameter ([&] (const AudioProcessorParameter& param, + LV2_URID paramUrid, + const ParameterStorage::Options& options) + { + const auto sendTouched = [&] (bool state) + { + // TODO Implement begin/end change gesture support once it's supported by LV2 + ignoreUnused (state); + }; + + if (options.gestureBegin) + sendTouched (true); + + if (options.parameterValue) + { + lv2_atom_forge_frame_time (forge, 0); + + lv2_shared::ObjectFrame object { forge, (uint32_t) 0, patchSetHelper.mLV2_PATCH__Set }; + + lv2_atom_forge_key (forge, patchSetHelper.mLV2_PATCH__property); + lv2_atom_forge_urid (forge, paramUrid); + + lv2_atom_forge_key (forge, patchSetHelper.mLV2_PATCH__value); + lv2_atom_forge_float (forge, [&] + { + if (auto* rangedParam = dynamic_cast (¶m)) + return rangedParam->convertFrom0to1 (rangedParam->getValue()); + + return param.getValue(); + }()); + } + + if (options.gestureEnd) + sendTouched (false); + }); + + if (shouldSendStateChange.exchange (false)) + { + lv2_atom_forge_frame_time (forge, 0); + lv2_shared::ObjectFrame { forge, (uint32_t) 0, mLV2_STATE__StateChanged }; + } + + for (const auto meta : midi) + { + const auto bytes = static_cast (meta.numBytes); + lv2_atom_forge_frame_time (forge, meta.samplePosition); + lv2_atom_forge_atom (forge, bytes, mLV2_MIDI__MidiEvent); + lv2_atom_forge_write (forge, meta.data, bytes); + } + + ports.writeLatency (processor->getLatencySamples()); + } + + void deactivate() {} + + LV2_State_Status store (LV2_State_Store_Function storeFn, + LV2_State_Handle handle, + uint32_t, + const LV2_Feature* const*) + { + MemoryBlock block; + processor->getStateInformation (block); + const auto text = block.toBase64Encoding(); + storeFn (handle, + mJucePluginLV2UriState, + text.toRawUTF8(), + text.getNumBytesAsUTF8() + 1, + mLV2_ATOM__String, + LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); + + return LV2_STATE_SUCCESS; + } + + LV2_State_Status retrieve (LV2_State_Retrieve_Function retrieveFn, + LV2_State_Handle handle, + uint32_t, + const LV2_Feature* const*) + { + size_t size = 0; + uint32_t type = 0; + uint32_t dataFlags = 0; + + // Try retrieving a port index (if this is a 'program' preset). + const auto* programData = retrieveFn (handle, mJucePluginLV2UriProgram, &size, &type, &dataFlags); + + if (programData != nullptr && type == mLV2_ATOM__Int && size == sizeof (int32_t)) + { + const auto programIndex = readUnaligned (programData); + processor->setCurrentProgram (programIndex); + return LV2_STATE_SUCCESS; + } + + // This doesn't seem to be a 'program' preset, try setting the full state from a string instead. + const auto* data = retrieveFn (handle, mJucePluginLV2UriState, &size, &type, &dataFlags); + + if (data == nullptr) + return LV2_STATE_ERR_NO_PROPERTY; + + if (type != mLV2_ATOM__String) + return LV2_STATE_ERR_BAD_TYPE; + + String text (static_cast (data), (size_t) size); + MemoryBlock block; + block.fromBase64Encoding (text); + processor->setStateInformation (block.getData(), (int) block.getSize()); + + return LV2_STATE_SUCCESS; + } + + std::unique_ptr createEditor() + { + return std::unique_ptr (processor->createEditorIfNeeded()); + } + + void editorBeingDeleted (AudioProcessorEditor* editor) + { + processor->editorBeingDeleted (editor); + } + + static std::unique_ptr createProcessorInstance() + { + auto result = createPluginFilterOfType (AudioProcessor::wrapperType_LV2); + + #if defined (JucePlugin_PreferredChannelConfigurations) + constexpr short channelConfigurations[][2] { JucePlugin_PreferredChannelConfigurations }; + + static_assert (numElementsInArray (channelConfigurations) > 0, + "JucePlugin_PreferredChannelConfigurations must contain at least one entry"); + static_assert (channelConfigurations[0][0] > 0 || channelConfigurations[0][1] > 0, + "JucePlugin_PreferredChannelConfigurations must have at least one input or output channel"); + result->setPlayConfigDetails (channelConfigurations[0][0], channelConfigurations[0][1], 44100.0, 1024); + + const auto desiredChannels = std::make_tuple (channelConfigurations[0][0], channelConfigurations[0][1]); + const auto actualChannels = std::make_tuple (result->getTotalNumInputChannels(), result->getTotalNumOutputChannels()); + + if (desiredChannels != actualChannels) + Logger::outputDebugString ("Failed to apply requested channel configuration!"); + #else + result->enableAllBuses(); + #endif + + return result; + } + +private: + void audioProcessorParameterChanged (AudioProcessor*, int, float) override {} + + void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override + { + // Only check for non-parameter state here because: + // - Latency is automatically written every block. + // - There's no way for an LV2 plugin to report an internal program change. + // - Parameter info is hard-coded in the plugin's turtle description. + if (details.nonParameterStateChanged) + shouldSendStateChange = true; + } + + void prepare (double sampleRate, int maxBlockSize) + { + jassert (processor != nullptr); + processor->setRateAndBufferSizeDetails (sampleRate, maxBlockSize); + processor->prepareToPlay (sampleRate, maxBlockSize); + + const auto numChannels = jmax (processor->getTotalNumInputChannels(), + processor->getTotalNumOutputChannels()); + + midi.ensureSize (8192); + audio.setSize (numChannels, maxBlockSize); + audio.clear(); + } + + LV2_URID map (StringRef uri) const { return mapFeature.map (mapFeature.handle, uri); } + + ScopedJuceInitialiser_GUI scopedJuceInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + std::unique_ptr processor = createProcessorInstance(); + const LV2_URID_Map mapFeature; + ParameterStorage parameters { *processor, mapFeature }; + Ports ports { mapFeature, + processor->getTotalNumInputChannels(), + processor->getTotalNumOutputChannels() }; + lv2_shared::PatchSetHelper patchSetHelper { mapFeature, JucePlugin_LV2URI }; + PlayHead playHead; + MidiBuffer midi; + AudioBuffer audio; + std::atomic shouldSendStateChange { false }; + + #define X(str) const LV2_URID m##str = map (str); + X (JucePluginLV2UriProgram) + X (JucePluginLV2UriState) + X (LV2_ATOM__Int) + X (LV2_ATOM__String) + X (LV2_BUF_SIZE__maxBlockLength) + X (LV2_BUF_SIZE__sequenceSize) + X (LV2_MIDI__MidiEvent) + X (LV2_PATCH__Set) + X (LV2_STATE__StateChanged) + #undef X + + JUCE_LEAK_DETECTOR (LV2PluginInstance) +}; + +//============================================================================== +struct RecallFeature +{ + int (*doRecall) (const char*) = [] (const char* libraryPath) -> int + { + const ScopedJuceInitialiser_GUI scope; + const auto processor = LV2PluginInstance::createProcessorInstance(); + + const String pathString { CharPointer_UTF8 { libraryPath } }; + + const auto absolutePath = File::isAbsolutePath (pathString) ? File (pathString) + : File::getCurrentWorkingDirectory().getChildFile (pathString); + + const auto writers = { writeManifestTtl, writeDspTtl, writeUiTtl }; + + const auto wroteSuccessfully = [&processor, &absolutePath] (auto* fn) + { + const auto result = fn (*processor, absolutePath); + + if (! result.wasOk()) + std::cerr << result.getErrorMessage() << '\n'; + + return result.wasOk(); + }; + + return std::all_of (writers.begin(), writers.end(), wroteSuccessfully) ? 0 : 1; + }; + +private: + static String getPresetUri (int index) + { + return JucePlugin_LV2URI + String (uriSeparator) + "preset" + String (index + 1); + } + + static FileOutputStream openStream (const File& libraryPath, StringRef name) + { + return FileOutputStream { libraryPath.getSiblingFile (name + ".ttl") }; + } + + static Result prepareStream (FileOutputStream& stream) + { + if (const auto result = stream.getStatus(); ! result) + return result; + + stream.setPosition (0); + stream.truncate(); + return Result::ok(); + } + + static Result writeManifestTtl (AudioProcessor& proc, const File& libraryPath) + { + auto os = openStream (libraryPath, "manifest"); + + if (const auto result = prepareStream (os); ! result) + return result; + + os << "@prefix lv2: .\n" + "@prefix rdfs: .\n" + "@prefix pset: .\n" + "@prefix state: .\n" + "@prefix ui: .\n" + "@prefix xsd: .\n" + "\n" + "<" JucePlugin_LV2URI ">\n" + "\ta lv2:Plugin ;\n" + "\tlv2:binary <" << URL::addEscapeChars (libraryPath.getFileName(), false) << "> ;\n" + "\trdfs:seeAlso .\n"; + + if (proc.hasEditor()) + { + #if JUCE_MAC + #define JUCE_LV2_UI_KIND "CocoaUI" + #elif JUCE_WINDOWS + #define JUCE_LV2_UI_KIND "WindowsUI" + #elif JUCE_LINUX || JUCE_BSD + #define JUCE_LV2_UI_KIND "X11UI" + #else + #error "LV2 UI is unsupported on this platform" + #endif + + os << "\n" + "<" << JucePluginLV2UriUi << ">\n" + "\ta ui:" JUCE_LV2_UI_KIND " ;\n" + "\tlv2:binary <" << URL::addEscapeChars (libraryPath.getFileName(), false) << "> ;\n" + "\trdfs:seeAlso .\n" + "\n"; + } + + for (auto i = 0, end = proc.getNumPrograms(); i < end; ++i) + { + os << "<" << getPresetUri (i) << ">\n" + "\ta pset:Preset ;\n" + "\tlv2:appliesTo <" JucePlugin_LV2URI "> ;\n" + "\trdfs:label \"" << proc.getProgramName (i) << "\" ;\n" + "\tstate:state [ <" << JucePluginLV2UriProgram << "> \"" << i << "\"^^xsd:int ; ] .\n" + "\n"; + } + + return Result::ok(); + } + + static std::vector findAllSubgroupsDepthFirst (const AudioProcessorParameterGroup& group, + std::vector foundSoFar = {}) + { + foundSoFar.push_back (&group); + + for (auto* node : group) + { + if (auto* subgroup = node->getGroup()) + foundSoFar = findAllSubgroupsDepthFirst (*subgroup, std::move (foundSoFar)); + } + + return foundSoFar; + } + + using GroupSymbolMap = std::map; + + static String getFlattenedGroupSymbol (const AudioProcessorParameterGroup& group, String symbol = "") + { + if (auto* parent = group.getParent()) + return getFlattenedGroupSymbol (*parent, group.getID() + (symbol.isEmpty() ? "" : group.getSeparator() + symbol)); + + return symbol; + } + + static String getSymbolForGroup (const AudioProcessorParameterGroup& group) + { + const String allowedCharacters ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"); + const auto base = getFlattenedGroupSymbol (group); + + if (base.isEmpty()) + return {}; + + String copy; + + for (const auto character : base) + copy << String::charToString (allowedCharacters.containsChar (character) ? character : (juce_wchar) '_'); + + return "paramgroup_" + copy; + } + + static GroupSymbolMap getGroupsAndSymbols (const std::vector& groups) + { + std::set symbols; + GroupSymbolMap result; + + for (const auto& group : groups) + { + const auto symbol = [&] + { + const auto idealSymbol = getSymbolForGroup (*group); + + if (symbols.find (idealSymbol) == symbols.cend()) + return idealSymbol; + + for (auto i = 2; i < std::numeric_limits::max(); ++i) + { + const auto toTest = idealSymbol + "_" + String (i); + + if (symbols.find (toTest) == symbols.cend()) + return toTest; + } + + jassertfalse; + return String(); + }(); + + symbols.insert (symbol); + result.emplace (group, symbol); + } + + return result; + } + + template + static void visitAllParameters (const GroupSymbolMap& groups, Fn&& fn) + { + for (const auto& group : groups) + for (const auto* node : *group.first) + if (auto* param = node->getParameter()) + fn (group.second, *param); + } + + static Result writeDspTtl (AudioProcessor& proc, const File& libraryPath) + { + auto os = openStream (libraryPath, "dsp"); + + if (const auto result = prepareStream (os); ! result) + return result; + + os << "@prefix atom: .\n" + "@prefix bufs: .\n" + "@prefix doap: .\n" + "@prefix foaf: .\n" + "@prefix lv2: .\n" + "@prefix midi: .\n" + "@prefix opts: .\n" + "@prefix param: .\n" + "@prefix patch: .\n" + "@prefix pg: .\n" + "@prefix plug: <" JucePlugin_LV2URI << uriSeparator << "> .\n" + "@prefix pprop: .\n" + "@prefix rdfs: .\n" + "@prefix rdf: .\n" + "@prefix rsz: .\n" + "@prefix state: .\n" + "@prefix time: .\n" + "@prefix ui: .\n" + "@prefix units: .\n" + "@prefix urid: .\n" + "@prefix xsd: .\n" + "\n"; + + LegacyAudioParametersWrapper legacyParameters (proc, false); + + const auto allGroups = findAllSubgroupsDepthFirst (legacyParameters.getGroup()); + const auto groupsAndSymbols = getGroupsAndSymbols (allGroups); + + const auto parameterVisitor = [&] (const String& symbol, + const AudioProcessorParameter& param) + { + os << "plug:" << ParameterStorage::getIri (param) << "\n" + "\ta lv2:Parameter ;\n" + "\trdfs:label \"" << param.getName (1024) << "\" ;\n"; + + if (symbol.isNotEmpty()) + os << "\tpg:group plug:" << symbol << " ;\n"; + + os << "\trdfs:range atom:Float ;\n"; + + if (auto* rangedParam = dynamic_cast (¶m)) + { + os << "\tlv2:default " << rangedParam->convertFrom0to1 (rangedParam->getDefaultValue()) << " ;\n" + "\tlv2:minimum " << rangedParam->getNormalisableRange().start << " ;\n" + "\tlv2:maximum " << rangedParam->getNormalisableRange().end; + } + else + { + os << "\tlv2:default " << param.getDefaultValue() << " ;\n" + "\tlv2:minimum 0.0 ;\n" + "\tlv2:maximum 1.0"; + } + + // Avoid writing out loads of scale points for parameters with lots of steps + constexpr auto stepLimit = 1000; + const auto numSteps = param.getNumSteps(); + + if (param.isDiscrete() && 2 <= numSteps && numSteps < stepLimit) + { + os << "\t ;\n" + "\tlv2:portProperty lv2:enumeration " << (param.isBoolean() ? ", lv2:toggled " : "") << ";\n" + "\tlv2:scalePoint "; + + const auto maxIndex = numSteps - 1; + + for (int i = 0; i < numSteps; ++i) + { + const auto value = (float) i / (float) maxIndex; + const auto text = param.getText (value, 1024); + + os << (i != 0 ? ", " : "") << "[\n" + "\t\trdfs:label \"" << text << "\" ;\n" + "\t\trdf:value " << value << " ;\n" + "\t]"; + } + } + + os << " .\n\n"; + }; + + visitAllParameters (groupsAndSymbols, parameterVisitor); + + for (const auto& groupInfo : groupsAndSymbols) + { + if (groupInfo.second.isEmpty()) + continue; + + os << "plug:" << groupInfo.second << "\n" + "\ta pg:Group ;\n"; + + if (auto* parent = groupInfo.first->getParent()) + { + if (parent->getParent() != nullptr) + { + const auto it = groupsAndSymbols.find (parent); + + if (it != groupsAndSymbols.cend()) + os << "\tpg:subGroupOf plug:" << it->second << " ;\n"; + } + } + + os << "\tlv2:symbol \"" << groupInfo.second << "\" ;\n" + "\tlv2:name \"" << groupInfo.first->getName() << "\" .\n\n"; + } + + const auto getBaseBusName = [] (bool isInput) { return isInput ? "input_group_" : "output_group_"; }; + + for (const auto isInput : { true, false }) + { + const auto baseBusName = getBaseBusName (isInput); + const auto groupKind = isInput ? "InputGroup" : "OutputGroup"; + const auto busCount = proc.getBusCount (isInput); + + for (auto i = 0; i < busCount; ++i) + { + if (const auto* bus = proc.getBus (isInput, i)) + { + os << "plug:" << baseBusName << (i + 1) << "\n" + "\ta pg:" << groupKind << " ;\n" + "\tlv2:name \"" << bus->getName() << "\" ;\n" + "\tlv2:symbol \"" << baseBusName << (i + 1) << "\" .\n\n"; + } + } + } + + os << "<" JucePlugin_LV2URI ">\n"; + + if (proc.hasEditor()) + os << "\tui:ui <" << JucePluginLV2UriUi << "> ;\n"; + + const auto versionParts = StringArray::fromTokens (JucePlugin_VersionString, ".", ""); + + const auto getVersionOrZero = [&] (int indexFromBack) + { + const auto str = versionParts[versionParts.size() - indexFromBack]; + return str.isEmpty() ? 0 : str.getIntValue(); + }; + + const auto minorVersion = getVersionOrZero (2); + const auto microVersion = getVersionOrZero (1); + + os << "\ta " + #if JucePlugin_IsSynth + "lv2:InstrumentPlugin" + #else + "lv2:Plugin" + #endif + " ;\n" + "\tdoap:name \"" JucePlugin_Name "\" ;\n" + "\tdoap:description \"" JucePlugin_Desc "\" ;\n" + "\tlv2:minorVersion " << minorVersion << " ;\n" + "\tlv2:microVersion " << microVersion << " ;\n" + "\tdoap:maintainer [\n" + "\t\ta foaf:Person ;\n" + "\t\tfoaf:name \"" JucePlugin_Manufacturer "\" ;\n" + "\t\tfoaf:homepage <" JucePlugin_ManufacturerWebsite "> ;\n" + "\t\tfoaf:mbox <" JucePlugin_ManufacturerEmail "> ;\n" + "\t] ;\n" + "\tdoap:release [\n" + "\t\ta doap:Version ;\n" + "\t\tdoap:revision \"" JucePlugin_VersionString "\" ;\n" + "\t] ;\n" + "\tlv2:optionalFeature\n" + "\t\tlv2:hardRTCapable ;\n" + "\tlv2:extensionData\n" + "\t\tstate:interface ;\n" + "\tlv2:requiredFeature\n" + "\t\turid:map ,\n" + "\t\topts:options ,\n" + "\t\tbufs:boundedBlockLength ;\n"; + + for (const auto isInput : { true, false }) + { + const auto kind = isInput ? "mainInput" : "mainOutput"; + + if (proc.getBusCount (isInput) > 0) + os << "\tpg:" << kind << " plug:" << getBaseBusName (isInput) << "1 ;\n"; + } + + if (legacyParameters.size() != 0) + { + for (const auto header : { "writable", "readable" }) + { + os << "\tpatch:" << header; + + bool isFirst = true; + + for (const auto* param : legacyParameters) + { + os << (isFirst ? "" : " ,") << "\n\t\tplug:" << ParameterStorage::getIri (*param); + isFirst = false; + } + + os << " ;\n"; + } + } + + os << "\tlv2:port [\n"; + + const PortIndices indices (proc.getTotalNumInputChannels(), + proc.getTotalNumOutputChannels()); + + const auto designationMap = [&] + { + std::map result; + + for (const auto& pair : lv2_shared::channelDesignationMap) + result.emplace (pair.second, pair.first); + + return result; + }(); + + // TODO add support for specific audio group kinds + for (const auto isInput : { true, false }) + { + const auto baseBusName = getBaseBusName (isInput); + const auto portKind = isInput ? "InputPort" : "OutputPort"; + const auto portName = isInput ? "Audio In " : "Audio Out "; + const auto portSymbol = isInput ? "audio_in_" : "audio_out_"; + const auto busCount = proc.getBusCount (isInput); + + auto channelCounter = 0; + + for (auto busIndex = 0; busIndex < busCount; ++busIndex) + { + if (const auto* bus = proc.getBus (isInput, busIndex)) + { + const auto channelCount = bus->getNumberOfChannels(); + const auto optionalBus = ! bus->isEnabledByDefault(); + + for (auto channelIndex = 0; channelIndex < channelCount; ++channelIndex, ++channelCounter) + { + const auto portIndex = isInput ? indices.getPortIndexForAudioInput (channelCounter) + : indices.getPortIndexForAudioOutput (channelCounter); + + os << "\t\ta lv2:" << portKind << " , lv2:AudioPort ;\n" + "\t\tlv2:index " << portIndex << " ;\n" + "\t\tlv2:symbol \"" << portSymbol << (channelCounter + 1) << "\" ;\n" + "\t\tlv2:name \"" << portName << (channelCounter + 1) << "\" ;\n" + "\t\tpg:group plug:" << baseBusName << (busIndex + 1) << " ;\n"; + + if (optionalBus) + os << "\t\tlv2:portProperty lv2:connectionOptional ;\n"; + + const auto designation = bus->getCurrentLayout().getTypeOfChannel (channelIndex); + const auto it = designationMap.find (designation); + + if (it != designationMap.end()) + os << "\t\tlv2:designation <" << it->second << "> ;\n"; + + os << "\t] , [\n"; + } + } + } + } + + // In the event that the plugin decides to send all of its parameters in one go, + // we should ensure that the output buffer is large enough to accommodate, with some + // extra room for the sequence header, MIDI messages etc.. + const auto patchSetSizeBytes = 72; + const auto additionalSize = 8192; + const auto atomPortMinSize = proc.getParameters().size() * patchSetSizeBytes + additionalSize; + + os << "\t\ta lv2:InputPort , atom:AtomPort ;\n" + "\t\trsz:minimumSize " << atomPortMinSize << " ;\n" + "\t\tatom:bufferType atom:Sequence ;\n" + "\t\tatom:supports\n"; + + #if ! JucePlugin_IsSynth && ! JucePlugin_IsMidiEffect + if (proc.acceptsMidi()) + #endif + os << "\t\t\tmidi:MidiEvent ,\n"; + + os << "\t\t\tpatch:Message ,\n" + "\t\t\ttime:Position ;\n" + "\t\tlv2:designation lv2:control ;\n" + "\t\tlv2:index " << indices.getPortIndexFor (PortKind::seqInput) << " ;\n" + "\t\tlv2:symbol \"in\" ;\n" + "\t\tlv2:name \"In\" ;\n" + "\t] , [\n" + "\t\ta lv2:OutputPort , atom:AtomPort ;\n" + "\t\trsz:minimumSize " << atomPortMinSize << " ;\n" + "\t\tatom:bufferType atom:Sequence ;\n" + "\t\tatom:supports\n"; + + #if ! JucePlugin_IsMidiEffect + if (proc.producesMidi()) + #endif + os << "\t\t\tmidi:MidiEvent ,\n"; + + os << "\t\t\tpatch:Message ;\n" + "\t\tlv2:designation lv2:control ;\n" + "\t\tlv2:index " << indices.getPortIndexFor (PortKind::seqOutput) << " ;\n" + "\t\tlv2:symbol \"out\" ;\n" + "\t\tlv2:name \"Out\" ;\n" + "\t] , [\n" + "\t\ta lv2:OutputPort , lv2:ControlPort ;\n" + "\t\tlv2:designation lv2:latency ;\n" + "\t\tlv2:symbol \"latency\" ;\n" + "\t\tlv2:name \"Latency\" ;\n" + "\t\tlv2:index " << indices.getPortIndexFor (PortKind::latencyOutput) << " ;\n" + "\t\tlv2:portProperty lv2:reportsLatency , lv2:integer , lv2:connectionOptional , pprop:notOnGUI ;\n" + "\t\tunits:unit units:frame ;\n" + "\t] , [\n" + "\t\ta lv2:InputPort , lv2:ControlPort ;\n" + "\t\tlv2:designation lv2:freeWheeling ;\n" + "\t\tlv2:symbol \"freeWheeling\" ;\n" + "\t\tlv2:name \"Free Wheeling\" ;\n" + "\t\tlv2:default 0.0 ;\n" + "\t\tlv2:minimum 0.0 ;\n" + "\t\tlv2:maximum 1.0 ;\n" + "\t\tlv2:index " << indices.getPortIndexFor (PortKind::freeWheelingInput) << " ;\n" + "\t\tlv2:portProperty lv2:toggled , lv2:connectionOptional , pprop:notOnGUI ;\n" + "\t] , [\n" + "\t\ta lv2:InputPort , lv2:ControlPort ;\n" + "\t\tlv2:designation lv2:enabled ;\n" + "\t\tlv2:symbol \"enabled\" ;\n" + "\t\tlv2:name \"Enabled\" ;\n" + "\t\tlv2:default 1.0 ;\n" + "\t\tlv2:minimum 0.0 ;\n" + "\t\tlv2:maximum 1.0 ;\n" + "\t\tlv2:index " << indices.getPortIndexFor (PortKind::enabledInput) << " ;\n" + "\t\tlv2:portProperty lv2:toggled , lv2:connectionOptional , pprop:notOnGUI ;\n" + "\t] ;\n" + "\topts:supportedOption\n" + "\t\tbufs:maxBlockLength .\n"; + + return Result::ok(); + } + + static Result writeUiTtl (AudioProcessor& proc, const File& libraryPath) + { + if (! proc.hasEditor()) + return Result::ok(); + + auto os = openStream (libraryPath, "ui"); + + if (const auto result = prepareStream (os); ! result) + return result; + + const auto editorInstance = rawToUniquePtr (proc.createEditor()); + const auto resizeFeatureString = editorInstance->isResizable() ? "ui:resize" : "ui:noUserResize"; + + os << "@prefix lv2: .\n" + "@prefix opts: .\n" + "@prefix param: .\n" + "@prefix ui: .\n" + "@prefix urid: .\n" + "\n" + "<" << JucePluginLV2UriUi << ">\n" + "\tlv2:extensionData\n" + #if JUCE_LINUX || JUCE_BSD + "\t\tui:idleInterface ,\n" + #endif + "\t\topts:interface ,\n" + "\t\tui:noUserResize ,\n" // resize and noUserResize are always present in the extension data array + "\t\tui:resize ;\n" + "\n" + "\tlv2:requiredFeature\n" + #if JUCE_LINUX || JUCE_BSD + "\t\tui:idleInterface ,\n" + #endif + "\t\turid:map ,\n" + "\t\tui:parent ,\n" + "\t\t ;\n" + "\n" + "\tlv2:optionalFeature\n" + "\t\t" << resizeFeatureString << " ,\n" + "\t\topts:interface ,\n" + "\t\topts:options ;\n\n" + "\topts:supportedOption\n" + "\t\tui:scaleFactor ,\n" + "\t\tparam:sampleRate .\n"; + + return Result::ok(); + } + + JUCE_LEAK_DETECTOR (RecallFeature) +}; + +//============================================================================== +LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor (uint32_t index) +{ + if (index != 0) + return nullptr; + + static const LV2_Descriptor descriptor + { + JucePlugin_LV2URI, // TODO some constexpr check that this is a valid URI in terms of RFC 3986 + [] (const LV2_Descriptor*, + double sampleRate, + const char* pathToBundle, + const LV2_Feature* const* features) -> LV2_Handle + { + const auto* mapFeature = findMatchingFeatureData (features, LV2_URID__map); + + if (mapFeature == nullptr) + { + // The host doesn't provide the 'urid map' feature + jassertfalse; + return nullptr; + } + + const auto boundedBlockLength = hasFeature (features, LV2_BUF_SIZE__boundedBlockLength); + + if (! boundedBlockLength) + { + // The host doesn't provide the 'bounded block length' feature + jassertfalse; + return nullptr; + } + + const auto* options = findMatchingFeatureData (features, LV2_OPTIONS__options); + + if (options == nullptr) + { + // The host doesn't provide the 'options' feature + jassertfalse; + return nullptr; + } + + const lv2_shared::NumericAtomParser parser { *mapFeature }; + const auto blockLengthUrid = mapFeature->map (mapFeature->handle, LV2_BUF_SIZE__maxBlockLength); + const auto blockSize = parser.parseNumericOption (findMatchingOption (options, blockLengthUrid)); + + if (! blockSize.hasValue()) + { + // The host doesn't specify a maximum block size + jassertfalse; + return nullptr; + } + + return new LV2PluginInstance { sampleRate, *blockSize, pathToBundle, *mapFeature }; + }, + [] (LV2_Handle instance, uint32_t port, void* data) + { + static_cast (instance)->connect (port, data); + }, + [] (LV2_Handle instance) { static_cast (instance)->activate(); }, + [] (LV2_Handle instance, uint32_t sampleCount) + { + static_cast (instance)->run (sampleCount); + }, + [] (LV2_Handle instance) { static_cast (instance)->deactivate(); }, + [] (LV2_Handle instance) + { + JUCE_AUTORELEASEPOOL + { + delete static_cast (instance); + } + }, + [] (const char* uri) -> const void* + { + const auto uriMatches = [&] (const LV2_Feature& f) { return std::strcmp (f.URI, uri) == 0; }; + + static RecallFeature recallFeature; + + static LV2_State_Interface stateInterface + { + [] (LV2_Handle instance, + LV2_State_Store_Function store, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features) -> LV2_State_Status + { + return static_cast (instance)->store (store, handle, flags, features); + }, + [] (LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features) -> LV2_State_Status + { + return static_cast (instance)->retrieve (retrieve, handle, flags, features); + } + }; + + static const LV2_Feature features[] { { JUCE_TURTLE_RECALL_URI, &recallFeature }, + { LV2_STATE__interface, &stateInterface } }; + + const auto it = std::find_if (std::begin (features), std::end (features), uriMatches); + return it != std::end (features) ? it->data : nullptr; + } + }; + + return &descriptor; +} + +static Optional findScaleFactor (const LV2_URID_Map* symap, const LV2_Options_Option* options) +{ + if (options == nullptr || symap == nullptr) + return {}; + + const lv2_shared::NumericAtomParser parser { *symap }; + const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); + const auto* scaleFactorOption = findMatchingOption (options, scaleFactorUrid); + return parser.parseNumericOption (scaleFactorOption); +} + +class LV2UIInstance : private Component, + private ComponentListener +{ +public: + LV2UIInstance (const char*, + const char*, + LV2UI_Write_Function writeFunctionIn, + LV2UI_Controller controllerIn, + LV2UI_Widget* widget, + LV2PluginInstance* pluginIn, + LV2UI_Widget parentIn, + const LV2_URID_Map* symapIn, + const LV2UI_Resize* resizeFeatureIn, + Optional scaleFactorIn) + : writeFunction (writeFunctionIn), + controller (controllerIn), + plugin (pluginIn), + parent (parentIn), + symap (symapIn), + resizeFeature (resizeFeatureIn), + scaleFactor (scaleFactorIn), + editor (plugin->createEditor()) + { + jassert (plugin != nullptr); + jassert (parent != nullptr); + jassert (editor != nullptr); + + if (editor == nullptr) + return; + + const auto bounds = getSizeToContainChild(); + setSize (bounds.getWidth(), bounds.getHeight()); + + addAndMakeVisible (*editor); + + setBroughtToFrontOnMouseClick (true); + setOpaque (true); + setVisible (false); + removeFromDesktop(); + addToDesktop (detail::PluginUtilities::getDesktopFlags (editor.get()), parent); + editor->addComponentListener (this); + + *widget = getWindowHandle(); + + setVisible (true); + + editor->setScaleFactor (getScaleFactor()); + requestResize(); + } + + ~LV2UIInstance() override + { + plugin->editorBeingDeleted (editor.get()); + } + + // This is called by the host when a parameter changes. + // We don't care, our UI will listen to the processor directly. + void portEvent (uint32_t, uint32_t, uint32_t, const void*) {} + + // Called when the host requests a resize + int resize (int width, int height) + { + const ScopedValueSetter scope (hostRequestedResize, true); + setSize (width, height); + return 0; + } + + // Called by the host to give us an opportunity to process UI events + void idleCallback() + { + #if JUCE_LINUX || JUCE_BSD + messageThread->processPendingEvents(); + #endif + } + + void resized() override + { + const ScopedValueSetter scope (hostRequestedResize, true); + + if (editor != nullptr) + { + const auto localArea = editor->getLocalArea (this, getLocalBounds()); + editor->setBoundsConstrained ({ localArea.getWidth(), localArea.getHeight() }); + } + } + + void paint (Graphics& g) override { g.fillAll (Colours::black); } + + uint32_t getOptions (LV2_Options_Option* options) + { + const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); + const auto floatUrid = symap->map (symap->handle, LV2_ATOM__Float);; + + for (auto* opt = options; opt->key != 0; ++opt) + { + if (opt->context != LV2_OPTIONS_INSTANCE || opt->subject != 0 || opt->key != scaleFactorUrid) + continue; + + if (scaleFactor.hasValue()) + { + opt->type = floatUrid; + opt->size = sizeof (float); + opt->value = &(*scaleFactor); + } + } + + return LV2_OPTIONS_SUCCESS; + } + + uint32_t setOptions (const LV2_Options_Option* options) + { + const auto scaleFactorUrid = symap->map (symap->handle, LV2_UI__scaleFactor); + const auto floatUrid = symap->map (symap->handle, LV2_ATOM__Float);; + + for (auto* opt = options; opt->key != 0; ++opt) + { + if (opt->context != LV2_OPTIONS_INSTANCE + || opt->subject != 0 + || opt->key != scaleFactorUrid + || opt->type != floatUrid + || opt->size != sizeof (float)) + { + continue; + } + + scaleFactor = *static_cast (opt->value); + updateScale(); + } + + return LV2_OPTIONS_SUCCESS; + } + +private: + void updateScale() + { + editor->setScaleFactor (getScaleFactor()); + requestResize(); + } + + Rectangle getSizeToContainChild() const + { + if (editor != nullptr) + return getLocalArea (editor.get(), editor->getLocalBounds()); + + return {}; + } + + float getScaleFactor() const noexcept + { + return scaleFactor.hasValue() ? *scaleFactor : 1.0f; + } + + void componentMovedOrResized (Component&, bool, bool wasResized) override + { + if (! hostRequestedResize && wasResized) + requestResize(); + } + + void write (uint32_t portIndex, uint32_t bufferSize, uint32_t portProtocol, const void* data) + { + writeFunction (controller, portIndex, bufferSize, portProtocol, data); + } + + void requestResize() + { + if (editor == nullptr) + return; + + const auto bounds = getSizeToContainChild(); + + if (resizeFeature == nullptr) + return; + + if (auto* fn = resizeFeature->ui_resize) + fn (resizeFeature->handle, bounds.getWidth(), bounds.getHeight()); + + setSize (bounds.getWidth(), bounds.getHeight()); + repaint(); + } + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + LV2UI_Write_Function writeFunction; + LV2UI_Controller controller; + LV2PluginInstance* plugin; + LV2UI_Widget parent; + const LV2_URID_Map* symap = nullptr; + const LV2UI_Resize* resizeFeature = nullptr; + Optional scaleFactor; + std::unique_ptr editor; + bool hostRequestedResize = false; + + JUCE_LEAK_DETECTOR (LV2UIInstance) +}; + +LV2_SYMBOL_EXPORT const LV2UI_Descriptor* lv2ui_descriptor (uint32_t index) +{ + if (index != 0) + return nullptr; + + static const LV2UI_Descriptor descriptor + { + JucePluginLV2UriUi.toRawUTF8(), // TODO some constexpr check that this is a valid URI in terms of RFC 3986 + [] (const LV2UI_Descriptor*, + const char* pluginUri, + const char* bundlePath, + LV2UI_Write_Function writeFunction, + LV2UI_Controller controller, + LV2UI_Widget* widget, + const LV2_Feature* const* features) -> LV2UI_Handle + { + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + auto* plugin = findMatchingFeatureData (features, LV2_INSTANCE_ACCESS_URI); + + if (plugin == nullptr) + { + // No instance access + jassertfalse; + return nullptr; + } + + auto* parent = findMatchingFeatureData (features, LV2_UI__parent); + + if (parent == nullptr) + { + // No parent access + jassertfalse; + return nullptr; + } + + auto* resizeFeature = findMatchingFeatureData (features, LV2_UI__resize); + + const auto* symap = findMatchingFeatureData (features, LV2_URID__map); + const auto scaleFactor = findScaleFactor (symap, findMatchingFeatureData (features, LV2_OPTIONS__options)); + + return new LV2UIInstance { pluginUri, + bundlePath, + writeFunction, + controller, + widget, + plugin, + parent, + symap, + resizeFeature, + scaleFactor }; + }, + [] (LV2UI_Handle ui) + { + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + JUCE_AUTORELEASEPOOL + { + delete static_cast (ui); + } + }, + [] (LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) + { + JUCE_ASSERT_MESSAGE_THREAD + static_cast (ui)->portEvent (portIndex, bufferSize, format, buffer); + }, + [] (const char* uri) -> const void* + { + const auto uriMatches = [&] (const LV2_Feature& f) { return std::strcmp (f.URI, uri) == 0; }; + + static LV2UI_Resize resize { nullptr, [] (LV2UI_Feature_Handle handle, int width, int height) -> int + { + JUCE_ASSERT_MESSAGE_THREAD + return static_cast (handle)->resize (width, height); + } }; + + static LV2UI_Idle_Interface idle { [] (LV2UI_Handle handle) + { + static_cast (handle)->idleCallback(); + return 0; + } }; + + static LV2_Options_Interface options + { + [] (LV2_Handle handle, LV2_Options_Option* optionsIn) + { + return static_cast (handle)->getOptions (optionsIn); + }, + [] (LV2_Handle handle, const LV2_Options_Option* optionsIn) + { + return static_cast (handle)->setOptions (optionsIn); + } + }; + + // We'll always define noUserResize and idle in the extension data array, but we'll + // only declare them in the ui.ttl if the UI is actually non-resizable, or requires + // idle callbacks. + // Well-behaved hosts should check the ttl before trying to search the + // extension-data array. + static const LV2_Feature features[] { { LV2_UI__resize, &resize }, + { LV2_UI__noUserResize, nullptr }, + { LV2_UI__idleInterface, &idle }, + { LV2_OPTIONS__interface, &options } }; + + const auto it = std::find_if (std::begin (features), std::end (features), uriMatches); + return it != std::end (features) ? it->data : nullptr; + } + }; + + return &descriptor; +} + +} +} + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp index e4c5c25bb018..caefcb797417 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp @@ -31,7 +31,152 @@ #error To compile AudioUnitv3 and/or Standalone plug-ins, you need to add the juce_audio_utils and juce_audio_devices modules! #endif -#include "Standalone/juce_StandaloneFilterApp.cpp" +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +// You can set this flag in your build if you need to specify a different +// standalone JUCEApplication class for your app to use. If you don't +// set it then by default we'll just create a simple one as below. +#if ! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP + +#include + +namespace juce +{ + +//============================================================================== +class StandaloneFilterApp : public JUCEApplication +{ +public: + StandaloneFilterApp() + { + PropertiesFile::Options options; + + options.applicationName = getApplicationName(); + options.filenameSuffix = ".settings"; + options.osxLibrarySubFolder = "Application Support"; + #if JUCE_LINUX || JUCE_BSD + options.folderName = "~/.config"; + #else + options.folderName = ""; + #endif + + appProperties.setStorageParameters (options); + } + + const String getApplicationName() override { return CharPointer_UTF8 (JucePlugin_Name); } + const String getApplicationVersion() override { return JucePlugin_VersionString; } + bool moreThanOneInstanceAllowed() override { return true; } + void anotherInstanceStarted (const String&) override {} + + virtual StandaloneFilterWindow* createWindow() + { + #ifdef JucePlugin_PreferredChannelConfigurations + StandalonePluginHolder::PluginInOuts channels[] = { JucePlugin_PreferredChannelConfigurations }; + #endif + + return new StandaloneFilterWindow (getApplicationName(), + LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId), + appProperties.getUserSettings(), + false, {}, nullptr + #ifdef JucePlugin_PreferredChannelConfigurations + , juce::Array (channels, juce::numElementsInArray (channels)) + #else + , {} + #endif + #if JUCE_DONT_AUTO_OPEN_MIDI_DEVICES_ON_MOBILE + , false + #endif + ); + } + + //============================================================================== + void initialise (const String&) override + { + mainWindow.reset (createWindow()); + + #if JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE + Desktop::getInstance().setKioskModeComponent (mainWindow.get(), false); + #endif + + mainWindow->setVisible (true); + } + + void shutdown() override + { + mainWindow = nullptr; + appProperties.saveIfNeeded(); + } + + //============================================================================== + void systemRequestedQuit() override + { + if (mainWindow.get() != nullptr) + mainWindow->pluginHolder->savePluginState(); + + if (ModalComponentManager::getInstance()->cancelAllModalComponents()) + { + Timer::callAfterDelay (100, []() + { + if (auto app = JUCEApplicationBase::getInstance()) + app->systemRequestedQuit(); + }); + } + else + { + quit(); + } + } + +protected: + ApplicationProperties appProperties; + std::unique_ptr mainWindow; +}; + +} // namespace juce + +#if JucePlugin_Build_Standalone && JUCE_IOS + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + +using namespace juce; + +bool JUCE_CALLTYPE juce_isInterAppAudioConnected() +{ + if (auto holder = StandalonePluginHolder::getInstance()) + return holder->isInterAppAudioConnected(); + + return false; +} + +void JUCE_CALLTYPE juce_switchToHostApplication() +{ + if (auto holder = StandalonePluginHolder::getInstance()) + holder->switchToHostApplication(); +} + +Image JUCE_CALLTYPE juce_getIAAHostIcon (int size) +{ + if (auto holder = StandalonePluginHolder::getInstance()) + return holder->getIAAHostIcon (size); + + return Image(); +} + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +#endif + +#endif #if JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP extern juce::JUCEApplicationBase* juce_CreateApplication(); diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp index 066754514169..aee1f4d36cbd 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_Unity.cpp @@ -23,4 +23,755 @@ ============================================================================== */ -#include "Unity/juce_Unity_Wrapper.cpp" +#include + +#if JucePlugin_Build_Unity + +#include +#include + +#if JUCE_WINDOWS + #include +#endif + +#include + +#include + +//============================================================================== +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 getBounds() const override { return bounds; } + Point localToGlobal (Point relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); } + Point globalToLocal (Point screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); } + + using ComponentPeer::localToGlobal; + using ComponentPeer::globalToLocal; + + StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); } + + void setBounds (const Rectangle& newBounds, bool) override + { + bounds = newBounds; + mouseWatcher.setBoundsToWatch (bounds); + } + + bool contains (Point 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 (&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 position, ModifierKeys mods) + { + ModifierKeys::currentModifiers = mods; + + handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::defaultPressure, + juce::MouseInputSource::defaultOrientation, 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) + { + } + + std::unique_ptr createType() const override + { + return std::make_unique(); + } + + std::unique_ptr createLowLevelContext() override + { + return std::make_unique (Image (this)); + } + + void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, [[maybe_unused]] Image::BitmapData::ReadWriteMode mode) override + { + const auto offset = (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride; + bitmap.data = imageData + offset; + bitmap.size = (size_t) (lineStride * height) - offset; + 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::defaultPressure, juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis()); + + lastMousePos = pos; + } + + } + + void setBoundsToWatch (Rectangle b) + { + if (boundsToWatch != b) + boundsToWatch = b; + + startTimer (250); + } + + ComponentPeer& owner; + Rectangle boundsToWatch; + Point 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 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; } + OptionalBorderSize getFrameSizeIfPresent() const override { return {}; } + BorderSize getFrameSize() const override { return {}; } + void setVisible (bool) override {} + void setTitle (const String&) override {} + void setIcon (const Image&) override {} + void textInputRequired (Point, TextInputTarget&) override {} + void setAlpha (float) override {} + void performAnyPendingRepaintsNow() override {} + void repaint (const Rectangle&) override {} + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer) +}; + +static ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); } + +//============================================================================== +class AudioProcessorUnityWrapper +{ +public: + AudioProcessorUnityWrapper (bool isTemporary) + { + detail::RunningInUnity::state = true; + pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_Unity); + + if (! isTemporary && pluginInstance->hasEditor()) + { + pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded()); + pluginInstanceEditor->setVisible (true); + detail::PluginUtilities::addToDesktop (*pluginInstanceEditor, nullptr); + } + + 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 = static_cast (state->dspBufferSize); + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + const int numConfigs = sizeof (configs) / sizeof (short[2]); + + jassertquiet (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); + + pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], state->sampleRate, samplesPerBlock); + #else + pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock); + #endif + + 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, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed) + { + // If the plugin has a bypass parameter, set it to the current bypass state + if (auto* param = pluginInstance->getBypassParameter()) + if (isBypassed != (param->getValue() >= 0.5f)) + param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f); + + for (int pos = 0; pos < bufferSize;) + { + auto max = jmin (bufferSize - pos, samplesPerBlock); + processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed); + + pos += max; + } + } + + void declareParameters (UnityAudioEffectDefinition& definition) + { + static std::unique_ptr parametersPtr; + static int numParams = 0; + + if (parametersPtr == nullptr) + { + numParams = (int) juceParameters.size(); + + parametersPtr.reset (static_cast (std::calloc (static_cast (numParams), + sizeof (UnityAudioParameterDefinition)))); + + parameterDescriptions.clear(); + + for (int i = 0; i < numParams; ++i) + { + auto* parameter = juceParameters.getParamForIndex (i); + auto& paramDef = parametersPtr.get()[i]; + + const auto nameLength = (size_t) numElementsInArray (paramDef.name); + const auto unitLength = (size_t) numElementsInArray (paramDef.unit); + + parameter->getName ((int) nameLength - 1).copyToUTF8 (paramDef.name, nameLength); + + if (parameter->getLabel().isNotEmpty()) + parameter->getLabel().copyToUTF8 (paramDef.unit, unitLength); + + parameterDescriptions.add (parameter->getName (15)); + paramDef.description = parameterDescriptions[i].toRawUTF8(); + + paramDef.defaultVal = parameter->getDefaultValue(); + paramDef.min = 0.0f; + paramDef.max = 1.0f; + paramDef.displayScale = 1.0f; + paramDef.displayExponent = 1.0f; + } + } + + definition.numParameters = static_cast (numParams); + definition.parameterDefintions = parametersPtr.get(); + } + + void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValueNotifyingHost (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 (pluginInstanceEditor->getPeer()); + + jassert (peer != nullptr); + return *peer; + } + +private: + //============================================================================== + void processBuffers (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed) + { + int ch; + for (ch = 0; ch < numInChannels; ++ch) + { + using DstSampleType = AudioData::Pointer; + using SrcSampleType = AudioData::Pointer; + + 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->getBypassParameter() == nullptr) + pluginInstance->processBlockBypassed (scratchBuffer, mb); + else + pluginInstance->processBlock (scratchBuffer, mb); + } + } + + for (ch = 0; ch < numOutChannels; ++ch) + { + using DstSampleType = AudioData::Pointer; + using SrcSampleType = AudioData::Pointer; + + DstSampleType dstData (outBuffer + ch, numOutChannels); + SrcSampleType srcData (scratchBuffer.getReadPointer (ch)); + dstData.convertSamples (srcData, bufferSize); + } + } + + //============================================================================== + std::unique_ptr pluginInstance; + std::unique_ptr pluginInstanceEditor; + + int samplesPerBlock = 1024; + StringArray parameterDescriptions; + + AudioBuffer scratchBuffer; + + LegacyAudioParametersWrapper juceParameters; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper) +}; + +//============================================================================== +static HashMap& getWrapperMap() +{ + static HashMap 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); +} + +//============================================================================== +static UnityAudioEffectDefinition getEffectDefinition() +{ + const auto wrapper = std::make_unique (true); + const String originalName { JucePlugin_Name }; + const auto name = (! originalName.startsWithIgnoreCase ("audioplugin") ? "audioplugin_" : "") + originalName; + + UnityAudioEffectDefinition result{}; + name.copyToUTF8 (result.name, (size_t) numElementsInArray (result.name)); + + result.structSize = sizeof (UnityAudioEffectDefinition); + result.parameterStructSize = sizeof (UnityAudioParameterDefinition); + + result.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION; + result.pluginVersion = JucePlugin_VersionCode; + + // effects must set this to 0, generators > 0 + result.channels = (wrapper->getNumInputChannels() != 0 ? 0 + : static_cast (wrapper->getNumOutputChannels())); + + wrapper->declareParameters (result); + + result.create = [] (UnityAudioEffectState* state) + { + auto* pluginInstance = new AudioProcessorUnityWrapper (false); + pluginInstance->create (state); + + state->effectData = pluginInstance; + + onWrapperCreation (pluginInstance); + + return 0; + }; + + result.release = [] (UnityAudioEffectState* state) + { + auto* pluginInstance = state->getEffectData(); + pluginInstance->release(); + + onWrapperDeletion (pluginInstance); + delete pluginInstance; + + if (getWrapperMap().size() == 0) + shutdownJuce_GUI(); + + return 0; + }; + + result.reset = [] (UnityAudioEffectState* state) + { + auto* pluginInstance = state->getEffectData(); + pluginInstance->reset(); + + return 0; + }; + + result.setPosition = [] (UnityAudioEffectState* state, unsigned int pos) + { + ignoreUnused (state, pos); + return 0; + }; + + result.process = [] (UnityAudioEffectState* state, + float* inBuffer, + float* outBuffer, + unsigned int bufferSize, + int numInChannels, + int numOutChannels) + { + auto* pluginInstance = state->getEffectData(); + + if (pluginInstance != nullptr) + { + auto isPlaying = ((state->flags & stateIsPlaying) != 0); + auto isMuted = ((state->flags & stateIsMuted) != 0); + auto isPaused = ((state->flags & stateIsPaused) != 0); + + const auto bypassed = ! isPlaying || (isMuted || isPaused); + pluginInstance->process (inBuffer, outBuffer, static_cast (bufferSize), numInChannels, numOutChannels, bypassed); + } + else + { + FloatVectorOperations::clear (outBuffer, static_cast (bufferSize) * numOutChannels); + } + + return 0; + }; + + result.setFloatParameter = [] (UnityAudioEffectState* state, int index, float value) + { + auto* pluginInstance = state->getEffectData(); + pluginInstance->setParameter (index, value); + + return 0; + }; + + result.getFloatParameter = [] (UnityAudioEffectState* state, int index, float* value, char* valueStr) + { + auto* pluginInstance = state->getEffectData(); + *value = pluginInstance->getParameter (index); + + pluginInstance->getParameterString (index).copyToUTF8 (valueStr, 15); + + return 0; + }; + + result.getFloatBuffer = [] (UnityAudioEffectState* state, const char* kind, float* buffer, int numSamples) + { + ignoreUnused (numSamples); + + const StringRef kindStr { kind }; + + if (kindStr == StringRef ("Editor")) + { + auto* pluginInstance = state->getEffectData(); + + buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f; + } + else if (kindStr == StringRef ("ID")) + { + auto* pluginInstance = state->getEffectData(); + + for (HashMap::Iterator i (getWrapperMap()); i.next();) + { + if (i.getValue() == pluginInstance) + { + buffer[0] = (float) i.getKey(); + break; + } + } + + return 0; + } + else if (kindStr == StringRef ("Size")) + { + auto* pluginInstance = state->getEffectData(); + + 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; + }; + + return result; +} + +} // namespace juce + +// From reading the example code, it seems that the triple indirection indicates +// an out-value of an array of pointers. That is, after calling this function, definitionsPtr +// should point to a pre-existing/static array of pointer-to-effect-definition. +UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr) +{ + if (juce::getWrapperMap().size() == 0) + juce::initialiseJuce_GUI(); + + static std::once_flag flag; + std::call_once (flag, [] { juce::juce_createUnityPeerFn = juce::createUnityPeer; }); + + static auto definition = juce::getEffectDefinition(); + static UnityAudioEffectDefinition* definitions[] { &definition }; + *definitionsPtr = definitions; + + 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 UNITY_INTERFACE_API unityInitialiseTexture (int id, void* data, int w, int h) +{ + getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast (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 + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + + extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) + { + if (reason == DLL_PROCESS_ATTACH) + juce::Process::setCurrentModuleInstanceHandle (instance); + + return true; + } + + JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp index befb88f10803..50b6c321dc06 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp @@ -23,4 +23,2186 @@ ============================================================================== */ -#include "VST/juce_VST_Wrapper.cpp" +#include +#include +#include + +#if JucePlugin_Build_VST + +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996 4100) + +#include +#include + +#if JucePlugin_VersionCode < 0x010000 // Major < 0 + + #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeds 9 + JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'minor' exceeding 9") + #endif + + #if (JucePlugin_VersionCode & 0xFF) > 9 // check if Bugfix number exceeds 9 + JUCE_COMPILER_WARNING ("When version has 'major' = 0, VST2 has trouble displaying 'bugfix' exceeding 9") + #endif + +#elif JucePlugin_VersionCode >= 0x650000 // Major >= 101 + + #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeds 99 + JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'minor' exceeding 99") + #endif + + #if (JucePlugin_VersionCode & 0xFF) > 99 // check if Bugfix number exceeds 99 + JUCE_COMPILER_WARNING ("When version has 'major' > 100, VST2 has trouble displaying 'bugfix' exceeding 99") + #endif + +#endif + +#ifdef PRAGMA_ALIGN_SUPPORTED + #undef PRAGMA_ALIGN_SUPPORTED + #define PRAGMA_ALIGN_SUPPORTED 1 +#endif + +#if ! JUCE_MSVC && ! defined (__cdecl) + #define __cdecl +#endif + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", + "-Wshadow", + "-Wdeprecated-register", + "-Wdeprecated-declarations", + "-Wunused-parameter", + "-Wdeprecated-writable-strings", + "-Wnon-virtual-dtor", + "-Wzero-as-null-pointer-constant") +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4458) + +#define VST_FORCE_DEPRECATED 0 + +namespace Vst2 +{ +// If the following files cannot be found then you are probably trying to build +// a VST2 plug-in or a VST2-compatible VST3 plug-in. To do this you must have a +// VST2 SDK in your header search paths or use the "VST (Legacy) SDK Folder" +// field in the Projucer. The VST2 SDK can be obtained from the +// vstsdk3610_11_06_2018_build_37 (or older) VST3 SDK or JUCE version 5.3.2. You +// also need a VST2 license from Steinberg to distribute VST2 plug-ins. +#include "pluginterfaces/vst2.x/aeffect.h" +#include "pluginterfaces/vst2.x/aeffectx.h" +} + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +//============================================================================== +#if JUCE_MSVC + #pragma pack (push, 8) +#endif + +#define JUCE_VSTINTERFACE_H_INCLUDED 1 +#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 + +#include + +using namespace juce; + +#include +#include +#include + +#include +#include + +#ifdef JUCE_MSVC + #pragma pack (pop) +#endif + +#undef MemoryBlock + +class JuceVSTWrapper; +static bool recursionCheck = false; + +namespace juce +{ + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + JUCE_API double getScaleFactorForWindow (HWND); + #endif +} + +//============================================================================== +#if JUCE_WINDOWS + +namespace +{ + // Returns the actual container window, unlike GetParent, which can also return a separate owner window. + static HWND getWindowParent (HWND w) noexcept { return GetAncestor (w, GA_PARENT); } + + static HWND findMDIParentOf (HWND w) + { + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + while (w != nullptr) + { + auto parent = getWindowParent (w); + + if (parent == nullptr) + break; + + TCHAR windowType[32] = { 0 }; + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase ("MDIClient")) + return parent; + + RECT windowPos, parentPos; + GetWindowRect (w, &windowPos); + GetWindowRect (parent, &parentPos); + + auto dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + auto dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + if (dw > 100 || dh > 100) + break; + + w = parent; + + if (dw == 2 * frameThickness) + break; + } + + return w; + } + + static int numActivePlugins = 0; + static bool messageThreadIsDefinitelyCorrect = false; +} + +#endif + +//============================================================================== +// Ableton Live host specific commands +struct AbletonLiveHostSpecific +{ + enum + { + KCantBeSuspended = (1 << 2) + }; + + uint32 magic; // 'AbLi' + int cmd; // 5 = realtime properties + size_t commandSize; // sizeof (int) + int flags; // KCantBeSuspended = (1 << 2) +}; + +//============================================================================== +/** + This is an AudioEffectX object that holds and wraps our AudioProcessor... +*/ +class JuceVSTWrapper : public AudioProcessorListener, + public AudioPlayHead, + private Timer, + private AudioProcessorParameter::Listener +{ +private: + //============================================================================== + template + struct VstTempBuffers + { + VstTempBuffers() {} + ~VstTempBuffers() { release(); } + + void release() noexcept + { + for (auto* c : tempChannels) + delete[] c; + + tempChannels.clear(); + } + + HeapBlock channels; + Array tempChannels; // see note in processReplacing() + juce::AudioBuffer processTempBuffer; + }; + + /** Use the same names as the VST SDK. */ + struct VstOpCodeArguments + { + int32 index; + pointer_sized_int value; + void* ptr; + float opt; + }; + +public: + //============================================================================== + JuceVSTWrapper (Vst2::audioMasterCallback cb, std::unique_ptr af) + : hostCallback (cb), + processor (std::move (af)) + { + inParameterChangedCallback = false; + + // VST-2 does not support disabling buses: so always enable all of them + processor->enableAllBuses(); + + findMaxTotalChannels (maxNumInChannels, maxNumOutChannels); + + // You must at least have some channels + jassert (processor->isMidiEffect() || (maxNumInChannels > 0 || maxNumOutChannels > 0)); + + if (processor->isMidiEffect()) + maxNumInChannels = maxNumOutChannels = 2; + + #ifdef JucePlugin_PreferredChannelConfigurations + processor->setPlayConfigDetails (maxNumInChannels, maxNumOutChannels, 44100.0, 1024); + #endif + + processor->setRateAndBufferSizeDetails (0, 0); + processor->setPlayHead (this); + processor->addListener (this); + + if (auto* juceParam = processor->getBypassParameter()) + juceParam->addListener (this); + + juceParameters.update (*processor, false); + + memset (&vstEffect, 0, sizeof (vstEffect)); + vstEffect.magic = 0x56737450 /* 'VstP' */; + vstEffect.dispatcher = (Vst2::AEffectDispatcherProc) dispatcherCB; + vstEffect.process = nullptr; + vstEffect.setParameter = (Vst2::AEffectSetParameterProc) setParameterCB; + vstEffect.getParameter = (Vst2::AEffectGetParameterProc) getParameterCB; + vstEffect.numPrograms = jmax (1, processor->getNumPrograms()); + vstEffect.numParams = juceParameters.getNumParameters(); + vstEffect.numInputs = maxNumInChannels; + vstEffect.numOutputs = maxNumOutChannels; + vstEffect.initialDelay = processor->getLatencySamples(); + vstEffect.object = this; + vstEffect.uniqueID = JucePlugin_VSTUniqueID; + + #ifdef JucePlugin_VSTChunkStructureVersion + vstEffect.version = JucePlugin_VSTChunkStructureVersion; + #else + vstEffect.version = JucePlugin_VersionCode; + #endif + + vstEffect.processReplacing = (Vst2::AEffectProcessProc) processReplacingCB; + vstEffect.processDoubleReplacing = (Vst2::AEffectProcessDoubleProc) processDoubleReplacingCB; + + vstEffect.flags |= Vst2::effFlagsHasEditor; + + vstEffect.flags |= Vst2::effFlagsCanReplacing; + if (processor->supportsDoublePrecisionProcessing()) + vstEffect.flags |= Vst2::effFlagsCanDoubleReplacing; + + vstEffect.flags |= Vst2::effFlagsProgramChunks; + + #if JucePlugin_IsSynth + vstEffect.flags |= Vst2::effFlagsIsSynth; + #else + if (processor->getTailLengthSeconds() == 0.0) + vstEffect.flags |= Vst2::effFlagsNoSoundInStop; + #endif + + #if JUCE_WINDOWS + ++numActivePlugins; + #endif + } + + ~JuceVSTWrapper() override + { + JUCE_AUTORELEASEPOOL + { + #if JUCE_LINUX || JUCE_BSD + MessageManagerLock mmLock; + #endif + + stopTimer(); + deleteEditor (false); + + hasShutdown = true; + + processor = nullptr; + + jassert (editorComp == nullptr); + + deleteTempChannels(); + + #if JUCE_WINDOWS + if (--numActivePlugins == 0) + messageThreadIsDefinitelyCorrect = false; + #endif + } + } + + Vst2::AEffect* getAEffect() noexcept { return &vstEffect; } + + template + void internalProcessReplacing (FloatType** inputs, FloatType** outputs, + int32 numSamples, VstTempBuffers& tmpBuffers) + { + const bool isMidiEffect = processor->isMidiEffect(); + + if (firstProcessCallback) + { + firstProcessCallback = false; + + // if this fails, the host hasn't called resume() before processing + jassert (isProcessing); + + // (tragically, some hosts actually need this, although it's stupid to have + // to do it here.) + if (! isProcessing) + resume(); + + processor->setNonRealtime (isProcessLevelOffline()); + + #if JUCE_WINDOWS + if (detail::PluginUtilities::getHostType().isWavelab()) + { + int priority = GetThreadPriority (GetCurrentThread()); + + if (priority <= THREAD_PRIORITY_NORMAL && priority >= THREAD_PRIORITY_LOWEST) + processor->setNonRealtime (true); + } + #endif + } + + #if JUCE_DEBUG && ! (JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect) + const int numMidiEventsComingIn = midiEvents.getNumEvents(); + #endif + + { + const int numIn = processor->getTotalNumInputChannels(); + const int numOut = processor->getTotalNumOutputChannels(); + + const ScopedLock sl (processor->getCallbackLock()); + + if (processor->isSuspended()) + { + for (int i = 0; i < numOut; ++i) + if (outputs[i] != nullptr) + FloatVectorOperations::clear (outputs[i], numSamples); + } + else + { + updateCallbackContextInfo(); + + int i; + for (i = 0; i < numOut; ++i) + { + auto* chan = tmpBuffers.tempChannels.getUnchecked(i); + + if (chan == nullptr) + { + chan = outputs[i]; + + bool bufferPointerReusedForOtherChannels = false; + + for (int j = i; --j >= 0;) + { + if (outputs[j] == chan) + { + bufferPointerReusedForOtherChannels = true; + break; + } + } + + // if some output channels are disabled, some hosts supply the same buffer + // for multiple channels or supply a nullptr - this buggers up our method + // of copying the inputs over the outputs, so we need to create unique temp + // buffers in this case.. + if (bufferPointerReusedForOtherChannels || chan == nullptr) + { + chan = new FloatType [(size_t) blockSize * 2]; + tmpBuffers.tempChannels.set (i, chan); + } + } + + if (i < numIn) + { + if (chan != inputs[i]) + memcpy (chan, inputs[i], (size_t) numSamples * sizeof (FloatType)); + } + else + { + FloatVectorOperations::clear (chan, numSamples); + } + + tmpBuffers.channels[i] = chan; + } + + for (; i < numIn; ++i) + tmpBuffers.channels[i] = inputs[i]; + + { + const int numChannels = jmax (numIn, numOut); + AudioBuffer chans (tmpBuffers.channels, isMidiEffect ? 0 : numChannels, numSamples); + + if (isBypassed && processor->getBypassParameter() == nullptr) + processor->processBlockBypassed (chans, midiEvents); + else + processor->processBlock (chans, midiEvents); + } + + // copy back any temp channels that may have been used.. + for (i = 0; i < numOut; ++i) + if (auto* chan = tmpBuffers.tempChannels.getUnchecked(i)) + if (auto* dest = outputs[i]) + memcpy (dest, chan, (size_t) numSamples * sizeof (FloatType)); + } + } + + if (! midiEvents.isEmpty()) + { + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + auto numEvents = midiEvents.getNumEvents(); + + outgoingEvents.ensureSize (numEvents); + outgoingEvents.clear(); + + for (const auto metadata : midiEvents) + { + jassert (metadata.samplePosition >= 0 && metadata.samplePosition < numSamples); + + outgoingEvents.addEvent (metadata.data, metadata.numBytes, metadata.samplePosition); + } + + // Send VST events to the host. + if (hostCallback != nullptr) + hostCallback (&vstEffect, Vst2::audioMasterProcessEvents, 0, 0, outgoingEvents.events, 0); + #elif JUCE_DEBUG + /* This assertion is caused when you've added some events to the + midiMessages array in your processBlock() method, which usually means + that you're trying to send them somewhere. But in this case they're + getting thrown away. + + If your plugin does want to send midi messages, you'll need to set + the JucePlugin_ProducesMidiOutput macro to 1 in your + JucePluginCharacteristics.h file. + + If you don't want to produce any midi output, then you should clear the + midiMessages array at the end of your processBlock() method, to + indicate that you don't want any of the events to be passed through + to the output. + */ + jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); + #endif + + midiEvents.clear(); + } + } + + void processReplacing (float** inputs, float** outputs, int32 sampleFrames) + { + jassert (! processor->isUsingDoublePrecision()); + internalProcessReplacing (inputs, outputs, sampleFrames, floatTempBuffers); + } + + static void processReplacingCB (Vst2::AEffect* vstInterface, float** inputs, float** outputs, int32 sampleFrames) + { + getWrapper (vstInterface)->processReplacing (inputs, outputs, sampleFrames); + } + + void processDoubleReplacing (double** inputs, double** outputs, int32 sampleFrames) + { + jassert (processor->isUsingDoublePrecision()); + internalProcessReplacing (inputs, outputs, sampleFrames, doubleTempBuffers); + } + + static void processDoubleReplacingCB (Vst2::AEffect* vstInterface, double** inputs, double** outputs, int32 sampleFrames) + { + getWrapper (vstInterface)->processDoubleReplacing (inputs, outputs, sampleFrames); + } + + //============================================================================== + void resume() + { + if (processor != nullptr) + { + isProcessing = true; + + auto numInAndOutChannels = static_cast (vstEffect.numInputs + vstEffect.numOutputs); + floatTempBuffers .channels.calloc (numInAndOutChannels); + doubleTempBuffers.channels.calloc (numInAndOutChannels); + + auto currentRate = sampleRate; + auto currentBlockSize = blockSize; + + firstProcessCallback = true; + + processor->setNonRealtime (isProcessLevelOffline()); + processor->setRateAndBufferSizeDetails (currentRate, currentBlockSize); + + deleteTempChannels(); + + processor->prepareToPlay (currentRate, currentBlockSize); + + midiEvents.ensureSize (2048); + midiEvents.clear(); + + vstEffect.initialDelay = processor->getLatencySamples(); + + /** If this plug-in is a synth or it can receive midi events we need to tell the + host that we want midi. In the SDK this method is marked as deprecated, but + some hosts rely on this behaviour. + */ + if (vstEffect.flags & Vst2::effFlagsIsSynth || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect) + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, Vst2::audioMasterWantMidi, 0, 1, nullptr, 0); + } + + if (detail::PluginUtilities::getHostType().isAbletonLive() + && hostCallback != nullptr + && std::isinf (processor->getTailLengthSeconds())) + { + AbletonLiveHostSpecific hostCmd; + + hostCmd.magic = 0x41624c69; // 'AbLi' + hostCmd.cmd = 5; + hostCmd.commandSize = sizeof (int); + hostCmd.flags = AbletonLiveHostSpecific::KCantBeSuspended; + + hostCallback (&vstEffect, Vst2::audioMasterVendorSpecific, 0, 0, &hostCmd, 0.0f); + } + + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + outgoingEvents.ensureSize (512); + #endif + } + } + + void suspend() + { + if (processor != nullptr) + { + processor->releaseResources(); + outgoingEvents.freeEvents(); + + isProcessing = false; + floatTempBuffers.channels.free(); + doubleTempBuffers.channels.free(); + + deleteTempChannels(); + } + } + + void updateCallbackContextInfo() + { + const Vst2::VstTimeInfo* ti = nullptr; + + if (hostCallback != nullptr) + { + int32 flags = Vst2::kVstPpqPosValid | Vst2::kVstTempoValid + | Vst2::kVstBarsValid | Vst2::kVstCyclePosValid + | Vst2::kVstTimeSigValid | Vst2::kVstSmpteValid + | Vst2::kVstClockValid | Vst2::kVstNanosValid; + + auto result = hostCallback (&vstEffect, Vst2::audioMasterGetTime, 0, flags, nullptr, 0); + ti = reinterpret_cast (result); + } + + if (ti == nullptr || ti->sampleRate <= 0) + { + currentPosition.reset(); + return; + } + + auto& info = currentPosition.emplace(); + info.setBpm ((ti->flags & Vst2::kVstTempoValid) != 0 ? makeOptional (ti->tempo) : nullopt); + + info.setTimeSignature ((ti->flags & Vst2::kVstTimeSigValid) != 0 ? makeOptional (TimeSignature { ti->timeSigNumerator, ti->timeSigDenominator }) + : nullopt); + + info.setTimeInSamples ((int64) (ti->samplePos + 0.5)); + info.setTimeInSeconds (ti->samplePos / ti->sampleRate); + info.setPpqPosition ((ti->flags & Vst2::kVstPpqPosValid) != 0 ? makeOptional (ti->ppqPos) : nullopt); + info.setPpqPositionOfLastBarStart ((ti->flags & Vst2::kVstBarsValid) != 0 ? makeOptional (ti->barStartPos) : nullopt); + + if ((ti->flags & Vst2::kVstSmpteValid) != 0) + { + info.setFrameRate ([&]() -> Optional + { + switch (ti->smpteFrameRate) + { + case Vst2::kVstSmpte24fps: return FrameRate().withBaseRate (24); + case Vst2::kVstSmpte239fps: return FrameRate().withBaseRate (24).withPullDown(); + + case Vst2::kVstSmpte25fps: return FrameRate().withBaseRate (25); + case Vst2::kVstSmpte249fps: return FrameRate().withBaseRate (25).withPullDown(); + + case Vst2::kVstSmpte30fps: return FrameRate().withBaseRate (30); + case Vst2::kVstSmpte30dfps: return FrameRate().withBaseRate (30).withDrop(); + case Vst2::kVstSmpte2997fps: return FrameRate().withBaseRate (30).withPullDown(); + case Vst2::kVstSmpte2997dfps: return FrameRate().withBaseRate (30).withPullDown().withDrop(); + + case Vst2::kVstSmpte60fps: return FrameRate().withBaseRate (60); + case Vst2::kVstSmpte599fps: return FrameRate().withBaseRate (60).withPullDown(); + + case Vst2::kVstSmpteFilm16mm: + case Vst2::kVstSmpteFilm35mm: return FrameRate().withBaseRate (24); + } + + return nullopt; + }()); + + const auto effectiveRate = info.getFrameRate().hasValue() ? info.getFrameRate()->getEffectiveRate() : 0.0; + info.setEditOriginTime (! approximatelyEqual (effectiveRate, 0.0) ? makeOptional (ti->smpteOffset / (80.0 * effectiveRate)) : nullopt); + } + + info.setIsRecording ((ti->flags & Vst2::kVstTransportRecording) != 0); + info.setIsPlaying ((ti->flags & (Vst2::kVstTransportRecording | Vst2::kVstTransportPlaying)) != 0); + info.setIsLooping ((ti->flags & Vst2::kVstTransportCycleActive) != 0); + + info.setLoopPoints ((ti->flags & Vst2::kVstCyclePosValid) != 0 ? makeOptional (LoopPoints { ti->cycleStartPos, ti->cycleEndPos }) + : nullopt); + + info.setHostTimeNs ((ti->flags & Vst2::kVstNanosValid) != 0 ? makeOptional ((uint64_t) ti->nanoSeconds) : nullopt); + } + + //============================================================================== + Optional getPosition() const override + { + return currentPosition; + } + + //============================================================================== + float getParameter (int32 index) const + { + if (auto* param = juceParameters.getParamForIndex (index)) + return param->getValue(); + + return 0.0f; + } + + static float getParameterCB (Vst2::AEffect* vstInterface, int32 index) + { + return getWrapper (vstInterface)->getParameter (index); + } + + void setParameter (int32 index, float value) + { + if (auto* param = juceParameters.getParamForIndex (index)) + setValueAndNotifyIfChanged (*param, value); + } + + static void setParameterCB (Vst2::AEffect* vstInterface, int32 index, float value) + { + getWrapper (vstInterface)->setParameter (index, value); + } + + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override + { + if (inParameterChangedCallback.get()) + { + inParameterChangedCallback = false; + return; + } + + if (hostCallback != nullptr) + hostCallback (&vstEffect, Vst2::audioMasterAutomate, index, 0, nullptr, newValue); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, Vst2::audioMasterBeginEdit, index, 0, nullptr, 0); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, Vst2::audioMasterEndEdit, index, 0, nullptr, 0); + } + + void parameterValueChanged (int, float newValue) override + { + // this can only come from the bypass parameter + isBypassed = (newValue >= 0.5f); + } + + void parameterGestureChanged (int, bool) override {} + + void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override + { + hostChangeUpdater.update (details); + } + + bool getPinProperties (Vst2::VstPinProperties& properties, bool direction, int index) const + { + if (processor->isMidiEffect()) + return false; + + int channelIdx, busIdx; + + // fill with default + properties.flags = 0; + properties.label[0] = 0; + properties.shortLabel[0] = 0; + properties.arrangementType = Vst2::kSpeakerArrEmpty; + + if ((channelIdx = processor->getOffsetInBusBufferForAbsoluteChannelIndex (direction, index, busIdx)) >= 0) + { + auto& bus = *processor->getBus (direction, busIdx); + auto& channelSet = bus.getCurrentLayout(); + auto channelType = channelSet.getTypeOfChannel (channelIdx); + + properties.flags = Vst2::kVstPinIsActive | Vst2::kVstPinUseSpeaker; + properties.arrangementType = SpeakerMappings::channelSetToVstArrangementType (channelSet); + String label = bus.getName(); + + #ifdef JucePlugin_PreferredChannelConfigurations + label += " " + String (channelIdx); + #else + if (channelSet.size() > 1) + label += " " + AudioChannelSet::getAbbreviatedChannelTypeName (channelType); + #endif + + label.copyToUTF8 (properties.label, (size_t) (Vst2::kVstMaxLabelLen + 1)); + label.copyToUTF8 (properties.shortLabel, (size_t) (Vst2::kVstMaxShortLabelLen + 1)); + + if (channelType == AudioChannelSet::left + || channelType == AudioChannelSet::leftSurround + || channelType == AudioChannelSet::leftCentre + || channelType == AudioChannelSet::leftSurroundSide + || channelType == AudioChannelSet::topFrontLeft + || channelType == AudioChannelSet::topRearLeft + || channelType == AudioChannelSet::leftSurroundRear + || channelType == AudioChannelSet::wideLeft) + properties.flags |= Vst2::kVstPinIsStereo; + + return true; + } + + return false; + } + + //============================================================================== + void timerCallback() override + { + if (shouldDeleteEditor) + { + shouldDeleteEditor = false; + deleteEditor (true); + } + + { + ScopedLock lock (stateInformationLock); + + if (chunkMemoryTime > 0 + && chunkMemoryTime < juce::Time::getApproximateMillisecondCounter() - 2000 + && ! recursionCheck) + { + chunkMemory.reset(); + chunkMemoryTime = 0; + } + } + } + + void setHasEditorFlag (bool shouldSetHasEditor) + { + auto hasEditor = (vstEffect.flags & Vst2::effFlagsHasEditor) != 0; + + if (shouldSetHasEditor == hasEditor) + return; + + if (shouldSetHasEditor) + vstEffect.flags |= Vst2::effFlagsHasEditor; + else + vstEffect.flags &= ~Vst2::effFlagsHasEditor; + } + + void createEditorComp() + { + if (hasShutdown || processor == nullptr) + return; + + if (editorComp == nullptr) + { + if (auto* ed = processor->createEditorIfNeeded()) + { + setHasEditorFlag (true); + editorComp.reset (new EditorCompWrapper (*this, *ed, editorScaleFactor)); + } + else + { + setHasEditorFlag (false); + } + } + + shouldDeleteEditor = false; + } + + void deleteEditor (bool canDeleteLaterIfModal) + { + JUCE_AUTORELEASEPOOL + { + PopupMenu::dismissAllActiveMenus(); + + jassert (! recursionCheck); + ScopedValueSetter svs (recursionCheck, true, false); + + if (editorComp != nullptr) + { + if (auto* modalComponent = Component::getCurrentlyModalComponent()) + { + modalComponent->exitModalState (0); + + if (canDeleteLaterIfModal) + { + shouldDeleteEditor = true; + return; + } + } + + editorComp->detachHostWindow(); + + if (auto* ed = editorComp->getEditorComp()) + processor->editorBeingDeleted (ed); + + editorComp = nullptr; + + // there's some kind of component currently modal, but the host + // is trying to delete our plugin. You should try to avoid this happening.. + jassert (Component::getCurrentlyModalComponent() == nullptr); + } + } + } + + pointer_sized_int dispatcher (int32 opCode, VstOpCodeArguments args) + { + if (hasShutdown) + return 0; + + switch (opCode) + { + case Vst2::effOpen: return handleOpen (args); + case Vst2::effClose: return handleClose (args); + case Vst2::effSetProgram: return handleSetCurrentProgram (args); + case Vst2::effGetProgram: return handleGetCurrentProgram (args); + case Vst2::effSetProgramName: return handleSetCurrentProgramName (args); + case Vst2::effGetProgramName: return handleGetCurrentProgramName (args); + case Vst2::effGetParamLabel: return handleGetParameterLabel (args); + case Vst2::effGetParamDisplay: return handleGetParameterText (args); + case Vst2::effGetParamName: return handleGetParameterName (args); + case Vst2::effSetSampleRate: return handleSetSampleRate (args); + case Vst2::effSetBlockSize: return handleSetBlockSize (args); + case Vst2::effMainsChanged: return handleResumeSuspend (args); + case Vst2::effEditGetRect: return handleGetEditorBounds (args); + case Vst2::effEditOpen: return handleOpenEditor (args); + case Vst2::effEditClose: return handleCloseEditor (args); + case Vst2::effIdentify: return (pointer_sized_int) ByteOrder::bigEndianInt ("NvEf"); + case Vst2::effGetChunk: return handleGetData (args); + case Vst2::effSetChunk: return handleSetData (args); + case Vst2::effProcessEvents: return handlePreAudioProcessingEvents (args); + case Vst2::effCanBeAutomated: return handleIsParameterAutomatable (args); + case Vst2::effString2Parameter: return handleParameterValueForText (args); + case Vst2::effGetProgramNameIndexed: return handleGetProgramName (args); + case Vst2::effGetInputProperties: return handleGetInputPinProperties (args); + case Vst2::effGetOutputProperties: return handleGetOutputPinProperties (args); + case Vst2::effGetPlugCategory: return handleGetPlugInCategory (args); + case Vst2::effSetSpeakerArrangement: return handleSetSpeakerConfiguration (args); + case Vst2::effSetBypass: return handleSetBypass (args); + case Vst2::effGetEffectName: return handleGetPlugInName (args); + case Vst2::effGetProductString: return handleGetPlugInName (args); + case Vst2::effGetVendorString: return handleGetManufacturerName (args); + case Vst2::effGetVendorVersion: return handleGetManufacturerVersion (args); + case Vst2::effVendorSpecific: return handleManufacturerSpecific (args); + case Vst2::effCanDo: return handleCanPlugInDo (args); + case Vst2::effGetTailSize: return handleGetTailSize (args); + case Vst2::effKeysRequired: return handleKeyboardFocusRequired (args); + case Vst2::effGetVstVersion: return handleGetVstInterfaceVersion (args); + case Vst2::effGetCurrentMidiProgram: return handleGetCurrentMidiProgram (args); + case Vst2::effGetSpeakerArrangement: return handleGetSpeakerConfiguration (args); + case Vst2::effSetTotalSampleToProcess: return handleSetNumberOfSamplesToProcess (args); + case Vst2::effSetProcessPrecision: return handleSetSampleFloatType (args); + case Vst2::effGetNumMidiInputChannels: return handleGetNumMidiInputChannels(); + case Vst2::effGetNumMidiOutputChannels: return handleGetNumMidiOutputChannels(); + case Vst2::effEditIdle: return handleEditIdle(); + default: return 0; + } + } + + static pointer_sized_int dispatcherCB (Vst2::AEffect* vstInterface, int32 opCode, int32 index, + pointer_sized_int value, void* ptr, float opt) + { + auto* wrapper = getWrapper (vstInterface); + VstOpCodeArguments args = { index, value, ptr, opt }; + + if (opCode == Vst2::effClose) + { + wrapper->dispatcher (opCode, args); + delete wrapper; + return 1; + } + + return wrapper->dispatcher (opCode, args); + } + + //============================================================================== + // A component to hold the AudioProcessorEditor, and cope with some housekeeping + // chores when it changes or repaints. + struct EditorCompWrapper : public Component + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + , public Timer + #endif + { + EditorCompWrapper (JuceVSTWrapper& w, AudioProcessorEditor& editor, [[maybe_unused]] float initialScale) + : wrapper (w) + { + editor.setOpaque (true); + #if ! JUCE_MAC + editor.setScaleFactor (initialScale); + #endif + addAndMakeVisible (editor); + + auto editorBounds = getSizeToContainChild(); + setSize (editorBounds.getWidth(), editorBounds.getHeight()); + + #if JUCE_WINDOWS + if (! detail::PluginUtilities::getHostType().isReceptor()) + addMouseListener (this, true); + #endif + + setOpaque (true); + } + + ~EditorCompWrapper() override + { + deleteAllChildren(); // note that we can't use a std::unique_ptr because the editor may + // have been transferred to another parent which takes over ownership. + } + + void paint (Graphics& g) override + { + g.fillAll (Colours::black); + } + + void getEditorBounds (Vst2::ERect& bounds) + { + auto editorBounds = getSizeToContainChild(); + bounds = convertToHostBounds ({ 0, 0, (int16) editorBounds.getHeight(), (int16) editorBounds.getWidth() }); + } + + void attachToHost (VstOpCodeArguments args) + { + setVisible (false); + + const auto desktopFlags = detail::PluginUtilities::getDesktopFlags (getEditorComp()); + + #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD + addToDesktop (desktopFlags, args.ptr); + hostWindow = (HostWindowType) args.ptr; + + #if JUCE_LINUX || JUCE_BSD + X11Symbols::getInstance()->xReparentWindow (display, + (Window) getWindowHandle(), + (HostWindowType) hostWindow, + 0, 0); + // The host is likely to attempt to move/resize the window directly after this call, + // and we need to ensure that the X server knows that our window has been attached + // before that happens. + X11Symbols::getInstance()->xFlush (display); + #elif JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + checkHostWindowScaleFactor (true); + startTimer (500); + #endif + #elif JUCE_MAC + hostWindow = detail::VSTWindowUtilities::attachComponentToWindowRefVST (this, desktopFlags, args.ptr); + #endif + + setVisible (true); + } + + void detachHostWindow() + { + #if JUCE_MAC + if (hostWindow != nullptr) + detail::VSTWindowUtilities::detachComponentFromWindowRefVST (this, hostWindow); + #endif + + hostWindow = {}; + } + + AudioProcessorEditor* getEditorComp() const noexcept + { + return dynamic_cast (getChildComponent (0)); + } + + void resized() override + { + if (auto* pluginEditor = getEditorComp()) + { + if (! resizingParent) + { + auto newBounds = getLocalBounds(); + + { + const ScopedValueSetter resizingChildSetter (resizingChild, true); + pluginEditor->setBounds (pluginEditor->getLocalArea (this, newBounds).withPosition (0, 0)); + } + + lastBounds = newBounds; + } + + updateWindowSize(); + } + } + + void parentSizeChanged() override + { + updateWindowSize(); + repaint(); + } + + void childBoundsChanged (Component*) override + { + if (resizingChild) + return; + + auto newBounds = getSizeToContainChild(); + + if (newBounds != lastBounds) + { + updateWindowSize(); + lastBounds = newBounds; + } + } + + juce::Rectangle getSizeToContainChild() + { + if (auto* pluginEditor = getEditorComp()) + return getLocalArea (pluginEditor, pluginEditor->getLocalBounds()); + + return {}; + } + + void resizeHostWindow (juce::Rectangle bounds) + { + auto rect = convertToHostBounds ({ 0, 0, (int16) bounds.getHeight(), (int16) bounds.getWidth() }); + const auto newWidth = rect.right - rect.left; + const auto newHeight = rect.bottom - rect.top; + + bool sizeWasSuccessful = false; + + if (auto host = wrapper.hostCallback) + { + auto status = host (wrapper.getAEffect(), Vst2::audioMasterCanDo, 0, 0, const_cast ("sizeWindow"), 0); + + if (status == (pointer_sized_int) 1 || detail::PluginUtilities::getHostType().isAbletonLive()) + { + const ScopedValueSetter resizingParentSetter (resizingParent, true); + + sizeWasSuccessful = (host (wrapper.getAEffect(), Vst2::audioMasterSizeWindow, + newWidth, newHeight, nullptr, 0) != 0); + } + } + + // some hosts don't support the sizeWindow call, so do it manually.. + if (! sizeWasSuccessful) + { + const ScopedValueSetter resizingParentSetter (resizingParent, true); + + #if JUCE_MAC + detail::VSTWindowUtilities::setNativeHostWindowSizeVST (hostWindow, this, newWidth, newHeight); + #elif JUCE_LINUX || JUCE_BSD + // (Currently, all linux hosts support sizeWindow, so this should never need to happen) + setSize (newWidth, newHeight); + #else + int dw = 0; + int dh = 0; + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + HWND w = (HWND) getWindowHandle(); + + while (w != nullptr) + { + HWND parent = getWindowParent (w); + + if (parent == nullptr) + break; + + TCHAR windowType [32] = { 0 }; + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase ("MDIClient")) + break; + + RECT windowPos, parentPos; + GetWindowRect (w, &windowPos); + GetWindowRect (parent, &parentPos); + + if (w != (HWND) getWindowHandle()) + SetWindowPos (w, nullptr, 0, 0, newWidth + dw, newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); + + dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + w = parent; + + if (dw == 2 * frameThickness) + break; + + if (dw > 100 || dh > 100) + w = nullptr; + } + + if (w != nullptr) + SetWindowPos (w, nullptr, 0, 0, newWidth + dw, newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); + #endif + } + + #if JUCE_LINUX || JUCE_BSD + X11Symbols::getInstance()->xResizeWindow (display, (Window) getWindowHandle(), + static_cast (rect.right - rect.left), + static_cast (rect.bottom - rect.top)); + #endif + } + + void setContentScaleFactor (float scale) + { + if (auto* pluginEditor = getEditorComp()) + { + auto prevEditorBounds = pluginEditor->getLocalArea (this, lastBounds); + + { + const ScopedValueSetter resizingChildSetter (resizingChild, true); + + pluginEditor->setScaleFactor (scale); + pluginEditor->setBounds (prevEditorBounds.withPosition (0, 0)); + } + + lastBounds = getSizeToContainChild(); + updateWindowSize(); + } + } + + #if JUCE_WINDOWS + void mouseDown (const MouseEvent&) override + { + broughtToFront(); + } + + void broughtToFront() override + { + // for hosts like nuendo, need to also pop the MDI container to the + // front when our comp is clicked on. + if (! isCurrentlyBlockedByAnotherModalComponent()) + if (HWND parent = findMDIParentOf ((HWND) getWindowHandle())) + SetWindowPos (parent, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + + #if JUCE_WIN_PER_MONITOR_DPI_AWARE + void checkHostWindowScaleFactor (bool force = false) + { + auto hostWindowScale = (float) getScaleFactorForWindow ((HostWindowType) hostWindow); + + if (force || (hostWindowScale > 0.0f && ! approximatelyEqual (hostWindowScale, wrapper.editorScaleFactor))) + wrapper.handleSetContentScaleFactor (hostWindowScale, force); + } + + void timerCallback() override + { + checkHostWindowScaleFactor(); + } + #endif + #endif + + private: + void updateWindowSize() + { + if (! resizingParent + && getEditorComp() != nullptr + && hostWindow != HostWindowType{}) + { + const auto editorBounds = getSizeToContainChild(); + resizeHostWindow (editorBounds); + + { + const ScopedValueSetter resizingParentSetter (resizingParent, true); + + // setSize() on linux causes renoise and energyxt to fail. + // We'll resize our peer during resizeHostWindow() instead. + #if ! (JUCE_LINUX || JUCE_BSD) + setSize (editorBounds.getWidth(), editorBounds.getHeight()); + #endif + + if (auto* p = getPeer()) + p->updateBounds(); + } + + #if JUCE_MAC + resizeHostWindow (editorBounds); // (doing this a second time seems to be necessary in tracktion) + #endif + } + } + + //============================================================================== + static Vst2::ERect convertToHostBounds (const Vst2::ERect& rect) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return rect; + + return { (int16) roundToInt (rect.top * desktopScale), + (int16) roundToInt (rect.left * desktopScale), + (int16) roundToInt (rect.bottom * desktopScale), + (int16) roundToInt (rect.right * desktopScale) }; + } + + //============================================================================== + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostEventLoop; + #endif + + //============================================================================== + JuceVSTWrapper& wrapper; + bool resizingChild = false, resizingParent = false; + + juce::Rectangle lastBounds; + + #if JUCE_LINUX || JUCE_BSD + using HostWindowType = ::Window; + ::Display* display = XWindowSystem::getInstance()->getDisplay(); + #elif JUCE_WINDOWS + using HostWindowType = HWND; + detail::WindowsHooks hooks; + #else + using HostWindowType = void*; + #endif + + HostWindowType hostWindow = {}; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EditorCompWrapper) + }; + + //============================================================================== +private: + struct HostChangeUpdater : private AsyncUpdater + { + explicit HostChangeUpdater (JuceVSTWrapper& o) : owner (o) {} + ~HostChangeUpdater() override { cancelPendingUpdate(); } + + void update (const ChangeDetails& details) + { + if (details.latencyChanged) + { + owner.vstEffect.initialDelay = owner.processor->getLatencySamples(); + callbackBits |= audioMasterIOChangedBit; + } + + if (details.parameterInfoChanged || details.programChanged) + callbackBits |= audioMasterUpdateDisplayBit; + + triggerAsyncUpdate(); + } + + private: + void handleAsyncUpdate() override + { + const auto callbacksToFire = callbackBits.exchange (0); + + if (auto* callback = owner.hostCallback) + { + struct FlagPair + { + Vst2::AudioMasterOpcodesX opcode; + int bit; + }; + + constexpr FlagPair pairs[] { { Vst2::audioMasterUpdateDisplay, audioMasterUpdateDisplayBit }, + { Vst2::audioMasterIOChanged, audioMasterIOChangedBit } }; + + for (const auto& pair : pairs) + if ((callbacksToFire & pair.bit) != 0) + callback (&owner.vstEffect, pair.opcode, 0, 0, nullptr, 0); + } + } + + static constexpr auto audioMasterUpdateDisplayBit = 1 << 0; + static constexpr auto audioMasterIOChangedBit = 1 << 1; + + JuceVSTWrapper& owner; + std::atomic callbackBits { 0 }; + }; + + static JuceVSTWrapper* getWrapper (Vst2::AEffect* v) noexcept { return static_cast (v->object); } + + bool isProcessLevelOffline() + { + return hostCallback != nullptr + && (int32) hostCallback (&vstEffect, Vst2::audioMasterGetCurrentProcessLevel, 0, 0, nullptr, 0) == 4; + } + + static int32 convertHexVersionToDecimal (const unsigned int hexVersion) + { + #if JUCE_VST_RETURN_HEX_VERSION_NUMBER_DIRECTLY + return (int32) hexVersion; + #else + // Currently, only Cubase displays the version number to the user + // We are hoping here that when other DAWs start to display the version + // number, that they do so according to yfede's encoding table in the link + // below. If not, then this code will need an if (isSteinberg()) in the + // future. + int major = (hexVersion >> 16) & 0xff; + int minor = (hexVersion >> 8) & 0xff; + int bugfix = hexVersion & 0xff; + + // for details, see: https://forum.juce.com/t/issues-with-version-integer-reported-by-vst2/23867 + + // Encoding B + if (major < 1) + return major * 1000 + minor * 100 + bugfix * 10; + + // Encoding E + if (major > 100) + return major * 10000000 + minor * 100000 + bugfix * 1000; + + // Encoding D + return static_cast (hexVersion); + #endif + } + + //============================================================================== + #if JUCE_WINDOWS + // Workarounds for hosts which attempt to open editor windows on a non-GUI thread.. (Grrrr...) + static void checkWhetherMessageThreadIsCorrect() + { + auto host = detail::PluginUtilities::getHostType(); + + if (host.isWavelab() || host.isCubaseBridged() || host.isPremiere()) + { + if (! messageThreadIsDefinitelyCorrect) + { + MessageManager::getInstance()->setCurrentThreadAsMessageThread(); + + struct MessageThreadCallback : public CallbackMessage + { + MessageThreadCallback (bool& tr) : triggered (tr) {} + void messageCallback() override { triggered = true; } + + bool& triggered; + }; + + (new MessageThreadCallback (messageThreadIsDefinitelyCorrect))->post(); + } + } + } + #else + static void checkWhetherMessageThreadIsCorrect() {} + #endif + + void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) + { + if (approximatelyEqual (param.getValue(), newValue)) + return; + + inParameterChangedCallback = true; + param.setValueNotifyingHost (newValue); + } + + //============================================================================== + template + void deleteTempChannels (VstTempBuffers& tmpBuffers) + { + tmpBuffers.release(); + + if (processor != nullptr) + tmpBuffers.tempChannels.insertMultiple (0, nullptr, vstEffect.numInputs + + vstEffect.numOutputs); + } + + void deleteTempChannels() + { + deleteTempChannels (floatTempBuffers); + deleteTempChannels (doubleTempBuffers); + } + + //============================================================================== + void findMaxTotalChannels (int& maxTotalIns, int& maxTotalOuts) + { + #ifdef JucePlugin_PreferredChannelConfigurations + int configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + maxTotalIns = maxTotalOuts = 0; + + for (auto& config : configs) + { + maxTotalIns = jmax (maxTotalIns, config[0]); + maxTotalOuts = jmax (maxTotalOuts, config[1]); + } + #else + auto numInputBuses = processor->getBusCount (true); + auto numOutputBuses = processor->getBusCount (false); + + if (numInputBuses > 1 || numOutputBuses > 1) + { + maxTotalIns = maxTotalOuts = 0; + + for (int i = 0; i < numInputBuses; ++i) + maxTotalIns += processor->getChannelCountOfBus (true, i); + + for (int i = 0; i < numOutputBuses; ++i) + maxTotalOuts += processor->getChannelCountOfBus (false, i); + } + else + { + maxTotalIns = numInputBuses > 0 ? processor->getBus (true, 0)->getMaxSupportedChannels (64) : 0; + maxTotalOuts = numOutputBuses > 0 ? processor->getBus (false, 0)->getMaxSupportedChannels (64) : 0; + } + #endif + } + + bool pluginHasSidechainsOrAuxs() const { return (processor->getBusCount (true) > 1 || processor->getBusCount (false) > 1); } + + //============================================================================== + /** Host to plug-in calls. */ + + pointer_sized_int handleOpen (VstOpCodeArguments) + { + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. + setHasEditorFlag (processor->hasEditor()); + + return 0; + } + + pointer_sized_int handleClose (VstOpCodeArguments) + { + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. + stopTimer(); + + if (MessageManager::getInstance()->isThisTheMessageThread()) + deleteEditor (false); + + return 0; + } + + pointer_sized_int handleSetCurrentProgram (VstOpCodeArguments args) + { + if (processor != nullptr && isPositiveAndBelow ((int) args.value, processor->getNumPrograms())) + processor->setCurrentProgram ((int) args.value); + + return 0; + } + + pointer_sized_int handleGetCurrentProgram (VstOpCodeArguments) + { + return (processor != nullptr && processor->getNumPrograms() > 0 ? processor->getCurrentProgram() : 0); + } + + pointer_sized_int handleSetCurrentProgramName (VstOpCodeArguments args) + { + if (processor != nullptr && processor->getNumPrograms() > 0) + processor->changeProgramName (processor->getCurrentProgram(), (char*) args.ptr); + + return 0; + } + + pointer_sized_int handleGetCurrentProgramName (VstOpCodeArguments args) + { + if (processor != nullptr && processor->getNumPrograms() > 0) + processor->getProgramName (processor->getCurrentProgram()).copyToUTF8 ((char*) args.ptr, 24 + 1); + + return 0; + } + + pointer_sized_int handleGetParameterLabel (VstOpCodeArguments args) + { + if (auto* param = juceParameters.getParamForIndex (args.index)) + { + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + param->getLabel().copyToUTF8 ((char*) args.ptr, 24 + 1); + } + + return 0; + } + + pointer_sized_int handleGetParameterText (VstOpCodeArguments args) + { + if (auto* param = juceParameters.getParamForIndex (args.index)) + { + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + param->getCurrentValueAsText().copyToUTF8 ((char*) args.ptr, 24 + 1); + } + + return 0; + } + + pointer_sized_int handleGetParameterName (VstOpCodeArguments args) + { + if (auto* param = juceParameters.getParamForIndex (args.index)) + { + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + param->getName (32).copyToUTF8 ((char*) args.ptr, 32 + 1); + } + + return 0; + } + + pointer_sized_int handleSetSampleRate (VstOpCodeArguments args) + { + sampleRate = args.opt; + return 0; + } + + pointer_sized_int handleSetBlockSize (VstOpCodeArguments args) + { + blockSize = (int32) args.value; + return 0; + } + + pointer_sized_int handleResumeSuspend (VstOpCodeArguments args) + { + if (args.value) + resume(); + else + suspend(); + + return 0; + } + + pointer_sized_int handleGetEditorBounds (VstOpCodeArguments args) + { + checkWhetherMessageThreadIsCorrect(); + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + #else + const MessageManagerLock mmLock; + #endif + createEditorComp(); + + if (editorComp != nullptr) + { + editorComp->getEditorBounds (editorRect); + *((Vst2::ERect**) args.ptr) = &editorRect; + return (pointer_sized_int) &editorRect; + } + + return 0; + } + + pointer_sized_int handleOpenEditor (VstOpCodeArguments args) + { + checkWhetherMessageThreadIsCorrect(); + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + #else + const MessageManagerLock mmLock; + #endif + jassert (! recursionCheck); + + startTimerHz (4); // performs misc housekeeping chores + + deleteEditor (true); + createEditorComp(); + + if (editorComp != nullptr) + { + editorComp->attachToHost (args); + return 1; + } + + return 0; + } + + pointer_sized_int handleCloseEditor (VstOpCodeArguments) + { + checkWhetherMessageThreadIsCorrect(); + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + #else + const MessageManagerLock mmLock; + #endif + + deleteEditor (true); + + return 0; + } + + pointer_sized_int handleGetData (VstOpCodeArguments args) + { + if (processor == nullptr) + return 0; + + auto data = (void**) args.ptr; + bool onlyStoreCurrentProgramData = (args.index != 0); + + MemoryBlock block; + + if (onlyStoreCurrentProgramData) + processor->getCurrentProgramStateInformation (block); + else + processor->getStateInformation (block); + + // IMPORTANT! Don't call getStateInfo while holding this lock! + const ScopedLock lock (stateInformationLock); + + chunkMemory = std::move (block); + *data = (void*) chunkMemory.getData(); + + // because the chunk is only needed temporarily by the host (or at least you'd + // hope so) we'll give it a while and then free it in the timer callback. + chunkMemoryTime = juce::Time::getApproximateMillisecondCounter(); + + return (int32) chunkMemory.getSize(); + } + + pointer_sized_int handleSetData (VstOpCodeArguments args) + { + if (processor != nullptr) + { + void* data = args.ptr; + int32 byteSize = (int32) args.value; + bool onlyRestoreCurrentProgramData = (args.index != 0); + + { + const ScopedLock lock (stateInformationLock); + + chunkMemory.reset(); + chunkMemoryTime = 0; + } + + if (byteSize > 0 && data != nullptr) + { + if (onlyRestoreCurrentProgramData) + processor->setCurrentProgramStateInformation (data, byteSize); + else + processor->setStateInformation (data, byteSize); + } + } + + return 0; + } + + pointer_sized_int handlePreAudioProcessingEvents ([[maybe_unused]] VstOpCodeArguments args) + { + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + VSTMidiEventList::addEventsToMidiBuffer ((Vst2::VstEvents*) args.ptr, midiEvents); + return 1; + #else + return 0; + #endif + } + + pointer_sized_int handleIsParameterAutomatable (VstOpCodeArguments args) + { + if (auto* param = juceParameters.getParamForIndex (args.index)) + { + const bool isMeter = ((((unsigned int) param->getCategory() & 0xffff0000) >> 16) == 2); + return (param->isAutomatable() && (! isMeter) ? 1 : 0); + } + + return 0; + } + + pointer_sized_int handleParameterValueForText (VstOpCodeArguments args) + { + if (auto* param = juceParameters.getParamForIndex (args.index)) + { + if (! LegacyAudioParameter::isLegacy (param)) + { + setValueAndNotifyIfChanged (*param, param->getValueForText (String::fromUTF8 ((char*) args.ptr))); + return 1; + } + } + + return 0; + } + + pointer_sized_int handleGetProgramName (VstOpCodeArguments args) + { + if (processor != nullptr && isPositiveAndBelow (args.index, processor->getNumPrograms())) + { + processor->getProgramName (args.index).copyToUTF8 ((char*) args.ptr, 24 + 1); + return 1; + } + + return 0; + } + + pointer_sized_int handleGetInputPinProperties (VstOpCodeArguments args) + { + return (processor != nullptr && getPinProperties (*(Vst2::VstPinProperties*) args.ptr, true, args.index)) ? 1 : 0; + } + + pointer_sized_int handleGetOutputPinProperties (VstOpCodeArguments args) + { + return (processor != nullptr && getPinProperties (*(Vst2::VstPinProperties*) args.ptr, false, args.index)) ? 1 : 0; + } + + pointer_sized_int handleGetPlugInCategory (VstOpCodeArguments) + { + return Vst2::JucePlugin_VSTCategory; + } + + pointer_sized_int handleSetSpeakerConfiguration (VstOpCodeArguments args) + { + auto* pluginInput = reinterpret_cast (args.value); + auto* pluginOutput = reinterpret_cast (args.ptr); + + if (processor->isMidiEffect()) + return 0; + + auto numIns = processor->getBusCount (true); + auto numOuts = processor->getBusCount (false); + + if (pluginInput != nullptr && pluginInput->type >= 0) + { + // inconsistent request? + if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput).size() != pluginInput->numChannels) + return 0; + } + + if (pluginOutput != nullptr && pluginOutput->type >= 0) + { + // inconsistent request? + if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput).size() != pluginOutput->numChannels) + return 0; + } + + if (pluginInput != nullptr && pluginInput->numChannels > 0 && numIns == 0) + return 0; + + if (pluginOutput != nullptr && pluginOutput->numChannels > 0 && numOuts == 0) + return 0; + + auto layouts = processor->getBusesLayout(); + + if (pluginInput != nullptr && pluginInput-> numChannels >= 0 && numIns > 0) + layouts.getChannelSet (true, 0) = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput); + + if (pluginOutput != nullptr && pluginOutput->numChannels >= 0 && numOuts > 0) + layouts.getChannelSet (false, 0) = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput); + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + if (! AudioProcessor::containsLayout (layouts, configs)) + return 0; + #endif + + return processor->setBusesLayout (layouts) ? 1 : 0; + } + + pointer_sized_int handleSetBypass (VstOpCodeArguments args) + { + isBypassed = args.value != 0; + + if (auto* param = processor->getBypassParameter()) + param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f); + + return 1; + } + + pointer_sized_int handleGetPlugInName (VstOpCodeArguments args) + { + String (JucePlugin_Name).copyToUTF8 ((char*) args.ptr, 64 + 1); + return 1; + } + + pointer_sized_int handleGetManufacturerName (VstOpCodeArguments args) + { + String (JucePlugin_Manufacturer).copyToUTF8 ((char*) args.ptr, 64 + 1); + return 1; + } + + pointer_sized_int handleGetManufacturerVersion (VstOpCodeArguments) + { + return convertHexVersionToDecimal (JucePlugin_VersionCode); + } + + pointer_sized_int handleManufacturerSpecific (VstOpCodeArguments args) + { + if (detail::PluginUtilities::handleManufacturerSpecificVST2Opcode (args.index, args.value, args.ptr, args.opt)) + return 1; + + if (args.index == (int32) ByteOrder::bigEndianInt ("PreS") + && args.value == (int32) ByteOrder::bigEndianInt ("AeCs")) + return handleSetContentScaleFactor (args.opt); + + if (args.index == Vst2::effGetParamDisplay) + return handleCockosGetParameterText (args.value, args.ptr, args.opt); + + if (auto callbackHandler = processor->getVST2ClientExtensions()) + return callbackHandler->handleVstManufacturerSpecific (args.index, args.value, args.ptr, args.opt); + + return 0; + } + + pointer_sized_int handleCanPlugInDo (VstOpCodeArguments args) + { + auto text = (const char*) args.ptr; + auto matches = [=] (const char* s) { return strcmp (text, s) == 0; }; + + if (matches ("receiveVstEvents") + || matches ("receiveVstMidiEvent") + || matches ("receiveVstMidiEvents")) + { + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + return 1; + #else + return -1; + #endif + } + + if (matches ("sendVstEvents") + || matches ("sendVstMidiEvent") + || matches ("sendVstMidiEvents")) + { + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + return 1; + #else + return -1; + #endif + } + + if (matches ("receiveVstTimeInfo") + || matches ("conformsToWindowRules") + || matches ("supportsViewDpiScaling") + || matches ("bypass")) + { + return 1; + } + + // This tells Wavelab to use the UI thread to invoke open/close, + // like all other hosts do. + if (matches ("openCloseAnyThread")) + return -1; + + if (matches ("MPE")) + return processor->supportsMPE() ? 1 : 0; + + #if JUCE_MAC + if (matches ("hasCockosViewAsConfig")) + { + return (int32) 0xbeef0000; + } + #endif + + if (matches ("hasCockosExtensions")) + return (int32) 0xbeef0000; + + if (auto callbackHandler = processor->getVST2ClientExtensions()) + return callbackHandler->handleVstPluginCanDo (args.index, args.value, args.ptr, args.opt); + + return 0; + } + + pointer_sized_int handleGetTailSize (VstOpCodeArguments) + { + if (processor != nullptr) + { + int32 result; + + auto tailSeconds = processor->getTailLengthSeconds(); + + if (std::isinf (tailSeconds)) + result = std::numeric_limits::max(); + else + result = static_cast (tailSeconds * sampleRate); + + return result; // Vst2 expects an int32 upcasted to a intptr_t here + } + + return 0; + } + + pointer_sized_int handleKeyboardFocusRequired (VstOpCodeArguments) + { + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6326) + return (JucePlugin_EditorRequiresKeyboardFocus != 0) ? 1 : 0; + JUCE_END_IGNORE_WARNINGS_MSVC + } + + pointer_sized_int handleGetVstInterfaceVersion (VstOpCodeArguments) + { + return kVstVersion; + } + + pointer_sized_int handleGetCurrentMidiProgram (VstOpCodeArguments) + { + return -1; + } + + pointer_sized_int handleGetSpeakerConfiguration (VstOpCodeArguments args) + { + auto** pluginInput = reinterpret_cast (args.value); + auto** pluginOutput = reinterpret_cast (args.ptr); + + if (pluginHasSidechainsOrAuxs() || processor->isMidiEffect()) + return false; + + auto inputLayout = processor->getChannelLayoutOfBus (true, 0); + auto outputLayout = processor->getChannelLayoutOfBus (false, 0); + + const auto speakerBaseSize = offsetof (Vst2::VstSpeakerArrangement, speakers); + + cachedInArrangement .malloc (speakerBaseSize + (static_cast (inputLayout. size()) * sizeof (Vst2::VstSpeakerProperties)), 1); + cachedOutArrangement.malloc (speakerBaseSize + (static_cast (outputLayout.size()) * sizeof (Vst2::VstSpeakerProperties)), 1); + + *pluginInput = cachedInArrangement. getData(); + *pluginOutput = cachedOutArrangement.getData(); + + SpeakerMappings::channelSetToVstArrangement (processor->getChannelLayoutOfBus (true, 0), **pluginInput); + SpeakerMappings::channelSetToVstArrangement (processor->getChannelLayoutOfBus (false, 0), **pluginOutput); + + return 1; + } + + pointer_sized_int handleSetNumberOfSamplesToProcess (VstOpCodeArguments args) + { + return args.value; + } + + pointer_sized_int handleSetSampleFloatType (VstOpCodeArguments args) + { + if (! isProcessing) + { + if (processor != nullptr) + { + processor->setProcessingPrecision ((args.value == Vst2::kVstProcessPrecision64 + && processor->supportsDoublePrecisionProcessing()) + ? AudioProcessor::doublePrecision + : AudioProcessor::singlePrecision); + + return 1; + } + } + + return 0; + } + + pointer_sized_int handleSetContentScaleFactor ([[maybe_unused]] float scale, [[maybe_unused]] bool force = false) + { + checkWhetherMessageThreadIsCorrect(); + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + #else + const MessageManagerLock mmLock; + #endif + + #if ! JUCE_MAC + if (force || ! approximatelyEqual (scale, editorScaleFactor)) + { + editorScaleFactor = scale; + + if (editorComp != nullptr) + editorComp->setContentScaleFactor (editorScaleFactor); + } + #endif + + return 1; + } + + pointer_sized_int handleCockosGetParameterText (pointer_sized_int paramIndex, + void* dest, + float value) + { + if (processor != nullptr && dest != nullptr) + { + if (auto* param = juceParameters.getParamForIndex ((int) paramIndex)) + { + if (! LegacyAudioParameter::isLegacy (param)) + { + String text (param->getText (value, 1024)); + memcpy (dest, text.toRawUTF8(), ((size_t) text.length()) + 1); + return 0xbeef; + } + } + } + + return 0; + } + + //============================================================================== + pointer_sized_int handleGetNumMidiInputChannels() + { + #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect + #ifdef JucePlugin_VSTNumMidiInputs + return JucePlugin_VSTNumMidiInputs; + #else + return 16; + #endif + #else + return 0; + #endif + } + + pointer_sized_int handleGetNumMidiOutputChannels() + { + #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect + #ifdef JucePlugin_VSTNumMidiOutputs + return JucePlugin_VSTNumMidiOutputs; + #else + return 16; + #endif + #else + return 0; + #endif + } + + pointer_sized_int handleEditIdle() + { + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + hostDrivenEventLoop->processPendingEvents(); + #endif + + return 0; + } + + //============================================================================== + ScopedJuceInitialiser_GUI libraryInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + Vst2::audioMasterCallback hostCallback; + std::unique_ptr processor; + double sampleRate = 44100.0; + int32 blockSize = 1024; + Vst2::AEffect vstEffect; + CriticalSection stateInformationLock; + juce::MemoryBlock chunkMemory; + uint32 chunkMemoryTime = 0; + float editorScaleFactor = 1.0f; + std::unique_ptr editorComp; + Vst2::ERect editorRect; + MidiBuffer midiEvents; + VSTMidiEventList outgoingEvents; + Optional currentPosition; + + LegacyAudioParametersWrapper juceParameters; + + bool isProcessing = false, isBypassed = false, hasShutdown = false; + bool firstProcessCallback = true, shouldDeleteEditor = false; + + VstTempBuffers floatTempBuffers; + VstTempBuffers doubleTempBuffers; + int maxNumInChannels = 0, maxNumOutChannels = 0; + + HeapBlock cachedInArrangement, cachedOutArrangement; + + ThreadLocalValue inParameterChangedCallback; + + HostChangeUpdater hostChangeUpdater { *this }; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVSTWrapper) +}; + + +//============================================================================== +namespace +{ + Vst2::AEffect* pluginEntryPoint (Vst2::audioMasterCallback audioMaster) + { + JUCE_AUTORELEASEPOOL + { + ScopedJuceInitialiser_GUI libraryInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer hostDrivenEventLoop; + #endif + + try + { + if (audioMaster (nullptr, Vst2::audioMasterVersion, 0, 0, nullptr, 0) != 0) + { + std::unique_ptr processor { createPluginFilterOfType (AudioProcessor::wrapperType_VST) }; + auto* processorPtr = processor.get(); + auto* wrapper = new JuceVSTWrapper (audioMaster, std::move (processor)); + auto* aEffect = wrapper->getAEffect(); + + if (auto* callbackHandler = processorPtr->getVST2ClientExtensions()) + { + callbackHandler->handleVstHostCallbackAvailable ([audioMaster, aEffect] (int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) + { + return audioMaster (aEffect, opcode, index, value, ptr, opt); + }); + } + + return aEffect; + } + } + catch (...) + {} + } + + return nullptr; + } +} + +#if ! JUCE_WINDOWS + #define JUCE_EXPORTED_FUNCTION extern "C" __attribute__ ((visibility("default"))) +#endif + +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + +//============================================================================== +// Mac startup code.. +#if JUCE_MAC + + JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster); + JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) + { + return pluginEntryPoint (audioMaster); + } + + JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_macho (Vst2::audioMasterCallback audioMaster); + JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_macho (Vst2::audioMasterCallback audioMaster) + { + return pluginEntryPoint (audioMaster); + } + +//============================================================================== +// Linux startup code.. +#elif JUCE_LINUX || JUCE_BSD + + JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster); + JUCE_EXPORTED_FUNCTION Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) + { + return pluginEntryPoint (audioMaster); + } + + JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_plugin (Vst2::audioMasterCallback audioMaster) asm ("main"); + JUCE_EXPORTED_FUNCTION Vst2::AEffect* main_plugin (Vst2::audioMasterCallback audioMaster) + { + return VSTPluginMain (audioMaster); + } + + // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash! + __attribute__((constructor)) void myPluginInit() {} + __attribute__((destructor)) void myPluginFini() {} + +//============================================================================== +// Win32 startup code.. +#else + + extern "C" __declspec (dllexport) Vst2::AEffect* VSTPluginMain (Vst2::audioMasterCallback audioMaster) + { + return pluginEntryPoint (audioMaster); + } + + #if ! defined (JUCE_64BIT) && JUCE_MSVC // (can't compile this on win64, but it's not needed anyway with VST2.4) + extern "C" __declspec (dllexport) int main (Vst2::audioMasterCallback audioMaster) + { + return (int) pluginEntryPoint (audioMaster); + } + #endif + + extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) + { + if (reason == DLL_PROCESS_ATTACH) + Process::setCurrentModuleInstanceHandle (instance); + + return true; + } +#endif + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +JUCE_END_IGNORE_WARNINGS_MSVC + +#endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_utils.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.mm similarity index 92% rename from modules/juce_audio_plugin_client/juce_audio_plugin_client_utils.cpp rename to modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.mm index 520c8bb828a5..aca798a0286f 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_utils.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.mm @@ -23,4 +23,4 @@ ============================================================================== */ -#include "utility/juce_PluginUtilities.cpp" +#include "juce_audio_plugin_client_VST2.cpp" diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp index 100cc0cf1272..cd38b33a482a 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp @@ -23,4 +23,4290 @@ ============================================================================== */ -#include "VST3/juce_VST3_Wrapper.cpp" +#include +#include + +//============================================================================== +#if JucePlugin_Build_VST3 + +JUCE_BEGIN_NO_SANITIZE ("vptr") + +#if JUCE_PLUGINHOST_VST3 + #if JUCE_MAC + #include + #endif + #undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY + #define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1 +#endif + +#include + +#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY +#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef JUCE_VST3_CAN_REPLACE_VST2 + #define JUCE_VST3_CAN_REPLACE_VST2 1 +#endif + +#if JUCE_VST3_CAN_REPLACE_VST2 + + #if ! JUCE_MSVC && ! defined (__cdecl) + #define __cdecl + #endif + + namespace Vst2 + { + struct AEffect; + #include "pluginterfaces/vst2.x/vstfxstore.h" + } + +#endif + +#ifndef JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS + #if JucePlugin_WantsMidiInput + #define JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS 1 + #endif +#endif + +#if JUCE_LINUX || JUCE_BSD + #include + #include +#endif + +#if JUCE_MAC + #include +#endif + +//============================================================================== +#if JucePlugin_Enable_ARA + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wpragma-pack") + #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + #if ARA_SUPPORT_VERSION_1 + #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation" + #endif + + DEF_CLASS_IID(ARA::IPlugInEntryPoint) + DEF_CLASS_IID(ARA::IPlugInEntryPoint2) + DEF_CLASS_IID(ARA::IMainFactory) +#endif + +namespace juce +{ + +JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4310) +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wall") + +#if JUCE_VST3_CAN_REPLACE_VST2 + static Steinberg::FUID getFUIDForVST2ID (bool forControllerUID) + { + Steinberg::TUID uuid; + detail::PluginUtilities::getUUIDForVST2ID (forControllerUID, (uint8*) uuid); + return Steinberg::FUID (uuid); + } +#endif + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +using namespace Steinberg; + +//============================================================================== +#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + double getScaleFactorForWindow (HWND); +#endif + +//============================================================================== +#if JUCE_LINUX || JUCE_BSD + +enum class HostMessageThreadAttached { no, yes }; + +class HostMessageThreadState +{ +public: + template + void setStateWithAction (HostMessageThreadAttached stateIn, Callback&& action) + { + const std::lock_guard lock { m }; + state = stateIn; + action(); + } + + void assertHostMessageThread() + { + const std::lock_guard lock { m }; + + if (state == HostMessageThreadAttached::no) + return; + + JUCE_ASSERT_MESSAGE_THREAD + } + +private: + HostMessageThreadAttached state = HostMessageThreadAttached::no; + std::mutex m; +}; + +class EventHandler final : public Steinberg::Linux::IEventHandler, + private LinuxEventLoopInternal::Listener +{ +public: + EventHandler() + { + LinuxEventLoopInternal::registerLinuxEventLoopListener (*this); + } + + ~EventHandler() override + { + jassert (hostRunLoops.empty()); + + LinuxEventLoopInternal::deregisterLinuxEventLoopListener (*this); + + if (! messageThread->isRunning()) + hostMessageThreadState.setStateWithAction (HostMessageThreadAttached::no, + [this]() { messageThread->start(); }); + } + + JUCE_DECLARE_VST3_COM_REF_METHODS + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + return testFor (*this, targetIID, UniqueBase{}).extract (obj); + } + + void PLUGIN_API onFDIsSet (Steinberg::Linux::FileDescriptor fd) override + { + updateCurrentMessageThread(); + LinuxEventLoopInternal::invokeEventLoopCallbackForFd (fd); + } + + //============================================================================== + void registerHandlerForFrame (IPlugFrame* plugFrame) + { + if (auto* runLoop = getRunLoopFromFrame (plugFrame)) + { + refreshAttachedEventLoop ([this, runLoop] { hostRunLoops.insert (runLoop); }); + updateCurrentMessageThread(); + } + } + + void unregisterHandlerForFrame (IPlugFrame* plugFrame) + { + if (auto* runLoop = getRunLoopFromFrame (plugFrame)) + refreshAttachedEventLoop ([this, runLoop] { hostRunLoops.erase (runLoop); }); + } + + /* Asserts if it can be established that the calling thread is different from the host's message + thread. + + On Linux this can only be determined if the host has already registered its run loop. Until + then JUCE messages are serviced by a background thread internal to the plugin. + */ + static void assertHostMessageThread() + { + hostMessageThreadState.assertHostMessageThread(); + } + +private: + //============================================================================== + /* Connects all known FDs to a single host event loop instance. */ + class AttachedEventLoop + { + public: + AttachedEventLoop() = default; + + AttachedEventLoop (Steinberg::Linux::IRunLoop* loopIn, Steinberg::Linux::IEventHandler* handlerIn) + : loop (loopIn), handler (handlerIn) + { + for (auto& fd : LinuxEventLoopInternal::getRegisteredFds()) + loop->registerEventHandler (handler, fd); + } + + AttachedEventLoop (AttachedEventLoop&& other) noexcept + { + swap (other); + } + + AttachedEventLoop& operator= (AttachedEventLoop&& other) noexcept + { + swap (other); + return *this; + } + + AttachedEventLoop (const AttachedEventLoop&) = delete; + AttachedEventLoop& operator= (const AttachedEventLoop&) = delete; + + ~AttachedEventLoop() + { + if (loop == nullptr) + return; + + loop->unregisterEventHandler (handler); + } + + private: + void swap (AttachedEventLoop& other) + { + std::swap (other.loop, loop); + std::swap (other.handler, handler); + } + + Steinberg::Linux::IRunLoop* loop = nullptr; + Steinberg::Linux::IEventHandler* handler = nullptr; + }; + + //============================================================================== + static Steinberg::Linux::IRunLoop* getRunLoopFromFrame (IPlugFrame* plugFrame) + { + Steinberg::Linux::IRunLoop* runLoop = nullptr; + + if (plugFrame != nullptr) + plugFrame->queryInterface (Steinberg::Linux::IRunLoop::iid, (void**) &runLoop); + + jassert (runLoop != nullptr); + return runLoop; + } + + void updateCurrentMessageThread() + { + if (! MessageManager::getInstance()->isThisTheMessageThread()) + { + if (messageThread->isRunning()) + messageThread->stop(); + + hostMessageThreadState.setStateWithAction (HostMessageThreadAttached::yes, + [] { MessageManager::getInstance()->setCurrentThreadAsMessageThread(); }); + } + } + + void fdCallbacksChanged() override + { + // The set of active FDs has changed, so deregister from the current event loop and then + // re-register the current set of FDs. + refreshAttachedEventLoop ([]{}); + } + + /* Deregisters from any attached event loop, updates the set of known event loops, and then + attaches all FDs to the first known event loop. + + The same event loop instance is shared between all plugin instances. Every time an event + loop is added or removed, this function should be called to register all FDs with a + suitable event loop. + + Note that there's no API to deregister a single FD for a given event loop. Instead, we must + deregister all FDs, and then register all known FDs again. + */ + template + void refreshAttachedEventLoop (Callback&& modifyKnownRunLoops) + { + // Deregister the old event loop. + // It's important to call the destructor from the old attached loop before calling the + // constructor of the new attached loop. + attachedEventLoop = AttachedEventLoop(); + + modifyKnownRunLoops(); + + // If we still know about an extant event loop, attach to it. + if (hostRunLoops.begin() != hostRunLoops.end()) + attachedEventLoop = AttachedEventLoop (*hostRunLoops.begin(), this); + } + + SharedResourcePointer messageThread; + + std::atomic refCount { 1 }; + + std::multiset hostRunLoops; + AttachedEventLoop attachedEventLoop; + + static HostMessageThreadState hostMessageThreadState; + + //============================================================================== + JUCE_DECLARE_NON_MOVEABLE (EventHandler) + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventHandler) +}; + +HostMessageThreadState EventHandler::hostMessageThreadState; + +#endif + +static void assertHostMessageThread() +{ + #if JUCE_LINUX || JUCE_BSD + EventHandler::assertHostMessageThread(); + #else + JUCE_ASSERT_MESSAGE_THREAD + #endif +} + +//============================================================================== +class InParameterChangedCallbackSetter +{ +public: + explicit InParameterChangedCallbackSetter (bool& ref) + : inner ([&]() -> auto& { jassert (! ref); return ref; }(), true, false) {} + +private: + ScopedValueSetter inner; +}; + +template +static QueryInterfaceResult queryAdditionalInterfaces (AudioProcessor* processor, + const TUID targetIID, + Member&& member) +{ + if (processor == nullptr) + return {}; + + void* obj = nullptr; + + if (auto* extensions = processor->getVST3ClientExtensions()) + { + const auto result = (extensions->*member) (targetIID, &obj); + return { result, obj }; + } + + return {}; +} + +static tresult extractResult (const QueryInterfaceResult& userInterface, + const InterfaceResultWithDeferredAddRef& juceInterface, + void** obj) +{ + if (userInterface.isOk() && juceInterface.isOk()) + { + // If you hit this assertion, you've provided a custom implementation of an interface + // that JUCE implements already. As a result, your plugin may not behave correctly. + // Consider removing your custom implementation. + jassertfalse; + + return userInterface.extract (obj); + } + + if (userInterface.isOk()) + return userInterface.extract (obj); + + return juceInterface.extract (obj); +} + +//============================================================================== +class JuceAudioProcessor : public Vst::IUnitInfo +{ +public: + explicit JuceAudioProcessor (AudioProcessor* source) noexcept + : audioProcessor (source) + { + setupParameters(); + } + + virtual ~JuceAudioProcessor() = default; + + AudioProcessor* get() const noexcept { return audioProcessor.get(); } + + JUCE_DECLARE_VST3_COM_QUERY_METHODS + JUCE_DECLARE_VST3_COM_REF_METHODS + + //============================================================================== + enum InternalParameters + { + paramPreset = 0x70727374, // 'prst' + paramMidiControllerOffset = 0x6d636d00, // 'mdm*' + paramBypass = 0x62797073 // 'byps' + }; + + //============================================================================== + Steinberg::int32 PLUGIN_API getUnitCount() override + { + return parameterGroups.size() + 1; + } + + tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override + { + if (unitIndex == 0) + { + info.id = Vst::kRootUnitId; + info.parentUnitId = Vst::kNoParentUnitId; + info.programListId = getProgramListCount() > 0 + ? static_cast (programParamID) + : Vst::kNoProgramListId; + + toString128 (info.name, TRANS ("Root Unit")); + + return kResultTrue; + } + + if (auto* group = parameterGroups[unitIndex - 1]) + { + info.id = JuceAudioProcessor::getUnitID (group); + info.parentUnitId = JuceAudioProcessor::getUnitID (group->getParent()); + info.programListId = Vst::kNoProgramListId; + + toString128 (info.name, group->getName()); + + return kResultTrue; + } + + return kResultFalse; + } + + Steinberg::int32 PLUGIN_API getProgramListCount() override + { + if (audioProcessor->getNumPrograms() > 0) + return 1; + + return 0; + } + + tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override + { + if (listIndex == 0) + { + info.id = static_cast (programParamID); + info.programCount = static_cast (audioProcessor->getNumPrograms()); + + toString128 (info.name, TRANS ("Factory Presets")); + + return kResultTrue; + } + + jassertfalse; + zerostruct (info); + return kResultFalse; + } + + tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override + { + if (listId == static_cast (programParamID) + && isPositiveAndBelow ((int) programIndex, audioProcessor->getNumPrograms())) + { + toString128 (name, audioProcessor->getProgramName ((int) programIndex)); + return kResultTrue; + } + + jassertfalse; + toString128 (name, juce::String()); + return kResultFalse; + } + + tresult PLUGIN_API getProgramInfo (Vst::ProgramListID, Steinberg::int32, Vst::CString, Vst::String128) override { return kNotImplemented; } + tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID, Steinberg::int32) override { return kNotImplemented; } + tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID, Steinberg::int32, Steinberg::int16, Vst::String128) override { return kNotImplemented; } + tresult PLUGIN_API selectUnit (Vst::UnitID) override { return kNotImplemented; } + tresult PLUGIN_API setUnitProgramData (Steinberg::int32, Steinberg::int32, IBStream*) override { return kNotImplemented; } + Vst::UnitID PLUGIN_API getSelectedUnit() override { return Vst::kRootUnitId; } + + tresult PLUGIN_API getUnitByBus (Vst::MediaType, Vst::BusDirection, Steinberg::int32, Steinberg::int32, Vst::UnitID& unitId) override + { + unitId = Vst::kRootUnitId; + return kResultOk; + } + + //============================================================================== + inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept + { + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + return static_cast (paramIndex); + #else + return vstParamIDs.getReference (paramIndex); + #endif + } + + AudioProcessorParameter* getParamForVSTParamID (Vst::ParamID paramID) const noexcept + { + return paramMap[static_cast (paramID)]; + } + + AudioProcessorParameter* getBypassParameter() const noexcept + { + return getParamForVSTParamID (bypassParamID); + } + + AudioProcessorParameter* getProgramParameter() const noexcept + { + return getParamForVSTParamID (programParamID); + } + + static Vst::UnitID getUnitID (const AudioProcessorParameterGroup* group) + { + if (group == nullptr || group->getParent() == nullptr) + return Vst::kRootUnitId; + + // From the VST3 docs (also applicable to unit IDs!): + // Up to 2^31 parameters can be exported with id range [0, 2147483648] + // (the range [2147483649, 429496729] is reserved for host application). + auto unitID = group->getID().hashCode() & 0x7fffffff; + + // If you hit this assertion then your group ID is hashing to a value + // reserved by the VST3 SDK. Please use a different group ID. + jassert (unitID != Vst::kRootUnitId); + + return unitID; + } + + const Array& getParamIDs() const noexcept { return vstParamIDs; } + Vst::ParamID getBypassParamID() const noexcept { return bypassParamID; } + Vst::ParamID getProgramParamID() const noexcept { return programParamID; } + bool isBypassRegularParameter() const noexcept { return bypassIsRegularParameter; } + + int findCacheIndexForParamID (Vst::ParamID paramID) const noexcept { return vstParamIDs.indexOf (paramID); } + + void setParameterValue (Steinberg::int32 paramIndex, float value) + { + cachedParamValues.set (paramIndex, value); + } + + template + void forAllChangedParameters (Callback&& callback) + { + cachedParamValues.ifSet ([&] (Steinberg::int32 index, float value) + { + callback (cachedParamValues.getParamID (index), value); + }); + } + + bool isUsingManagedParameters() const noexcept { return juceParameters.isUsingManagedParameters(); } + + //============================================================================== + inline static const FUID iid { TUID INLINE_UID (0x0101ABAB, 0xABCDEF01, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + +private: + //============================================================================== + void setupParameters() + { + parameterGroups = audioProcessor->getParameterTree().getSubgroups (true); + + #if JUCE_DEBUG + auto allGroups = parameterGroups; + allGroups.add (&audioProcessor->getParameterTree()); + std::unordered_set unitIDs; + + for (auto* group : allGroups) + { + auto insertResult = unitIDs.insert (getUnitID (group)); + + // If you hit this assertion then either a group ID is not unique or + // you are very unlucky and a hashed group ID is not unique + jassert (insertResult.second); + } + #endif + + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + const bool forceLegacyParamIDs = true; + #else + const bool forceLegacyParamIDs = false; + #endif + + juceParameters.update (*audioProcessor, forceLegacyParamIDs); + auto numParameters = juceParameters.getNumParameters(); + + bool vst3WrapperProvidedBypassParam = false; + auto* bypassParameter = audioProcessor->getBypassParameter(); + + if (bypassParameter == nullptr) + { + vst3WrapperProvidedBypassParam = true; + ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false)); + bypassParameter = ownedBypassParameter.get(); + } + + // if the bypass parameter is not part of the exported parameters that the plug-in supports + // then add it to the end of the list as VST3 requires the bypass parameter to be exported! + bypassIsRegularParameter = juceParameters.contains (audioProcessor->getBypassParameter()); + + if (! bypassIsRegularParameter) + juceParameters.addNonOwning (bypassParameter); + + int i = 0; + for (auto* juceParam : juceParameters) + { + bool isBypassParameter = (juceParam == bypassParameter); + + Vst::ParamID vstParamID = forceLegacyParamIDs ? static_cast (i++) + : generateVSTParamIDForParam (juceParam); + + if (isBypassParameter) + { + // we need to remain backward compatible with the old bypass id + if (vst3WrapperProvidedBypassParam) + { + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6240) + vstParamID = static_cast ((isUsingManagedParameters() && ! forceLegacyParamIDs) ? paramBypass : numParameters); + JUCE_END_IGNORE_WARNINGS_MSVC + } + + bypassParamID = vstParamID; + } + + vstParamIDs.add (vstParamID); + paramMap.set (static_cast (vstParamID), juceParam); + } + + auto numPrograms = audioProcessor->getNumPrograms(); + + if (numPrograms > 1) + { + ownedProgramParameter = std::make_unique ("juceProgramParameter", "Program", + 0, numPrograms - 1, + audioProcessor->getCurrentProgram()); + + juceParameters.addNonOwning (ownedProgramParameter.get()); + + if (forceLegacyParamIDs) + programParamID = static_cast (i++); + + vstParamIDs.add (programParamID); + paramMap.set (static_cast (programParamID), ownedProgramParameter.get()); + } + + cachedParamValues = CachedParamValues { { vstParamIDs.begin(), vstParamIDs.end() } }; + } + + Vst::ParamID generateVSTParamIDForParam (const AudioProcessorParameter* param) + { + auto juceParamID = LegacyAudioParameter::getParamID (param, false); + + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + return static_cast (juceParamID.getIntValue()); + #else + auto paramHash = static_cast (juceParamID.hashCode()); + + #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS + // studio one doesn't like negative parameters + paramHash &= ~(((Vst::ParamID) 1) << (sizeof (Vst::ParamID) * 8 - 1)); + #endif + + return paramHash; + #endif + } + + //============================================================================== + Array vstParamIDs; + CachedParamValues cachedParamValues; + Vst::ParamID bypassParamID = 0, programParamID = static_cast (paramPreset); + bool bypassIsRegularParameter = false; + + //============================================================================== + std::atomic refCount { 0 }; + std::unique_ptr audioProcessor; + + //============================================================================== + LegacyAudioParametersWrapper juceParameters; + HashMap paramMap; + std::unique_ptr ownedBypassParameter, ownedProgramParameter; + Array parameterGroups; + + JuceAudioProcessor() = delete; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAudioProcessor) +}; + +class JuceVST3Component; + +static thread_local bool inParameterChangedCallback = false; + +static void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float newValue) +{ + if (approximatelyEqual (param.getValue(), newValue)) + return; + + const InParameterChangedCallbackSetter scopedSetter { inParameterChangedCallback }; + param.setValueNotifyingHost (newValue); +} + +//============================================================================== +class JuceVST3EditController : public Vst::EditController, + public Vst::IMidiMapping, + public Vst::IUnitInfo, + public Vst::ChannelContext::IInfoListener, + #if JucePlugin_Enable_ARA + public Presonus::IPlugInViewEmbedding, + #endif + public AudioProcessorListener, + private ComponentRestarter::Listener +{ +public: + explicit JuceVST3EditController (Vst::IHostApplication* host) + { + if (host != nullptr) + host->queryInterface (FUnknown::iid, (void**) &hostContext); + + blueCatPatchwork |= isBlueCatHost (host); + } + + //============================================================================== + + #if JUCE_VST3_CAN_REPLACE_VST2 + inline static const FUID iid = getFUIDForVST2ID (true); + #else + inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0x1234ABCD, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + #endif + + //============================================================================== + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Winconsistent-missing-override") + + REFCOUNT_METHODS (ComponentBase) + + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + const auto userProvidedInterface = queryAdditionalInterfaces (getPluginInstance(), + targetIID, + &VST3ClientExtensions::queryIEditController); + + const auto juceProvidedInterface = queryInterfaceInternal (targetIID); + + return extractResult (userProvidedInterface, juceProvidedInterface, obj); + } + + //============================================================================== + tresult PLUGIN_API initialize (FUnknown* context) override + { + if (hostContext != context) + hostContext = context; + + blueCatPatchwork |= isBlueCatHost (context); + + return kResultTrue; + } + + tresult PLUGIN_API terminate() override + { + if (auto* pluginInstance = getPluginInstance()) + pluginInstance->removeListener (this); + + audioProcessor = nullptr; + + return EditController::terminate(); + } + + //============================================================================== + struct Param : public Vst::Parameter + { + Param (JuceVST3EditController& editController, AudioProcessorParameter& p, + Vst::ParamID vstParamID, Vst::UnitID vstUnitID, + bool isBypassParameter) + : owner (editController), param (p) + { + info.id = vstParamID; + info.unitId = vstUnitID; + + updateParameterInfo(); + + info.stepCount = (Steinberg::int32) 0; + + #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE + if (param.isDiscrete()) + #endif + { + const int numSteps = param.getNumSteps(); + info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0); + } + + info.defaultNormalizedValue = param.getDefaultValue(); + jassert (info.defaultNormalizedValue >= 0 && info.defaultNormalizedValue <= 1.0f); + + // Is this a meter? + if ((((unsigned int) param.getCategory() & 0xffff0000) >> 16) == 2) + info.flags = Vst::ParameterInfo::kIsReadOnly; + else + info.flags = param.isAutomatable() ? Vst::ParameterInfo::kCanAutomate : 0; + + if (isBypassParameter) + info.flags |= Vst::ParameterInfo::kIsBypass; + + valueNormalized = info.defaultNormalizedValue; + } + + bool updateParameterInfo() + { + auto updateParamIfChanged = [] (Vst::String128& paramToUpdate, const String& newValue) + { + if (juce::toString (paramToUpdate) == newValue) + return false; + + toString128 (paramToUpdate, newValue); + return true; + }; + + auto anyUpdated = updateParamIfChanged (info.title, param.getName (128)); + anyUpdated |= updateParamIfChanged (info.shortTitle, param.getName (8)); + anyUpdated |= updateParamIfChanged (info.units, param.getLabel()); + + return anyUpdated; + } + + bool setNormalized (Vst::ParamValue v) override + { + v = jlimit (0.0, 1.0, v); + + if (! approximatelyEqual (v, valueNormalized)) + { + valueNormalized = v; + + // Only update the AudioProcessor here if we're not playing, + // otherwise we get parallel streams of parameter value updates + // during playback + if (! owner.vst3IsPlaying) + setValueAndNotifyIfChanged (param, (float) v); + + changed(); + return true; + } + + return false; + } + + void toString (Vst::ParamValue value, Vst::String128 result) const override + { + if (LegacyAudioParameter::isLegacy (¶m)) + // remain backward-compatible with old JUCE code + toString128 (result, param.getCurrentValueAsText()); + else + toString128 (result, param.getText ((float) value, 128)); + } + + bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override + { + if (! LegacyAudioParameter::isLegacy (¶m)) + { + outValueNormalized = param.getValueForText (getStringFromVstTChars (text)); + return true; + } + + return false; + } + + static String getStringFromVstTChars (const Vst::TChar* text) + { + return juce::String (juce::CharPointer_UTF16 (reinterpret_cast (text))); + } + + Vst::ParamValue toPlain (Vst::ParamValue v) const override { return v; } + Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v; } + + private: + JuceVST3EditController& owner; + AudioProcessorParameter& param; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Param) + }; + + //============================================================================== + struct ProgramChangeParameter : public Vst::Parameter + { + ProgramChangeParameter (AudioProcessor& p, Vst::ParamID vstParamID) + : owner (p) + { + jassert (owner.getNumPrograms() > 1); + + info.id = vstParamID; + toString128 (info.title, "Program"); + toString128 (info.shortTitle, "Program"); + toString128 (info.units, ""); + info.stepCount = owner.getNumPrograms() - 1; + info.defaultNormalizedValue = static_cast (owner.getCurrentProgram()) + / static_cast (info.stepCount); + info.unitId = Vst::kRootUnitId; + info.flags = Vst::ParameterInfo::kIsProgramChange | Vst::ParameterInfo::kCanAutomate; + } + + ~ProgramChangeParameter() override = default; + + bool setNormalized (Vst::ParamValue v) override + { + const auto programValue = getProgramValueFromNormalised (v); + + if (programValue != owner.getCurrentProgram()) + owner.setCurrentProgram (programValue); + + if (! approximatelyEqual (valueNormalized, v)) + { + valueNormalized = v; + changed(); + + return true; + } + + return false; + } + + void toString (Vst::ParamValue value, Vst::String128 result) const override + { + toString128 (result, owner.getProgramName (roundToInt (value * info.stepCount))); + } + + bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override + { + auto paramValueString = getStringFromVstTChars (text); + auto n = owner.getNumPrograms(); + + for (int i = 0; i < n; ++i) + { + if (paramValueString == owner.getProgramName (i)) + { + outValueNormalized = static_cast (i) / info.stepCount; + return true; + } + } + + return false; + } + + static String getStringFromVstTChars (const Vst::TChar* text) + { + return String (CharPointer_UTF16 (reinterpret_cast (text))); + } + + Steinberg::int32 getProgramValueFromNormalised (Vst::ParamValue v) const + { + return jmin (info.stepCount, (Steinberg::int32) (v * (info.stepCount + 1))); + } + + Vst::ParamValue toPlain (Vst::ParamValue v) const override { return getProgramValueFromNormalised (v); } + Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v / info.stepCount; } + + private: + AudioProcessor& owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter) + }; + + //============================================================================== + tresult PLUGIN_API setChannelContextInfos (Vst::IAttributeList* list) override + { + if (auto* instance = getPluginInstance()) + { + if (list != nullptr) + { + AudioProcessor::TrackProperties trackProperties; + + { + Vst::String128 channelName; + if (list->getString (Vst::ChannelContext::kChannelNameKey, channelName, sizeof (channelName)) == kResultTrue) + trackProperties.name = toString (channelName); + } + + { + Steinberg::int64 colour; + if (list->getInt (Vst::ChannelContext::kChannelColorKey, colour) == kResultTrue) + trackProperties.colour = Colour (Vst::ChannelContext::GetRed ((uint32) colour), Vst::ChannelContext::GetGreen ((uint32) colour), + Vst::ChannelContext::GetBlue ((uint32) colour), Vst::ChannelContext::GetAlpha ((uint32) colour)); + } + + + + if (MessageManager::getInstance()->isThisTheMessageThread()) + instance->updateTrackProperties (trackProperties); + else + MessageManager::callAsync ([trackProperties, instance] + { instance->updateTrackProperties (trackProperties); }); + } + } + + return kResultOk; + } + + //============================================================================== + #if JucePlugin_Enable_ARA + Steinberg::TBool PLUGIN_API isViewEmbeddingSupported() override + { + if (auto* pluginInstance = getPluginInstance()) + return (Steinberg::TBool) dynamic_cast (pluginInstance)->isEditorView(); + return (Steinberg::TBool) false; + } + + Steinberg::tresult PLUGIN_API setViewIsEmbedded (Steinberg::IPlugView* /*view*/, Steinberg::TBool /*embedded*/) override + { + return kResultOk; + } + #endif + + //============================================================================== + tresult PLUGIN_API setComponentState (IBStream* stream) override + { + // As an IEditController member, the host should only call this from the message thread. + assertHostMessageThread(); + + if (auto* pluginInstance = getPluginInstance()) + { + for (auto vstParamId : audioProcessor->getParamIDs()) + { + auto paramValue = [&] + { + if (vstParamId == audioProcessor->getProgramParamID()) + return EditController::plainParamToNormalized (audioProcessor->getProgramParamID(), + pluginInstance->getCurrentProgram()); + + return (double) audioProcessor->getParamForVSTParamID (vstParamId)->getValue(); + }(); + + setParamNormalized (vstParamId, paramValue); + } + } + + if (auto* handler = getComponentHandler()) + handler->restartComponent (Vst::kParamValuesChanged); + + return Vst::EditController::setComponentState (stream); + } + + void setAudioProcessor (JuceAudioProcessor* audioProc) + { + if (audioProcessor != audioProc) + installAudioProcessor (audioProc); + } + + tresult PLUGIN_API connect (IConnectionPoint* other) override + { + if (other != nullptr && audioProcessor == nullptr) + { + auto result = ComponentBase::connect (other); + + if (! audioProcessor.loadFrom (other)) + sendIntMessage ("JuceVST3EditController", (Steinberg::int64) (pointer_sized_int) this); + else + installAudioProcessor (audioProcessor); + + return result; + } + + jassertfalse; + return kResultFalse; + } + + //============================================================================== + tresult PLUGIN_API getMidiControllerAssignment ([[maybe_unused]] Steinberg::int32 busIndex, + [[maybe_unused]] Steinberg::int16 channel, + [[maybe_unused]] Vst::CtrlNumber midiControllerNumber, + [[maybe_unused]] Vst::ParamID& resultID) override + { + #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS + resultID = midiControllerToParameter[channel][midiControllerNumber]; + return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments + #else + return kResultFalse; + #endif + } + + // Converts an incoming parameter index to a MIDI controller: + bool getMidiControllerForParameter (Vst::ParamID index, int& channel, int& ctrlNumber) + { + auto mappedIndex = static_cast (index - parameterToMidiControllerOffset); + + if (isPositiveAndBelow (mappedIndex, numElementsInArray (parameterToMidiController))) + { + auto& mc = parameterToMidiController[mappedIndex]; + + if (mc.channel != -1 && mc.ctrlNumber != -1) + { + channel = jlimit (1, 16, mc.channel + 1); + ctrlNumber = mc.ctrlNumber; + return true; + } + } + + return false; + } + + inline bool isMidiControllerParamID (Vst::ParamID paramID) const noexcept + { + return (paramID >= parameterToMidiControllerOffset + && isPositiveAndBelow (paramID - parameterToMidiControllerOffset, + static_cast (numElementsInArray (parameterToMidiController)))); + } + + //============================================================================== + Steinberg::int32 PLUGIN_API getUnitCount() override + { + if (audioProcessor != nullptr) + return audioProcessor->getUnitCount(); + + jassertfalse; + return 1; + } + + tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override + { + if (audioProcessor != nullptr) + return audioProcessor->getUnitInfo (unitIndex, info); + + jassertfalse; + if (unitIndex == 0) + { + info.id = Vst::kRootUnitId; + info.parentUnitId = Vst::kNoParentUnitId; + info.programListId = Vst::kNoProgramListId; + + toString128 (info.name, TRANS ("Root Unit")); + + return kResultTrue; + } + + zerostruct (info); + return kResultFalse; + } + + Steinberg::int32 PLUGIN_API getProgramListCount() override + { + if (audioProcessor != nullptr) + return audioProcessor->getProgramListCount(); + + jassertfalse; + return 0; + } + + tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override + { + if (audioProcessor != nullptr) + return audioProcessor->getProgramListInfo (listIndex, info); + + jassertfalse; + zerostruct (info); + return kResultFalse; + } + + tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override + { + if (audioProcessor != nullptr) + return audioProcessor->getProgramName (listId, programIndex, name); + + jassertfalse; + toString128 (name, juce::String()); + return kResultFalse; + } + + tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex, + Vst::CString attributeId, Vst::String128 attributeValue) override + { + if (audioProcessor != nullptr) + return audioProcessor->getProgramInfo (listId, programIndex, attributeId, attributeValue); + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override + { + if (audioProcessor != nullptr) + return audioProcessor->hasProgramPitchNames (listId, programIndex); + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex, + Steinberg::int16 midiPitch, Vst::String128 name) override + { + if (audioProcessor != nullptr) + return audioProcessor->getProgramPitchName (listId, programIndex, midiPitch, name); + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override + { + if (audioProcessor != nullptr) + return audioProcessor->selectUnit (unitId); + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex, + Steinberg::IBStream* data) override + { + if (audioProcessor != nullptr) + return audioProcessor->setUnitProgramData (listOrUnitId, programIndex, data); + + jassertfalse; + return kResultFalse; + } + + Vst::UnitID PLUGIN_API getSelectedUnit() override + { + if (audioProcessor != nullptr) + return audioProcessor->getSelectedUnit(); + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex, + Steinberg::int32 channel, Vst::UnitID& unitId) override + { + if (audioProcessor != nullptr) + return audioProcessor->getUnitByBus (type, dir, busIndex, channel, unitId); + + jassertfalse; + return kResultFalse; + } + + //============================================================================== + IPlugView* PLUGIN_API createView (const char* name) override + { + if (auto* pluginInstance = getPluginInstance()) + { + const auto mayCreateEditor = pluginInstance->hasEditor() + && name != nullptr + && std::strcmp (name, Vst::ViewType::kEditor) == 0 + && (pluginInstance->getActiveEditor() == nullptr + || detail::PluginUtilities::getHostType().isAdobeAudition() + || detail::PluginUtilities::getHostType().isPremiere()); + + if (mayCreateEditor) + return new JuceVST3Editor (*this, *audioProcessor); + } + + return nullptr; + } + + //============================================================================== + void beginGesture (Vst::ParamID vstParamId) + { + if (! inSetState && MessageManager::getInstance()->isThisTheMessageThread()) + beginEdit (vstParamId); + } + + void endGesture (Vst::ParamID vstParamId) + { + if (! inSetState && MessageManager::getInstance()->isThisTheMessageThread()) + endEdit (vstParamId); + } + + void paramChanged (Steinberg::int32 parameterIndex, Vst::ParamID vstParamId, double newValue) + { + if (inParameterChangedCallback || inSetState) + return; + + if (MessageManager::getInstance()->isThisTheMessageThread()) + { + // NB: Cubase has problems if performEdit is called without setParamNormalized + EditController::setParamNormalized (vstParamId, newValue); + performEdit (vstParamId, newValue); + } + else + { + audioProcessor->setParameterValue (parameterIndex, (float) newValue); + } + } + + //============================================================================== + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override + { + beginGesture (audioProcessor->getVSTParamIDForIndex (index)); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override + { + endGesture (audioProcessor->getVSTParamIDForIndex (index)); + } + + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override + { + paramChanged (index, audioProcessor->getVSTParamIDForIndex (index), newValue); + } + + void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override + { + int32 flags = 0; + + if (details.parameterInfoChanged) + { + for (int32 i = 0; i < parameters.getParameterCount(); ++i) + if (auto* param = dynamic_cast (parameters.getParameterByIndex (i))) + if (param->updateParameterInfo() && (flags & Vst::kParamTitlesChanged) == 0) + flags |= Vst::kParamTitlesChanged; + } + + if (auto* pluginInstance = getPluginInstance()) + { + if (details.programChanged) + { + const auto programParameterId = audioProcessor->getProgramParamID(); + + if (audioProcessor->getParamForVSTParamID (programParameterId) != nullptr) + { + const auto currentProgram = pluginInstance->getCurrentProgram(); + const auto paramValue = roundToInt (EditController::normalizedParamToPlain (programParameterId, + EditController::getParamNormalized (programParameterId))); + + if (currentProgram != paramValue) + { + beginGesture (programParameterId); + paramChanged (audioProcessor->findCacheIndexForParamID (programParameterId), + programParameterId, + EditController::plainParamToNormalized (programParameterId, currentProgram)); + endGesture (programParameterId); + + flags |= Vst::kParamValuesChanged; + } + } + } + + auto latencySamples = pluginInstance->getLatencySamples(); + + #if JucePlugin_Enable_ARA + jassert (latencySamples == 0 || ! dynamic_cast (pluginInstance)->isBoundToARA()); + #endif + + if (details.latencyChanged && latencySamples != lastLatencySamples) + { + flags |= Vst::kLatencyChanged; + lastLatencySamples = latencySamples; + } + } + + if (details.nonParameterStateChanged) + flags |= pluginShouldBeMarkedDirtyFlag; + + if (inSetupProcessing) + flags &= Vst::kLatencyChanged; + + componentRestarter.restart (flags); + } + + //============================================================================== + AudioProcessor* getPluginInstance() const noexcept + { + if (audioProcessor != nullptr) + return audioProcessor->get(); + + return nullptr; + } + + static constexpr auto pluginShouldBeMarkedDirtyFlag = 1 << 16; + +private: + bool isBlueCatHost (FUnknown* context) const + { + // We can't use the normal PluginHostType mechanism here because that will give us the name + // of the host process. However, this plugin instance might be loaded in an instance of + // the BlueCat PatchWork host, which might itself be a plugin. + + VSTComSmartPtr host; + host.loadFrom (context); + + if (host == nullptr) + return false; + + Vst::String128 name; + + if (host->getName (name) != kResultOk) + return false; + + const auto hostName = toString (name); + return hostName.contains ("Blue Cat's VST3 Host"); + } + + friend class JuceVST3Component; + friend struct Param; + + //============================================================================== + VSTComSmartPtr audioProcessor; + + struct MidiController + { + int channel = -1, ctrlNumber = -1; + }; + + ComponentRestarter componentRestarter { *this }; + + enum { numMIDIChannels = 16 }; + Vst::ParamID parameterToMidiControllerOffset; + MidiController parameterToMidiController[(int) numMIDIChannels * (int) Vst::kCountCtrlNumber]; + Vst::ParamID midiControllerToParameter[numMIDIChannels][Vst::kCountCtrlNumber]; + + void restartComponentOnMessageThread (int32 flags) override + { + if ((flags & pluginShouldBeMarkedDirtyFlag) != 0) + setDirty (true); + + flags &= ~pluginShouldBeMarkedDirtyFlag; + + if (auto* handler = componentHandler.get()) + handler->restartComponent (flags); + } + + //============================================================================== + struct OwnedParameterListener : public AudioProcessorParameter::Listener + { + OwnedParameterListener (JuceVST3EditController& editController, + AudioProcessorParameter& parameter, + Vst::ParamID paramID, + int cacheIndex) + : owner (editController), + vstParamID (paramID), + parameterIndex (cacheIndex) + { + // We shouldn't be using an OwnedParameterListener for parameters that have + // been added directly to the AudioProcessor. We observe those via the + // normal audioProcessorParameterChanged mechanism. + jassert (parameter.getParameterIndex() == -1); + // The parameter must have a non-negative index in the parameter cache. + jassert (parameterIndex >= 0); + parameter.addListener (this); + } + + void parameterValueChanged (int, float newValue) override + { + owner.paramChanged (parameterIndex, vstParamID, newValue); + } + + void parameterGestureChanged (int, bool gestureIsStarting) override + { + if (gestureIsStarting) + owner.beginGesture (vstParamID); + else + owner.endGesture (vstParamID); + } + + JuceVST3EditController& owner; + const Vst::ParamID vstParamID = Vst::kNoParamId; + const int parameterIndex = -1; + }; + + std::vector> ownedParameterListeners; + + //============================================================================== + bool inSetState = false; + std::atomic vst3IsPlaying { false }, + inSetupProcessing { false }; + + int lastLatencySamples = 0; + bool blueCatPatchwork = isBlueCatHost (hostContext.get()); + + #if ! JUCE_MAC + float lastScaleFactorReceived = 1.0f; + #endif + + InterfaceResultWithDeferredAddRef queryInterfaceInternal (const TUID targetIID) + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + SharedBase{}, + UniqueBase{}, + #if JucePlugin_Enable_ARA + UniqueBase{}, + #endif + SharedBase{}); + + if (result.isOk()) + return result; + + if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) + return { kResultOk, audioProcessor.get() }; + + return {}; + } + + void installAudioProcessor (const VSTComSmartPtr& newAudioProcessor) + { + audioProcessor = newAudioProcessor; + + if (auto* extensions = audioProcessor->get()->getVST3ClientExtensions()) + { + extensions->setIComponentHandler (componentHandler); + extensions->setIHostApplication (hostContext.get()); + } + + if (auto* pluginInstance = getPluginInstance()) + { + lastLatencySamples = pluginInstance->getLatencySamples(); + + pluginInstance->addListener (this); + + // as the bypass is not part of the regular parameters we need to listen for it explicitly + if (! audioProcessor->isBypassRegularParameter()) + { + const auto paramID = audioProcessor->getBypassParamID(); + ownedParameterListeners.push_back (std::make_unique (*this, + *audioProcessor->getParamForVSTParamID (paramID), + paramID, + audioProcessor->findCacheIndexForParamID (paramID))); + } + + if (parameters.getParameterCount() <= 0) + { + auto n = audioProcessor->getParamIDs().size(); + + for (int i = 0; i < n; ++i) + { + auto vstParamID = audioProcessor->getVSTParamIDForIndex (i); + + if (vstParamID == audioProcessor->getProgramParamID()) + continue; + + auto* juceParam = audioProcessor->getParamForVSTParamID (vstParamID); + auto* parameterGroup = pluginInstance->getParameterTree().getGroupsForParameter (juceParam).getLast(); + auto unitID = JuceAudioProcessor::getUnitID (parameterGroup); + + parameters.addParameter (new Param (*this, *juceParam, vstParamID, unitID, + (vstParamID == audioProcessor->getBypassParamID()))); + } + + const auto programParamId = audioProcessor->getProgramParamID(); + + if (auto* programParam = audioProcessor->getParamForVSTParamID (programParamId)) + { + ownedParameterListeners.push_back (std::make_unique (*this, + *programParam, + programParamId, + audioProcessor->findCacheIndexForParamID (programParamId))); + + parameters.addParameter (new ProgramChangeParameter (*pluginInstance, audioProcessor->getProgramParamID())); + } + } + + #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS + parameterToMidiControllerOffset = static_cast (audioProcessor->isUsingManagedParameters() ? JuceAudioProcessor::paramMidiControllerOffset + : parameters.getParameterCount()); + + initialiseMidiControllerMappings(); + #endif + + audioProcessorChanged (pluginInstance, ChangeDetails().withParameterInfoChanged (true)); + } + } + + void initialiseMidiControllerMappings() + { + for (int c = 0, p = 0; c < numMIDIChannels; ++c) + { + for (int i = 0; i < Vst::kCountCtrlNumber; ++i, ++p) + { + midiControllerToParameter[c][i] = static_cast (p) + parameterToMidiControllerOffset; + parameterToMidiController[p].channel = c; + parameterToMidiController[p].ctrlNumber = i; + + parameters.addParameter (new Vst::Parameter (toString ("MIDI CC " + String (c) + "|" + String (i)), + static_cast (p) + parameterToMidiControllerOffset, nullptr, 0, 0, + 0, Vst::kRootUnitId)); + } + } + } + + void sendIntMessage (const char* idTag, const Steinberg::int64 value) + { + jassert (hostContext != nullptr); + + if (auto* message = allocateMessage()) + { + const FReleaser releaser (message); + message->setMessageID (idTag); + message->getAttributes()->setInt (idTag, value); + sendMessage (message); + } + } + + class EditorContextMenu : public HostProvidedContextMenu + { + public: + EditorContextMenu (AudioProcessorEditor& editorIn, + VSTComSmartPtr contextMenuIn) + : editor (editorIn), contextMenu (contextMenuIn) {} + + PopupMenu getEquivalentPopupMenu() const override + { + using MenuItem = Steinberg::Vst::IContextMenuItem; + using MenuTarget = Steinberg::Vst::IContextMenuTarget; + + struct Submenu + { + PopupMenu menu; + String name; + bool enabled; + }; + + std::vector menuStack (1); + + for (int32_t i = 0, end = contextMenu->getItemCount(); i < end; ++i) + { + MenuItem item{}; + MenuTarget* target = nullptr; + contextMenu->getItem (i, item, &target); + + if ((item.flags & MenuItem::kIsGroupStart) == MenuItem::kIsGroupStart) + { + menuStack.push_back ({ PopupMenu{}, + toString (item.name), + (item.flags & MenuItem::kIsDisabled) == 0 }); + } + else if ((item.flags & MenuItem::kIsGroupEnd) == MenuItem::kIsGroupEnd) + { + const auto back = menuStack.back(); + menuStack.pop_back(); + + if (menuStack.empty()) + { + // malformed menu + jassertfalse; + return {}; + } + + menuStack.back().menu.addSubMenu (back.name, back.menu, back.enabled); + } + else if ((item.flags & MenuItem::kIsSeparator) == MenuItem::kIsSeparator) + { + menuStack.back().menu.addSeparator(); + } + else + { + VSTComSmartPtr ownedTarget (target); + const auto tag = item.tag; + menuStack.back().menu.addItem (toString (item.name), + (item.flags & MenuItem::kIsDisabled) == 0, + (item.flags & MenuItem::kIsChecked) != 0, + [ownedTarget, tag] { ownedTarget->executeMenuItem (tag); }); + } + } + + if (menuStack.size() != 1) + { + // malformed menu + jassertfalse; + return {}; + } + + return menuStack.back().menu; + } + + void showNativeMenu (Point pos) const override + { + const auto scaled = pos * Component::getApproximateScaleFactorForComponent (&editor); + contextMenu->popup (scaled.x, scaled.y); + } + + private: + AudioProcessorEditor& editor; + VSTComSmartPtr contextMenu; + }; + + class EditorHostContext : public AudioProcessorEditorHostContext + { + public: + EditorHostContext (JuceAudioProcessor& processorIn, + AudioProcessorEditor& editorIn, + Steinberg::Vst::IComponentHandler* handler, + Steinberg::IPlugView* viewIn) + : processor (processorIn), editor (editorIn), componentHandler (handler), view (viewIn) {} + + std::unique_ptr getContextMenuForParameter (const AudioProcessorParameter* parameter) const override + { + if (componentHandler == nullptr || view == nullptr) + return {}; + + Steinberg::FUnknownPtr handler (componentHandler); + + if (handler == nullptr) + return {}; + + const auto idToUse = parameter != nullptr ? processor.getVSTParamIDForIndex (parameter->getParameterIndex()) : 0; + const auto menu = VSTComSmartPtr (handler->createContextMenu (view, &idToUse)); + return std::make_unique (editor, menu); + } + + private: + JuceAudioProcessor& processor; + AudioProcessorEditor& editor; + Steinberg::Vst::IComponentHandler* componentHandler = nullptr; + Steinberg::IPlugView* view = nullptr; + }; + + //============================================================================== + class JuceVST3Editor : public Vst::EditorView, + public Steinberg::IPlugViewContentScaleSupport, + private Timer + { + public: + JuceVST3Editor (JuceVST3EditController& ec, JuceAudioProcessor& p) + : EditorView (&ec, nullptr), + owner (&ec), + pluginInstance (*p.get()) + { + createContentWrapperComponentIfNeeded(); + + #if JUCE_MAC + if (detail::PluginUtilities::getHostType().type == PluginHostType::SteinbergCubase10) + cubase10Workaround.reset (new Cubase10WindowResizeWorkaround (*this)); + #endif + } + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + const auto result = testFor (*this, targetIID, UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + return Vst::EditorView::queryInterface (targetIID, obj); + } + + REFCOUNT_METHODS (Vst::EditorView) + + //============================================================================== + tresult PLUGIN_API isPlatformTypeSupported (FIDString type) override + { + if (type != nullptr && pluginInstance.hasEditor()) + { + #if JUCE_WINDOWS + if (strcmp (type, kPlatformTypeHWND) == 0) + #elif JUCE_MAC + if (strcmp (type, kPlatformTypeNSView) == 0 || strcmp (type, kPlatformTypeHIView) == 0) + #elif JUCE_LINUX || JUCE_BSD + if (strcmp (type, kPlatformTypeX11EmbedWindowID) == 0) + #endif + return kResultTrue; + } + + return kResultFalse; + } + + tresult PLUGIN_API attached (void* parent, FIDString type) override + { + if (parent == nullptr || isPlatformTypeSupported (type) == kResultFalse) + return kResultFalse; + + #if JUCE_LINUX || JUCE_BSD + eventHandler->registerHandlerForFrame (plugFrame); + #endif + + systemWindow = parent; + + createContentWrapperComponentIfNeeded(); + + const auto desktopFlags = detail::PluginUtilities::getDesktopFlags (component->pluginEditor.get()); + + #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD + // If the plugin was last opened at a particular scale, try to reapply that scale here. + // Note that we do this during attach(), rather than in JuceVST3Editor(). During the + // constructor, we don't have a host plugFrame, so + // ContentWrapperComponent::resizeHostWindow() won't do anything, and the content + // wrapper component will be left at the wrong size. + applyScaleFactor (StoredScaleFactor{}.withInternal (owner->lastScaleFactorReceived)); + + // Check the host scale factor *before* calling addToDesktop, so that the initial + // window size during addToDesktop is correct for the current platform scale factor. + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + component->checkHostWindowScaleFactor(); + #endif + + component->setOpaque (true); + component->addToDesktop (desktopFlags, systemWindow); + component->setVisible (true); + + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + component->startTimer (500); + #endif + + #else + macHostWindow = detail::VSTWindowUtilities::attachComponentToWindowRefVST (component.get(), desktopFlags, parent); + #endif + + component->resizeHostWindow(); + attachedToParent(); + + // Life's too short to faff around with wave lab + if (detail::PluginUtilities::getHostType().isWavelab()) + startTimer (200); + + return kResultTrue; + } + + tresult PLUGIN_API removed() override + { + if (component != nullptr) + { + #if JUCE_WINDOWS + component->removeFromDesktop(); + #elif JUCE_MAC + if (macHostWindow != nullptr) + { + detail::VSTWindowUtilities::detachComponentFromWindowRefVST (component.get(), macHostWindow); + macHostWindow = nullptr; + } + #endif + + component = nullptr; + } + + #if JUCE_LINUX || JUCE_BSD + eventHandler->unregisterHandlerForFrame (plugFrame); + #endif + + return CPluginView::removed(); + } + + tresult PLUGIN_API onSize (ViewRect* newSize) override + { + if (newSize != nullptr) + { + rect = convertFromHostBounds (*newSize); + + if (component != nullptr) + { + component->setSize (rect.getWidth(), rect.getHeight()); + + #if JUCE_MAC + if (cubase10Workaround != nullptr) + { + cubase10Workaround->triggerAsyncUpdate(); + } + else + #endif + { + if (auto* peer = component->getPeer()) + peer->updateBounds(); + } + } + + return kResultTrue; + } + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API getSize (ViewRect* size) override + { + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + if (detail::PluginUtilities::getHostType().isAbletonLive() && systemWindow == nullptr) + return kResultFalse; + #endif + + if (size != nullptr && component != nullptr) + { + auto editorBounds = component->getSizeToContainChild(); + + *size = convertToHostBounds ({ 0, 0, editorBounds.getWidth(), editorBounds.getHeight() }); + return kResultTrue; + } + + return kResultFalse; + } + + tresult PLUGIN_API canResize() override + { + if (component != nullptr) + if (auto* editor = component->pluginEditor.get()) + if (editor->isResizable()) + return kResultTrue; + + return kResultFalse; + } + + tresult PLUGIN_API checkSizeConstraint (ViewRect* rectToCheck) override + { + if (rectToCheck != nullptr && component != nullptr) + { + if (auto* editor = component->pluginEditor.get()) + { + if (canResize() == kResultFalse) + { + // Ableton Live will call checkSizeConstraint even if the view returns false + // from canResize. Set the out param to an appropriate size for the editor + // and return. + auto constrainedRect = component->getLocalArea (editor, editor->getLocalBounds()) + .getSmallestIntegerContainer(); + + *rectToCheck = convertFromHostBounds (*rectToCheck); + rectToCheck->right = rectToCheck->left + roundToInt (constrainedRect.getWidth()); + rectToCheck->bottom = rectToCheck->top + roundToInt (constrainedRect.getHeight()); + *rectToCheck = convertToHostBounds (*rectToCheck); + } + else if (auto* constrainer = editor->getConstrainer()) + { + *rectToCheck = convertFromHostBounds (*rectToCheck); + + auto editorBounds = editor->getLocalArea (component.get(), + Rectangle::leftTopRightBottom (rectToCheck->left, rectToCheck->top, + rectToCheck->right, rectToCheck->bottom).toFloat()); + + auto minW = (float) constrainer->getMinimumWidth(); + auto maxW = (float) constrainer->getMaximumWidth(); + auto minH = (float) constrainer->getMinimumHeight(); + auto maxH = (float) constrainer->getMaximumHeight(); + + auto width = jlimit (minW, maxW, editorBounds.getWidth()); + auto height = jlimit (minH, maxH, editorBounds.getHeight()); + + auto aspectRatio = (float) constrainer->getFixedAspectRatio(); + + if (! approximatelyEqual (aspectRatio, 0.0f)) + { + bool adjustWidth = (width / height > aspectRatio); + + if (detail::PluginUtilities::getHostType().type == PluginHostType::SteinbergCubase9) + { + auto currentEditorBounds = editor->getBounds().toFloat(); + + if (approximatelyEqual (currentEditorBounds.getWidth(), width) && ! approximatelyEqual (currentEditorBounds.getHeight(), height)) + adjustWidth = true; + else if (approximatelyEqual (currentEditorBounds.getHeight(), height) && ! approximatelyEqual (currentEditorBounds.getWidth(), width)) + adjustWidth = false; + } + + if (adjustWidth) + { + width = height * aspectRatio; + + if (width > maxW || width < minW) + { + width = jlimit (minW, maxW, width); + height = width / aspectRatio; + } + } + else + { + height = width / aspectRatio; + + if (height > maxH || height < minH) + { + height = jlimit (minH, maxH, height); + width = height * aspectRatio; + } + } + } + + auto constrainedRect = component->getLocalArea (editor, Rectangle (width, height)) + .getSmallestIntegerContainer(); + + rectToCheck->right = rectToCheck->left + roundToInt (constrainedRect.getWidth()); + rectToCheck->bottom = rectToCheck->top + roundToInt (constrainedRect.getHeight()); + + *rectToCheck = convertToHostBounds (*rectToCheck); + } + } + + return kResultTrue; + } + + jassertfalse; + return kResultFalse; + } + + tresult PLUGIN_API setContentScaleFactor ([[maybe_unused]] const Steinberg::IPlugViewContentScaleSupport::ScaleFactor factor) override + { + #if ! JUCE_MAC + const auto scaleToApply = [&] + { + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + // Cubase 10 only sends integer scale factors, so correct this for fractional scales + if (detail::PluginUtilities::getHostType().type != PluginHostType::SteinbergCubase10) + return factor; + + const auto hostWindowScale = (Steinberg::IPlugViewContentScaleSupport::ScaleFactor) getScaleFactorForWindow (static_cast (systemWindow)); + + if (hostWindowScale <= 0.0 || approximatelyEqual (factor, hostWindowScale)) + return factor; + + return hostWindowScale; + #else + return factor; + #endif + }(); + + applyScaleFactor (scaleFactor.withHost (scaleToApply)); + + return kResultTrue; + #else + return kResultFalse; + #endif + } + + private: + void timerCallback() override + { + stopTimer(); + + ViewRect viewRect; + getSize (&viewRect); + onSize (&viewRect); + } + + static ViewRect convertToHostBounds (ViewRect pluginRect) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return pluginRect; + + return { roundToInt ((float) pluginRect.left * desktopScale), + roundToInt ((float) pluginRect.top * desktopScale), + roundToInt ((float) pluginRect.right * desktopScale), + roundToInt ((float) pluginRect.bottom * desktopScale) }; + } + + static ViewRect convertFromHostBounds (ViewRect hostRect) + { + auto desktopScale = Desktop::getInstance().getGlobalScaleFactor(); + + if (approximatelyEqual (desktopScale, 1.0f)) + return hostRect; + + return { roundToInt ((float) hostRect.left / desktopScale), + roundToInt ((float) hostRect.top / desktopScale), + roundToInt ((float) hostRect.right / desktopScale), + roundToInt ((float) hostRect.bottom / desktopScale) }; + } + + //============================================================================== + struct ContentWrapperComponent : public Component + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + , public Timer + #endif + { + ContentWrapperComponent (JuceVST3Editor& editor) : owner (editor) + { + setOpaque (true); + setBroughtToFrontOnMouseClick (true); + } + + ~ContentWrapperComponent() override + { + if (pluginEditor != nullptr) + { + PopupMenu::dismissAllActiveMenus(); + pluginEditor->processor.editorBeingDeleted (pluginEditor.get()); + } + } + + void createEditor (AudioProcessor& plugin) + { + pluginEditor.reset (plugin.createEditorIfNeeded()); + + #if JucePlugin_Enable_ARA + jassert (dynamic_cast (pluginEditor.get()) != nullptr); + // for proper view embedding, ARA plug-ins must be resizable + jassert (pluginEditor->isResizable()); + #endif + + if (pluginEditor != nullptr) + { + editorHostContext = std::make_unique (*owner.owner->audioProcessor, + *pluginEditor, + owner.owner->getComponentHandler(), + &owner); + + pluginEditor->setHostContext (editorHostContext.get()); + #if ! JUCE_MAC + pluginEditor->setScaleFactor (owner.scaleFactor.get()); + #endif + + addAndMakeVisible (pluginEditor.get()); + pluginEditor->setTopLeftPosition (0, 0); + + lastBounds = getSizeToContainChild(); + + { + const ScopedValueSetter resizingParentSetter (resizingParent, true); + setBounds (lastBounds); + } + + resizeHostWindow(); + } + else + { + // if hasEditor() returns true then createEditorIfNeeded has to return a valid editor + jassertfalse; + } + } + + void paint (Graphics& g) override + { + g.fillAll (Colours::black); + } + + juce::Rectangle getSizeToContainChild() + { + if (pluginEditor != nullptr) + return getLocalArea (pluginEditor.get(), pluginEditor->getLocalBounds()); + + return {}; + } + + void childBoundsChanged (Component*) override + { + if (resizingChild) + return; + + auto newBounds = getSizeToContainChild(); + + if (newBounds != lastBounds) + { + resizeHostWindow(); + + #if JUCE_LINUX || JUCE_BSD + if (detail::PluginUtilities::getHostType().isBitwigStudio()) + repaint(); + #endif + + lastBounds = newBounds; + } + } + + void resized() override + { + if (pluginEditor != nullptr) + { + if (! resizingParent) + { + auto newBounds = getLocalBounds(); + + { + const ScopedValueSetter resizingChildSetter (resizingChild, true); + pluginEditor->setBounds (pluginEditor->getLocalArea (this, newBounds).withPosition (0, 0)); + } + + lastBounds = newBounds; + } + } + } + + void parentSizeChanged() override + { + if (pluginEditor != nullptr) + { + resizeHostWindow(); + pluginEditor->repaint(); + } + } + + void resizeHostWindow() + { + if (pluginEditor != nullptr) + { + if (owner.plugFrame != nullptr) + { + auto editorBounds = getSizeToContainChild(); + auto newSize = convertToHostBounds ({ 0, 0, editorBounds.getWidth(), editorBounds.getHeight() }); + + { + const ScopedValueSetter resizingParentSetter (resizingParent, true); + owner.plugFrame->resizeView (&owner, &newSize); + } + + auto host = detail::PluginUtilities::getHostType(); + + #if JUCE_MAC + if (host.isWavelab() || host.isReaper() || owner.owner->blueCatPatchwork) + #else + if (host.isWavelab() || host.isAbletonLive() || host.isBitwigStudio() || owner.owner->blueCatPatchwork) + #endif + setBounds (editorBounds.withPosition (0, 0)); + } + } + } + + void setEditorScaleFactor (float scale) + { + if (pluginEditor != nullptr) + { + auto prevEditorBounds = pluginEditor->getLocalArea (this, lastBounds); + + { + const ScopedValueSetter resizingChildSetter (resizingChild, true); + + pluginEditor->setScaleFactor (scale); + pluginEditor->setBounds (prevEditorBounds.withPosition (0, 0)); + } + + lastBounds = getSizeToContainChild(); + + resizeHostWindow(); + repaint(); + } + } + + #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE + void checkHostWindowScaleFactor() + { + const auto estimatedScale = (float) getScaleFactorForWindow (static_cast (owner.systemWindow)); + + if (estimatedScale > 0.0) + owner.applyScaleFactor (owner.scaleFactor.withInternal (estimatedScale)); + } + + void timerCallback() override + { + checkHostWindowScaleFactor(); + } + #endif + + std::unique_ptr pluginEditor; + + private: + JuceVST3Editor& owner; + std::unique_ptr editorHostContext; + Rectangle lastBounds; + bool resizingChild = false, resizingParent = false; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent) + }; + + void createContentWrapperComponentIfNeeded() + { + if (component == nullptr) + { + #if JUCE_LINUX || JUCE_BSD + const MessageManagerLock mmLock; + #endif + + component.reset (new ContentWrapperComponent (*this)); + component->createEditor (pluginInstance); + } + } + + //============================================================================== + ScopedJuceInitialiser_GUI libraryInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + SharedResourcePointer eventHandler; + #endif + + VSTComSmartPtr owner; + AudioProcessor& pluginInstance; + + #if JUCE_LINUX || JUCE_BSD + struct MessageManagerLockedDeleter + { + template + void operator() (ObjectType* object) const noexcept + { + const MessageManagerLock mmLock; + delete object; + } + }; + + std::unique_ptr component; + #else + std::unique_ptr component; + #endif + + friend struct ContentWrapperComponent; + + #if JUCE_MAC + void* macHostWindow = nullptr; + + // On macOS Cubase 10 resizes the host window after calling onSize() resulting in the peer + // bounds being a step behind the plug-in. Calling updateBounds() asynchronously seems to fix things... + struct Cubase10WindowResizeWorkaround : public AsyncUpdater + { + Cubase10WindowResizeWorkaround (JuceVST3Editor& o) : owner (o) {} + + void handleAsyncUpdate() override + { + if (owner.component != nullptr) + if (auto* peer = owner.component->getPeer()) + peer->updateBounds(); + } + + JuceVST3Editor& owner; + }; + + std::unique_ptr cubase10Workaround; + #else + class StoredScaleFactor + { + public: + StoredScaleFactor withHost (float x) const { return withMember (*this, &StoredScaleFactor::host, x); } + StoredScaleFactor withInternal (float x) const { return withMember (*this, &StoredScaleFactor::internal, x); } + float get() const { return host.value_or (internal); } + + private: + std::optional host; + float internal = 1.0f; + }; + + void applyScaleFactor (const StoredScaleFactor newFactor) + { + const auto previous = std::exchange (scaleFactor, newFactor).get(); + + if (approximatelyEqual (previous, scaleFactor.get())) + return; + + if (owner != nullptr) + owner->lastScaleFactorReceived = scaleFactor.get(); + + if (component != nullptr) + { + #if JUCE_LINUX || JUCE_BSD + const MessageManagerLock mmLock; + #endif + component->setEditorScaleFactor (scaleFactor.get()); + } + } + + StoredScaleFactor scaleFactor; + + #if JUCE_WINDOWS + detail::WindowsHooks hooks; + #endif + + #endif + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Editor) + }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3EditController) +}; + + +//============================================================================== +#if JucePlugin_Enable_ARA + class JuceARAFactory : public ARA::IMainFactory + { + public: + JuceARAFactory() = default; + virtual ~JuceARAFactory() = default; + + JUCE_DECLARE_VST3_COM_REF_METHODS + + tresult PLUGIN_API queryInterface (const ::Steinberg::TUID targetIID, void** obj) override + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + if (doUIDsMatch (targetIID, JuceARAFactory::iid)) + { + addRef(); + *obj = this; + return kResultOk; + } + + *obj = nullptr; + return kNoInterface; + } + + //---from ARA::IMainFactory------- + const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE + { + return createARAFactory(); + } + + inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0xA1B2C3D4, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + + private: + //============================================================================== + std::atomic refCount { 1 }; + }; +#endif + +//============================================================================== +class JuceVST3Component : public Vst::IComponent, + public Vst::IAudioProcessor, + public Vst::IUnitInfo, + public Vst::IConnectionPoint, + public Vst::IProcessContextRequirements, + #if JucePlugin_Enable_ARA + public ARA::IPlugInEntryPoint, + public ARA::IPlugInEntryPoint2, + #endif + public AudioPlayHead +{ +public: + JuceVST3Component (Vst::IHostApplication* h) + : pluginInstance (createPluginFilterOfType (AudioProcessor::wrapperType_VST3).release()), + host (h) + { + inParameterChangedCallback = false; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + [[maybe_unused]] const int numConfigs = numElementsInArray (configs); + + jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0)); + + pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024); + #endif + + // VST-3 requires your default layout to be non-discrete! + // For example, your default layout must be mono, stereo, quadrophonic + // and not AudioChannelSet::discreteChannels (2) etc. + jassert (checkBusFormatsAreNotDiscrete()); + + comPluginInstance = VSTComSmartPtr { new JuceAudioProcessor (pluginInstance) }; + + zerostruct (processContext); + + processSetup.maxSamplesPerBlock = 1024; + processSetup.processMode = Vst::kRealtime; + processSetup.sampleRate = 44100.0; + processSetup.symbolicSampleSize = Vst::kSample32; + + pluginInstance->setPlayHead (this); + + // Constructing the underlying static object involves dynamic allocation. + // This call ensures that the construction won't happen on the audio thread. + detail::PluginUtilities::getHostType(); + } + + ~JuceVST3Component() override + { + if (juceVST3EditController != nullptr) + juceVST3EditController->vst3IsPlaying = false; + + if (pluginInstance != nullptr) + if (pluginInstance->getPlayHead() == this) + pluginInstance->setPlayHead (nullptr); + } + + //============================================================================== + AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } + + //============================================================================== + #if JUCE_VST3_CAN_REPLACE_VST2 + inline static const FUID iid = getFUIDForVST2ID (false); + #else + inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0x9182FAEB, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + #endif + + JUCE_DECLARE_VST3_COM_REF_METHODS + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + const auto userProvidedInterface = queryAdditionalInterfaces (&getPluginInstance(), + targetIID, + &VST3ClientExtensions::queryIAudioProcessor); + + const auto juceProvidedInterface = queryInterfaceInternal (targetIID); + + return extractResult (userProvidedInterface, juceProvidedInterface, obj); + } + + enum class CallPrepareToPlay { no, yes }; + + //============================================================================== + tresult PLUGIN_API initialize (FUnknown* hostContext) override + { + if (host != hostContext) + host.loadFrom (hostContext); + + processContext.sampleRate = processSetup.sampleRate; + preparePlugin (processSetup.sampleRate, (int) processSetup.maxSamplesPerBlock, CallPrepareToPlay::no); + + return kResultTrue; + } + + tresult PLUGIN_API terminate() override + { + getPluginInstance().releaseResources(); + return kResultTrue; + } + + //============================================================================== + tresult PLUGIN_API connect (IConnectionPoint* other) override + { + if (other != nullptr && juceVST3EditController == nullptr) + juceVST3EditController.loadFrom (other); + + return kResultTrue; + } + + tresult PLUGIN_API disconnect (IConnectionPoint*) override + { + if (juceVST3EditController != nullptr) + juceVST3EditController->vst3IsPlaying = false; + + juceVST3EditController = {}; + return kResultTrue; + } + + tresult PLUGIN_API notify (Vst::IMessage* message) override + { + if (message != nullptr && juceVST3EditController == nullptr) + { + Steinberg::int64 value = 0; + + if (message->getAttributes()->getInt ("JuceVST3EditController", value) == kResultTrue) + { + juceVST3EditController = VSTComSmartPtr { (JuceVST3EditController*) (pointer_sized_int) value }; + + if (juceVST3EditController != nullptr) + juceVST3EditController->setAudioProcessor (comPluginInstance); + else + jassertfalse; + } + } + + return kResultTrue; + } + + tresult PLUGIN_API getControllerClassId (TUID classID) override + { + memcpy (classID, JuceVST3EditController::iid, sizeof (TUID)); + return kResultTrue; + } + + //============================================================================== + tresult PLUGIN_API setActive (TBool state) override + { + const FLStudioDIYSpecificationEnforcementLock lock (flStudioDIYSpecificationEnforcementMutex); + + const auto willBeActive = (state != 0); + + active = false; + // Some hosts may call setBusArrangements in response to calls made during prepareToPlay + // or releaseResources. Specifically, Wavelab 11.1 calls setBusArrangements in the same + // call stack when the AudioProcessor calls setLatencySamples inside prepareToPlay. + // In order for setBusArrangements to return successfully, the plugin must not be activated + // until after prepareToPlay has completely finished. + const ScopeGuard scope { [&] { active = willBeActive; } }; + + if (willBeActive) + { + const auto sampleRate = processSetup.sampleRate > 0.0 + ? processSetup.sampleRate + : getPluginInstance().getSampleRate(); + + const auto bufferSize = processSetup.maxSamplesPerBlock > 0 + ? (int) processSetup.maxSamplesPerBlock + : getPluginInstance().getBlockSize(); + + preparePlugin (sampleRate, bufferSize, CallPrepareToPlay::yes); + } + else + { + getPluginInstance().releaseResources(); + } + + return kResultOk; + } + + tresult PLUGIN_API setIoMode (Vst::IoMode) override { return kNotImplemented; } + tresult PLUGIN_API getRoutingInfo (Vst::RoutingInfo&, Vst::RoutingInfo&) override { return kNotImplemented; } + + //============================================================================== + bool isBypassed() const + { + if (auto* bypassParam = comPluginInstance->getBypassParameter()) + return bypassParam->getValue() >= 0.5f; + + return false; + } + + void setBypassed (bool shouldBeBypassed) + { + if (auto* bypassParam = comPluginInstance->getBypassParameter()) + setValueAndNotifyIfChanged (*bypassParam, shouldBeBypassed ? 1.0f : 0.0f); + } + + //============================================================================== + void writeJucePrivateStateInformation (MemoryOutputStream& out) + { + if (pluginInstance->getBypassParameter() == nullptr) + { + ValueTree privateData (kJucePrivateDataIdentifier); + + // for now we only store the bypass value + privateData.setProperty ("Bypass", var (isBypassed()), nullptr); + privateData.writeToStream (out); + } + } + + void setJucePrivateStateInformation (const void* data, int sizeInBytes) + { + if (pluginInstance->getBypassParameter() == nullptr) + { + if (comPluginInstance->getBypassParameter() != nullptr) + { + auto privateData = ValueTree::readFromData (data, static_cast (sizeInBytes)); + setBypassed (static_cast (privateData.getProperty ("Bypass", var (false)))); + } + } + } + + void getStateInformation (MemoryBlock& destData) + { + pluginInstance->getStateInformation (destData); + + // With bypass support, JUCE now needs to store private state data. + // Put this at the end of the plug-in state and add a few null characters + // so that plug-ins built with older versions of JUCE will hopefully ignore + // this data. Additionally, we need to add some sort of magic identifier + // at the very end of the private data so that JUCE has some sort of + // way to figure out if the data was stored with a newer JUCE version. + MemoryOutputStream extraData; + + extraData.writeInt64 (0); + writeJucePrivateStateInformation (extraData); + auto privateDataSize = (int64) (extraData.getDataSize() - sizeof (int64)); + extraData.writeInt64 (privateDataSize); + extraData << kJucePrivateDataIdentifier; + + // write magic string + destData.append (extraData.getData(), extraData.getDataSize()); + } + + void setStateInformation (const void* data, int sizeAsInt) + { + bool unusedState = false; + auto& flagToSet = juceVST3EditController != nullptr ? juceVST3EditController->inSetState : unusedState; + const ScopedValueSetter scope (flagToSet, true); + + auto size = (uint64) sizeAsInt; + + // Check if this data was written with a newer JUCE version + // and if it has the JUCE private data magic code at the end + auto jucePrivDataIdentifierSize = std::strlen (kJucePrivateDataIdentifier); + + if ((size_t) size >= jucePrivDataIdentifierSize + sizeof (int64)) + { + auto buffer = static_cast (data); + + String magic (CharPointer_UTF8 (buffer + size - jucePrivDataIdentifierSize), + CharPointer_UTF8 (buffer + size)); + + if (magic == kJucePrivateDataIdentifier) + { + // found a JUCE private data section + uint64 privateDataSize; + + std::memcpy (&privateDataSize, + buffer + ((size_t) size - jucePrivDataIdentifierSize - sizeof (uint64)), + sizeof (uint64)); + + privateDataSize = ByteOrder::swapIfBigEndian (privateDataSize); + size -= privateDataSize + jucePrivDataIdentifierSize + sizeof (uint64); + + if (privateDataSize > 0) + setJucePrivateStateInformation (buffer + size, static_cast (privateDataSize)); + + size -= sizeof (uint64); + } + } + + if (size > 0) + pluginInstance->setStateInformation (data, static_cast (size)); + } + + //============================================================================== + #if JUCE_VST3_CAN_REPLACE_VST2 + bool loadVST2VstWBlock (const char* data, int size) + { + jassert (ByteOrder::bigEndianInt ("VstW") == htonl ((uint32) readUnaligned (data))); + jassert (1 == htonl ((uint32) readUnaligned (data + 8))); // version should be 1 according to Steinberg's docs + + auto headerLen = (int) htonl ((uint32) readUnaligned (data + 4)) + 8; + return loadVST2CcnKBlock (data + headerLen, size - headerLen); + } + + bool loadVST2CcnKBlock (const char* data, int size) + { + auto* bank = reinterpret_cast (data); + + jassert (ByteOrder::bigEndianInt ("CcnK") == htonl ((uint32) bank->chunkMagic)); + jassert (ByteOrder::bigEndianInt ("FBCh") == htonl ((uint32) bank->fxMagic)); + jassert (htonl ((uint32) bank->version) == 1 || htonl ((uint32) bank->version) == 2); + jassert (JucePlugin_VSTUniqueID == htonl ((uint32) bank->fxID)); + + setStateInformation (bank->content.data.chunk, + jmin ((int) (size - (bank->content.data.chunk - data)), + (int) htonl ((uint32) bank->content.data.size))); + return true; + } + + bool loadVST3PresetFile (const char* data, int size) + { + if (size < 48) + return false; + + // At offset 4 there's a little-endian version number which seems to typically be 1 + // At offset 8 there's 32 bytes the SDK calls "ASCII-encoded class id" + auto chunkListOffset = (int) ByteOrder::littleEndianInt (data + 40); + jassert (memcmp (data + chunkListOffset, "List", 4) == 0); + auto entryCount = (int) ByteOrder::littleEndianInt (data + chunkListOffset + 4); + jassert (entryCount > 0); + + for (int i = 0; i < entryCount; ++i) + { + auto entryOffset = chunkListOffset + 8 + 20 * i; + + if (entryOffset + 20 > size) + return false; + + if (memcmp (data + entryOffset, "Comp", 4) == 0) + { + // "Comp" entries seem to contain the data. + auto chunkOffset = ByteOrder::littleEndianInt64 (data + entryOffset + 4); + auto chunkSize = ByteOrder::littleEndianInt64 (data + entryOffset + 12); + + if (static_cast (chunkOffset + chunkSize) > static_cast (size)) + { + jassertfalse; + return false; + } + + loadVST2VstWBlock (data + chunkOffset, (int) chunkSize); + } + } + + return true; + } + + bool loadVST2CompatibleState (const char* data, int size) + { + if (size < 4) + return false; + + auto header = htonl ((uint32) readUnaligned (data)); + + if (header == ByteOrder::bigEndianInt ("VstW")) + return loadVST2VstWBlock (data, size); + + if (header == ByteOrder::bigEndianInt ("CcnK")) + return loadVST2CcnKBlock (data, size); + + if (memcmp (data, "VST3", 4) == 0) + { + // In Cubase 5, when loading VST3 .vstpreset files, + // we get the whole content of the files to load. + // In Cubase 7 we get just the contents within and + // we go directly to the loadVST2VstW codepath instead. + return loadVST3PresetFile (data, size); + } + + return false; + } + #endif + + void loadStateData (const void* data, int size) + { + #if JUCE_VST3_CAN_REPLACE_VST2 + if (loadVST2CompatibleState ((const char*) data, size)) + return; + #endif + setStateInformation (data, size); + } + + bool readFromMemoryStream (IBStream* state) + { + FUnknownPtr s (state); + Steinberg::int64 size = 0; + + if (s != nullptr + && s->getStreamSize (size) == kResultOk + && size > 0 + && size < 1024 * 1024 * 100) // (some hosts seem to return junk for the size) + { + MemoryBlock block (static_cast (size)); + + // turns out that Cubase 9 might give you the incorrect stream size :-( + Steinberg::int32 bytesRead = 1; + int len; + + for (len = 0; bytesRead > 0 && len < static_cast (block.getSize()); len += bytesRead) + if (state->read (block.getData(), static_cast (block.getSize()), &bytesRead) != kResultOk) + break; + + if (len == 0) + return false; + + block.setSize (static_cast (len)); + + // Adobe Audition CS6 hack to avoid trying to use corrupted streams: + if (detail::PluginUtilities::getHostType().isAdobeAudition()) + if (block.getSize() >= 5 && memcmp (block.getData(), "VC2!E", 5) == 0) + return false; + + loadStateData (block.getData(), (int) block.getSize()); + return true; + } + + return false; + } + + bool readFromUnknownStream (IBStream* state) + { + MemoryOutputStream allData; + + { + const size_t bytesPerBlock = 4096; + HeapBlock buffer (bytesPerBlock); + + for (;;) + { + Steinberg::int32 bytesRead = 0; + auto status = state->read (buffer, (Steinberg::int32) bytesPerBlock, &bytesRead); + + if (bytesRead <= 0 || (status != kResultTrue && ! detail::PluginUtilities::getHostType().isWavelab())) + break; + + allData.write (buffer, static_cast (bytesRead)); + } + } + + const size_t dataSize = allData.getDataSize(); + + if (dataSize <= 0 || dataSize >= 0x7fffffff) + return false; + + loadStateData (allData.getData(), (int) dataSize); + return true; + } + + tresult PLUGIN_API setState (IBStream* state) override + { + // The VST3 spec requires that this function is called from the UI thread. + // If this assertion fires, your host is misbehaving! + assertHostMessageThread(); + + if (state == nullptr) + return kInvalidArgument; + + FUnknownPtr stateRefHolder (state); // just in case the caller hasn't properly ref-counted the stream object + + if (state->seek (0, IBStream::kIBSeekSet, nullptr) == kResultTrue) + { + if (! detail::PluginUtilities::getHostType().isFruityLoops() && readFromMemoryStream (state)) + return kResultTrue; + + if (readFromUnknownStream (state)) + return kResultTrue; + } + + return kResultFalse; + } + + #if JUCE_VST3_CAN_REPLACE_VST2 + static tresult writeVST2Header (IBStream* state, bool bypassed) + { + auto writeVST2IntToState = [state] (uint32 n) + { + auto t = (int32) htonl (n); + return state->write (&t, 4); + }; + + auto status = writeVST2IntToState (ByteOrder::bigEndianInt ("VstW")); + + if (status == kResultOk) status = writeVST2IntToState (8); // header size + if (status == kResultOk) status = writeVST2IntToState (1); // version + if (status == kResultOk) status = writeVST2IntToState (bypassed ? 1 : 0); // bypass + + return status; + } + #endif + + tresult PLUGIN_API getState (IBStream* state) override + { + if (state == nullptr) + return kInvalidArgument; + + MemoryBlock mem; + getStateInformation (mem); + + #if JUCE_VST3_CAN_REPLACE_VST2 + tresult status = writeVST2Header (state, isBypassed()); + + if (status != kResultOk) + return status; + + const int bankBlockSize = 160; + Vst2::fxBank bank; + + zerostruct (bank); + bank.chunkMagic = (int32) htonl (ByteOrder::bigEndianInt ("CcnK")); + bank.byteSize = (int32) htonl (bankBlockSize - 8 + (unsigned int) mem.getSize()); + bank.fxMagic = (int32) htonl (ByteOrder::bigEndianInt ("FBCh")); + bank.version = (int32) htonl (2); + bank.fxID = (int32) htonl (JucePlugin_VSTUniqueID); + bank.fxVersion = (int32) htonl (JucePlugin_VersionCode); + bank.content.data.size = (int32) htonl ((unsigned int) mem.getSize()); + + status = state->write (&bank, bankBlockSize); + + if (status != kResultOk) + return status; + #endif + + return state->write (mem.getData(), (Steinberg::int32) mem.getSize()); + } + + //============================================================================== + Steinberg::int32 PLUGIN_API getUnitCount() override { return comPluginInstance->getUnitCount(); } + tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override { return comPluginInstance->getUnitInfo (unitIndex, info); } + Steinberg::int32 PLUGIN_API getProgramListCount() override { return comPluginInstance->getProgramListCount(); } + tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override { return comPluginInstance->getProgramListInfo (listIndex, info); } + tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override { return comPluginInstance->getProgramName (listId, programIndex, name); } + tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex, + Vst::CString attributeId, Vst::String128 attributeValue) override { return comPluginInstance->getProgramInfo (listId, programIndex, attributeId, attributeValue); } + tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override { return comPluginInstance->hasProgramPitchNames (listId, programIndex); } + tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex, + Steinberg::int16 midiPitch, Vst::String128 name) override { return comPluginInstance->getProgramPitchName (listId, programIndex, midiPitch, name); } + tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override { return comPluginInstance->selectUnit (unitId); } + tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex, + Steinberg::IBStream* data) override { return comPluginInstance->setUnitProgramData (listOrUnitId, programIndex, data); } + Vst::UnitID PLUGIN_API getSelectedUnit() override { return comPluginInstance->getSelectedUnit(); } + tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex, + Steinberg::int32 channel, Vst::UnitID& unitId) override { return comPluginInstance->getUnitByBus (type, dir, busIndex, channel, unitId); } + + //============================================================================== + Optional getPosition() const override + { + PositionInfo info; + info.setTimeInSamples (jmax ((Steinberg::int64) 0, processContext.projectTimeSamples)); + info.setTimeInSeconds (static_cast (*info.getTimeInSamples()) / processContext.sampleRate); + info.setIsRecording ((processContext.state & Vst::ProcessContext::kRecording) != 0); + info.setIsPlaying ((processContext.state & Vst::ProcessContext::kPlaying) != 0); + info.setIsLooping ((processContext.state & Vst::ProcessContext::kCycleActive) != 0); + + info.setBpm ((processContext.state & Vst::ProcessContext::kTempoValid) != 0 + ? makeOptional (processContext.tempo) + : nullopt); + + info.setTimeSignature ((processContext.state & Vst::ProcessContext::kTimeSigValid) != 0 + ? makeOptional (TimeSignature { processContext.timeSigNumerator, processContext.timeSigDenominator }) + : nullopt); + + info.setLoopPoints ((processContext.state & Vst::ProcessContext::kCycleValid) != 0 + ? makeOptional (LoopPoints { processContext.cycleStartMusic, processContext.cycleEndMusic }) + : nullopt); + + info.setPpqPosition ((processContext.state & Vst::ProcessContext::kProjectTimeMusicValid) != 0 + ? makeOptional (processContext.projectTimeMusic) + : nullopt); + + info.setPpqPositionOfLastBarStart ((processContext.state & Vst::ProcessContext::kBarPositionValid) != 0 + ? makeOptional (processContext.barPositionMusic) + : nullopt); + + info.setFrameRate ((processContext.state & Vst::ProcessContext::kSmpteValid) != 0 + ? makeOptional (FrameRate().withBaseRate ((int) processContext.frameRate.framesPerSecond) + .withDrop ((processContext.frameRate.flags & Vst::FrameRate::kDropRate) != 0) + .withPullDown ((processContext.frameRate.flags & Vst::FrameRate::kPullDownRate) != 0)) + : nullopt); + + info.setEditOriginTime (info.getFrameRate().hasValue() + ? makeOptional ((double) processContext.smpteOffsetSubframes / (80.0 * info.getFrameRate()->getEffectiveRate())) + : nullopt); + + info.setHostTimeNs ((processContext.state & Vst::ProcessContext::kSystemTimeValid) != 0 + ? makeOptional ((uint64_t) processContext.systemTime) + : nullopt); + + return info; + } + + //============================================================================== + int getNumAudioBuses (bool isInput) const + { + int busCount = pluginInstance->getBusCount (isInput); + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = {JucePlugin_PreferredChannelConfigurations}; + const int numConfigs = numElementsInArray (configs); + + bool hasOnlyZeroChannels = true; + + for (int i = 0; i < numConfigs && hasOnlyZeroChannels == true; ++i) + if (configs[i][isInput ? 0 : 1] != 0) + hasOnlyZeroChannels = false; + + busCount = jmin (busCount, hasOnlyZeroChannels ? 0 : 1); + #endif + + return busCount; + } + + //============================================================================== + Steinberg::int32 PLUGIN_API getBusCount (Vst::MediaType type, Vst::BusDirection dir) override + { + if (type == Vst::kAudio) + return getNumAudioBuses (dir == Vst::kInput); + + if (type == Vst::kEvent) + { + #if JucePlugin_WantsMidiInput + if (dir == Vst::kInput) + return 1; + #endif + + #if JucePlugin_ProducesMidiOutput + if (dir == Vst::kOutput) + return 1; + #endif + } + + return 0; + } + + tresult PLUGIN_API getBusInfo (Vst::MediaType type, Vst::BusDirection dir, + Steinberg::int32 index, Vst::BusInfo& info) override + { + if (type == Vst::kAudio) + { + if (index < 0 || index >= getNumAudioBuses (dir == Vst::kInput)) + return kResultFalse; + + if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index)) + { + info.mediaType = Vst::kAudio; + info.direction = dir; + info.channelCount = bus->getLastEnabledLayout().size(); + + [[maybe_unused]] const auto lastEnabledVst3Layout = getVst3SpeakerArrangement (bus->getLastEnabledLayout()); + jassert (lastEnabledVst3Layout.has_value() && info.channelCount == Steinberg::Vst::SpeakerArr::getChannelCount (*lastEnabledVst3Layout)); + toString128 (info.name, bus->getName()); + + info.busType = [&] + { + const auto isFirstBus = (index == 0); + + if (dir == Vst::kInput) + { + if (isFirstBus) + { + if (auto* extensions = pluginInstance->getVST3ClientExtensions()) + return extensions->getPluginHasMainInput() ? Vst::kMain : Vst::kAux; + + return Vst::kMain; + } + + return Vst::kAux; + } + + #if JucePlugin_IsSynth + return Vst::kMain; + #else + return isFirstBus ? Vst::kMain : Vst::kAux; + #endif + }(); + + #ifdef JucePlugin_PreferredChannelConfigurations + info.flags = Vst::BusInfo::kDefaultActive; + #else + info.flags = (bus->isEnabledByDefault()) ? Vst::BusInfo::kDefaultActive : 0; + #endif + + return kResultTrue; + } + } + + if (type == Vst::kEvent) + { + info.flags = Vst::BusInfo::kDefaultActive; + + #if JucePlugin_WantsMidiInput + if (dir == Vst::kInput && index == 0) + { + info.mediaType = Vst::kEvent; + info.direction = dir; + + #ifdef JucePlugin_VSTNumMidiInputs + info.channelCount = JucePlugin_VSTNumMidiInputs; + #else + info.channelCount = 16; + #endif + + toString128 (info.name, TRANS("MIDI Input")); + info.busType = Vst::kMain; + return kResultTrue; + } + #endif + + #if JucePlugin_ProducesMidiOutput + if (dir == Vst::kOutput && index == 0) + { + info.mediaType = Vst::kEvent; + info.direction = dir; + + #ifdef JucePlugin_VSTNumMidiOutputs + info.channelCount = JucePlugin_VSTNumMidiOutputs; + #else + info.channelCount = 16; + #endif + + toString128 (info.name, TRANS("MIDI Output")); + info.busType = Vst::kMain; + return kResultTrue; + } + #endif + } + + zerostruct (info); + return kResultFalse; + } + + tresult PLUGIN_API activateBus (Vst::MediaType type, + Vst::BusDirection dir, + Steinberg::int32 index, + TBool state) override + { + const FLStudioDIYSpecificationEnforcementLock lock (flStudioDIYSpecificationEnforcementMutex); + + // The host is misbehaving! The plugin must be deactivated before setting new arrangements. + jassert (! active); + + if (type == Vst::kEvent) + { + #if JucePlugin_WantsMidiInput + if (index == 0 && dir == Vst::kInput) + { + isMidiInputBusEnabled = (state != 0); + return kResultTrue; + } + #endif + + #if JucePlugin_ProducesMidiOutput + if (index == 0 && dir == Vst::kOutput) + { + isMidiOutputBusEnabled = (state != 0); + return kResultTrue; + } + #endif + + return kResultFalse; + } + + if (type == Vst::kAudio) + { + const auto numPublicInputBuses = getNumAudioBuses (true); + const auto numPublicOutputBuses = getNumAudioBuses (false); + + if (! isPositiveAndBelow (index, dir == Vst::kInput ? numPublicInputBuses : numPublicOutputBuses)) + return kResultFalse; + + // The host is allowed to enable/disable buses as it sees fit, so the plugin needs to be + // able to handle any set of enabled/disabled buses, including layouts for which + // AudioProcessor::isBusesLayoutSupported would return false. + // Our strategy is to keep track of the layout that the host last requested, and to + // attempt to apply that layout directly. + // If the layout isn't supported by the processor, we'll try enabling all the buses + // instead. + // If the host enables a bus that the processor refused to enable, then we'll ignore + // that bus (and return silence for output buses). If the host disables a bus that the + // processor refuses to disable, the wrapper will provide the processor with silence for + // input buses, and ignore the contents of output buses. + // Note that some hosts (old bitwig and cakewalk) may incorrectly call this function + // when the plugin is in an activated state. + if (dir == Vst::kInput) + bufferMapper.setInputBusHostActive ((size_t) index, state != 0); + else + bufferMapper.setOutputBusHostActive ((size_t) index, state != 0); + + AudioProcessor::BusesLayout desiredLayout; + + for (const auto isInput : { true, false }) + { + const auto numPublicBuses = isInput ? numPublicInputBuses : numPublicOutputBuses; + auto& layoutBuses = isInput ? desiredLayout.inputBuses : desiredLayout.outputBuses; + + for (auto i = 0; i < numPublicBuses; ++i) + { + layoutBuses.add (isInput ? bufferMapper.getRequestedLayoutForInputBus ((size_t) i) + : bufferMapper.getRequestedLayoutForOutputBus ((size_t) i)); + } + + while (layoutBuses.size() < pluginInstance->getBusCount (isInput)) + layoutBuses.add (AudioChannelSet::disabled()); + } + + const auto prev = pluginInstance->getBusesLayout(); + + const auto busesLayoutSupported = [&] + { + #ifdef JucePlugin_PreferredChannelConfigurations + struct ChannelPair + { + short ins, outs; + + auto tie() const { return std::tie (ins, outs); } + bool operator== (ChannelPair x) const { return tie() == x.tie(); } + }; + + const auto countChannels = [] (auto& range) + { + return std::accumulate (range.begin(), range.end(), 0, [] (auto acc, auto set) + { + return acc + set.size(); + }); + }; + + const auto toShort = [] (int x) + { + jassert (0 <= x && x <= std::numeric_limits::max()); + return (short) x; + }; + + const ChannelPair requested { toShort (countChannels (desiredLayout.inputBuses)), + toShort (countChannels (desiredLayout.outputBuses)) }; + const ChannelPair configs[] = { JucePlugin_PreferredChannelConfigurations }; + return std::find (std::begin (configs), std::end (configs), requested) != std::end (configs); + #else + return pluginInstance->checkBusesLayoutSupported (desiredLayout); + #endif + }(); + + if (busesLayoutSupported) + pluginInstance->setBusesLayout (desiredLayout); + else + pluginInstance->enableAllBuses(); + + bufferMapper.updateActiveClientBuses (pluginInstance->getBusesLayout()); + + return kResultTrue; + } + + return kResultFalse; + } + + bool checkBusFormatsAreNotDiscrete() + { + auto numInputBuses = pluginInstance->getBusCount (true); + auto numOutputBuses = pluginInstance->getBusCount (false); + + for (int i = 0; i < numInputBuses; ++i) + { + auto layout = pluginInstance->getChannelLayoutOfBus (true, i); + + if (layout.isDiscreteLayout() && ! layout.isDisabled()) + return false; + } + + for (int i = 0; i < numOutputBuses; ++i) + { + auto layout = pluginInstance->getChannelLayoutOfBus (false, i); + + if (layout.isDiscreteLayout() && ! layout.isDisabled()) + return false; + } + + return true; + } + + tresult PLUGIN_API setBusArrangements (Vst::SpeakerArrangement* inputs, Steinberg::int32 numIns, + Vst::SpeakerArrangement* outputs, Steinberg::int32 numOuts) override + { + const FLStudioDIYSpecificationEnforcementLock lock (flStudioDIYSpecificationEnforcementMutex); + + if (active) + { + // The host is misbehaving! The plugin must be deactivated before setting new arrangements. + jassertfalse; + return kResultFalse; + } + + auto numInputBuses = pluginInstance->getBusCount (true); + auto numOutputBuses = pluginInstance->getBusCount (false); + + if (numIns > numInputBuses || numOuts > numOutputBuses) + return kResultFalse; + + // see the following documentation to understand the correct way to react to this callback + // https://steinbergmedia.github.io/vst3_doc/vstinterfaces/classSteinberg_1_1Vst_1_1IAudioProcessor.html#ad3bc7bac3fd3b194122669be2a1ecc42 + + const auto toLayoutsArray = [] (auto begin, auto end) -> std::optional> + { + Array result; + + for (auto it = begin; it != end; ++it) + { + const auto set = getChannelSetForSpeakerArrangement (*it); + + if (! set.has_value()) + return {}; + + result.add (*set); + } + + return result; + }; + + const auto optionalRequestedLayout = [&]() -> std::optional + { + const auto ins = toLayoutsArray (inputs, inputs + numIns); + const auto outs = toLayoutsArray (outputs, outputs + numOuts); + + if (! ins.has_value() || ! outs.has_value()) + return {}; + + AudioProcessor::BusesLayout result; + result.inputBuses = *ins; + result.outputBuses = *outs; + return result; + }(); + + if (! optionalRequestedLayout.has_value()) + return kResultFalse; + + const auto& requestedLayout = *optionalRequestedLayout; + + #ifdef JucePlugin_PreferredChannelConfigurations + short configs[][2] = { JucePlugin_PreferredChannelConfigurations }; + if (! AudioProcessor::containsLayout (requestedLayout, configs)) + return kResultFalse; + #endif + + if (pluginInstance->checkBusesLayoutSupported (requestedLayout)) + { + if (! pluginInstance->setBusesLayoutWithoutEnabling (requestedLayout)) + return kResultFalse; + + bufferMapper.updateFromProcessor (*pluginInstance); + return kResultTrue; + } + + // apply layout changes in reverse order as Steinberg says we should prioritize main buses + const auto nextBest = [this, numInputBuses, numOutputBuses, &requestedLayout] + { + auto layout = pluginInstance->getBusesLayout(); + + for (auto busIdx = jmax (numInputBuses, numOutputBuses) - 1; busIdx >= 0; --busIdx) + for (const auto isInput : { true, false }) + if (auto* bus = pluginInstance->getBus (isInput, busIdx)) + bus->isLayoutSupported (requestedLayout.getChannelSet (isInput, busIdx), &layout); + + return layout; + }(); + + if (pluginInstance->setBusesLayoutWithoutEnabling (nextBest)) + bufferMapper.updateFromProcessor (*pluginInstance); + + return kResultFalse; + } + + tresult PLUGIN_API getBusArrangement (Vst::BusDirection dir, Steinberg::int32 index, Vst::SpeakerArrangement& arr) override + { + if (auto* bus = pluginInstance->getBus (dir == Vst::kInput, index)) + { + if (const auto arrangement = getVst3SpeakerArrangement (bus->getLastEnabledLayout())) + { + arr = *arrangement; + return kResultTrue; + } + + // There's a bus here, but we can't represent its layout in terms of VST3 speakers! + jassertfalse; + } + + return kResultFalse; + } + + //============================================================================== + tresult PLUGIN_API canProcessSampleSize (Steinberg::int32 symbolicSampleSize) override + { + return (symbolicSampleSize == Vst::kSample32 + || (getPluginInstance().supportsDoublePrecisionProcessing() + && symbolicSampleSize == Vst::kSample64)) ? kResultTrue : kResultFalse; + } + + Steinberg::uint32 PLUGIN_API getLatencySamples() override + { + return (Steinberg::uint32) jmax (0, getPluginInstance().getLatencySamples()); + } + + tresult PLUGIN_API setupProcessing (Vst::ProcessSetup& newSetup) override + { + ScopedInSetupProcessingSetter inSetupProcessingSetter (juceVST3EditController); + + if (canProcessSampleSize (newSetup.symbolicSampleSize) != kResultTrue) + return kResultFalse; + + processSetup = newSetup; + processContext.sampleRate = processSetup.sampleRate; + + getPluginInstance().setProcessingPrecision (newSetup.symbolicSampleSize == Vst::kSample64 + ? AudioProcessor::doublePrecision + : AudioProcessor::singlePrecision); + getPluginInstance().setNonRealtime (newSetup.processMode == Vst::kOffline); + + preparePlugin (processSetup.sampleRate, processSetup.maxSamplesPerBlock, CallPrepareToPlay::no); + + return kResultTrue; + } + + tresult PLUGIN_API setProcessing (TBool state) override + { + if (! state) + getPluginInstance().reset(); + + return kResultTrue; + } + + Steinberg::uint32 PLUGIN_API getTailSamples() override + { + auto tailLengthSeconds = getPluginInstance().getTailLengthSeconds(); + + if (tailLengthSeconds <= 0.0 || processSetup.sampleRate <= 0.0) + return Vst::kNoTail; + + if (std::isinf (tailLengthSeconds)) + return Vst::kInfiniteTail; + + return (Steinberg::uint32) roundToIntAccurate (tailLengthSeconds * processSetup.sampleRate); + } + + //============================================================================== + void processParameterChanges (Vst::IParameterChanges& paramChanges) + { + jassert (pluginInstance != nullptr); + + struct ParamChangeInfo + { + Steinberg::int32 offsetSamples = 0; + double value = 0.0; + }; + + const auto getPointFromQueue = [] (Steinberg::Vst::IParamValueQueue* queue, Steinberg::int32 index) + { + ParamChangeInfo result; + return queue->getPoint (index, result.offsetSamples, result.value) == kResultTrue + ? makeOptional (result) + : nullopt; + }; + + const auto numParamsChanged = paramChanges.getParameterCount(); + + for (Steinberg::int32 i = 0; i < numParamsChanged; ++i) + { + if (auto* paramQueue = paramChanges.getParameterData (i)) + { + const auto vstParamID = paramQueue->getParameterId(); + const auto numPoints = paramQueue->getPointCount(); + + #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS + if (juceVST3EditController != nullptr && juceVST3EditController->isMidiControllerParamID (vstParamID)) + { + for (Steinberg::int32 point = 0; point < numPoints; ++point) + { + if (const auto change = getPointFromQueue (paramQueue, point)) + addParameterChangeToMidiBuffer (change->offsetSamples, vstParamID, change->value); + } + } + else + #endif + if (const auto change = getPointFromQueue (paramQueue, numPoints - 1)) + { + if (auto* param = comPluginInstance->getParamForVSTParamID (vstParamID)) + setValueAndNotifyIfChanged (*param, (float) change->value); + } + } + } + } + + void addParameterChangeToMidiBuffer (const Steinberg::int32 offsetSamples, const Vst::ParamID id, const double value) + { + // If the parameter is mapped to a MIDI CC message then insert it into the midiBuffer. + int channel, ctrlNumber; + + if (juceVST3EditController->getMidiControllerForParameter (id, channel, ctrlNumber)) + { + if (ctrlNumber == Vst::kAfterTouch) + midiBuffer.addEvent (MidiMessage::channelPressureChange (channel, + jlimit (0, 127, (int) (value * 128.0))), offsetSamples); + else if (ctrlNumber == Vst::kPitchBend) + midiBuffer.addEvent (MidiMessage::pitchWheel (channel, + jlimit (0, 0x3fff, (int) (value * 0x4000))), offsetSamples); + else + midiBuffer.addEvent (MidiMessage::controllerEvent (channel, + jlimit (0, 127, ctrlNumber), + jlimit (0, 127, (int) (value * 128.0))), offsetSamples); + } + } + + tresult PLUGIN_API process (Vst::ProcessData& data) override + { + const FLStudioDIYSpecificationEnforcementLock lock (flStudioDIYSpecificationEnforcementMutex); + + if (pluginInstance == nullptr) + return kResultFalse; + + if ((processSetup.symbolicSampleSize == Vst::kSample64) != pluginInstance->isUsingDoublePrecision()) + return kResultFalse; + + if (data.processContext != nullptr) + { + processContext = *data.processContext; + + if (juceVST3EditController != nullptr) + juceVST3EditController->vst3IsPlaying = (processContext.state & Vst::ProcessContext::kPlaying) != 0; + } + else + { + zerostruct (processContext); + + if (juceVST3EditController != nullptr) + juceVST3EditController->vst3IsPlaying = false; + } + + midiBuffer.clear(); + + if (data.inputParameterChanges != nullptr) + processParameterChanges (*data.inputParameterChanges); + + #if JucePlugin_WantsMidiInput + if (isMidiInputBusEnabled && data.inputEvents != nullptr) + MidiEventList::toMidiBuffer (midiBuffer, *data.inputEvents); + #endif + + if (detail::PluginUtilities::getHostType().isWavelab()) + { + const int numInputChans = (data.inputs != nullptr && data.inputs[0].channelBuffers32 != nullptr) ? (int) data.inputs[0].numChannels : 0; + const int numOutputChans = (data.outputs != nullptr && data.outputs[0].channelBuffers32 != nullptr) ? (int) data.outputs[0].numChannels : 0; + + if ((pluginInstance->getTotalNumInputChannels() + pluginInstance->getTotalNumOutputChannels()) > 0 + && (numInputChans + numOutputChans) == 0) + return kResultFalse; + } + + // If all of these are zero, the host is attempting to flush parameters without processing audio. + if (data.numSamples != 0 || data.numInputs != 0 || data.numOutputs != 0) + { + if (processSetup.symbolicSampleSize == Vst::kSample32) processAudio (data); + else if (processSetup.symbolicSampleSize == Vst::kSample64) processAudio (data); + else jassertfalse; + } + + if (auto* changes = data.outputParameterChanges) + { + comPluginInstance->forAllChangedParameters ([&] (Vst::ParamID paramID, float value) + { + Steinberg::int32 queueIndex = 0; + + if (auto* queue = changes->addParameterData (paramID, queueIndex)) + { + Steinberg::int32 pointIndex = 0; + queue->addPoint (0, value, pointIndex); + } + }); + } + + #if JucePlugin_ProducesMidiOutput + if (isMidiOutputBusEnabled && data.outputEvents != nullptr) + MidiEventList::pluginToHostEventList (*data.outputEvents, midiBuffer); + #endif + + return kResultTrue; + } + +private: + /* FL's Patcher implements the VST3 specification incorrectly, calls process() before/during + setActive(). + */ + class [[nodiscard]] FLStudioDIYSpecificationEnforcementLock + { + public: + explicit FLStudioDIYSpecificationEnforcementLock (CriticalSection& mutex) + { + static const auto lockRequired = PluginHostType().isFruityLoops(); + + if (lockRequired) + lock.emplace (mutex); + } + + private: + std::optional lock; + }; + + InterfaceResultWithDeferredAddRef queryInterfaceInternal (const TUID targetIID) + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + #if JucePlugin_Enable_ARA + UniqueBase{}, + UniqueBase{}, + #endif + SharedBase{}); + + if (result.isOk()) + return result; + + if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) + return { kResultOk, comPluginInstance.get() }; + + return {}; + } + + //============================================================================== + struct ScopedInSetupProcessingSetter + { + ScopedInSetupProcessingSetter (JuceVST3EditController* c) + : controller (c) + { + if (controller != nullptr) + controller->inSetupProcessing = true; + } + + ~ScopedInSetupProcessingSetter() + { + if (controller != nullptr) + controller->inSetupProcessing = false; + } + + private: + JuceVST3EditController* controller = nullptr; + }; + + //============================================================================== + template + void processAudio (Vst::ProcessData& data) + { + ClientRemappedBuffer remappedBuffer { bufferMapper, data }; + auto& buffer = remappedBuffer.buffer; + + jassert ((int) buffer.getNumChannels() == jmax (pluginInstance->getTotalNumInputChannels(), + pluginInstance->getTotalNumOutputChannels())); + + { + const ScopedLock sl (pluginInstance->getCallbackLock()); + + pluginInstance->setNonRealtime (data.processMode == Vst::kOffline); + + #if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput + const int numMidiEventsComingIn = midiBuffer.getNumEvents(); + #endif + + if (pluginInstance->isSuspended()) + { + buffer.clear(); + } + else + { + // processBlockBypassed should only ever be called if the AudioProcessor doesn't + // return a valid parameter from getBypassParameter + if (pluginInstance->getBypassParameter() == nullptr && comPluginInstance->getBypassParameter()->getValue() >= 0.5f) + pluginInstance->processBlockBypassed (buffer, midiBuffer); + else + pluginInstance->processBlock (buffer, midiBuffer); + } + + #if JUCE_DEBUG && (! JucePlugin_ProducesMidiOutput) + /* This assertion is caused when you've added some events to the + midiMessages array in your processBlock() method, which usually means + that you're trying to send them somewhere. But in this case they're + getting thrown away. + + If your plugin does want to send MIDI messages, you'll need to set + the JucePlugin_ProducesMidiOutput macro to 1 in your + JucePluginCharacteristics.h file. + + If you don't want to produce any MIDI output, then you should clear the + midiMessages array at the end of your processBlock() method, to + indicate that you don't want any of the events to be passed through + to the output. + */ + jassert (midiBuffer.getNumEvents() <= numMidiEventsComingIn); + #endif + } + } + + //============================================================================== + Steinberg::uint32 PLUGIN_API getProcessContextRequirements() override + { + return kNeedSystemTime + | kNeedContinousTimeSamples + | kNeedProjectTimeMusic + | kNeedBarPositionMusic + | kNeedCycleMusic + | kNeedSamplesToNextClock + | kNeedTempo + | kNeedTimeSignature + | kNeedChord + | kNeedFrameRate + | kNeedTransportState; + } + + void preparePlugin (double sampleRate, int bufferSize, CallPrepareToPlay callPrepareToPlay) + { + auto& p = getPluginInstance(); + + p.setRateAndBufferSizeDetails (sampleRate, bufferSize); + + if (callPrepareToPlay == CallPrepareToPlay::yes) + p.prepareToPlay (sampleRate, bufferSize); + + midiBuffer.ensureSize (2048); + midiBuffer.clear(); + + bufferMapper.updateFromProcessor (p); + bufferMapper.prepare (bufferSize); + } + + //============================================================================== + #if JucePlugin_Enable_ARA + const ARA::ARAFactory* PLUGIN_API getFactory() SMTG_OVERRIDE + { + return createARAFactory(); + } + + const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentController (ARA::ARADocumentControllerRef /*controllerRef*/) SMTG_OVERRIDE + { + ARA_VALIDATE_API_STATE (false && "call is deprecated in ARA 2, host must not call this"); + return nullptr; + } + + const ARA::ARAPlugInExtensionInstance* PLUGIN_API bindToDocumentControllerWithRoles (ARA::ARADocumentControllerRef documentControllerRef, + ARA::ARAPlugInInstanceRoleFlags knownRoles, ARA::ARAPlugInInstanceRoleFlags assignedRoles) SMTG_OVERRIDE + { + AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast (pluginInstance); + return araAudioProcessorExtension->bindToARA (documentControllerRef, knownRoles, assignedRoles); + } + #endif + + //============================================================================== + ScopedJuceInitialiser_GUI libraryInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + std::atomic refCount { 1 }; + AudioProcessor* pluginInstance = nullptr; + + #if JUCE_LINUX || JUCE_BSD + template + struct LockedVSTComSmartPtr + { + LockedVSTComSmartPtr() = default; + LockedVSTComSmartPtr (const VSTComSmartPtr& ptrIn) : ptr (ptrIn) {} + LockedVSTComSmartPtr (const LockedVSTComSmartPtr&) = default; + LockedVSTComSmartPtr& operator= (const LockedVSTComSmartPtr&) = default; + + ~LockedVSTComSmartPtr() + { + const MessageManagerLock mmLock; + ptr = {}; + } + + T* operator->() const { return ptr.operator->(); } + T* get() const noexcept { return ptr.get(); } + operator T*() const noexcept { return ptr.get(); } + + template + bool loadFrom (Args&&... args) { return ptr.loadFrom (std::forward (args)...); } + + private: + VSTComSmartPtr ptr; + }; + + LockedVSTComSmartPtr host; + LockedVSTComSmartPtr comPluginInstance; + LockedVSTComSmartPtr juceVST3EditController; + #else + VSTComSmartPtr host; + VSTComSmartPtr comPluginInstance; + VSTComSmartPtr juceVST3EditController; + #endif + + /** + Since VST3 does not provide a way of knowing the buffer size and sample rate at any point, + this object needs to be copied on every call to process() to be up-to-date... + */ + Vst::ProcessContext processContext; + Vst::ProcessSetup processSetup; + + MidiBuffer midiBuffer; + ClientBufferMapper bufferMapper; + + bool active = false; + + #if JucePlugin_WantsMidiInput + std::atomic isMidiInputBusEnabled { true }; + #endif + #if JucePlugin_ProducesMidiOutput + std::atomic isMidiOutputBusEnabled { true }; + #endif + + inline static constexpr const char* kJucePrivateDataIdentifier = "JUCEPrivateData"; + CriticalSection flStudioDIYSpecificationEnforcementMutex; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Component) +}; + +//============================================================================== +bool initModule(); +bool initModule() +{ + return true; +} + +bool shutdownModule(); +bool shutdownModule() +{ + return true; +} + +#undef JUCE_EXPORTED_FUNCTION + +#if JUCE_WINDOWS + #define JUCE_EXPORTED_FUNCTION +#else + #define JUCE_EXPORTED_FUNCTION extern "C" __attribute__ ((visibility("default"))) +#endif + +#if JUCE_WINDOWS + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + + extern "C" __declspec (dllexport) bool InitDll() { return initModule(); } + extern "C" __declspec (dllexport) bool ExitDll() { return shutdownModule(); } + + JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#elif JUCE_LINUX || JUCE_BSD + void* moduleHandle = nullptr; + int moduleEntryCounter = 0; + + JUCE_EXPORTED_FUNCTION bool ModuleEntry (void* sharedLibraryHandle); + JUCE_EXPORTED_FUNCTION bool ModuleEntry (void* sharedLibraryHandle) + { + if (++moduleEntryCounter == 1) + { + moduleHandle = sharedLibraryHandle; + return initModule(); + } + + return true; + } + + JUCE_EXPORTED_FUNCTION bool ModuleExit(); + JUCE_EXPORTED_FUNCTION bool ModuleExit() + { + if (--moduleEntryCounter == 0) + { + moduleHandle = nullptr; + return shutdownModule(); + } + + return true; + } +#elif JUCE_MAC + CFBundleRef globalBundleInstance = nullptr; + juce::uint32 numBundleRefs = 0; + juce::Array bundleRefs; + + enum { MaxPathLength = 2048 }; + char modulePath[MaxPathLength] = { 0 }; + void* moduleHandle = nullptr; + + JUCE_EXPORTED_FUNCTION bool bundleEntry (CFBundleRef ref); + JUCE_EXPORTED_FUNCTION bool bundleEntry (CFBundleRef ref) + { + if (ref != nullptr) + { + ++numBundleRefs; + CFRetain (ref); + + bundleRefs.add (ref); + + if (moduleHandle == nullptr) + { + globalBundleInstance = ref; + moduleHandle = ref; + + CFUniquePtr tempURL (CFBundleCopyBundleURL (ref)); + CFURLGetFileSystemRepresentation (tempURL.get(), true, (UInt8*) modulePath, MaxPathLength); + } + } + + return initModule(); + } + + JUCE_EXPORTED_FUNCTION bool bundleExit(); + JUCE_EXPORTED_FUNCTION bool bundleExit() + { + if (shutdownModule()) + { + if (--numBundleRefs == 0) + { + for (int i = 0; i < bundleRefs.size(); ++i) + CFRelease (bundleRefs.getUnchecked (i)); + + bundleRefs.clear(); + } + + return true; + } + + return false; + } +#endif + +// See https://steinbergmedia.github.io/vst3_dev_portal/pages/FAQ/Compatibility+with+VST+2.x+or+VST+1.html +class JucePluginCompatibility : public IPluginCompatibility +{ +public: + virtual ~JucePluginCompatibility() = default; + + JUCE_DECLARE_VST3_COM_REF_METHODS + + tresult PLUGIN_API getCompatibilityJSON (IBStream* stream) override + { + const ScopedJuceInitialiser_GUI libraryInitialiser; + + auto filter = createPluginFilterOfType (AudioProcessor::WrapperType::wrapperType_VST3); + auto* extensions = filter->getVST3ClientExtensions(); + + if (extensions == nullptr || extensions->getCompatibleClasses().empty()) + return kResultFalse; + + DynamicObject::Ptr object { new DynamicObject }; + + // New iid is the ID of our Audio Effect class + object->setProperty ("New", String (VST3::UID (JuceVST3Component::iid).toString())); + object->setProperty ("Old", [&] + { + Array oldArray; + + for (const auto& uid : extensions->getCompatibleClasses()) + { + // All UIDs returned from getCompatibleClasses should be 32 characters long + jassert (uid.length() == 32); + + // All UIDs returned from getCompatibleClasses should be in hex notation + jassert (uid.containsOnly ("ABCDEF0123456789")); + + oldArray.add (uid); + } + + return oldArray; + }()); + + MemoryOutputStream memory; + JSON::writeToStream (memory, var { Array { object.get() } }); + return stream->write (memory.getMemoryBlock().getData(), (Steinberg::int32) memory.getDataSize()); + } + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + jassertfalse; // Something new? + *obj = nullptr; + return kNotImplemented; + } + + inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0xC0DEF00D, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + +private: + std::atomic refCount { 1 }; +}; + +//============================================================================== +/** This typedef represents VST3's createInstance() function signature */ +using CreateFunction = FUnknown* (*)(Vst::IHostApplication*); + +//============================================================================== +struct JucePluginFactory : public IPluginFactory3 +{ + JucePluginFactory() + : factoryInfo (JucePlugin_Manufacturer, JucePlugin_ManufacturerWebsite, + JucePlugin_ManufacturerEmail, Vst::kDefaultFactoryFlags) {} + + virtual ~JucePluginFactory() = default; + + //============================================================================== + JUCE_DECLARE_VST3_COM_REF_METHODS + + tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + jassertfalse; // Something new? + *obj = nullptr; + return kNotImplemented; + } + + //============================================================================== + Steinberg::int32 PLUGIN_API countClasses() override + { + return (Steinberg::int32) getClassEntries().size(); + } + + tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) override + { + if (info == nullptr) + return kInvalidArgument; + + memcpy (info, &factoryInfo, sizeof (PFactoryInfo)); + return kResultOk; + } + + tresult PLUGIN_API getClassInfo (Steinberg::int32 index, PClassInfo* info) override + { + return getPClassInfo (index, info); + } + + tresult PLUGIN_API getClassInfo2 (Steinberg::int32 index, PClassInfo2* info) override + { + return getPClassInfo (index, info); + } + + tresult PLUGIN_API getClassInfoUnicode (Steinberg::int32 index, PClassInfoW* info) override + { + if (info != nullptr) + { + memcpy (info, &getClassEntries()[static_cast (index)].infoW, sizeof (PClassInfoW)); + return kResultOk; + } + + return kInvalidArgument; + } + + tresult PLUGIN_API createInstance (FIDString cid, FIDString sourceIid, void** obj) override + { + ScopedJuceInitialiser_GUI libraryInitialiser; + + #if JUCE_LINUX || JUCE_BSD + SharedResourcePointer messageThread; + #endif + + *obj = nullptr; + + TUID tuid; + memcpy (tuid, sourceIid, sizeof (TUID)); + + #if VST_VERSION >= 0x030608 + auto sourceFuid = FUID::fromTUID (tuid); + #else + FUID sourceFuid; + sourceFuid = tuid; + #endif + + if (cid == nullptr || sourceIid == nullptr || ! sourceFuid.isValid()) + { + jassertfalse; // The host you're running in has severe implementation issues! + return kInvalidArgument; + } + + TUID iidToQuery; + sourceFuid.toTUID (iidToQuery); + + for (auto& entry : getClassEntries()) + { + if (doUIDsMatch (entry.infoW.cid, cid)) + { + if (auto* instance = entry.createFunction (host)) + { + const FReleaser releaser (instance); + + if (instance->queryInterface (iidToQuery, obj) == kResultOk) + return kResultOk; + } + + break; + } + } + + return kNoInterface; + } + + tresult PLUGIN_API setHostContext (FUnknown* context) override + { + host.loadFrom (context); + + if (host != nullptr) + { + Vst::String128 name; + host->getName (name); + + return kResultTrue; + } + + return kNotImplemented; + } + +private: + //============================================================================== + std::atomic refCount { 1 }; + const PFactoryInfo factoryInfo; + VSTComSmartPtr host; + + //============================================================================== + struct ClassEntry + { + ClassEntry (const PClassInfo2& info, CreateFunction fn) noexcept + : info2 (info), createFunction (fn) + { + infoW.fromAscii (info); + } + + PClassInfo2 info2; + PClassInfoW infoW; + CreateFunction createFunction = {}; + + private: + JUCE_DECLARE_NON_COPYABLE (ClassEntry) + }; + + static Span getClassEntries() + { + #ifndef JucePlugin_Vst3ComponentFlags + #if JucePlugin_IsSynth + #define JucePlugin_Vst3ComponentFlags Vst::kSimpleModeSupported + #else + #define JucePlugin_Vst3ComponentFlags 0 + #endif + #endif + + #ifndef JucePlugin_Vst3Category + #if JucePlugin_IsSynth + #define JucePlugin_Vst3Category Vst::PlugType::kInstrumentSynth + #else + #define JucePlugin_Vst3Category Vst::PlugType::kFx + #endif + #endif + + static const PClassInfo2 compatibilityClass { JucePluginCompatibility::iid, + PClassInfo::kManyInstances, + kPluginCompatibilityClass, + JucePlugin_Name, + 0, + "", + JucePlugin_Manufacturer, + JucePlugin_VersionString, + kVstVersionString }; + + static const PClassInfo2 componentClass { JuceVST3Component::iid, + PClassInfo::kManyInstances, + kVstAudioEffectClass, + JucePlugin_Name, + JucePlugin_Vst3ComponentFlags, + JucePlugin_Vst3Category, + JucePlugin_Manufacturer, + JucePlugin_VersionString, + kVstVersionString }; + + static const PClassInfo2 controllerClass { JuceVST3EditController::iid, + PClassInfo::kManyInstances, + kVstComponentControllerClass, + JucePlugin_Name, + JucePlugin_Vst3ComponentFlags, + JucePlugin_Vst3Category, + JucePlugin_Manufacturer, + JucePlugin_VersionString, + kVstVersionString }; + #if JucePlugin_Enable_ARA + static const PClassInfo2 araFactoryClass { JuceARAFactory::iid, + PClassInfo::kManyInstances, + kARAMainFactoryClass, + JucePlugin_Name, + JucePlugin_Vst3ComponentFlags, + JucePlugin_Vst3Category, + JucePlugin_Manufacturer, + JucePlugin_VersionString, + kVstVersionString }; + #endif + + static const ClassEntry classEntries[] + { + ClassEntry { compatibilityClass, [] (Vst::IHostApplication*) -> Steinberg::FUnknown* + { + return new JucePluginCompatibility; + } }, + ClassEntry { componentClass, [] (Vst::IHostApplication* h) -> Steinberg::FUnknown* + { + return static_cast (new JuceVST3Component (h)); + } }, + ClassEntry { controllerClass, [] (Vst::IHostApplication* h) -> Steinberg::FUnknown* + { + return static_cast (new JuceVST3EditController (h)); + } }, + #if JucePlugin_Enable_ARA + ClassEntry { araFactoryClass, [] (Vst::IHostApplication*) -> Steinberg::FUnknown* + { + return static_cast (new JuceARAFactory); + } }, + #endif + }; + + return Span { classEntries }; + } + + //============================================================================== + template + tresult PLUGIN_API getPClassInfo (Steinberg::int32 index, PClassInfoType* info) + { + if (info != nullptr) + { + zerostruct (*info); + memcpy (info, (PClassInfoType*) &getClassEntries()[static_cast (index)].info2, sizeof (PClassInfoType)); + return kResultOk; + } + + jassertfalse; + return kInvalidArgument; + } + + //============================================================================== + // no leak detector here to prevent it firing on shutdown when running in hosts that + // don't release the factory object correctly... + JUCE_DECLARE_NON_COPYABLE (JucePluginFactory) +}; + +} // namespace juce + +//============================================================================== +using namespace juce; + +//============================================================================== +// The VST3 plugin entry point. +extern "C" SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API GetPluginFactory() +{ + #if (JUCE_MSVC || (JUCE_WINDOWS && JUCE_CLANG)) && JUCE_32BIT + // Cunning trick to force this function to be exported. Life's too short to + // faff around creating .def files for this kind of thing. + // Unnecessary for 64-bit builds because those don't use decorated function names. + #pragma comment(linker, "/EXPORT:GetPluginFactory=_GetPluginFactory@0") + #endif + + return new JucePluginFactory(); +} + +//============================================================================== +#if JUCE_WINDOWS +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes") + +extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) Process::setCurrentModuleInstanceHandle (instance); return true; } + +JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif + +JUCE_END_NO_SANITIZE + +#endif //JucePlugin_Build_VST3 diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.mm new file mode 100644 index 000000000000..54b145434e8e --- /dev/null +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.mm @@ -0,0 +1,26 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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 "juce_audio_plugin_client_VST3.cpp" diff --git a/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp b/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp deleted file mode 100644 index f6b4b2689deb..000000000000 --- a/modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2022 - Raw Material Software Limited - - 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 7 End-User License - Agreement and JUCE Privacy Policy. - - End User License Agreement: www.juce.com/juce-7-licence - Privacy Policy: www.juce.com/juce-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 _MSC_VER || defined (__MINGW32__) || defined (__MINGW64__) - #include -#endif - -#include -#include "../utility/juce_CheckSettingMacros.h" -#include "juce_IncludeModuleHeaders.h" - -namespace juce -{ - -#if JucePlugin_Build_Unity - bool juce_isRunningInUnity(); - bool juce_isRunningInUnity() { return PluginHostType::getPluginLoadedAs() == AudioProcessor::wrapperType_Unity; } -#endif - -#ifndef JUCE_VST3_CAN_REPLACE_VST2 - #define JUCE_VST3_CAN_REPLACE_VST2 1 -#endif - -#if JucePlugin_Build_VST3 && JUCE_VST3_CAN_REPLACE_VST2 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD) - #define VST3_REPLACEMENT_AVAILABLE 1 - - // NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code. - void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16]); - void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16]) - { - #if JUCE_MSVC - const auto juce_sprintf = [] (auto&& head, auto&&... tail) { sprintf_s (head, numElementsInArray (head), tail...); }; - const auto juce_strcpy = [] (auto&& head, auto&&... tail) { strcpy_s (head, numElementsInArray (head), tail...); }; - const auto juce_strcat = [] (auto&& head, auto&&... tail) { strcat_s (head, numElementsInArray (head), tail...); }; - const auto juce_sscanf = [] (auto&&... args) { sscanf_s (args...); }; - #else - const auto juce_sprintf = [] (auto&& head, auto&&... tail) { snprintf (head, (size_t) numElementsInArray (head), tail...); }; - const auto juce_strcpy = [] (auto&&... args) { strcpy (args...); }; - const auto juce_strcat = [] (auto&&... args) { strcat (args...); }; - const auto juce_sscanf = [] (auto&&... args) { sscanf (args...); }; - #endif - - char uidString[33]; - - const int vstfxid = (('V' << 16) | ('S' << 8) | (forControllerUID ? 'E' : 'T')); - char vstfxidStr[7] = { 0 }; - juce_sprintf (vstfxidStr, "%06X", vstfxid); - - juce_strcpy (uidString, vstfxidStr); - - char uidStr[9] = { 0 }; - juce_sprintf (uidStr, "%08X", JucePlugin_VSTUniqueID); - juce_strcat (uidString, uidStr); - - char nameidStr[3] = { 0 }; - const size_t len = strlen (JucePlugin_Name); - - for (size_t i = 0; i <= 8; ++i) - { - juce::uint8 c = i < len ? static_cast (JucePlugin_Name[i]) : 0; - - if (c >= 'A' && c <= 'Z') - c += 'a' - 'A'; - - juce_sprintf (nameidStr, "%02X", c); - juce_strcat (uidString, nameidStr); - } - - unsigned long p0; - unsigned int p1, p2; - unsigned int p3[8]; - - juce_sscanf (uidString, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", - &p0, &p1, &p2, &p3[0], &p3[1], &p3[2], &p3[3], &p3[4], &p3[5], &p3[6], &p3[7]); - - union q0_u { - uint32 word; - uint8 bytes[4]; - } q0; - - union q1_u { - uint16 half; - uint8 bytes[2]; - } q1, q2; - - q0.word = static_cast (p0); - q1.half = static_cast (p1); - q2.half = static_cast (p2); - - // VST3 doesn't use COM compatible UUIDs on non windows platforms - #if ! JUCE_WINDOWS - q0.word = ByteOrder::swap (q0.word); - q1.half = ByteOrder::swap (q1.half); - q2.half = ByteOrder::swap (q2.half); - #endif - - for (int i = 0; i < 4; ++i) - uuid[i+0] = q0.bytes[i]; - - for (int i = 0; i < 2; ++i) - uuid[i+4] = q1.bytes[i]; - - for (int i = 0; i < 2; ++i) - uuid[i+6] = q2.bytes[i]; - - for (int i = 0; i < 8; ++i) - uuid[i+8] = static_cast (p3[i]); - } -#else - #define VST3_REPLACEMENT_AVAILABLE 0 -#endif - -#if JucePlugin_Build_VST - bool JUCE_API handleManufacturerSpecificVST2Opcode (int32 index, pointer_sized_int value, void* ptr, float); - bool JUCE_API handleManufacturerSpecificVST2Opcode ([[maybe_unused]] int32 index, - [[maybe_unused]] pointer_sized_int value, - [[maybe_unused]] void* ptr, - float) - { - #if VST3_REPLACEMENT_AVAILABLE - if ((index == (int32) ByteOrder::bigEndianInt ("stCA") || index == (int32) ByteOrder::bigEndianInt ("stCa")) - && value == (int32) ByteOrder::bigEndianInt ("FUID") && ptr != nullptr) - { - uint8 fuid[16]; - getUUIDForVST2ID (false, fuid); - ::memcpy (ptr, fuid, 16); - return true; - } - #endif - return false; - } -#endif - -} // namespace juce diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/JUCE_README.md b/modules/juce_audio_processors/format_types/VST3_SDK/JUCE_README.md index d337f051b127..f3e3689c36db 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/JUCE_README.md +++ b/modules/juce_audio_processors/format_types/VST3_SDK/JUCE_README.md @@ -1,6 +1,5 @@ This list details modifications made to the VST3 SDK in order to facilitate inclusion in JUCE. -- `#warning` directives were removed from fstring.cpp, as these cannot be - silenced with a `pragma GCC diagnostic ignored "-Wcpp"` when building with - g++. +- The main.cpp of moduleinfotool was updated to include information exported + by the plugin's IPluginCompatibility object, if present. diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt b/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt index b5fddfe769da..6daa072e68e6 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt +++ b/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt @@ -1,41 +1,44 @@ -//----------------------------------------------------------------------------- -// LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved -//----------------------------------------------------------------------------- -This license applies only to files referencing this license, -for other files of the Software Development Kit the respective embedded license text -is applicable. The license can be found at: www.steinberg.net/sdklicenses_vst3 - -This Software Development Kit is licensed under the terms of the Steinberg VST3 License, -or alternatively under the terms of the General Public License (GPL) Version 3. -You may use the Software Development Kit according to either of these licenses as it is -most appropriate for your project on a case-by-case basis (commercial or not). - -a) Proprietary Steinberg VST3 License -The Software Development Kit may not be distributed in parts or its entirety -without prior written agreement by Steinberg Media Technologies GmbH. -The SDK must not be used to re-engineer or manipulate any technology used -in any Steinberg or Third-party application or software module, -unless permitted by law. -Neither the name of the Steinberg Media Technologies GmbH nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. -Before publishing a software under the proprietary license, you need to obtain a copy -of the License Agreement signed by Steinberg Media Technologies GmbH. -The Steinberg VST SDK License Agreement can be found at: -www.steinberg.net/en/company/developers.html - -THE SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - -b) General Public License (GPL) Version 3 -Details of these licenses can be found at: www.gnu.org/licenses/gpl-3.0.html -//---------------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +This license applies only to files referencing this license, +for other files of the Software Development Kit the respective embedded license text +is applicable. The license can be found at: www.steinberg.net/sdklicenses_vst3 + +This Software Development Kit is licensed under the terms of the Steinberg VST3 License, +or alternatively under the terms of the General Public License (GPL) Version 3. +You may use the Software Development Kit according to either of these licenses as it is +most appropriate for your project on a case-by-case basis (commercial or not). + +a) Proprietary Steinberg VST3 License +The Software Development Kit may not be distributed in parts or its entirety +without prior written agreement by Steinberg Media Technologies GmbH. +The SDK must not be used to re-engineer or manipulate any technology used +in any Steinberg or Third-party application or software module, +unless permitted by law. +Neither the name of the Steinberg Media Technologies GmbH nor the names of its +contributors may be used to endorse or promote products derived from this +software without specific prior written permission. +Before publishing a software under the proprietary license, you need to obtain a copy +of the License Agreement signed by Steinberg Media Technologies GmbH. +The Steinberg VST SDK License Agreement can be found at: +www.steinberg.net/en/company/developers.html + +THE SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +b) General Public License (GPL) Version 3 +Details of these licenses can be found at: www.gnu.org/licenses/gpl-3.0.html +Please refer to the Steinberg VST usage guidelines for the use of VST, VST logo and VST +compatible logos: +https://steinbergmedia.github.io/vst3_dev_portal/pages/VST+3+Licensing/Usage+guidelines.html +//---------------------------------------------------------------------------------- diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/README.md b/modules/juce_audio_processors/format_types/VST3_SDK/README.md index 7be410549f6d..191fe7994842 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/README.md +++ b/modules/juce_audio_processors/format_types/VST3_SDK/README.md @@ -1,10 +1,267 @@ -# Welcome to VST 3 SDK Interfaces - -Here are located all VST interfaces definitions (including VST Component/Controller, UI, Test). - -## License & Usage guidelines - -More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) - ----- -Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) \ No newline at end of file +
+VST 3 SDK
+ +# Welcome to VST SDK 3.7.x + +## Table Of Contents + +1. [The VST SDK package](#100) +1. [System requirements](#200) +1. [About VST plug-ins in general](#300) +1. [About VST 3](#400) +1. [How to build VST 3](#500) +1. [Contributing](#600) +1. [License & Usage guidelines](#700) + +
+ +## The VST SDK package contains + +- VST 3 API +- VST 3 Implementation Helper Classes +- AAX, AU, AUv3 and VST 2 wrappers +- VST 3 plug-ins Examples + +The full VST 3 SDK is available [here!](https://www.steinberg.net/en/company/developers.html). It contains : + +- VST 3 plug-in Test Host Application/Validator, +- the **Steinberg VST 3 Plug-In SDK Licensing Agreement** that you have to sign if you want to develop or host **VST 3** plug-ins. + +
+ +## System requirements + +Supported Platforms: + +| Operating System |Architecture |Compiler | Notes| +| :------------------------------------ | :-----------------------: | :-------------------------------: | :-----------: | +|Windows 10/11 |x86, x86_64, arm64 |MSVC 2022, MSVC 2019 | | +|Windows 8.1 |x86, x86_64 |MSVC 2019, MSVC 2017 | | +|macOS 10.13, 10.14, 10.15, 11, 12, 13 |x86, x86_64, Apple Silicon |Xcode 10 - 14 | | +|iOS 13 - iOS 16 |arm64 |Xcode 11 - 14 | | +|Linux - Raspberry Pi OS (Buster) |arm32 |GCC 8.3 and higher |Visual Studio Code| +|Linux - Ubuntu 18.04 LTS |x86, x86_64 |GCC 8.3 and higher |Visual Studio Code, Qt Creator| +|Linux - Ubuntu 20.04 LTS |x86, x86_64 |GCC 8.3 and higher |Visual Studio Code, Qt Creator| + +--- +
+ +## About VST plug-ins in general + +A VST plug-in is an audio processing component that is utilized within a host application. This host application provides the audio or/and event streams that are processed by the plug-in's code. Generally speaking, a VST plug-in can take a stream of audio data, apply a process to the audio, and return the result to the host application. A VST plug-in performs its process normally using the processor of the computer. The audio stream is broken down into a series of blocks. The host supplies the blocks in sequence. The host and its current environment control the block-size. The VST plug-in maintains the status of all its own parameters relating to the running process: The host does not maintain any information about what the plug-in did with the last block of data it processed. + +From the host application's point of view, a VST plug-in is a black box with an arbitrary number of inputs, outputs (Event (MIDI) or Audio), and associated parameters. The host needs no implicit knowledge of the plug-in's process to be able to use it. The plug-in process can use whatever parameters it wishes, internally to the process, but depending on the capabilities of the host, it can allow the changes to user parameters to be automated by the host. + +The source code of a VST plug-in is platform independent, but the delivery system depends on the platform architecture: + +- On **Windows**, a VST plug-in is a multi-threaded DLL (Dynamic Link Library), recently packaged into a folder structure. +- On **Mac OS X**, a VST plug-in is a Mach-O Bundle +- On **Linux**, a VST plug-in is a package + +To learn more about VST you can: + +- subscribe to the [VST Developer Forum](https://sdk.steinberg.net) +- check the 3rd Party Developer Support section at [www.steinberg.net](https://www.steinberg.net/en/company/developers.html) +- check the VST 3 SDK online documentation under: [steinbergmedia.github.io/vst3_dev_portal](https://steinbergmedia.github.io/vst3_dev_portal/pages/index.html) +- check the online documentation under: [steinbergmedia.github.io/vst3_doc](https://steinbergmedia.github.io/vst3_doc) + + --- +
+ +## About VST 3 + +VST 3 is a general rework of the long-serving VST plug-in interface. It is not compatible with the older VST versions, but it includes some new features and possibilities. We have redesigned the API to make it not only far easier and more reliable for developers to work with, but have also provided completely new possibilities for plug-ins. These include: + +### 1. Improved Performance with the Silence Flag + +Processing can optionally be applied to plug-ins only when audio signals are present on their respective inputs, so VST 3 plug-ins can apply their processing economically and only when it is needed. + +### 2. Multiple Dynamic I/Os + +VST 3 plug-ins are no longer limited to a fixed number of inputs and outputs, and their I/O configuration can dynamically adapt to the channel configuration. Side-chains are also very easily realizable. This includes the possibility to deactivate unused busses after loading and even reactivate those when needed. This cleans up the mixer and further helps to reduce CPU load. + +### 3. Sample-accurate Automation + +VST 3 also features vastly improved parameter automation with sample accuracy and support for ramped automation data, allowing completely accurate and rapid parameter automation changes. + +### 4. Logical Parameter Organization + +The VST 3 plug-in parameters are displayed in a tree structure. Parameters are grouped into sections which represent the structure of the plug-in. Plug-ins can communicate their internal structure for the purpose of overview, but also for some associated functionality (eg. program-lists). + +### 5. Resizeable UI Editor + +VST 3 defines a way to allow resizing of the plug-in editor by a user. + +### 6. Mouse Over Support + +The host could ask the plug-in which parameter is under the mouse. + +### 7. Context Menu Support + +VST 3 defines a way to allow the host to add its own entries in the plug-in context menu of a specific parameter. + +### 8. Channel Context Information + +A VST 3 plug-in could access some channel information where it is instantiated: name, color, ... + +### 9. Note Expression + +VST 3 defines with Note Expression a new way of event controller editing. The plug-in is able to break free from the limitations of MIDI controller events by providing access to new VST 3 controller events that circumvent the laws of MIDI and provide articulation information for each individual note (event) in a polyphonic arrangement according to its noteId. + +### 10. 3D Support + +VST 3 supports new speaker configurations like Ambisonic, Atmos, Auro 3D or 22.2. + +### 11. Factory Concept + +VST 3 plug-in library could export multiple plug-ins and in this way replaces the shell concept of VST 2 (kPlugCategShell). + +### 12. Support Remote control Representation + +VST 3 plug-in can deliver a specific parameter mapping for remote controls like Nuage. + +### 13. Others + +While designing VST 3, we performed a careful analysis of the existing functionality of VST and rewrote the interfaces from scratch. In doing so, we focused a lot on providing clear interfaces and their documentation in order to avoid usage errors from the deepest possible layer. +Some more features implemented specifically for developers include: + +- More stable technical host/plug-in environment +- Advanced technical definition of the standard +- Modular approach +- Separation of UI and processing +- Advanced Preset System +- Multiple plug-ins per Library +- Test Host included +- Automated Testing Environment +- Validator (small command line Test Host) and plug-in examples code included + +--- +
+ +## How to build VST3 + +### Get the source code from GitHub + +```c +git clone --recursive https://github.com/steinbergmedia/vst3sdk.git +``` + +### Adding VST2 version + +The **VST 2 SDK** is not part anymore of the **VST 3 SDK**, you have to use an older version of the SDK and copy the vst2sdk folder into the VST_SDK folder. +In order to build a VST2 version of the plug-in and a VST3 at the same time, you need to copy the VST2 folder into the VST3 folder, simply run the following commands: + +- for macOS: + +```c +cd TheFolderWhereYouDownloadTheSDK +./copy_vst2_to_vst3_sdk.sh +``` + +- for Windows: + +```c +cd TheFolderWhereYouDownloadTheSDK +copy_vst2_to_vst3_sdk.bat +``` + +### Build the examples on Windows + +- Create a folder for the build and move to this folder (using cd): + +```c +mkdir build +cd build +``` + +- Generate the Solution/Projects: provide the path of the Project where CMakeLists.txt is located: + +```c +// examples: +cmake.exe -G "Visual Studio 17 2022" -A x64 ..\vst3sdk +// or without symbolic links +cmake.exe -G "Visual Studio 17 2022" -A x64 ..\vst3sdk -DSMTG_CREATE_PLUGIN_LINK=0 +// or by using the local user program folder (FOLDERID_UserProgramFilesCommon) as VST3 folder +cmake.exe -G "Visual Studio 17 2022" -A x64 -DSMTG_PLUGIN_TARGET_USER_PROGRAM_FILES_COMMON=1 +``` + +- Now you can build the plug-in (you can use Visual Studio too): + +```c +msbuild.exe vstsdk.sln +// (or alternatively for example for release) +cmake --build . --config Release +``` + +### Build the examples on macOS + +- Create a folder for the build and move to this folder (using cd): + +```c +mkdir build +cd build +``` + +- Generate the Solution/Projects: provide the path of the Project where CMakeLists.txt is located: + +```c +// For XCode: +cmake -GXcode ../vst3sdk +// Without XCode (here debug variant): +cmake -DCMAKE_BUILD_TYPE=Debug ../ +``` + +- Now you can build the plug-in (you can use XCode too): + +```c +xcodebuild +// (or alternatively for example for release) +cmake --build . --config Release +``` + +### Build the examples on Linux + +- Install the required packages [Package Requirements](https://steinbergmedia.github.io/vst3_dev_portal/pages/Getting+Started/How+to+setup+my+system.html#for-linux) +- Create a folder for the build and move to this folder (using cd): + +```c +mkdir build +cd build +``` + +- Generate the Solution/Projects: provide the path of the Project where CMakeLists.txt is located: + +```c +cmake ../vst3sdk +``` + +- Now you can build the plug-in: + +```c +make +// (or alternatively for example for release) +cmake --build . --config Release +``` + +### Build using cmake-gui + +- start the cmake-gui Application +- **Browse Source...**: select the folder vst3sdk +- **Browse Build...**: select a folder where the outputs (projects/...) will be created. Typically, a folder named "build" +- you can check the SMTG Options +- Press **Configure** +- Press **Generate** and the project will be created + +--- +
+ +## Contributing + +For bug reports and features requests, please visit the [VST Developer Forum](https://sdk.steinberg.net) + +--- +
+ +## License & Usage guidelines + +More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf b/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf index 04349f443ac0..ad8c399b48ea 100644 Binary files a/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf and b/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf differ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/VST3_Usage_Guidelines.pdf b/modules/juce_audio_processors/format_types/VST3_SDK/VST3_Usage_Guidelines.pdf index 27c196068ab5..cf4ea4eea8d4 100644 Binary files a/modules/juce_audio_processors/format_types/VST3_SDK/VST3_Usage_Guidelines.pdf and b/modules/juce_audio_processors/format_types/VST3_SDK/VST3_Usage_Guidelines.pdf differ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt b/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt index d5d3145b1cdb..f9c531e7455a 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt @@ -1,27 +1,27 @@ -//----------------------------------------------------------------------------- -// LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved -//----------------------------------------------------------------------------- -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -// OF THE POSSIBILITY OF SUCH DAMAGE. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/README.md b/modules/juce_audio_processors/format_types/VST3_SDK/base/README.md index d612400fcb22..ab5a7a6a3426 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/README.md +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/README.md @@ -1,9 +1,10 @@ -# Welcome to VST SDK 3 base - -Here you can find some helper classes useful for developing VST3 Plug-Ins. - -## License & Usage guidelines -More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) - ----- -Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) \ No newline at end of file +# Welcome to VST SDK 3 base + +Here you can find some helper classes useful for developing **VST 3** plug-ins. + +## License & Usage guidelines + +More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) + +---- +Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp index d7b1f7b52f55..7d12c713a443 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h index 075c0a738c2e..5a531e93d3b4 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp index a67ad5691ef0..83866ea9bb79 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -529,12 +529,10 @@ int8* Buffer::operator + (uint32 i) { if (i < memSize) return buffer + i; - else - { - static int8 eof; - eof = 0; - return &eof; - } + + static int8 eof; + eof = 0; + return &eof; } //------------------------------------------------------------------------------------- @@ -605,7 +603,7 @@ bool Buffer::toWideString (int32 sourceCodePage) endString8 (); Buffer dest (getFillSize () * sizeof (char16)); - int32 result = String::multiByteToWideString (dest.str16 (), buffer, dest.getFree () / sizeof (char16), sourceCodePage); + int32 result = String::multiByteToWideString (dest.str16 (), str8 (), dest.getFree () / sizeof (char16), sourceCodePage); if (result > 0) { dest.setFillSize ((result - 1) * sizeof (char16)); diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h index d0e2f39405be..0a8c1ff6b5b8 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h new file mode 100644 index 000000000000..653fb7c62949 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h @@ -0,0 +1,366 @@ +//------------------------------------------------------------------------ +// Project : SDK Base +// Version : 1.0 +// +// Category : Helpers +// Filename : base/source/fcommandline.h +// Created by : Steinberg, 2007 +// Description : Very simple command-line parser. +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------ +/** @file base/source/fcommandline.h + Very simple command-line parser. + @see Steinberg::CommandLine */ +//------------------------------------------------------------------------ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace Steinberg { +//------------------------------------------------------------------------ +/** Very simple command-line parser. + +Parses the command-line into a CommandLine::VariablesMap.\n +The command-line parser uses CommandLine::Descriptions to define the available options. + +@b Example: +\code +#include "base/source/fcommandline.h" +#include + +int main (int argc, char* argv[]) +{ + using namespace std; + + CommandLine::Descriptions desc; + CommandLine::VariablesMap valueMap; + + desc.addOptions ("myTool") + ("help", "produce help message") + ("opt1", string(), "option 1") + ("opt2", string(), "option 2") + ; + CommandLine::parse (argc, argv, desc, valueMap); + + if (valueMap.hasError () || valueMap.count ("help")) + { + cout << desc << "\n"; + return 1; + } + if (valueMap.count ("opt1")) + { + cout << "Value of option 1 " << valueMap["opt1"] << "\n"; + } + if (valueMap.count ("opt2")) + { + cout << "Value of option 2 " << valueMap["opt2"] << "\n"; + } + return 0; +} +\endcode +@note +This is a "header only" implementation.\n +If you need the declarations in more than one cpp file, you have to define +@c SMTG_NO_IMPLEMENTATION in all but one file. + +*/ +//------------------------------------------------------------------------ +namespace CommandLine { + + //------------------------------------------------------------------------ + /** Command-line parsing result. + + This is the result of the parser.\n + - Use hasError() to check for errors.\n + - To test if a option was specified on the command-line use: count()\n + - To retrieve the value of an options, use operator [](const VariablesMapContainer::key_type k)\n + */ + //------------------------------------------------------------------------ + class VariablesMap + { + bool mParaError; + using VariablesMapContainer = std::map; + VariablesMapContainer mVariablesMapContainer; + public: + VariablesMap () : mParaError (false) {} ///< Constructor. Creates a empty VariablesMap. + bool hasError () const { return mParaError; } ///< Returns @c true when an error has occurred. + void setError () { mParaError = true; } ///< Sets the error state to @c true. + std::string& operator [](const VariablesMapContainer::key_type k); ///< Retrieve the value of option @c k. + const std::string& operator [](const VariablesMapContainer::key_type k) const; ///< Retrieve the value of option @c k. + VariablesMapContainer::size_type count (const VariablesMapContainer::key_type k) const; ///< Returns @c != @c 0 if command-line contains option @c k. + }; + + //! type of the list of elements on the command line that are not handled by options parsing + using FilesVector = std::vector; + + //------------------------------------------------------------------------ + /** The description of one single command-line option. + + Normally you rarely use a Description directly.\n + In most cases you will use the Descriptions::addOptions (const std::string&) method to create and add descriptions. + */ + //------------------------------------------------------------------------ + class Description : public std::string + { + public: + Description (const std::string& name, const std::string& help, const std::string& valueType ); ///< Construct a Description + std::string mHelp; ///< The help string for this option. + std::string mType; ///< The type of this option (kBool, kString). + static const std::string kBool; + static const std::string kString; + }; + //------------------------------------------------------------------------ + /** List of command-line option descriptions. + + Use addOptions(const std::string&) to add Descriptions. + */ + //------------------------------------------------------------------------ + class Descriptions + { + using DescriptionsList = std::deque; + DescriptionsList mDescriptions; + std::string mCaption; + public: + /** Sets the command-line tool caption and starts adding Descriptions. */ + Descriptions& addOptions (const std::string& caption = "", + std::initializer_list&& options = {}); + /** Parse the command-line. */ + bool parse (int ac, char* av[], VariablesMap& result, FilesVector* files = nullptr) const; + /** Print a brief description for the command-line tool into the stream @c os. */ + void print (std::ostream& os) const; + /** Add a new switch. Only */ + Descriptions& operator() (const std::string& name, const std::string& help); + /** Add a new option of type @c inType. Currently only std::string is supported. */ + template + Descriptions& operator () (const std::string& name, const Type& inType, std::string help); + }; + +//------------------------------------------------------------------------ +// If you need the declarations in more than one cpp file you have to define +// SMTG_NO_IMPLEMENTATION in all but one file. +//------------------------------------------------------------------------ +#ifndef SMTG_NO_IMPLEMENTATION + + //------------------------------------------------------------------------ + /*! If command-line contains option @c k more than once, only the last value will survive. */ + //------------------------------------------------------------------------ + std::string& VariablesMap::operator [](const VariablesMapContainer::key_type k) + { + return mVariablesMapContainer[k]; + } + + //------------------------------------------------------------------------ + /*! If command-line contains option @c k more than once, only the last value will survive. */ + //------------------------------------------------------------------------ + const std::string& VariablesMap::operator [](const VariablesMapContainer::key_type k) const + { + return (*const_cast(this))[k]; + } + + //------------------------------------------------------------------------ + VariablesMap::VariablesMapContainer::size_type VariablesMap::count (const VariablesMapContainer::key_type k) const + { + return mVariablesMapContainer.count (k); + } + + //------------------------------------------------------------------------ + /** Add a new option with a string as parameter. */ + //------------------------------------------------------------------------ + template <> Descriptions& Descriptions::operator() (const std::string& name, const std::string& inType, std::string help) + { + mDescriptions.emplace_back (name, help, inType); + return *this; + } + bool parse (int ac, char* av[], const Descriptions& desc, VariablesMap& result, FilesVector* files = nullptr); ///< Parse the command-line. + std::ostream& operator<< (std::ostream& os, const Descriptions& desc); ///< Make Descriptions stream able. + + const std::string Description::kBool = "bool"; + const std::string Description::kString = "string"; + + //------------------------------------------------------------------------ + /*! In most cases you will use the Descriptions::addOptions (const std::string&) method to create and add descriptions. + + @param[in] name of the option. + @param[in] help a help description for this option. + @param[out] valueType Description::kBool or Description::kString. + */ + Description::Description (const std::string& name, const std::string& help, const std::string& valueType) + : std::string (name) + , mHelp (help) + , mType (valueType) + { + } + +//------------------------------------------------------------------------ + /*! Returning a reference to *this, enables chaining of calls to operator()(const std::string&, + const std::string&). + @param[in] name of the added option. + @param[in] help a help description for this option. + @return a reference to *this. + */ + Descriptions& Descriptions::operator () (const std::string& name, const std::string& help) + { + mDescriptions.emplace_back (name, help, Description::kBool); + return *this; + } + +//------------------------------------------------------------------------ + /*! Usage example: + @code + CommandLine::Descriptions desc; + desc.addOptions ("myTool") // Set caption to "myTool" + ("help", "produce help message") // add switch -help + ("opt1", string(), "option 1") // add string option -opt1 + ("opt2", string(), "option 2") // add string option -opt2 + ; + @endcode + @note + The operator() is used for every additional option. + + Or with initializer list : + @code + CommandLine::Descriptions desc; + desc.addOptions ("myTool", // Set caption to "myTool" + {{"help", "produce help message", Description::kBool}, // add switch -help + {"opt1", "option 1", Description::kString}, // add string option -opt1 + {"opt2", "option 2", Description::kString}} // add string option -opt2 + ); + @endcode + @param[in] caption the caption of the command-line tool. + @param[in] options initializer list with options + @return a reverense to *this. + */ + Descriptions& Descriptions::addOptions (const std::string& caption, + std::initializer_list&& options) + { + mCaption = caption; + std::move (options.begin (), options.end (), std::back_inserter (mDescriptions)); + return *this; + } + + //------------------------------------------------------------------------ + /*! @param[in] ac count of command-line parameters + @param[in] av command-line as array of strings + @param[out] result the parsing result + @param[out] files optional list of elements on the command line that are not handled by options parsing + */ + bool Descriptions::parse (int ac, char* av[], VariablesMap& result, FilesVector* files) const + { + using namespace std; + + for (int i = 1; i < ac; i++) + { + string current = av[i]; + if (current[0] == '-') + { + int pos = current[1] == '-' ? 2 : 1; + current = current.substr (pos, string::npos); + + DescriptionsList::const_iterator found = + find (mDescriptions.begin (), mDescriptions.end (), current); + if (found != mDescriptions.end ()) + { + result[*found] = "true"; + if (found->mType != Description::kBool) + { + if (((i + 1) < ac) && *av[i + 1] != '-') + { + result[*found] = av[++i]; + } + else + { + result[*found] = "error!"; + result.setError (); + return false; + } + } + } + else + { + result.setError (); + return false; + } + } + else if (files) + files->push_back (av[i]); + } + return true; + } + +//------------------------------------------------------------------------ + /*! The description includes the help strings for all options. */ + //------------------------------------------------------------------------ + void Descriptions::print (std::ostream& os) const + { + if (!mCaption.empty ()) + os << mCaption << ":\n"; + + size_t maxLength = 0u; + std::for_each (mDescriptions.begin (), mDescriptions.end (), + [&] (const Description& d) { maxLength = std::max (maxLength, d.size ()); }); + + for (const Description& opt : mDescriptions) + { + os << "-" << opt; + for (auto s = opt.size (); s < maxLength; ++s) + os << " "; + os << " | " << opt.mHelp << "\n"; + } + } + +//------------------------------------------------------------------------ + std::ostream& operator<< (std::ostream& os, const Descriptions& desc) + { + desc.print (os); + return os; + } + + //------------------------------------------------------------------------ + /*! @param[in] ac count of command-line parameters + @param[in] av command-line as array of strings + @param[in] desc Descriptions including all allowed options + @param[out] result the parsing result + @param[out] files optional list of elements on the command line that are not handled by options parsing + */ + bool parse (int ac, char* av[], const Descriptions& desc, VariablesMap& result, FilesVector* files) + { + return desc.parse (ac, av, result, files); + } +#endif + +} //namespace CommandLine +} //namespace Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp index 6355feba1983..9fe27d85aada 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp @@ -11,7 +11,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -107,6 +107,8 @@ bool AmIBeingDebugged () #include #include #include +#include +#include #if SMTG_OS_WINDOWS #ifndef _WIN32_WINNT @@ -141,6 +143,20 @@ DebugPrintLogger gDebugPrintLogger = nullptr; static const int kDebugPrintfBufferSize = 10000; static bool neverDebugger = false; // so I can switch it off in the debugger... +static std::once_flag neverDebuggerEnvCheckFlag {}; + +//-------------------------------------------------------------------------- +static void initNeverDebugger () +{ + std::call_once (neverDebuggerEnvCheckFlag, [] () { + // add this environment variable to not stop in the debugger on ASSERT + if (std::getenv ("SMTG_DEBUG_IGNORE_ASSERT")) + { + neverDebugger = true; + } + }); +} + //-------------------------------------------------------------------------- static void printDebugString (const char* string) { @@ -193,6 +209,7 @@ void FDebugBreak (const char* format, ...) gPreAssertionHook (string); } + initNeverDebugger (); if (neverDebugger) return; if (AmIBeingDebugged ()) @@ -228,7 +245,7 @@ void FDebugBreak (const char* format, ...) void FPrintLastError (const char* file, int line) { #if SMTG_OS_WINDOWS - LPVOID lpMessageBuffer; + LPVOID lpMessageBuffer = nullptr; FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMessageBuffer, 0, nullptr); @@ -291,12 +308,16 @@ void* operator new[] (size_t size, int, const char* file, int line) //------------------------------------------------------------------------ void operator delete (void* p, int, const char* file, int line) { + (void)file; + (void)line; ::operator delete (p); } //------------------------------------------------------------------------ void operator delete[] (void* p, int, const char* file, int line) { + (void)file; + (void)line; ::operator delete[] (p); } diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h index a5d9923f8247..3b376ae6420c 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h @@ -11,7 +11,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -97,6 +97,10 @@ bool AmIBeingDebugged (); if (!(f)) \ FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f); +#define SMTG_ASSERT_MSG(f, msg) \ + if (!(f)) \ + FDebugBreak ("%s(%d) : Assert failed: [%s] [%s]\n", __FILE__, __LINE__, #f, msg); + /** Send "comment" string to the debugger for display. */ #define SMTG_WARNING(comment) FDebugPrint ("%s(%d) : %s\n", __FILE__, __LINE__, comment); @@ -194,6 +198,7 @@ void* operator new (size_t, int, const char*, int); #else /** if DEVELOPMENT is not set, these macros will do nothing. */ #define SMTG_ASSERT(f) +#define SMTG_ASSERT_MSG(f, msg) #define SMTG_WARNING(s) #define SMTG_PRINTSYSERROR #define SMTG_DEBUGSTR(s) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp index e085a3435c7f..a061556b928f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp @@ -1,4 +1,5 @@ //------------------------------------------------------------------------ +// Flags : clang-format SMTGSequencer // Project : SDK Base // Version : 1.0 // @@ -9,28 +10,28 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, +// +// * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation +// this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this +// contributors may be used to endorse or promote products derived from this // software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. //----------------------------------------------------------------------------- @@ -39,6 +40,12 @@ #include "base/thread/include/flock.h" #include +#define SMTG_VALIDATE_DEPENDENCY_COUNT DEVELOPMENT // validating dependencyCount + +#if SMTG_DEPENDENCY_COUNT +#include "base/source/updatehandler.h" +#define SMTG_DEPENDENCY_CHECK_LEVEL 1 // 1 => minimal assert, 2 => full assert +#endif // SMTG_DEPENDENCY_COUNT namespace Steinberg { @@ -54,52 +61,132 @@ struct FObjectIIDInitializer // only can cast to their own objects // this initializer must be after the definition of FObject::iid, otherwise // the default constructor of FUID will clear the generated iid - FObjectIIDInitializer () - { - const_cast (FObject::iid).generate (); - } + FObjectIIDInitializer () { const_cast (FObject::iid).generate (); } } gFObjectIidInitializer; //------------------------------------------------------------------------ -uint32 PLUGIN_API FObject::addRef () -{ +FObject::~FObject () +{ +#if SMTG_DEPENDENCY_COUNT && DEVELOPMENT + static bool localNeverDebugger = false; +#endif + +#if DEVELOPMENT + if (refCount > 1) + FDebugPrint ("Refcount is %d when trying to delete %s\n", refCount, isA ()); +#endif + +#if SMTG_DEPENDENCY_COUNT +#if SMTG_DEPENDENCY_CHECK_LEVEL >= 1 + if (gUpdateHandler) + { +#if DEVELOPMENT + SMTG_ASSERT (dependencyCount == 0 || localNeverDebugger); +#endif // DEVELOPMENT + } +#endif +#endif // SMTG_DEPENDENCY_COUNT + +#if SMTG_VALIDATE_DEPENDENCY_COUNT + if (!gUpdateHandler || gUpdateHandler != UpdateHandler::instance (false)) + return; + + auto updateHandler = UpdateHandler::instance (); + if (!updateHandler || updateHandler == this) + return; + + SMTG_ASSERT ((updateHandler->checkDeferred (this) == false || localNeverDebugger) && + "'this' has scheduled a deferUpdate that was not yet delivered"); + + if (updateHandler->hasDependencies (this)) + { + SMTG_ASSERT ( + (false || localNeverDebugger) && + "Another object is still dependent on 'this'. This leads to zombie entries in the dependency map that can later crash."); + FDebugPrint ("Object still has dependencies %x %s\n", this, this->isA ()); + updateHandler->printForObject (this); + } +#endif // SMTG_VALIDATE_DEPENDENCY_COUNT +} + +//------------------------------------------------------------------------ +uint32 PLUGIN_API FObject::addRef () +{ return FUnknownPrivate::atomicAdd (refCount, 1); -} +} //------------------------------------------------------------------------ -uint32 PLUGIN_API FObject::release () +uint32 PLUGIN_API FObject::release () { if (FUnknownPrivate::atomicAdd (refCount, -1) == 0) { refCount = -1000; delete this; return 0; - } - return refCount; + } + return refCount; } //------------------------------------------------------------------------ tresult PLUGIN_API FObject::queryInterface (const TUID _iid, void** obj) { - QUERY_INTERFACE (_iid, obj, FUnknown::iid, FUnknown) - QUERY_INTERFACE (_iid, obj, IDependent::iid, IDependent) - QUERY_INTERFACE (_iid, obj, FObject::iid, FObject) + QUERY_INTERFACE (_iid, obj, FUnknown::iid, FUnknown) + QUERY_INTERFACE (_iid, obj, IDependent::iid, IDependent) + QUERY_INTERFACE (_iid, obj, FObject::iid, FObject) *obj = nullptr; - return kNoInterface; + return kNoInterface; } //------------------------------------------------------------------------ void FObject::addDependent (IDependent* dep) { - if (gUpdateHandler) - gUpdateHandler->addDependent (unknownCast (), dep); + if (!gUpdateHandler) + return; + + gUpdateHandler->addDependent (unknownCast (), dep); +#if SMTG_DEPENDENCY_COUNT + dependencyCount++; +#endif } //------------------------------------------------------------------------ void FObject::removeDependent (IDependent* dep) { - if (gUpdateHandler) +#if SMTG_DEPENDENCY_COUNT && DEVELOPMENT + static bool localNeverDebugger = false; +#endif + + if (!gUpdateHandler) + return; + +#if SMTG_DEPENDENCY_COUNT + if (gUpdateHandler != UpdateHandler::instance (false)) + { gUpdateHandler->removeDependent (unknownCast (), dep); + dependencyCount--; + return; + } +#if SMTG_DEPENDENCY_CHECK_LEVEL > 1 + SMTG_ASSERT ((dependencyCount > 0 || localNeverDebugger) && + "All dependencies have already been removed - mmichaelis 7/2021"); +#endif + size_t removeCount; + UpdateHandler::instance ()->removeDependent (unknownCast (), dep, removeCount); + if (removeCount == 0) + { +#if SMTG_DEPENDENCY_CHECK_LEVEL > 1 + SMTG_ASSERT (localNeverDebugger && "No dependency to remove - ygrabit 8/2021"); +#endif + } + else + { + SMTG_ASSERT ((removeCount == 1 || localNeverDebugger) && + "Duplicated dependencies established - mmichaelis 7/2021"); + } + dependencyCount -= (int16)removeCount; +#else + gUpdateHandler->removeDependent (unknownCast (), dep); +#endif // SMTG_DEPENDENCY_COUNT } //------------------------------------------------------------------------ @@ -123,61 +210,61 @@ void FObject::deferUpdate (int32 msg) //------------------------------------------------------------------------ /** Automatic creation and destruction of singleton instances. */ //------------------------------------------------------------------------ -namespace Singleton +namespace Singleton { +using ObjectVector = std::vector; +ObjectVector* singletonInstances = nullptr; +bool singletonsTerminated = false; +Steinberg::Base::Thread::FLock* singletonsLock; + +bool isTerminated () { - using ObjectVector = std::vector; - ObjectVector* singletonInstances = nullptr; - bool singletonsTerminated = false; - Steinberg::Base::Thread::FLock* singletonsLock; + return singletonsTerminated; +} - bool isTerminated () {return singletonsTerminated;} +void lockRegister () +{ + if (!singletonsLock) // assume first call not from multiple threads + singletonsLock = NEW Steinberg::Base::Thread::FLock; + singletonsLock->lock (); +} - void lockRegister () - { - if (!singletonsLock) // assume first call not from multiple threads - singletonsLock = NEW Steinberg::Base::Thread::FLock; - singletonsLock->lock (); - } - void unlockRegister () - { - singletonsLock->unlock (); - } +void unlockRegister () +{ + singletonsLock->unlock (); +} - void registerInstance (FObject** o) +void registerInstance (FObject** o) +{ + SMTG_ASSERT (singletonsTerminated == false) + if (singletonsTerminated == false) { - SMTG_ASSERT (singletonsTerminated == false) - if (singletonsTerminated == false) - { - if (singletonInstances == nullptr) - singletonInstances = NEW std::vector; - singletonInstances->push_back (o); - } + if (singletonInstances == nullptr) + singletonInstances = NEW std::vector; + singletonInstances->push_back (o); } +} - struct Deleter +struct Deleter +{ + ~Deleter () { - ~Deleter () + singletonsTerminated = true; + if (singletonInstances) { - singletonsTerminated = true; - if (singletonInstances) + for (Steinberg::FObject** obj : *singletonInstances) { - for (ObjectVector::iterator it = singletonInstances->begin (), - end = singletonInstances->end (); - it != end; ++it) - { - FObject** obj = (*it); - (*obj)->release (); - *obj = nullptr; - obj = nullptr; - } - - delete singletonInstances; - singletonInstances = nullptr; + (*obj)->release (); + *obj = nullptr; + obj = nullptr; } - delete singletonsLock; - singletonsLock = nullptr; + + delete singletonInstances; + singletonInstances = nullptr; } - } deleter; + delete singletonsLock; + singletonsLock = nullptr; + } +} deleter; } //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h index 9bcf4435ced2..4165a7b400da 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -45,6 +45,8 @@ #include "pluginterfaces/base/iupdatehandler.h" #include "base/source/fdebug.h" // use of NEW +#define SMTG_DEPENDENCY_COUNT DEVELOPMENT + namespace Steinberg { //---------------------------------- @@ -82,10 +84,15 @@ class FObject : public IDependent { public: //------------------------------------------------------------------------ - FObject () : refCount (1) {} ///< default constructor... - FObject (const FObject&) : refCount (1) {} ///< overloaded constructor... - virtual ~FObject () {} ///< destructor... - FObject& operator = (const FObject&) { return *this; } ///< overloads operator "=" as the reference assignment + FObject () = default; ///< default constructor... + FObject (const FObject&) ///< overloaded constructor... + : refCount (1) +#if SMTG_DEPENDENCY_COUNT + , dependencyCount (0) +#endif + {} + FObject& operator= (const FObject&) { return *this; } ///< overloads operator "=" as the reference assignment + virtual ~FObject (); ///< destructor... // OBJECT_METHODS static inline FClassID getFClassID () {return "FObject";} ///< return Class ID as an ASCII string (statically) @@ -124,8 +131,10 @@ class FObject : public IDependent //------------------------------------------------------------------------ protected: - int32 refCount; ///< COM-model local reference count - + int32 refCount = 1; ///< COM-model local reference count +#if SMTG_DEPENDENCY_COUNT + int16 dependencyCount = 0; +#endif static IUpdateHandler* gUpdateHandler; }; @@ -341,7 +350,7 @@ namespace Singleton { virtual Steinberg::FClassID isA () const SMTG_OVERRIDE {return className::getFClassID ();} \ virtual bool isA (Steinberg::FClassID s) const SMTG_OVERRIDE {return isTypeOf (s, false);} \ virtual bool isTypeOf (Steinberg::FClassID s, bool askBaseClass = true) const SMTG_OVERRIDE \ - { return (classIDsEqual (s, #className) ? true : (askBaseClass ? baseClass::isTypeOf (s, true) : false)); } + { return (FObject::classIDsEqual (s, #className) ? true : (askBaseClass ? baseClass::isTypeOf (s, true) : false)); } //------------------------------------------------------------------------ /** Delegate refcount functions to BaseClass. diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp index b9af91e08607..524956b9efff 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -187,6 +187,30 @@ bool FStreamer::readChar16 (char16& c) return false; } +//------------------------------------------------------------------------ +bool FStreamer::writeInt8 (int8 c) +{ + return writeRaw ((void*)&c, sizeof (int8)) == sizeof (int8); +} + +//------------------------------------------------------------------------ +bool FStreamer::readInt8 (int8& c) +{ + return readRaw ((void*)&c, sizeof (int8)) == sizeof (int8); +} + +//------------------------------------------------------------------------ +bool FStreamer::writeInt8u (uint8 c) +{ + return writeRaw ((void*)&c, sizeof (uint8)) == sizeof (uint8); +} + +//------------------------------------------------------------------------ +bool FStreamer::readInt8u (uint8& c) +{ + return readRaw ((void*)&c, sizeof (uint8)) == sizeof (uint8); +} + // int16 ----------------------------------------------------------------- //------------------------------------------------------------------------ bool FStreamer::writeInt16 (int16 i) @@ -563,6 +587,9 @@ TSize FStreamer::writeString8 (const char8* ptr, bool terminate) //------------------------------------------------------------------------ TSize FStreamer::readString8 (char8* ptr, TSize size) { + if (size < 1 || ptr == nullptr) + return 0; + TSize i = 0; char8 c = 0; while (i < size) @@ -570,18 +597,19 @@ TSize FStreamer::readString8 (char8* ptr, TSize size) if (readRaw ((void*)&c, sizeof (char)) != sizeof (char)) break; ptr[i] = c; - i++; if (c == '\n' || c == '\0') break; + i++; } - if (c == '\n' && ptr[i - 2] == '\r') - ptr[i - 2] = 0; - if (i < size) - ptr[i] = 0; - else - ptr[size - 1] = 0; + // remove at end \n (LF) or \r\n (CR+LF) + if (c == '\n') + { + if (i > 0 && ptr[i - 1] == '\r') + i--; + } + ptr[i] = 0; - return strlen (ptr); + return i; } //------------------------------------------------------------------------ @@ -630,7 +658,7 @@ int32 FStreamer::readStringUtf8 (tchar* ptr, int32 nChars) break; } - char8* source = tmp.int8Ptr (); + char8* source = tmp.str8 (); uint32 codePage = kCP_Default; // for legacy take default page if no utf8 bom is present... if (tmp.getFillSize () > 2) { diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h index 750e5e183cae..8b97bb6cd199 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -84,10 +84,10 @@ class FStreamer bool writeChar16 (char16 c); bool readChar16 (char16& c); - bool writeInt8 (int8 c){return writeChar8 (c);} - bool readInt8 (int8& c){return readChar8 (c);} - bool writeInt8u (uint8 c){return writeUChar8 (c);} - bool readInt8u (uint8& c){return readUChar8 (c);} + bool writeInt8 (int8 c); + bool readInt8 (int8& c); + bool writeInt8u (uint8 c); + bool readInt8u (uint8& c); ///@} /** @name read and write int16. */ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp index 7fae6b0c8caf..907baa7338fe 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -45,8 +45,15 @@ #include #include #include +#include +#include +#include +#include #if SMTG_OS_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif #include #ifdef _MSC_VER #pragma warning (disable : 4244) @@ -202,34 +209,32 @@ static bool fromCFStringRef (Steinberg::char8* dest, Steinberg::int32 destSize, #endif // SMTG_OS_MACOS #if SMTG_OS_WINDOWS -#define stricmp16 wcsicmp -#define strnicmp16 wcsnicmp -#define strrchr16 wcsrchr -#define sprintf16 swprintf -#define snprintf16 snwprintf -#define vsnprintf16 vsnwprintf -#define vsprintf16 wvsprintf -#define vfprintf16 vfwprintf -#define sscanf16 swscanf -#define toupper16 towupper -#define tolower16 towlower -#define isupper16 iswupper -#define islower16 iswlower -#define isspace16 iswspace -#define isalpha16 iswalpha -#define isdigit16 iswdigit -#define isalnum16 iswalnum - -#define stricmp _stricmp -#define strnicmp _strnicmp -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define snwprintf _snwprintf -#define vsnwprintf _vsnwprintf - -#define wtoi _wtoi -#define wtol _wtol -#define wtof _wtof +//----------------------------------------------------------------------------- +static inline int stricmp16 (const Steinberg::tchar* s1, const Steinberg::tchar* s2) +{ + return wcsicmp (Steinberg::wscast (s1), Steinberg::wscast (s2)); +} + +//----------------------------------------------------------------------------- +static inline int strnicmp16 (const Steinberg::tchar* s1, const Steinberg::tchar* s2, size_t l) +{ + return wcsnicmp (Steinberg::wscast (s1), Steinberg::wscast (s2), l); +} + +//----------------------------------------------------------------------------- +static inline int vsnwprintf (Steinberg::char16* buffer, size_t bufferSize, + const Steinberg::char16* format, va_list args) +{ + return _vsnwprintf (Steinberg::wscast (buffer), bufferSize, Steinberg::wscast (format), args); +} + +//----------------------------------------------------------------------------- +static inline Steinberg::int32 sprintf16 (Steinberg::char16* str, const Steinberg::char16* format, ...) +{ + va_list marker; + va_start (marker, format); + return vsnwprintf (str, -1, format, marker); +} #elif SMTG_OS_LINUX #include @@ -288,7 +293,7 @@ static inline int strnicmp16 (const Steinberg::char16* s1, const Steinberg::char //----------------------------------------------------------------------------- static inline int sprintf16 (Steinberg::char16* wcs, const Steinberg::char16* format, ...) { - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); return 0; } @@ -311,7 +316,7 @@ static inline int vsnwprintf (Steinberg::char16* wcs, size_t maxlen, //----------------------------------------------------------------------------- static inline Steinberg::char16* strrchr16 (const Steinberg::char16* str, Steinberg::char16 c) { - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); return nullptr; } @@ -533,6 +538,9 @@ bool ConstString::testChar16 (uint32 index, char16 c) const //----------------------------------------------------------------------------- bool ConstString::extract (String& result, uint32 idx, int32 n) const { + // AddressSanitizer : when extracting part of "this" on itself, it can lead to heap-use-after-free. + SMTG_ASSERT (this != static_cast (&result)) + if (len == 0|| idx >= len) return false; @@ -659,7 +667,7 @@ int32 ConstString::compare (const ConstString& str, int32 n, CompareMode mode) c return 0; return 1; } - else if (isEmpty ()) + if (isEmpty ()) return -1; if (!isWide && !str.isWide) @@ -668,33 +676,23 @@ int32 ConstString::compare (const ConstString& str, int32 n, CompareMode mode) c { if (isCaseSensitive (mode)) return strcmp (*this, str); - else - return stricmp (*this, str); - } - else - { - if (isCaseSensitive (mode)) - return strncmp (*this, str, n); - else - return strnicmp (*this, str, n); + return stricmp (*this, str); } + if (isCaseSensitive (mode)) + return strncmp (*this, str, n); + return strnicmp (*this, str, n); } - else if (isWide && str.isWide) + if (isWide && str.isWide) { if (n < 0) { if (isCaseSensitive (mode)) return strcmp16 (*this, str); - else - return stricmp16 (*this, str); - } - else - { - if (isCaseSensitive (mode)) - return strncmp16 (*this, str, n); - else - return strnicmp16 (*this, str, n); + return stricmp16 (*this, str); } + if (isCaseSensitive (mode)) + return strncmp16 (*this, str, n); + return strnicmp16 (*this, str, n); } return compareAt (0, str, n, mode); } @@ -717,7 +715,7 @@ int32 ConstString::compareAt (uint32 index, const ConstString& str, int32 n, Com return 0; return 1; } - else if (isEmpty ()) + if (isEmpty ()) return -1; if (!isWide && !str.isWide) @@ -738,18 +736,13 @@ int32 ConstString::compareAt (uint32 index, const ConstString& str, int32 n, Com { if (isCaseSensitive (mode)) return strcmp (toCompare, str); - else - return stricmp (toCompare, str); - } - else - { - if (isCaseSensitive (mode)) - return strncmp (toCompare, str, n); - else - return strnicmp (toCompare, str, n); + return stricmp (toCompare, str); } + if (isCaseSensitive (mode)) + return strncmp (toCompare, str, n); + return strnicmp (toCompare, str, n); } - else if (isWide && str.isWide) + if (isWide && str.isWide) { char16* toCompare = buffer16; if (index > 0) @@ -767,34 +760,25 @@ int32 ConstString::compareAt (uint32 index, const ConstString& str, int32 n, Com { if (isCaseSensitive (mode)) return strcmp16 (toCompare, str.text16 ()); - else - return stricmp16 (toCompare, str.text16 ()); - } - else - { - if (isCaseSensitive (mode)) - return strncmp16 (toCompare, str.text16 (), n); - else - return strnicmp16 (toCompare, str.text16 (), n); + return stricmp16 (toCompare, str.text16 ()); } + if (isCaseSensitive (mode)) + return strncmp16 (toCompare, str.text16 (), n); + return strnicmp16 (toCompare, str.text16 (), n); } - else + + if (isWide) { - if (isWide) - { - String tmp (str.text8 ()); - if (tmp.toWideString () == false) - return -1; - return compareAt (index, tmp, n, mode); - } - else - { - String tmp (text8 ()); - if (tmp.toWideString () == false) - return 1; - return tmp.compareAt (index, str, n, mode); - } + String tmp (str.text8 ()); + if (tmp.toWideString () == false) + return -1; + return compareAt (index, tmp, n, mode); } + + String tmp (text8 ()); + if (tmp.toWideString () == false) + return 1; + return tmp.compareAt (index, str, n, mode); } //------------------------------------------------------------------------ @@ -806,28 +790,23 @@ Steinberg::int32 ConstString::naturalCompare (const ConstString& str, CompareMod return 0; return 1; } - else if (isEmpty ()) + if (isEmpty ()) return -1; if (!isWide && !str.isWide) return strnatcmp8 (buffer8, str.text8 (), isCaseSensitive (mode)); - else if (isWide && str.isWide) + if (isWide && str.isWide) return strnatcmp16 (buffer16, str.text16 (), isCaseSensitive (mode)); - else + + if (isWide) { - if (isWide) - { - String tmp (str.text8 ()); - tmp.toWideString (); - return strnatcmp16 (buffer16, tmp.text16 (), isCaseSensitive (mode)); - } - else - { - String tmp (text8 ()); - tmp.toWideString (); - return strnatcmp16 (tmp.text16 (), str.text16 (), isCaseSensitive (mode)); - } + String tmp (str.text8 ()); + tmp.toWideString (); + return strnatcmp16 (buffer16, tmp.text16 (), isCaseSensitive (mode)); } + String tmp (text8 ()); + tmp.toWideString (); + return strnatcmp16 (tmp.text16 (), str.text16 (), isCaseSensitive (mode)); } //----------------------------------------------------------------------------- @@ -837,7 +816,7 @@ bool ConstString::startsWith (const ConstString& str, CompareMode mode /*= kCase { return isEmpty (); } - else if (isEmpty ()) + if (isEmpty ()) { return false; } @@ -851,13 +830,13 @@ bool ConstString::startsWith (const ConstString& str, CompareMode mode /*= kCase return strncmp (buffer8, str.buffer8, str.length ()) == 0; return strnicmp (buffer8, str.buffer8, str.length ()) == 0; } - else if (isWide && str.isWide) + if (isWide && str.isWide) { if (isCaseSensitive (mode)) return strncmp16 (buffer16, str.buffer16, str.length ()) == 0; return strnicmp16 (buffer16, str.buffer16, str.length ()) == 0; } - else if (isWide) + if (isWide) { String tmp (str.text8 ()); tmp.toWideString (); @@ -867,16 +846,13 @@ bool ConstString::startsWith (const ConstString& str, CompareMode mode /*= kCase return strncmp16 (buffer16, tmp.buffer16, tmp.length ()) == 0; return strnicmp16 (buffer16, tmp.buffer16, tmp.length ()) == 0; } - else - { - String tmp (text8 ()); - tmp.toWideString (); - if (str.length () > tmp.length ()) - return false; - if (isCaseSensitive (mode)) - return strncmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0; - return strnicmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0; - } + String tmp (text8 ()); + tmp.toWideString (); + if (str.length () > tmp.length ()) + return false; + if (isCaseSensitive (mode)) + return strncmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0; + return strnicmp16 (tmp.buffer16, str.buffer16, str.length ()) == 0; } //----------------------------------------------------------------------------- @@ -886,7 +862,7 @@ bool ConstString::endsWith (const ConstString& str, CompareMode mode /*= kCaseSe { return isEmpty (); } - else if (isEmpty ()) + if (isEmpty ()) { return false; } @@ -900,13 +876,13 @@ bool ConstString::endsWith (const ConstString& str, CompareMode mode /*= kCaseSe return strncmp (buffer8 + (length () - str.length ()), str.buffer8, str.length ()) == 0; return strnicmp (buffer8 + (length () - str.length ()), str.buffer8, str.length ()) == 0; } - else if (isWide && str.isWide) + if (isWide && str.isWide) { if (isCaseSensitive (mode)) return strncmp16 (buffer16 + (length () - str.length ()), str.buffer16, str.length ()) == 0; return strnicmp16 (buffer16 + (length () - str.length ()), str.buffer16, str.length ()) == 0; } - else if (isWide) + if (isWide) { String tmp (str.text8 ()); tmp.toWideString (); @@ -916,16 +892,13 @@ bool ConstString::endsWith (const ConstString& str, CompareMode mode /*= kCaseSe return strncmp16 (buffer16 + (length () - tmp.length ()), tmp.buffer16, tmp.length ()) == 0; return strnicmp16 (buffer16 + (length () - tmp.length ()), tmp.buffer16, tmp.length ()) == 0; } - else - { - String tmp (text8 ()); - tmp.toWideString (); - if (str.length () > tmp.length ()) - return false; - if (isCaseSensitive (mode)) - return strncmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0; - return strnicmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0; - } + String tmp (text8 ()); + tmp.toWideString (); + if (str.length () > tmp.length ()) + return false; + if (isCaseSensitive (mode)) + return strncmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0; + return strnicmp16 (tmp.buffer16 + (tmp.length () - str.length ()), str.buffer16, str.length ()) == 0; } //----------------------------------------------------------------------------- @@ -968,7 +941,7 @@ int32 ConstString::findNext (int32 startIndex, const ConstString& str, int32 n, } return -1; } - else if (!isWide && !str.isWide) + if (!isWide && !str.isWide) { uint32 stringLength = str.length (); n = n < 0 ? stringLength : Min (n, stringLength); @@ -1199,7 +1172,7 @@ int32 ConstString::findPrev (int32 startIndex, const ConstString& str, int32 n, } return -1; } - else if (!isWide && !str.isWide) + if (!isWide && !str.isWide) { uint32 stringLength = str.length (); n = n < 0 ? stringLength : Min (n, stringLength); @@ -1305,13 +1278,11 @@ int32 ConstString::getFirstDifferent (const ConstString& str, CompareMode mode) return -1; return getFirstDifferent (tmp, mode); } - else - { - String tmp (text8 ()); - if (tmp.toWideString () == false) - return -1; - return tmp.getFirstDifferent (str, mode); - } + + String tmp (text8 ()); + if (tmp.toWideString () == false) + return -1; + return tmp.getFirstDifferent (str, mode); } uint32 len1 = len; @@ -1367,8 +1338,7 @@ bool ConstString::scanInt64 (int64& value, uint32 offset, bool scanToEnd) const if (isWide) return scanInt64_16 (buffer16 + offset, value, scanToEnd); - else - return scanInt64_8 (buffer8 + offset, value, scanToEnd); + return scanInt64_8 (buffer8 + offset, value, scanToEnd); } //----------------------------------------------------------------------------- @@ -1379,8 +1349,7 @@ bool ConstString::scanUInt64 (uint64& value, uint32 offset, bool scanToEnd) cons if (isWide) return scanUInt64_16 (buffer16 + offset, value, scanToEnd); - else - return scanUInt64_8 (buffer8 + offset, value, scanToEnd); + return scanUInt64_8 (buffer8 + offset, value, scanToEnd); } //----------------------------------------------------------------------------- @@ -1391,8 +1360,7 @@ bool ConstString::scanHex (uint8& value, uint32 offset, bool scanToEnd) const if (isWide) return scanHex_16 (buffer16 + offset, value, scanToEnd); - else - return scanHex_8 (buffer8 + offset, value, scanToEnd); + return scanHex_8 (buffer8 + offset, value, scanToEnd); } //----------------------------------------------------------------------------- @@ -1403,8 +1371,7 @@ bool ConstString::scanInt32 (int32& value, uint32 offset, bool scanToEnd) const if (isWide) return scanInt32_16 (buffer16 + offset, value, scanToEnd); - else - return scanInt32_8 (buffer8 + offset, value, scanToEnd); + return scanInt32_8 (buffer8 + offset, value, scanToEnd); } //----------------------------------------------------------------------------- @@ -1415,8 +1382,7 @@ bool ConstString::scanUInt32 (uint32& value, uint32 offset, bool scanToEnd) cons if (isWide) return scanUInt32_16 (buffer16 + offset, value, scanToEnd); - else - return scanUInt32_8 (buffer8 + offset, value, scanToEnd); + return scanUInt32_8 (buffer8 + offset, value, scanToEnd); } //----------------------------------------------------------------------------- @@ -1426,7 +1392,7 @@ bool ConstString::scanInt64_8 (const char8* text, int64& value, bool scanToEnd) { if (sscanf (text, "%" FORMAT_INT64A, &value) == 1) return true; - else if (scanToEnd == false) + if (scanToEnd == false) return false; text++; } @@ -1452,7 +1418,7 @@ bool ConstString::scanUInt64_8 (const char8* text, uint64& value, bool scanToEnd { if (sscanf (text, "%" FORMAT_UINT64A, &value) == 1) return true; - else if (scanToEnd == false) + if (scanToEnd == false) return false; text++; } @@ -1502,7 +1468,7 @@ bool ConstString::scanHex_8 (const char8* text, uint8& value, bool scanToEnd) value = (uint8)v; return true; } - else if (scanToEnd == false) + if (scanToEnd == false) return false; text++; } @@ -1557,7 +1523,7 @@ bool ConstString::scanFloat (double& value, uint32 offset, bool scanToEnd) const { if (sscanf (txt, "%lf", &value) == 1) return true; - else if (scanToEnd == false) + if (scanToEnd == false) return false; txt++; } @@ -1585,7 +1551,7 @@ char16 ConstString::toLower (char16 c) } return c; #elif SMTG_OS_LINUX - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); return c; #else return towlower (c); @@ -1613,7 +1579,7 @@ char16 ConstString::toUpper (char16 c) } return c; #elif SMTG_OS_LINUX - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); return c; #else return towupper (c); @@ -1759,8 +1725,7 @@ bool ConstString::isDigit (uint32 index) const if (isWide) return ConstString::isCharDigit (buffer16[index]); - else - return ConstString::isCharDigit (buffer8[index]); + return ConstString::isCharDigit (buffer8[index]); } //----------------------------------------------------------------------------- @@ -1867,7 +1832,7 @@ int32 ConstString::multiByteToWideString (char16* dest, const char8* source, int } int32 result = 0; #if SMTG_OS_WINDOWS - result = MultiByteToWideChar (sourceCodePage, MB_ERR_INVALID_CHARS, source, -1, dest, charCount); + result = MultiByteToWideChar (sourceCodePage, MB_ERR_INVALID_CHARS, source, -1, wscast (dest), charCount); #endif #if SMTG_OS_MACOS @@ -1911,7 +1876,7 @@ int32 ConstString::multiByteToWideString (char16* dest, const char8* source, int } else { - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); } #endif @@ -1924,7 +1889,7 @@ int32 ConstString::multiByteToWideString (char16* dest, const char8* source, int int32 ConstString::wideStringToMultiByte (char8* dest, const char16* wideString, int32 charCount, uint32 destCodePage) { #if SMTG_OS_WINDOWS - return WideCharToMultiByte (destCodePage, 0, wideString, -1, dest, charCount, nullptr, nullptr); + return WideCharToMultiByte (destCodePage, 0, wscast (wideString), -1, dest, charCount, nullptr, nullptr); #elif SMTG_OS_MACOS int32 result = 0; @@ -1991,13 +1956,12 @@ int32 ConstString::wideStringToMultiByte (char8* dest, const char16* wideString, } else { - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); } return result; #else -#warning DEPRECATED No Linux implementation - assert(false && "DEPRECATED No Linux implementation"); + assert (false && "DEPRECATED No Linux implementation"); return 0; #endif @@ -2013,7 +1977,7 @@ bool ConstString::isNormalized (UnicodeNormalization n) #ifdef UNICODE if (n != kUnicodeNormC) return false; - uint32 normCharCount = static_cast (FoldString (MAP_PRECOMPOSED, buffer16, len, nullptr, 0)); + uint32 normCharCount = static_cast (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len, nullptr, 0)); return (normCharCount == len); #else return false; @@ -2043,11 +2007,27 @@ String::String () //----------------------------------------------------------------------------- String::String (const char8* str, MBCodePage codePage, int32 n, bool isTerminated) { - isWide = 0; + isWide = false; if (str) { - assign (str, n, isTerminated); - toWideString (codePage); + if (isTerminated && n >= 0 && str[n] != 0) + { + // isTerminated is not always set correctly + isTerminated = false; + } + + if (!isTerminated) + { + assign (str, n, isTerminated); + toWideString (codePage); + } + else + { + if (n < 0) + n = static_cast (strlen (str)); + if (n > 0) + _toWideString (str, n, codePage); + } } } @@ -2139,22 +2119,33 @@ void String::updateLength () //----------------------------------------------------------------------------- bool String::toWideString (uint32 sourceCodePage) +{ + if (!isWide && buffer8 && len > 0) + return _toWideString (buffer8, len, sourceCodePage); + isWide = true; + return true; +} + +//----------------------------------------------------------------------------- +bool String::_toWideString (const char8* src, int32 length, uint32 sourceCodePage) { if (!isWide) { - if (buffer8 && len > 0) + if (src && length > 0) { - int32 bytesNeeded = multiByteToWideString (nullptr, buffer8, 0, sourceCodePage) * sizeof (char16); + int32 bytesNeeded = multiByteToWideString (nullptr, src, 0, sourceCodePage) * sizeof (char16); if (bytesNeeded) { bytesNeeded += sizeof (char16); - char16* newStr = (char16*) malloc (bytesNeeded); - if (multiByteToWideString (newStr, buffer8, len + 1, sourceCodePage) <= 0) + char16* newStr = (char16*)malloc (bytesNeeded); + if (multiByteToWideString (newStr, src, length + 1, sourceCodePage) < 0) { free (newStr); return false; } - free (buffer8); + if (buffer8) + free (buffer8); + buffer16 = newStr; isWide = true; updateLength (); @@ -2254,8 +2245,8 @@ bool String::toMultiByte (uint32 destCodePage) //----------------------------------------------------------------------------- void String::fromUTF8 (const char8* utf8String) { - assign (utf8String); - toWideString (kCP_Utf8); + resize (0, false); + _toWideString (utf8String, static_cast (strlen (utf8String)), kCP_Utf8); } //----------------------------------------------------------------------------- @@ -2272,12 +2263,12 @@ bool String::normalize (UnicodeNormalization n) if (n != kUnicodeNormC) return false; - uint32 normCharCount = static_cast (FoldString (MAP_PRECOMPOSED, buffer16, len, nullptr, 0)); + uint32 normCharCount = static_cast (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len, nullptr, 0)); if (normCharCount == len) return true; char16* newString = (char16*)malloc ((normCharCount + 1) * sizeof (char16)); - uint32 converterCount = static_cast (FoldString (MAP_PRECOMPOSED, buffer16, len, newString, normCharCount + 1)); + uint32 converterCount = static_cast (FoldString (MAP_PRECOMPOSED, wscast (buffer16), len, wscast (newString), normCharCount + 1)); if (converterCount != normCharCount) { free (newString); @@ -2410,12 +2401,10 @@ bool String::setChar8 (uint32 index, char8 c) len = index; return true; } - else - { - if (resize (index + 1, isWide, true) == false) - return false; - len = index + 1; - } + + if (resize (index + 1, isWide, true) == false) + return false; + len = index + 1; } if (index < len && buffer) @@ -2462,12 +2451,9 @@ bool String::setChar16 (uint32 index, char16 c) len = index; return true; } - else - { - if (resize (index + 1, isWide, true) == false) - return false; - len = index + 1; - } + if (resize (index + 1, isWide, true) == false) + return false; + len = index + 1; } if (index < len && buffer) @@ -2501,8 +2487,7 @@ String& String::assign (const ConstString& str, int32 n) { if (str.isWideString ()) return assign (str.text16 (), n < 0 ? str.length () : n); - else - return assign (str.text8 (), n < 0 ? str.length () : n); + return assign (str.text8 (), n < 0 ? str.length () : n); } //----------------------------------------------------------------------------- @@ -2598,8 +2583,7 @@ String& String::append (const ConstString& str, int32 n) { if (str.isWideString ()) return append (str.text16 (), n); - else - return append (str.text8 (), n); + return append (str.text8 (), n); } //----------------------------------------------------------------------------- @@ -2683,7 +2667,7 @@ String& String::append (const char8 c, int32 n) { return append (str, 1); } - else if (n > 1) + if (n > 1) { if (isWide) { @@ -2717,7 +2701,7 @@ String& String::append (const char16 c, int32 n) char16 str[] = {c, 0}; return append (str, 1); } - else if (n > 1) + if (n > 1) { if (!isWide) { @@ -2746,8 +2730,7 @@ String& String::insertAt (uint32 idx, const ConstString& str, int32 n) { if (str.isWideString ()) return insertAt (idx, str.text16 (), n); - else - return insertAt (idx, str.text8 (), n); + return insertAt (idx, str.text8 (), n); } //----------------------------------------------------------------------------- @@ -2825,8 +2808,7 @@ String& String::replace (uint32 idx, int32 n1, const ConstString& str, int32 n2) { if (str.isWideString ()) return replace (idx, n1, str.text16 (), n2); - else - return replace (idx, n1, str.text8 (), n2); + return replace (idx, n1, str.text8 (), n2); } // "replace" replaces n1 number of characters at the specified index with @@ -3369,55 +3351,44 @@ String& String::printInt64 (int64 value) } //----------------------------------------------------------------------------- -String& String::printFloat (double value) +String& String::printFloat (double value, uint32 maxPrecision) { + static constexpr auto kMaxAfterCommaResolution = 16; + // escape point for integer values, avoid unnecessary complexity later on + const bool withinInt64Boundaries = value <= std::numeric_limits::max () && value >= std::numeric_limits::lowest (); + if (withinInt64Boundaries && (maxPrecision == 0 || std::round (value) == value)) + return printInt64 (value); + + const auto absValue = std::abs (value); + const uint32 valueExponent = absValue >= 1 ? std::log10 (absValue) : -std::log10 (absValue) + 1; + + maxPrecision = std::min (kMaxAfterCommaResolution - valueExponent, maxPrecision); + if (isWide) - { - char16 string[kPrintfBufferSize]; - sprintf16 (string, STR16 ("%lf"), value); + printf (STR ("%s%dlf"), STR ("%."), maxPrecision); + else + printf ("%s%dlf", "%.", maxPrecision); - char16* pointPtr = strrchr16 (string, STR ('.')); - if (pointPtr) - { - pointPtr++; // keep 1st digit after point - int32 index = strlen16 (string) - 1; - char16 zero = STR16 ('0'); - while (pointPtr < (string + index)) - { - if (string[index] == zero) - { - string[index] = 0; - index--; - } - else - break; - } - } - return assign (string); - } + if (isWide) + printf (text16 (), value); else - { - char8 string[kPrintfBufferSize]; - sprintf (string, "%lf", value); + printf (text8 (), value); - char8* pointPtr = strrchr (string, '.'); - if (pointPtr) + // trim trail zeros + for (int32 i = length () - 1; i >= 0; i--) + { + if (isWide && testChar16 (i, '0') || testChar8 (i, '0')) + remove (i); + else if (isWide && testChar16(i,'.') || testChar8(i, '.')) { - pointPtr++; // keep 1st digit after point - int32 index = (int32) (strlen (string) - 1); - while (pointPtr < (string + index)) - { - if (string[index] == '0') - { - string[index] = 0; - index--; - } - else - break; - } + remove(i); + break; } - return assign (string); + else + break; } + + return *this; } //----------------------------------------------------------------------------- @@ -3461,17 +3432,19 @@ bool String::incrementTrailingNumber (uint32 width, tchar separator, uint32 minN } else { - char format[64]; - char trail[128]; + static constexpr auto kFormatSize = 64u; + static constexpr auto kTrailSize = 64u; + char format[kFormatSize]; + char trail[kTrailSize]; if (separator && isEmpty () == false) { - sprintf (format, "%%c%%0%uu", width); - sprintf (trail, format, separator, (uint32) number); + snprintf (format, kFormatSize, "%%c%%0%uu", width); + snprintf (trail, kTrailSize, format, separator, (uint32) number); } else { - sprintf (format, "%%0%uu", width); - sprintf (trail, format, (uint32) number); + snprintf (format, kFormatSize, "%%0%uu", width); + snprintf (trail, kTrailSize, format, (uint32) number); } append (trail); } @@ -3723,11 +3696,9 @@ unsigned char* String::toPascalString (unsigned char* buf) } return buf; } - else - { - *buf = 0; - return buf; - } + + *buf = 0; + return buf; } //----------------------------------------------------------------------------- @@ -3826,7 +3797,7 @@ void* ConstString::toCFStringRef (uint32 encoding, bool mutableCFString) const return (void*)CFStringCreateWithCString (kCFAllocator, "", encoding); } } - return 0; + return nullptr; } #endif @@ -3860,9 +3831,9 @@ template int32 tstrnatcmp (const T* s1, const T* s2, bool caseSensitiv { if (s1 == nullptr && s2 == nullptr) return 0; - else if (s1 == nullptr) + if (s1 == nullptr) return -1; - else if (s2 == nullptr) + if (s2 == nullptr) return 1; while (*s1 && *s2) @@ -3923,12 +3894,11 @@ template int32 tstrnatcmp (const T* s1, const T* s2, bool caseSensitiv if (*s1 == 0 && *s2 == 0) return 0; - else if (*s1 == 0) + if (*s1 == 0) return -1; - else if (*s2 == 0) + if (*s2 == 0) return 1; - else - return (int32)(*s1 - *s2); + return (int32)(*s1 - *s2); } //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h index 80ff82acfc3e..7fc758aa77a3 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -278,6 +278,11 @@ class ConstString bool isNormalized (UnicodeNormalization = kUnicodeNormC); ///< On PC only kUnicodeNormC is working +#if SMTG_OS_WINDOWS + ConstString (const wchar_t* str, int32 length = -1) : ConstString (wscast (str), length) {} + operator const wchar_t* () const { return wscast (text16 ());} +#endif + #if SMTG_OS_MACOS virtual void* toCFStringRef (uint32 encoding = 0xFFFF, bool mutableCFString = false) const; ///< CFString conversion #endif @@ -317,7 +322,7 @@ class String : public ConstString String (const ConstString& str, int32 n = -1); ///< assign n characters of str (-1: all) String (const FVariant& var); ///< assign from FVariant String (IString* str); ///< assign from IString - ~String (); + ~String () SMTG_OVERRIDE; #if SMTG_CPP11_STDLIBSUPPORT String (String&& str); @@ -416,7 +421,15 @@ class String : public ConstString // numbers----------------------------------------------------------------- String& printInt64 (int64 value); - String& printFloat (double value); + + /** + * @brief print a float into a string, trailing zeros will be trimmed + * @param value the floating value to be printed + * @param maxPrecision (optional) the max precision allowed for this, num of significant digits after the comma + * For instance printFloat (1.234, 2) => 1.23 + * @return the resulting string. + */ + String& printFloat (double value, uint32 maxPrecision = 6); /** Increment the trailing number if present else start with minNumber, width specifies the string width format (width 2 for number 3 is 03), applyOnlyFormat set to true will only format the string to the given width without incrementing the founded trailing number */ bool incrementTrailingNumber (uint32 width = 2, tchar separator = STR (' '), uint32 minNumber = 1, bool applyOnlyFormat = false); @@ -448,6 +461,11 @@ class String : public ConstString void fromUTF8 (const char8* utf8String); ///< Assigns from UTF8 string bool normalize (UnicodeNormalization = kUnicodeNormC); ///< On PC only kUnicodeNormC is working +#if SMTG_OS_WINDOWS + String (const wchar_t* str, int32 length = -1, bool isTerminated = true) : String (wscast (str), length, isTerminated) {} + String& operator= (const wchar_t* str) {return String::operator= (wscast (str)); } +#endif + #if SMTG_OS_MACOS virtual bool fromCFStringRef (const void*, uint32 encoding = 0xFFFF); ///< CFString conversion #endif @@ -458,6 +476,7 @@ class String : public ConstString bool resize (uint32 newSize, bool wide, bool fill = false); private: + bool _toWideString (const char8* src, int32 length, uint32 sourceCodePage = kCP_Default); void tryFreeBuffer (); bool checkToMultiByte (uint32 destCodePage = kCP_Default) const; // to remove debug code from inline - const_cast inside!!! }; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp index 9213ebc95ac3..f4ac80cc570b 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -56,7 +56,6 @@ using Steinberg::Base::Thread::FGuard; namespace Steinberg { DEF_CLASS_IID (IUpdateManager) -bool UpdateHandler::lockUpdates = false; namespace Update { const uint32 kHashSize = (1 << 8); // must be power of 2 (16 bytes * 256 == 4096) @@ -243,10 +242,17 @@ tresult PLUGIN_API UpdateHandler::addDependent (FUnknown* u, IDependent* _depend return kResultTrue; } - //------------------------------------------------------------------------ tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* dependent) { + size_t eraseCount; + return removeDependent (u, dependent, eraseCount); +} + +//------------------------------------------------------------------------ +tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* dependent, size_t& eraseCount) +{ + eraseCount = 0; IPtr unknown = Update::getUnknownBase (u); if (unknown == nullptr && dependent == nullptr) return kResultFalse; @@ -287,13 +293,16 @@ tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* depe if ((*iterList) == dependent) #endif { + eraseCount = list.size (); if (list.size () == 1u) { listIsEmpty = true; break; } else + { iterList = list.erase (iterList); + } } else { @@ -322,11 +331,11 @@ tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* depe { if (dependent == nullptr) // Remove all dependents of object { + eraseCount = iterList->second.size (); map.erase (iterList); } else // Remove one dependent { - int32 eraseCount = 0; Update::DependentList& dependentlist = (*iterList).second; Update::DependentListIter iterDependentlist = dependentlist.begin (); while (iterDependentlist != dependentlist.end ()) @@ -363,8 +372,6 @@ tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* depe //------------------------------------------------------------------------ tresult UpdateHandler::doTriggerUpdates (FUnknown* u, int32 message, bool suppressUpdateDone) { - if (lockUpdates) - return kResultFalse; IPtr unknown = Update::getUnknownBase (u); if (!unknown) return kResultFalse; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h index 538022e62fcb..e85a9bbcc39c 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -78,18 +78,22 @@ class UpdateHandler : public FObject, public IUpdateHandler, public IUpdateManag public: //------------------------------------------------------------------------------ UpdateHandler (); - ~UpdateHandler (); + ~UpdateHandler () SMTG_OVERRIDE; using FObject::addDependent; using FObject::removeDependent; using FObject::deferUpdate; // IUpdateHandler +//private: + friend class FObject; /** register \param dependent to get messages from \param object */ tresult PLUGIN_API addDependent (FUnknown* object, IDependent* dependent) SMTG_OVERRIDE; /** unregister \param dependent to get no messages from \param object */ + tresult PLUGIN_API removeDependent (FUnknown* object, IDependent* dependent, size_t& earseCount); tresult PLUGIN_API removeDependent (FUnknown* object, IDependent* dependent) SMTG_OVERRIDE; +public: /** send \param message to all dependents of \param object immediately */ tresult PLUGIN_API triggerUpdates (FUnknown* object, int32 message) SMTG_OVERRIDE; /** send \param message to all dependents of \param object when idle */ @@ -103,15 +107,24 @@ class UpdateHandler : public FObject, public IUpdateHandler, public IUpdateManag /// @cond ignore // obsolete functions kept for compatibility - void checkUpdates (FObject* object = nullptr) { triggerDeferedUpdates (object->unknownCast ()); } - void flushUpdates (FObject* object) { cancelUpdates (object->unknownCast ()); } + void checkUpdates (FObject* object = nullptr) + { + triggerDeferedUpdates (object ? object->unknownCast () : nullptr); + } + void flushUpdates (FObject* object) + { + if (object) + cancelUpdates (object->unknownCast ()); + } void deferUpdate (FObject* object, int32 message) { - deferUpdates (object->unknownCast (), message); + if (object) + deferUpdates (object->unknownCast (), message); } void signalChange (FObject* object, int32 message, bool suppressUpdateDone = false) { - doTriggerUpdates (object->unknownCast (), message, suppressUpdateDone); + if (object) + doTriggerUpdates (object->unknownCast (), message, suppressUpdateDone); } #if DEVELOPMENT bool checkDeferred (FUnknown* object); @@ -130,8 +143,6 @@ class UpdateHandler : public FObject, public IUpdateHandler, public IUpdateManag Steinberg::Base::Thread::FLock lock; Update::Table* table = nullptr; - friend struct LockUpdateDependencies; - static bool lockUpdates; }; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h b/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h index bc452502a25e..2ef35ba8d8b0 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -99,7 +99,7 @@ class FLock : public ILock FLock (const char8* name = "FLock"); /** Lock destructor. */ - ~FLock (); + ~FLock () SMTG_OVERRIDE; //-- ILock ----------------------------------------------------------- void lock () SMTG_OVERRIDE; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp index 8135cb6c7eae..e7c154bad793 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/helper.manifest b/modules/juce_audio_processors/format_types/VST3_SDK/helper.manifest new file mode 100644 index 000000000000..c9b910cfe663 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/helper.manifest @@ -0,0 +1,10 @@ + + + + + + UTF-8 + + + + diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt index b5fddfe769da..6daa072e68e6 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt @@ -1,41 +1,44 @@ -//----------------------------------------------------------------------------- -// LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved -//----------------------------------------------------------------------------- -This license applies only to files referencing this license, -for other files of the Software Development Kit the respective embedded license text -is applicable. The license can be found at: www.steinberg.net/sdklicenses_vst3 - -This Software Development Kit is licensed under the terms of the Steinberg VST3 License, -or alternatively under the terms of the General Public License (GPL) Version 3. -You may use the Software Development Kit according to either of these licenses as it is -most appropriate for your project on a case-by-case basis (commercial or not). - -a) Proprietary Steinberg VST3 License -The Software Development Kit may not be distributed in parts or its entirety -without prior written agreement by Steinberg Media Technologies GmbH. -The SDK must not be used to re-engineer or manipulate any technology used -in any Steinberg or Third-party application or software module, -unless permitted by law. -Neither the name of the Steinberg Media Technologies GmbH nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. -Before publishing a software under the proprietary license, you need to obtain a copy -of the License Agreement signed by Steinberg Media Technologies GmbH. -The Steinberg VST SDK License Agreement can be found at: -www.steinberg.net/en/company/developers.html - -THE SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - -b) General Public License (GPL) Version 3 -Details of these licenses can be found at: www.gnu.org/licenses/gpl-3.0.html -//---------------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +This license applies only to files referencing this license, +for other files of the Software Development Kit the respective embedded license text +is applicable. The license can be found at: www.steinberg.net/sdklicenses_vst3 + +This Software Development Kit is licensed under the terms of the Steinberg VST3 License, +or alternatively under the terms of the General Public License (GPL) Version 3. +You may use the Software Development Kit according to either of these licenses as it is +most appropriate for your project on a case-by-case basis (commercial or not). + +a) Proprietary Steinberg VST3 License +The Software Development Kit may not be distributed in parts or its entirety +without prior written agreement by Steinberg Media Technologies GmbH. +The SDK must not be used to re-engineer or manipulate any technology used +in any Steinberg or Third-party application or software module, +unless permitted by law. +Neither the name of the Steinberg Media Technologies GmbH nor the names of its +contributors may be used to endorse or promote products derived from this +software without specific prior written permission. +Before publishing a software under the proprietary license, you need to obtain a copy +of the License Agreement signed by Steinberg Media Technologies GmbH. +The Steinberg VST SDK License Agreement can be found at: +www.steinberg.net/en/company/developers.html + +THE SDK IS PROVIDED BY STEINBERG MEDIA TECHNOLOGIES GMBH "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL STEINBERG MEDIA TECHNOLOGIES GMBH BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +b) General Public License (GPL) Version 3 +Details of these licenses can be found at: www.gnu.org/licenses/gpl-3.0.html +Please refer to the Steinberg VST usage guidelines for the use of VST, VST logo and VST +compatible logos: +https://steinbergmedia.github.io/vst3_dev_portal/pages/VST+3+Licensing/Usage+guidelines.html +//---------------------------------------------------------------------------------- diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md index 7be410549f6d..8a864b60a0cc 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md @@ -1,10 +1,10 @@ -# Welcome to VST 3 SDK Interfaces - -Here are located all VST interfaces definitions (including VST Component/Controller, UI, Test). - -## License & Usage guidelines - -More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) - ----- -Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) \ No newline at end of file +# Welcome to VST 3 SDK Interfaces + +Here are located all **VST 3** interfaces definitions (including VST Component/Controller, UI, Test). + +## License & Usage guidelines + +More details are found at [www.steinberg.net/sdklicenses_vst3](http://www.steinberg.net/sdklicenses_vst3) + +---- +Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.cpp index 4891cefa15b1..29e453aedce2 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.cpp @@ -44,7 +44,7 @@ const char16* ConstStringTable::getString (const char8* str) const } //---------------------------------------------------------------------------- -const char16 ConstStringTable::getString (const char8 str) const +char16 ConstStringTable::getString (const char8 str) const { std::map::iterator iter = charMap->find (str); if (iter != charMap->end ()) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.h index e19cae6512fc..f9450222ba7a 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/conststringtable.h @@ -32,7 +32,7 @@ class ConstStringTable /** Returns a char16 string of a ASCII string literal*/ const char16* getString (const char8* str) const; /** Returns a char16 character of a ASCII character */ - const char16 getString (const char8 str) const; + char16 getString (const char8 str) const; protected: ConstStringTable (); diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/falignpush.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/falignpush.h index 5ff11f22ce2f..49eb5736de97 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/falignpush.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/falignpush.h @@ -26,6 +26,10 @@ #elif defined __BORLANDC__ #pragma -a8 #elif SMTG_OS_WINDOWS + //! @brief warning C4103: alignment changed after including header, may be due to missing #pragma pack(pop) + #ifdef _MSC_VER + #pragma warning(disable : 4103) + #endif #pragma pack(push) #if SMTG_PLATFORM_64 #pragma pack(16) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h index dea70d0f794a..7b4a78d27aa3 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h @@ -16,6 +16,7 @@ #pragma once +// values for BYTEORDER according to the used platform #define kLittleEndian 0 #define kBigEndian 1 @@ -38,21 +39,39 @@ //----------------------------------------------------------------------------- #if defined (_WIN32) //----------------------------------------------------------------------------- - // ARM32 AND ARM64 (WINDOWS) - #if (defined(_M_ARM64) || defined(_M_ARM)) - #define SMTG_OS_WINDOWS_ARM 1 - #endif - #define SMTG_OS_LINUX 0 #define SMTG_OS_MACOS 0 #define SMTG_OS_WINDOWS 1 #define SMTG_OS_IOS 0 #define SMTG_OS_OSX 0 - #define SMTG_CPU_X86 _M_IX86 - #define SMTG_CPU_X86_64 _M_AMD64 - #define SMTG_CPU_ARM (_M_ARM && !_M_ARM64) - #define SMTG_CPU_ARM_64 _M_ARM64 + #if defined(_M_IX86) + #define SMTG_CPU_X86 1 + #else + #define SMTG_CPU_X86 0 + #endif + #if defined(_M_AMD64) + #define SMTG_CPU_X86_64 1 + #else + #define SMTG_CPU_X86_64 0 + #endif + #if defined(_M_ARM) + #define SMTG_CPU_ARM 1 + #else + #define SMTG_CPU_ARM 0 + #endif + #if defined(_M_ARM64) + #define SMTG_CPU_ARM_64 1 + #else + #define SMTG_CPU_ARM_64 0 + #endif + #if defined(_M_ARM64EC) + #define SMTG_CPU_ARM_64EC 1 + #else + #define SMTG_CPU_ARM_64EC 0 + #endif + + #define SMTG_OS_WINDOWS_ARM (SMTG_CPU_ARM_64EC || SMTG_CPU_ARM_64 || SMTG_CPU_ARM) #define BYTEORDER kLittleEndian @@ -61,18 +80,19 @@ #define SMTG_PTHREADS 0 #define SMTG_EXPORT_SYMBOL __declspec (dllexport) + #define SMTG_HIDDEN_SYMBOL #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #ifdef _MSC_VER - #pragma warning (disable : 4244) // Conversion from 'type1' to 'type2', possible loss of data. - #pragma warning (disable : 4250) // Inheritance via dominance is allowed - #pragma warning (disable : 4996) // deprecated functions + #pragma warning (disable : 4244) //! @brief warning C4244: Conversion from 'type1' to 'type2', possible loss of data. + #pragma warning (disable : 4250) //! @brief warning C4250: Inheritance via dominance is allowed + #pragma warning (disable : 4996) //! @brief warning C4996: deprecated functions - #pragma warning (3 : 4189) // local variable is initialized but not referenced - #pragma warning (3 : 4238) // nonstandard extension used : class rvalue used as lvalue + #pragma warning (3 : 4189) //! @brief warning C4189: local variable is initialized but not referenced + #pragma warning (3 : 4238) //! @brief warning C4238: nonstandard extension used : class rvalue used as lvalue #endif #if defined (_WIN64) || defined (_M_ARM64) @@ -86,26 +106,49 @@ #endif #ifdef __cplusplus - #define SMTG_CPP11 __cplusplus >= 201103L || _MSC_VER > 1600 || SMTG_INTEL_CXX11_MODE + #define SMTG_CPP11 (__cplusplus >= 201103L || _MSC_VER > 1600 || SMTG_INTEL_CXX11_MODE) #define SMTG_CPP11_STDLIBSUPPORT SMTG_CPP11 - #define SMTG_HAS_NOEXCEPT _MSC_VER >= 1900 || (SMTG_INTEL_CXX11_MODE && SMTG_INTEL_COMPILER >= 1300) - #endif + #define SMTG_CPP14 (__cplusplus >= 201402L || ((_MSC_FULL_VER >= 190024210L) && (_MSVC_LANG >= 201402L))) + #define SMTG_CPP17 (__cplusplus >= 201703L || ((_MSC_FULL_VER >= 190024210L) && (_MSVC_LANG >= 201703L))) + #define SMTG_CPP20 (__cplusplus >= 202002L) + #define SMTG_HAS_NOEXCEPT ((_MSC_FULL_VER >= 190023026L) || (SMTG_INTEL_CXX11_MODE && SMTG_INTEL_COMPILER >= 1300)) + #if ((_MSC_FULL_VER >= 190024210L) || (SMTG_INTEL_CXX11_MODE && SMTG_INTEL_COMPILER >= 1500) || (defined(__MINGW32__) && SMTG_CPP11)) + #define SMTG_HAS_CPP11_CONSTEXPR 1 + #else + #define SMTG_HAS_CPP11_CONSTEXPR 0 + #endif + #if (((_MSC_VER >= 1915L) && (_MSVC_LANG >= 201402L)) || (SMTG_INTEL_CXX11_MODE && SMTG_INTEL_COMPILER > 1700) || (defined(__MINGW32__) && SMTG_CPP14)) + #define SMTG_HAS_CPP14_CONSTEXPR 1 + #else + #define SMTG_HAS_CPP14_CONSTEXPR 0 + #endif + #endif //__cplusplus #define SMTG_DEPRECATED_ATTRIBUTE(message) __declspec (deprecated ("Is Deprecated: " message)) //----------------------------------------------------------------------------- // LINUX //----------------------------------------------------------------------------- #elif __gnu_linux__ || __linux__ - #define SMTG_OS_LINUX 1 - #define SMTG_OS_MACOS 0 - #define SMTG_OS_WINDOWS 0 - #define SMTG_OS_IOS 0 - #define SMTG_OS_OSX 0 + #define SMTG_OS_LINUX 1 + #define SMTG_OS_MACOS 0 + #define SMTG_OS_WINDOWS 0 + #define SMTG_OS_WINDOWS_ARM 0 + #define SMTG_OS_IOS 0 + #define SMTG_OS_OSX 0 #define SMTG_CPU_X86 __i386__ #define SMTG_CPU_X86_64 __x86_64__ - #define SMTG_CPU_ARM __arm__ - #define SMTG_CPU_ARM_64 __aarch64__ + #if defined(__arm__) + #define SMTG_CPU_ARM __arm__ + #else + #define SMTG_CPU_ARM 0 + #endif + #if defined(__aarch64__) + #define SMTG_CPU_ARM_64 __aarch64__ + #else + #define SMTG_CPU_ARM_64 0 + #endif + #define SMTG_CPU_ARM_64EC 0 #include #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -119,6 +162,7 @@ #define SMTG_PTHREADS 1 #define SMTG_EXPORT_SYMBOL __attribute__ ((visibility ("default"))) + #define SMTG_HIDDEN_SYMBOL __attribute__ ((visibility ("hidden"))) #if __LP64__ #define SMTG_PLATFORM_64 1 @@ -131,28 +175,35 @@ #ifndef SMTG_CPP11 #error unsupported compiler #endif + #define SMTG_CPP14 (__cplusplus >= 201402L) + #define SMTG_CPP17 (__cplusplus >= 201703L) + #define SMTG_CPP20 (__cplusplus >= 202002L) #if defined(__GNUG__) && __GNUG__ < 8 #define SMTG_CPP11_STDLIBSUPPORT 0 #else #define SMTG_CPP11_STDLIBSUPPORT 1 #endif #define SMTG_HAS_NOEXCEPT 1 - #endif + #define SMTG_HAS_CPP11_CONSTEXPR SMTG_CPP11 + #define SMTG_HAS_CPP14_CONSTEXPR SMTG_CPP14 + #endif // __cplusplus //----------------------------------------------------------------------------- // Mac and iOS //----------------------------------------------------------------------------- #elif __APPLE__ #include - #define SMTG_OS_LINUX 0 - #define SMTG_OS_MACOS 1 - #define SMTG_OS_WINDOWS 0 - #define SMTG_OS_IOS TARGET_OS_IPHONE - #define SMTG_OS_OSX TARGET_OS_MAC && !TARGET_OS_IPHONE - - #define SMTG_CPU_X86 TARGET_CPU_X86 - #define SMTG_CPU_X86_64 TARGET_CPU_X86_64 - #define SMTG_CPU_ARM TARGET_CPU_ARM - #define SMTG_CPU_ARM_64 TARGET_CPU_ARM64 + #define SMTG_OS_LINUX 0 + #define SMTG_OS_MACOS 1 + #define SMTG_OS_WINDOWS 0 + #define SMTG_OS_WINDOWS_ARM 0 + #define SMTG_OS_IOS TARGET_OS_IPHONE + #define SMTG_OS_OSX TARGET_OS_MAC && !TARGET_OS_IPHONE + + #define SMTG_CPU_X86 TARGET_CPU_X86 + #define SMTG_CPU_X86_64 TARGET_CPU_X86_64 + #define SMTG_CPU_ARM TARGET_CPU_ARM + #define SMTG_CPU_ARM_64 TARGET_CPU_ARM64 + #define SMTG_CPU_ARM_64EC 0 #if !SMTG_OS_IOS #ifndef __CF_USE_FRAMEWORK_INCLUDES__ @@ -178,6 +229,7 @@ #define SMTG_PTHREADS 1 #define SMTG_EXPORT_SYMBOL __attribute__ ((visibility ("default"))) + #define SMTG_HIDDEN_SYMBOL __attribute__ ((visibility ("hidden"))) #if !defined(__PLIST__) && !defined(SMTG_DISABLE_DEFAULT_DIAGNOSTICS) #ifdef __clang__ @@ -203,6 +255,9 @@ #ifdef __cplusplus #include #define SMTG_CPP11 (__cplusplus >= 201103L || SMTG_INTEL_CXX11_MODE) + #define SMTG_CPP14 (__cplusplus >= 201402L) + #define SMTG_CPP17 (__cplusplus >= 201703L) + #define SMTG_CPP20 (__cplusplus >= 202002L) #if defined (_LIBCPP_VERSION) && SMTG_CPP11 #define SMTG_CPP11_STDLIBSUPPORT 1 #define SMTG_HAS_NOEXCEPT 1 @@ -210,7 +265,12 @@ #define SMTG_CPP11_STDLIBSUPPORT 0 #define SMTG_HAS_NOEXCEPT 0 #endif - #endif + #define SMTG_HAS_CPP11_CONSTEXPR SMTG_CPP11 + #define SMTG_HAS_CPP14_CONSTEXPR SMTG_CPP14 + #endif // __cplusplus +//----------------------------------------------------------------------------- +// Unknown Platform +//----------------------------------------------------------------------------- #else #pragma error unknown platform #endif @@ -236,11 +296,22 @@ //----------------------------------------------------------------------------- #if SMTG_CPP11 #define SMTG_OVERRIDE override -#define SMTG_CONSTEXPR constexpr #else #define SMTG_OVERRIDE +#endif + +#if SMTG_HAS_CPP11_CONSTEXPR +#define SMTG_CONSTEXPR constexpr +#else #define SMTG_CONSTEXPR #endif + +#if SMTG_HAS_CPP14_CONSTEXPR +#define SMTG_CONSTEXPR14 constexpr +#else +#define SMTG_CONSTEXPR14 +#endif + #if SMTG_HAS_NOEXCEPT #define SMTG_NOEXCEPT noexcept #else diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h index 00eaa1de98a2..fea4522c560f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h @@ -25,11 +25,7 @@ // 16 bit string operations #if SMTG_CPP11 // if c++11 unicode string literals #define SMTG_CPP11_CAT_PRIVATE_DONT_USE(a,b) a ## b - #if SMTG_OS_WINDOWS - #define STR16(x) SMTG_CPP11_CAT_PRIVATE_DONT_USE(L,x) - #else - #define STR16(x) SMTG_CPP11_CAT_PRIVATE_DONT_USE(u,x) - #endif + #define STR16(x) SMTG_CPP11_CAT_PRIVATE_DONT_USE(u,x) #else #include "conststringtable.h" #define STR16(x) Steinberg::ConstStringTable::instance ()->getString (x) @@ -99,19 +95,19 @@ namespace Steinberg { //---------------------------------------------------------------------------- -static const tchar kEmptyString[] = { 0 }; -static const char8 kEmptyString8[] = { 0 }; -static const char16 kEmptyString16[] = { 0 }; +static SMTG_CONSTEXPR const tchar kEmptyString[] = { 0 }; +static SMTG_CONSTEXPR const char8 kEmptyString8[] = { 0 }; +static SMTG_CONSTEXPR const char16 kEmptyString16[] = { 0 }; #ifdef UNICODE -static const tchar kInfiniteSymbol[] = { 0x221E, 0 }; +static SMTG_CONSTEXPR const tchar kInfiniteSymbol[] = { 0x221E, 0 }; #else -static const tchar* const kInfiniteSymbol = STR ("oo"); +static SMTG_CONSTEXPR const tchar* const kInfiniteSymbol = STR ("oo"); #endif //---------------------------------------------------------------------------- template -inline int32 _tstrlen (const T* wcs) +inline SMTG_CONSTEXPR14 int32 _tstrlen (const T* wcs) { const T* eos = wcs; @@ -121,13 +117,13 @@ inline int32 _tstrlen (const T* wcs) return (int32) (eos - wcs - 1); } -inline int32 tstrlen (const tchar* str) {return _tstrlen (str);} -inline int32 strlen8 (const char8* str) {return _tstrlen (str);} -inline int32 strlen16 (const char16* str) {return _tstrlen (str);} +inline SMTG_CONSTEXPR14 int32 tstrlen (const tchar* str) {return _tstrlen (str);} +inline SMTG_CONSTEXPR14 int32 strlen8 (const char8* str) {return _tstrlen (str);} +inline SMTG_CONSTEXPR14 int32 strlen16 (const char16* str) {return _tstrlen (str);} //---------------------------------------------------------------------------- template -inline int32 _tstrcmp (const T* src, const T* dst) +inline SMTG_CONSTEXPR14 int32 _tstrcmp (const T* src, const T* dst) { while (*src == *dst && *dst) { @@ -137,30 +133,29 @@ inline int32 _tstrcmp (const T* src, const T* dst) if (*src == 0 && *dst == 0) return 0; - else if (*src == 0) + if (*src == 0) return -1; - else if (*dst == 0) + if (*dst == 0) return 1; - else - return (int32) (*src - *dst); + return (int32) (*src - *dst); } -inline int32 tstrcmp (const tchar* src, const tchar* dst) {return _tstrcmp (src, dst);} -inline int32 strcmp8 (const char8* src, const char8* dst) {return _tstrcmp (src, dst);} -inline int32 strcmp16 (const char16* src, const char16* dst) {return _tstrcmp (src, dst);} +inline SMTG_CONSTEXPR14 int32 tstrcmp (const tchar* src, const tchar* dst) {return _tstrcmp (src, dst);} +inline SMTG_CONSTEXPR14 int32 strcmp8 (const char8* src, const char8* dst) {return _tstrcmp (src, dst);} +inline SMTG_CONSTEXPR14 int32 strcmp16 (const char16* src, const char16* dst) {return _tstrcmp (src, dst);} template -inline int32 strcmpT (const T* first, const T* last); +inline SMTG_CONSTEXPR14 int32 strcmpT (const T* first, const T* last); template <> -inline int32 strcmpT (const char8* first, const char8* last) { return _tstrcmp (first, last); } +inline SMTG_CONSTEXPR14 int32 strcmpT (const char8* first, const char8* last) { return _tstrcmp (first, last); } template <> -inline int32 strcmpT (const char16* first, const char16* last) { return _tstrcmp (first, last); } +inline SMTG_CONSTEXPR14 int32 strcmpT (const char16* first, const char16* last) { return _tstrcmp (first, last); } //---------------------------------------------------------------------------- template -inline int32 _tstrncmp (const T* first, const T* last, uint32 count) +inline SMTG_CONSTEXPR14 int32 _tstrncmp (const T* first, const T* last, uint32 count) { if (count == 0) return 0; @@ -173,43 +168,42 @@ inline int32 _tstrncmp (const T* first, const T* last, uint32 count) if (*first == 0 && *last == 0) return 0; - else if (*first == 0) + if (*first == 0) return -1; - else if (*last == 0) + if (*last == 0) return 1; - else - return (int32) (*first - *last); + return (int32) (*first - *last); } -inline int32 tstrncmp (const tchar* first, const tchar* last, uint32 count) {return _tstrncmp (first, last, count);} -inline int32 strncmp8 (const char8* first, const char8* last, uint32 count) {return _tstrncmp (first, last, count);} -inline int32 strncmp16 (const char16* first, const char16* last, uint32 count) {return _tstrncmp (first, last, count);} +inline SMTG_CONSTEXPR14 int32 tstrncmp (const tchar* first, const tchar* last, uint32 count) {return _tstrncmp (first, last, count);} +inline SMTG_CONSTEXPR14 int32 strncmp8 (const char8* first, const char8* last, uint32 count) {return _tstrncmp (first, last, count);} +inline SMTG_CONSTEXPR14 int32 strncmp16 (const char16* first, const char16* last, uint32 count) {return _tstrncmp (first, last, count);} template -inline int32 strncmpT (const T* first, const T* last, uint32 count); +inline SMTG_CONSTEXPR14 int32 strncmpT (const T* first, const T* last, uint32 count); template <> -inline int32 strncmpT (const char8* first, const char8* last, uint32 count) { return _tstrncmp (first, last, count); } +inline SMTG_CONSTEXPR14 int32 strncmpT (const char8* first, const char8* last, uint32 count) { return _tstrncmp (first, last, count); } template <> -inline int32 strncmpT (const char16* first, const char16* last, uint32 count) {return _tstrncmp (first, last, count); } +inline SMTG_CONSTEXPR14 int32 strncmpT (const char16* first, const char16* last, uint32 count) {return _tstrncmp (first, last, count); } //---------------------------------------------------------------------------- template -inline T* _tstrcpy (T* dst, const T* src) +inline SMTG_CONSTEXPR14 T* _tstrcpy (T* dst, const T* src) { T* cp = dst; while ((*cp++ = *src++) != 0) // copy string ; return dst; } -inline tchar* tstrcpy (tchar* dst, const tchar* src) {return _tstrcpy (dst, src);} -inline char8* strcpy8 (char8* dst, const char8* src) {return _tstrcpy (dst, src);} -inline char16* strcpy16 (char16* dst, const char16* src) {return _tstrcpy (dst, src);} +inline SMTG_CONSTEXPR14 tchar* tstrcpy (tchar* dst, const tchar* src) {return _tstrcpy (dst, src);} +inline SMTG_CONSTEXPR14 char8* strcpy8 (char8* dst, const char8* src) {return _tstrcpy (dst, src);} +inline SMTG_CONSTEXPR14 char16* strcpy16 (char16* dst, const char16* src) {return _tstrcpy (dst, src);} //---------------------------------------------------------------------------- template -inline T* _tstrncpy (T* dest, const T* source, uint32 count) +inline SMTG_CONSTEXPR14 T* _tstrncpy (T* dest, const T* source, uint32 count) { T* start = dest; while (count && (*dest++ = *source++) != 0) // copy string @@ -223,13 +217,13 @@ inline T* _tstrncpy (T* dest, const T* source, uint32 count) return start; } -inline tchar* tstrncpy (tchar* dest, const tchar* source, uint32 count) {return _tstrncpy (dest, source, count);} -inline char8* strncpy8 (char8* dest, const char8* source, uint32 count) {return _tstrncpy (dest, source, count);} -inline char16* strncpy16 (char16* dest, const char16* source, uint32 count) {return _tstrncpy (dest, source, count);} +inline SMTG_CONSTEXPR14 tchar* tstrncpy (tchar* dest, const tchar* source, uint32 count) {return _tstrncpy (dest, source, count);} +inline SMTG_CONSTEXPR14 char8* strncpy8 (char8* dest, const char8* source, uint32 count) {return _tstrncpy (dest, source, count);} +inline SMTG_CONSTEXPR14 char16* strncpy16 (char16* dest, const char16* source, uint32 count) {return _tstrncpy (dest, source, count);} //---------------------------------------------------------------------------- template -inline T* _tstrcat (T* dst, const T* src) +inline SMTG_CONSTEXPR14 T* _tstrcat (T* dst, const T* src) { T* cp = dst; @@ -242,12 +236,12 @@ inline T* _tstrcat (T* dst, const T* src) return dst; } -inline tchar* tstrcat (tchar* dst, const tchar* src) {return _tstrcat (dst, src); } -inline char8* strcat8 (char8* dst, const char8* src) {return _tstrcat (dst, src); } -inline char16* strcat16 (char16* dst, const char16* src) {return _tstrcat (dst, src); } +inline SMTG_CONSTEXPR14 tchar* tstrcat (tchar* dst, const tchar* src) {return _tstrcat (dst, src); } +inline SMTG_CONSTEXPR14 char8* strcat8 (char8* dst, const char8* src) {return _tstrcat (dst, src); } +inline SMTG_CONSTEXPR14 char16* strcat16 (char16* dst, const char16* src) {return _tstrcat (dst, src); } //---------------------------------------------------------------------------- -inline void str8ToStr16 (char16* dst, const char8* src, int32 n = -1) +inline SMTG_CONSTEXPR14 void str8ToStr16 (char16* dst, const char8* src, int32 n = -1) { int32 i = 0; for (;;) @@ -278,12 +272,20 @@ inline void str8ToStr16 (char16* dst, const char8* src, int32 n = -1) } //------------------------------------------------------------------------ -inline bool FIDStringsEqual (FIDString id1, FIDString id2) +inline SMTG_CONSTEXPR14 bool FIDStringsEqual (FIDString id1, FIDString id2) { return (id1 && id2) ? (strcmp8 (id1, id2) == 0) : false; } -static const uint32 kPrintfBufferSize = 4096; +static SMTG_CONSTEXPR const uint32 kPrintfBufferSize = 4096; + +#if SMTG_OS_WINDOWS +/* cast between wchar_t and char16 */ +inline wchar_t* wscast (char16* s) { static_assert (sizeof (wchar_t) == sizeof (char16), ""); return reinterpret_cast (s); } +inline char16* wscast (wchar_t* s) { static_assert (sizeof (wchar_t) == sizeof (char16), ""); return reinterpret_cast (s);} +inline const wchar_t* wscast (const char16* s) { static_assert (sizeof (wchar_t) == sizeof (char16), ""); return reinterpret_cast (s); } +inline const char16* wscast (const wchar_t* s) { static_assert (sizeof (wchar_t) == sizeof (char16), ""); return reinterpret_cast (s); } +#endif //------------------------------------------------------------------------ } // namespace Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h index 1f95bd116d53..133dbba38d3c 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h @@ -18,6 +18,8 @@ #include "fplatform.h" +#include + //#define UNICODE_OFF // disable / enable unicode #ifdef UNICODE_OFF @@ -37,38 +39,26 @@ namespace Steinberg //----------------------------------------------------------------- // Integral Types typedef char int8; - typedef unsigned char uint8; + typedef uint8_t uint8; typedef unsigned char uchar; - typedef short int16; - typedef unsigned short uint16; + typedef int16_t int16; + typedef uint16_t uint16; -#if SMTG_OS_WINDOWS && !defined(__GNUC__) - typedef long int32; - typedef unsigned long uint32; -#else - typedef int int32; - typedef unsigned int uint32; -#endif + typedef int32_t int32; + typedef uint32_t uint32; - static const int32 kMaxLong = 0x7fffffff; - static const int32 kMinLong = (-0x7fffffff - 1); - static const int32 kMaxInt32 = kMaxLong; - static const int32 kMinInt32 = kMinLong; - static const uint32 kMaxInt32u = 0xffffffff; - -#if SMTG_OS_WINDOWS && !defined(__GNUC__) - typedef __int64 int64; - typedef unsigned __int64 uint64; - static const int64 kMaxInt64 = 9223372036854775807i64; - static const int64 kMinInt64 = (-9223372036854775807i64 - 1); -#else - typedef long long int64; - typedef unsigned long long uint64; - static const int64 kMaxInt64 = 0x7fffffffffffffffLL; - static const int64 kMinInt64 = (-0x7fffffffffffffffLL-1); -#endif - static const uint64 kMaxInt64u = uint64 (0xffffffff) | (uint64 (0xffffffff) << 32); + static const int32 kMaxInt32 = INT32_MAX; + static const int32 kMinInt32 = INT32_MIN; + static const int32 kMaxLong = kMaxInt32; + static const int32 kMinLong = kMinInt32; + static const uint32 kMaxInt32u = UINT32_MAX; + + typedef int64_t int64; + typedef uint64_t uint64; + static const int64 kMaxInt64 = INT64_MAX; + static const int64 kMinInt64 = INT64_MIN; + static const uint64 kMaxInt64u = UINT64_MAX; //----------------------------------------------------------------- // other Semantic Types @@ -91,15 +81,7 @@ namespace Steinberg //------------------------------------------------------------------ // Char / Strings typedef char char8; -#ifdef _NATIVE_WCHAR_T_DEFINED - typedef __wchar_t char16; -#elif defined(__MINGW32__) - typedef wchar_t char16; -#elif SMTG_CPP11 typedef char16_t char16; -#else - typedef int16 char16; -#endif #ifdef UNICODE typedef char16 tchar; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.cpp index 23ca64e6cb42..b88fc5bf9b4b 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.cpp @@ -406,17 +406,23 @@ void FUID::toRegistryString (char8* string) const char8 s5[13]; Steinberg::toString8 (s5, data, 10, 16); - sprintf (string, "{%s-%s-%s-%s-%s}", s1, s2, s3, s4, s5); + snprintf (string, 40, "{%s-%s-%s-%s-%s}", s1, s2, s3, s4, s5); #endif } //------------------------------------------------------------------------ void FUID::print (char8* string, int32 style) const { - if (!string) // no string: debug output + print (style, string, 62); +} + +//------------------------------------------------------------------------ +void FUID::print (int32 style, char8* string, size_t stringBufferSize) const +{ + if (!string || stringBufferSize == 0) // no string: debug output { char8 str[128]; - print (str, style); + print (style, str, 128); #if SMTG_OS_WINDOWS OutputDebugStringA (str); @@ -433,21 +439,25 @@ void FUID::print (char8* string, int32 style) const switch (style) { case kINLINE_UID: - sprintf (string, "INLINE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); + snprintf (string, stringBufferSize, "INLINE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, + l2, l3, l4); break; case kDECLARE_UID: - sprintf (string, "DECLARE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); + snprintf (string, stringBufferSize, "DECLARE_UID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, + l2, l3, l4); break; case kFUID: - sprintf (string, "FUID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, l4); + snprintf (string, stringBufferSize, "FUID (0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, + l4); break; case kCLASS_UID: default: - sprintf (string, "DECLARE_CLASS_IID (Interface, 0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, - l2, l3, l4); + snprintf (string, stringBufferSize, + "DECLARE_CLASS_IID (Interface, 0x%08X, 0x%08X, 0x%08X, 0x%08X)", l1, l2, l3, + l4); break; } } @@ -467,7 +477,7 @@ static void toString8 (char8* string, const char* data, int32 i1, int32 i2) for (int32 i = i1; i < i2; i++) { char8 s[3]; - sprintf (s, "%02X", (uint8)data[i]); + snprintf (s, 3, "%02X", (uint8)data[i]); strcat (string, s); } } diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.h index d5a5cfc62fa5..56cf292cbcfb 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/funknown.h @@ -60,19 +60,18 @@ #endif //------------------------------------------------------------------------ -#define DECLARE_UID(name, l1, l2, l3, l4) ::Steinberg::TUID name = INLINE_UID (l1, l2, l3, l4); +#define DECLARE_UID(name, l1, l2, l3, l4) SMTG_CONSTEXPR14 ::Steinberg::TUID name = INLINE_UID (l1, l2, l3, l4); //------------------------------------------------------------------------ #define EXTERN_UID(name) extern const ::Steinberg::TUID name; #ifdef INIT_CLASS_IID -#define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \ - static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); \ - \ -const ::Steinberg::FUID ClassName::iid (ClassName##_iid); +#define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \ + static SMTG_CONSTEXPR14 const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); \ + const ::Steinberg::FUID ClassName::iid (ClassName##_iid); #else #define DECLARE_CLASS_IID(ClassName, l1, l2, l3, l4) \ - static const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); + static SMTG_CONSTEXPR14 const ::Steinberg::TUID ClassName##_iid = INLINE_UID (l1, l2, l3, l4); #endif #define DEF_CLASS_IID(ClassName) const ::Steinberg::FUID ClassName::iid (ClassName##_iid); @@ -207,7 +206,16 @@ typedef int64 LARGE_INT; // obsolete //------------------------------------------------------------------------ // FUID class declaration //------------------------------------------------------------------------ -typedef int8 TUID[16]; ///< plain UID type +typedef char TUID[16]; ///< plain UID type + +#if SMTG_CPP14 +//------------------------------------------------------------------------ +inline SMTG_CONSTEXPR14 void copyTUID (char* dst, const char* src) +{ + for (auto i = 0; i < 16; ++i) + dst[i] = src[i]; +} +#endif //------------------------------------------------------------------------ /* FUnknown private */ @@ -301,12 +309,18 @@ class FUID kCLASS_UID ///< "DECLARE_CLASS_IID (Interface, 0x00000000, 0x00000000, 0x00000000, 0x00000000)" }; /** Prints the UID to a string (or debug output if string is NULL). - \param string is the output string if not NULL. - \param style can be chosen from the FUID::UIDPrintStyle enumeration. */ + \param style can be chosen from the FUID::UIDPrintStyle enumeration. + \param string is the output string if not NULL. + \param stringBufferSize is the size of the output string */ + void print (int32 style, char8* string = nullptr, size_t stringBufferSize = 0) const; + +#if SMTG_CPP17 + [[deprecated ("Use the print method with the buffer size")]] +#endif void print (char8* string = nullptr, int32 style = kINLINE_UID) const; template - inline explicit FUID (const int8 (&uid)[N]) + inline explicit FUID (const char (&uid)[N]) { #if SMTG_CPP11_STDLIBSUPPORT static_assert (N == sizeof (TUID), "only TUID allowed"); @@ -442,7 +456,7 @@ using VoidT = typename Void::Type; //------------------------------------------------------------------------ /** * This type trait detects if a class has an @c iid member variable. It is used to detect if - * the FUID and DECLARE_CLASS_IID method or the SKI::UID method is used. + * the FUID and DECLARE_CLASS_IID method or the U::UID method is used. */ template struct HasIIDType : std::false_type @@ -459,7 +473,7 @@ struct HasIIDType> : std::true_type } // FUnknownPrivate //------------------------------------------------------------------------ -/** @return the TUID for a SKI interface which uses the SKI::UID method. */ +/** @return the TUID for an interface which uses the U::UID method. */ template ::value>::type* = nullptr> const TUID& getTUID () @@ -468,7 +482,7 @@ const TUID& getTUID () } //------------------------------------------------------------------------ -/** @return the TUID for a SKI interface which uses the FUID and DECLARE_CLASS_IID method. */ +/** @return the TUID for an interface which uses the FUID and DECLARE_CLASS_IID method. */ template ::value>::type* = nullptr> const TUID& getTUID () diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/futils.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/futils.h index 5ce9e295a8fa..e5d8a5f3ab45 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/futils.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/futils.h @@ -27,34 +27,39 @@ inline const T& Min (const T& a, const T& b) return b < a ? b : a; } +//---------------------------------------------------------------------------- template inline const T& Max (const T& a, const T& b) { return a < b ? b : a; } +//---------------------------------------------------------------------------- template inline T Abs (const T& value) { return (value >= (T)0) ? value : -value; } +//---------------------------------------------------------------------------- template inline T Sign (const T& value) { return (value == (T)0) ? 0 : ((value >= (T)0) ? 1 : -1); } +//---------------------------------------------------------------------------- template inline T Bound (T minval, T maxval, T x) { if (x < minval) return minval; - else if (x > maxval) + if (x > maxval) return maxval; return x; } +//---------------------------------------------------------------------------- template void Swap (T& t1, T& t2) { @@ -63,6 +68,7 @@ void Swap (T& t1, T& t2) t2 = tmp; } +//---------------------------------------------------------------------------- template bool IsApproximateEqual (T t1, T t2, T epsilon) { @@ -76,18 +82,21 @@ bool IsApproximateEqual (T t1, T t2, T epsilon) return false; } +//---------------------------------------------------------------------------- template inline T ToNormalized (const T& value, const int32 numSteps) { return value / T (numSteps); } +//---------------------------------------------------------------------------- template inline int32 FromNormalized (const T& norm, const int32 numSteps) { return Min (numSteps, int32 (norm * (numSteps + 1))); } +//---------------------------------------------------------------------------- // Four character constant #ifndef CCONST #define CCONST(a, b, c, d) \ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h index 10325fe85640..36bc263f6bd6 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ipluginbase.h @@ -38,8 +38,10 @@ class IPluginBase: public FUnknown public: //------------------------------------------------------------------------ /** The host passes a number of interfaces as context to initialize the plug-in class. - @note Extensive memory allocations etc. should be performed in this method rather than in the class' constructor! - If the method does NOT return kResultOk, the object is released immediately. In this case terminate is not called! */ + \param context, passed by the host, is mandatory and should implement IHostApplication + @note Extensive memory allocations etc. should be performed in this method rather than in + the class' constructor! If the method does NOT return kResultOk, the object is released + immediately. In this case terminate is not called! */ virtual tresult PLUGIN_API initialize (FUnknown* context) = 0; /** This function is called before the plug-in is unloaded and can be used for @@ -62,11 +64,23 @@ struct PFactoryInfo //------------------------------------------------------------------------ enum FactoryFlags { - kNoFlags = 0, ///< Nothing - kClassesDiscardable = 1 << 0, ///< The number of exported classes can change each time the Module is loaded. If this flag is set, the host does not cache class information. This leads to a longer startup time because the host always has to load the Module to get the current class information. - kLicenseCheck = 1 << 1, ///< Class IDs of components are interpreted as Syncrosoft-License (LICENCE_UID). Loaded in a Steinberg host, the module will not be loaded when the license is not valid - kComponentNonDiscardable = 1 << 3, ///< Component will not be unloaded until process exit - kUnicode = 1 << 4 ///< Components have entirely unicode encoded strings. (True for VST 3 plug-ins so far) + /** Nothing */ + kNoFlags = 0, + + /** The number of exported classes can change each time the Module is loaded. If this flag + is set, the host does not cache class information. This leads to a longer startup time + because the host always has to load the Module to get the current class information. */ + kClassesDiscardable = 1 << 0, + + /** This flag is deprecated, do not use anymore, resp. it will get ignored from + Cubase/Nuendo 12 and later. */ + kLicenseCheck = 1 << 1, + + /** Component will not be unloaded until process exit */ + kComponentNonDiscardable = 1 << 3, + + /** Components have entirely unicode encoded strings (True for VST 3 plug-ins so far). */ + kUnicode = 1 << 4 }; enum @@ -77,12 +91,16 @@ struct PFactoryInfo }; //------------------------------------------------------------------------ - char8 vendor[kNameSize]; ///< e.g. "Steinberg Media Technologies" - char8 url[kURLSize]; ///< e.g. "http://www.steinberg.de" - char8 email[kEmailSize]; ///< e.g. "info@steinberg.de" - int32 flags; ///< (see above) + char8 vendor[kNameSize]; ///< e.g. "Steinberg Media Technologies" + char8 url[kURLSize]; ///< e.g. "http://www.steinberg.de" + char8 email[kEmailSize]; ///< e.g. "info@steinberg.de" + int32 flags; ///< (see FactoryFlags above) //------------------------------------------------------------------------ - PFactoryInfo (const char8* _vendor, const char8* _url, const char8* _email, int32 _flags) + SMTG_CONSTEXPR14 PFactoryInfo (const char8* _vendor, const char8* _url, const char8* _email, + int32 _flags) +#if SMTG_CPP14 + : vendor (), url (), email (), flags () +#endif { strncpy8 (vendor, _vendor, kNameSize); strncpy8 (url, _url, kURLSize); @@ -117,16 +135,32 @@ struct PClassInfo kNameSize = 64 }; //------------------------------------------------------------------------ - TUID cid; ///< Class ID 16 Byte class GUID - int32 cardinality; ///< cardinality of the class, set to kManyInstances (see \ref ClassCardinality) - char8 category[kCategorySize]; ///< class category, host uses this to categorize interfaces - char8 name[kNameSize]; ///< class name, visible to the user + /** Class ID 16 Byte class GUID */ + TUID cid; + + /** Cardinality of the class, set to kManyInstances (see \ref PClassInfo::ClassCardinality) */ + int32 cardinality; + + /** Class category, host uses this to categorize interfaces */ + char8 category[kCategorySize]; + + /** Class name, visible to the user */ + char8 name[kNameSize]; + //------------------------------------------------------------------------ - PClassInfo (const TUID _cid, int32 _cardinality, const char8* _category, const char8* _name) + SMTG_CONSTEXPR14 PClassInfo (const TUID _cid, int32 _cardinality, const char8* _category, + const char8* _name) +#if SMTG_CPP14 + : cid (), cardinality (), category (), name () +#endif { +#if SMTG_CPP14 + copyTUID (cid, _cid); +#else memset (this, 0, sizeof (PClassInfo)); memcpy (cid, _cid, sizeof (TUID)); +#endif if (_category) strncpy8 (category, _category, kCategorySize); if (_name) @@ -162,8 +196,9 @@ class IPluginFactory : public FUnknown /** Fill a PFactoryInfo structure with information about the plug-in vendor. */ virtual tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) = 0; - /** Returns the number of exported classes by this factory. - If you are using the CPluginFactory implementation provided by the SDK, it returns the number of classes you registered with CPluginFactory::registerClass. */ + /** Returns the number of exported classes by this factory. If you are using the CPluginFactory + * implementation provided by the SDK, it returns the number of classes you registered with + * CPluginFactory::registerClass. */ virtual int32 PLUGIN_API countClasses () = 0; /** Fill a PClassInfo structure with information about the class at the specified index. */ @@ -186,10 +221,17 @@ DECLARE_CLASS_IID (IPluginFactory, 0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9 struct PClassInfo2 { //------------------------------------------------------------------------ - TUID cid; ///< Class ID 16 Byte class GUID - int32 cardinality; ///< cardinality of the class, set to kManyInstances (see \ref PClassInfo::ClassCardinality) - char8 category[PClassInfo::kCategorySize]; ///< class category, host uses this to categorize interfaces - char8 name[PClassInfo::kNameSize]; ///< class name, visible to the user + /** Class ID 16 Byte class GUID */ + TUID cid; + + /** Cardinality of the class, set to kManyInstances (see \ref PClassInfo::ClassCardinality) */ + int32 cardinality; + + /** Class category, host uses this to categorize interfaces */ + char8 category[PClassInfo::kCategorySize]; + + /** Class name, visible to the user */ + char8 name[PClassInfo::kNameSize]; enum { kVendorSize = 64, @@ -197,20 +239,44 @@ struct PClassInfo2 kSubCategoriesSize = 128 }; - uint32 classFlags; ///< flags used for a specific category, must be defined where category is defined - char8 subCategories[kSubCategoriesSize]; ///< module specific subcategories, can be more than one, logically added by the \c OR operator - char8 vendor[kVendorSize]; ///< overwrite vendor information from factory info - char8 version[kVersionSize]; ///< Version string (e.g. "1.0.0.512" with Major.Minor.Subversion.Build) - char8 sdkVersion[kVersionSize]; ///< SDK version used to build this class (e.g. "VST 3.0") + /** flags used for a specific category, must be defined where category is defined */ + uint32 classFlags; + /** module specific subcategories, can be more than one, logically added by the OR operator */ + char8 subCategories[kSubCategoriesSize]; + + /** overwrite vendor information from factory info */ + char8 vendor[kVendorSize]; + + /** Version string (e.g. "1.0.0.512" with Major.Minor.Subversion.Build) */ + char8 version[kVersionSize]; + + /** SDK version used to build this class (e.g. "VST 3.0") */ + char8 sdkVersion[kVersionSize]; //------------------------------------------------------------------------ - PClassInfo2 (const TUID _cid, int32 _cardinality, const char8* _category, const char8* _name, - int32 _classFlags, const char8* _subCategories, const char8* _vendor, const char8* _version, - const char8* _sdkVersion) + SMTG_CONSTEXPR14 PClassInfo2 (const TUID _cid, int32 _cardinality, const char8* _category, + const char8* _name, int32 _classFlags, + const char8* _subCategories, const char8* _vendor, + const char8* _version, const char8* _sdkVersion) +#if SMTG_CPP14 + : cid () + , cardinality () + , category () + , name () + , classFlags () + , subCategories () + , vendor () + , version () + , sdkVersion () +#endif { +#if SMTG_CPP14 + copyTUID (cid, _cid); +#else memset (this, 0, sizeof (PClassInfo2)); memcpy (cid, _cid, sizeof (TUID)); +#endif cardinality = _cardinality; if (_category) strncpy8 (category, _category, PClassInfo::kCategorySize); @@ -281,19 +347,44 @@ struct PClassInfoW kSubCategoriesSize = 128 }; - uint32 classFlags; ///< flags used for a specific category, must be defined where category is defined - char8 subCategories[kSubCategoriesSize];///< module specific subcategories, can be more than one, logically added by the \c OR operator - char16 vendor[kVendorSize]; ///< overwrite vendor information from factory info - char16 version[kVersionSize]; ///< Version string (e.g. "1.0.0.512" with Major.Minor.Subversion.Build) - char16 sdkVersion[kVersionSize]; ///< SDK version used to build this class (e.g. "VST 3.0") - -//------------------------------------------------------------------------ - PClassInfoW (const TUID _cid, int32 _cardinality, const char8* _category, const char16* _name, - int32 _classFlags, const char8* _subCategories, const char16* _vendor, const char16* _version, - const char16* _sdkVersion) + /** flags used for a specific category, must be defined where category is defined */ + uint32 classFlags; + + /** module specific subcategories, can be more than one, logically added by the OR operator */ + char8 subCategories[kSubCategoriesSize]; + + /** overwrite vendor information from factory info */ + char16 vendor[kVendorSize]; + + /** Version string (e.g. "1.0.0.512" with Major.Minor.Subversion.Build) */ + char16 version[kVersionSize]; + + /** SDK version used to build this class (e.g. "VST 3.0") */ + char16 sdkVersion[kVersionSize]; + +//------------------------------------------------------------------------ + SMTG_CONSTEXPR14 PClassInfoW (const TUID _cid, int32 _cardinality, const char8* _category, + const char16* _name, int32 _classFlags, + const char8* _subCategories, const char16* _vendor, + const char16* _version, const char16* _sdkVersion) +#if SMTG_CPP14 + : cid () + , cardinality () + , category () + , name () + , classFlags () + , subCategories () + , vendor () + , version () + , sdkVersion () +#endif { +#if SMTG_CPP14 + copyTUID (cid, _cid); +#else memset (this, 0, sizeof (PClassInfoW)); memcpy (cid, _cid, sizeof (TUID)); +#endif cardinality = _cardinality; if (_category) strncpy8 (category, _category, PClassInfo::kCategorySize); @@ -326,9 +417,13 @@ struct PClassInfoW PClassInfoW () { memset (this, 0, sizeof (PClassInfoW)); } #endif - void fromAscii (const PClassInfo2& ci2) + SMTG_CONSTEXPR14 void fromAscii (const PClassInfo2& ci2) { +#if SMTG_CPP14 + copyTUID (cid, ci2.cid); +#else memcpy (cid, ci2.cid, sizeof (TUID)); +#endif cardinality = ci2.cardinality; strncpy8 (category, ci2.category, PClassInfo::kCategorySize); str8ToStr16 (name, ci2.name, PClassInfo::kNameSize); diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h new file mode 100644 index 000000000000..d3f67e9b86eb --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/iplugincompatibility.h @@ -0,0 +1,122 @@ +//----------------------------------------------------------------------------- +// Project : SDK Core +// +// Category : SDK Core Interfaces +// Filename : pluginterfaces/base/iplugincompatibility.h +// Created by : Steinberg, 02/2022 +// Description : Basic Plug-in Interfaces +// +//----------------------------------------------------------------------------- +// This file is part of a Steinberg SDK. It is subject to the license terms +// in the LICENSE file found in the top-level directory of this distribution +// and at www.steinberg.net/sdklicenses. +// No part of the SDK, including this file, may be copied, modified, propagated, +// or distributed except according to the terms contained in the LICENSE file. +//----------------------------------------------------------------------------- + +#pragma once + +#include "ibstream.h" + +//------------------------------------------------------------------------ +namespace Steinberg { + +//------------------------------------------------------------------------ +/** moduleinfo.json + +The moduleinfo.json describes the contents of the plug-in in a JSON5 compatible format (See https://json5.org/). +It contains the factory info (see PFactoryInfo), the contained classes (see PClassInfo), the +included snapshots and a list of compatibility of the included classes. + +An example moduleinfo.json: + +\code +{ + "Name": "", + "Version": "1.0", + "Factory Info": { + "Vendor": "Steinberg Media Technologies", + "URL": "http://www.steinberg.net", + "E-Mail": "mailto:info@steinberg.de", + "Flags": { + "Unicode": true, + "Classes Discardable": false, + "Component Non Discardable": false, + }, + }, + "Compatibility": [ + { + "New": "B9F9ADE1CD9C4B6DA57E61E3123535FD", + "Old": [ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // just an example + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", // another example + ], + }, + ], + "Classes": [ + { + "CID": "B9F9ADE1CD9C4B6DA57E61E3123535FD", + "Category": "Audio Module Class", + "Name": "AGainSimple VST3", + "Vendor": "Steinberg Media Technologies", + "Version": "1.3.0.1", + "SDKVersion": "VST 3.7.4", + "Sub Categories": [ + "Fx", + ], + "Class Flags": 0, + "Cardinality": 2147483647, + "Snapshots": [ + ], + }, + ], +} +\endcode + +*/ + +#define kPluginCompatibilityClass "Plugin Compatibility Class" + +//------------------------------------------------------------------------ +/** optional interface to query the compatibility of the plug-ins classes +- [plug imp] + +A plug-in can add a class with this interface to its class factory if it cannot provide a +moduleinfo.json file in its plug-in package/bundle where the compatibility is normally part of. + +If the module contains a moduleinfo.json the host will ignore this class. + +The class must write into the stream an UTF-8 encoded json description of the compatibility of +the other classes in the factory. + +It is expected that the JSON5 written starts with an array: +\code +[ + { + "New": "B9F9ADE1CD9C4B6DA57E61E3123535FD", + "Old": [ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // just an example + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", // another example + ], + }, +] +\endcode +*/ +class IPluginCompatibility : public FUnknown +{ +public: + /** get the compatibility stream + * @param stream the stream the plug-in must write the UTF8 encoded JSON5 compatibility + * string. + * @return kResultTrue on success + */ + virtual tresult PLUGIN_API getCompatibilityJSON (IBStream* stream) = 0; + +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (IPluginCompatibility, 0x4AFD4B6A, 0x35D7C240, 0xA5C31414, 0xFB7D15E6) + +//------------------------------------------------------------------------ +} // Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugviewcontentscalesupport.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugviewcontentscalesupport.h index 532c94105e29..f529031f7f5f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugviewcontentscalesupport.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugviewcontentscalesupport.h @@ -36,16 +36,24 @@ namespace Steinberg { This interface communicates the content scale factor from the host to the plug-in view on systems where plug-ins cannot get this information directly like Microsoft Windows. -The host calls setContentScaleFactor directly after the plug-in view is attached and when the scale -factor changes (system change or window moved to another screen with different scaling settings). -The host could call setContentScaleFactor in a different context, for example: scaling the -plug-in editor for better readability. +The host calls setContentScaleFactor directly before or after the plug-in view is attached and when +the scale factor changes while the view is attached (system change or window moved to another screen +with different scaling settings). + +The host may call setContentScaleFactor in a different context, for example: scaling the plug-in +editor for better readability. + When a plug-in handles this (by returning kResultTrue), it needs to scale the width and height of -its view by the scale factor and inform the host via a IPlugFrame::resizeView(), the host will then +its view by the scale factor and inform the host via a IPlugFrame::resizeView(). The host will then call IPlugView::onSize(). Note that the host is allowed to call setContentScaleFactor() at any time the IPlugView is valid. - */ +If this happens before the IPlugFrame object is set on your view, make sure that when the host calls +IPlugView::getSize() afterwards you return the size of your view for that new scale factor. + +It is recommended to implement this interface on Microsoft Windows to let the host know that the +plug-in is able to render in different scalings. +*/ class IPlugViewContentScaleSupport : public FUnknown { public: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstattributes.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstattributes.h index fb63b30c73f9..7d4e68fb95ec 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstattributes.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstattributes.h @@ -55,7 +55,7 @@ class IAttributeList : public FUnknown /** Gets float value. */ virtual tresult PLUGIN_API getFloat (AttrID id, double& value) = 0; - /** Sets string value (UTF16) (should be null-terminated!). */ + /** Sets string value (UTF16) (must be null-terminated!). */ virtual tresult PLUGIN_API setString (AttrID id, const TChar* string) = 0; /** Gets string value (UTF16). Note that Size is in Byte, not the string Length! @@ -106,7 +106,7 @@ tresult PLUGIN_API MyPlugin::setState (IBStream* state) UString128 tmp (string); char ascii[128]; tmp.toAscii (ascii, 128); - if (!strncmp (ascii, StateType::kProject, strlen (StateType::kProject))) + if (strncmp (ascii, StateType::kProject, strlen (StateType::kProject)) == 0) { // we are in project loading context... } diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h index f2dd5e7d6419..82d550e32773 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h @@ -46,48 +46,48 @@ namespace PlugType \defgroup plugType Plug-in Type used for subCategories */ /*@{*/ //------------------------------------------------------------------------ -const CString kFxAnalyzer = "Fx|Analyzer"; ///< Scope, FFT-Display, Loudness Processing... -const CString kFxDelay = "Fx|Delay"; ///< Delay, Multi-tap Delay, Ping-Pong Delay... -const CString kFxDistortion = "Fx|Distortion"; ///< Amp Simulator, Sub-Harmonic, SoftClipper... -const CString kFxDynamics = "Fx|Dynamics"; ///< Compressor, Expander, Gate, Limiter, Maximizer, Tape Simulator, EnvelopeShaper... -const CString kFxEQ = "Fx|EQ"; ///< Equalization, Graphical EQ... -const CString kFxFilter = "Fx|Filter"; ///< WahWah, ToneBooster, Specific Filter,... -const CString kFx = "Fx"; ///< others type (not categorized) -const CString kFxInstrument = "Fx|Instrument"; ///< Fx which could be loaded as Instrument too -const CString kFxInstrumentExternal = "Fx|Instrument|External"; ///< Fx which could be loaded as Instrument too and is external (wrapped Hardware) -const CString kFxSpatial = "Fx|Spatial"; ///< MonoToStereo, StereoEnhancer,... -const CString kFxGenerator = "Fx|Generator"; ///< Tone Generator, Noise Generator... -const CString kFxMastering = "Fx|Mastering"; ///< Dither, Noise Shaping,... -const CString kFxModulation = "Fx|Modulation"; ///< Phaser, Flanger, Chorus, Tremolo, Vibrato, AutoPan, Rotary, Cloner... -const CString kFxPitchShift = "Fx|Pitch Shift"; ///< Pitch Processing, Pitch Correction, Vocal Tuning... -const CString kFxRestoration = "Fx|Restoration"; ///< Denoiser, Declicker,... -const CString kFxReverb = "Fx|Reverb"; ///< Reverberation, Room Simulation, Convolution Reverb... -const CString kFxSurround = "Fx|Surround"; ///< dedicated to surround processing: LFE Splitter, Bass Manager... -const CString kFxTools = "Fx|Tools"; ///< Volume, Mixer, Tuner... -const CString kFxNetwork = "Fx|Network"; ///< using Network - -const CString kInstrument = "Instrument"; ///< Effect used as instrument (sound generator), not as insert -const CString kInstrumentDrum = "Instrument|Drum"; ///< Instrument for Drum sounds -const CString kInstrumentExternal = "Instrument|External";///< External Instrument (wrapped Hardware) -const CString kInstrumentPiano = "Instrument|Piano"; ///< Instrument for Piano sounds -const CString kInstrumentSampler = "Instrument|Sampler"; ///< Instrument based on Samples -const CString kInstrumentSynth = "Instrument|Synth"; ///< Instrument based on Synthesis -const CString kInstrumentSynthSampler = "Instrument|Synth|Sampler"; ///< Instrument based on Synthesis and Samples - -const CString kSpatial = "Spatial"; ///< used for SurroundPanner -const CString kSpatialFx = "Spatial|Fx"; ///< used for SurroundPanner and as insert effect -const CString kOnlyRealTime = "OnlyRT"; ///< indicates that it supports only realtime process call, no processing faster than realtime -const CString kOnlyOfflineProcess = "OnlyOfflineProcess"; ///< used for plug-in offline processing (will not work as normal insert plug-in) -const CString kOnlyARA = "OnlyARA"; ///< used for plug-ins that require ARA to operate (will not work as normal insert plug-in) - -const CString kNoOfflineProcess = "NoOfflineProcess"; ///< will be NOT used for plug-in offline processing (will work as normal insert plug-in) -const CString kUpDownMix = "Up-Downmix"; ///< used for Mixconverter/Up-Mixer/Down-Mixer -const CString kAnalyzer = "Analyzer"; ///< Meter, Scope, FFT-Display, not selectable as insert plug-in -const CString kAmbisonics = "Ambisonics"; ///< used for Ambisonics channel (FX or Panner/Mixconverter/Up-Mixer/Down-Mixer when combined with other category) - -const CString kMono = "Mono"; ///< used for Mono only plug-in [optional] -const CString kStereo = "Stereo"; ///< used for Stereo only plug-in [optional] -const CString kSurround = "Surround"; ///< used for Surround only plug-in [optional] +SMTG_CONSTEXPR const CString kFx = "Fx"; ///< others type (not categorized) +SMTG_CONSTEXPR const CString kFxAnalyzer = "Fx|Analyzer"; ///< Scope, FFT-Display, Loudness Processing... +SMTG_CONSTEXPR const CString kFxDelay = "Fx|Delay"; ///< Delay, Multi-tap Delay, Ping-Pong Delay... +SMTG_CONSTEXPR const CString kFxDistortion = "Fx|Distortion"; ///< Amp Simulator, Sub-Harmonic, SoftClipper... +SMTG_CONSTEXPR const CString kFxDynamics = "Fx|Dynamics"; ///< Compressor, Expander, Gate, Limiter, Maximizer, Tape Simulator, EnvelopeShaper... +SMTG_CONSTEXPR const CString kFxEQ = "Fx|EQ"; ///< Equalization, Graphical EQ... +SMTG_CONSTEXPR const CString kFxFilter = "Fx|Filter"; ///< WahWah, ToneBooster, Specific Filter,... +SMTG_CONSTEXPR const CString kFxGenerator = "Fx|Generator"; ///< Tone Generator, Noise Generator... +SMTG_CONSTEXPR const CString kFxInstrument = "Fx|Instrument"; ///< Fx which could be loaded as Instrument too +SMTG_CONSTEXPR const CString kFxInstrumentExternal = "Fx|Instrument|External"; ///< Fx which could be loaded as Instrument too and is external (wrapped Hardware) +SMTG_CONSTEXPR const CString kFxMastering = "Fx|Mastering"; ///< Dither, Noise Shaping,... +SMTG_CONSTEXPR const CString kFxModulation = "Fx|Modulation"; ///< Phaser, Flanger, Chorus, Tremolo, Vibrato, AutoPan, Rotary, Cloner... +SMTG_CONSTEXPR const CString kFxNetwork = "Fx|Network"; ///< using Network +SMTG_CONSTEXPR const CString kFxPitchShift = "Fx|Pitch Shift"; ///< Pitch Processing, Pitch Correction, Vocal Tuning... +SMTG_CONSTEXPR const CString kFxRestoration = "Fx|Restoration"; ///< Denoiser, Declicker,... +SMTG_CONSTEXPR const CString kFxReverb = "Fx|Reverb"; ///< Reverberation, Room Simulation, Convolution Reverb... +SMTG_CONSTEXPR const CString kFxSpatial = "Fx|Spatial"; ///< MonoToStereo, StereoEnhancer,... +SMTG_CONSTEXPR const CString kFxSurround = "Fx|Surround"; ///< dedicated to surround processing: LFE Splitter, Bass Manager... +SMTG_CONSTEXPR const CString kFxTools = "Fx|Tools"; ///< Volume, Mixer, Tuner... +SMTG_CONSTEXPR const CString kFxVocals = "Fx|Vocals"; ///< Tools dedicated to vocals + +SMTG_CONSTEXPR const CString kInstrument = "Instrument"; ///< Effect used as instrument (sound generator), not as insert +SMTG_CONSTEXPR const CString kInstrumentDrum = "Instrument|Drum"; ///< Instrument for Drum sounds +SMTG_CONSTEXPR const CString kInstrumentExternal = "Instrument|External";///< External Instrument (wrapped Hardware) +SMTG_CONSTEXPR const CString kInstrumentPiano = "Instrument|Piano"; ///< Instrument for Piano sounds +SMTG_CONSTEXPR const CString kInstrumentSampler = "Instrument|Sampler"; ///< Instrument based on Samples +SMTG_CONSTEXPR const CString kInstrumentSynth = "Instrument|Synth"; ///< Instrument based on Synthesis +SMTG_CONSTEXPR const CString kInstrumentSynthSampler = "Instrument|Synth|Sampler"; ///< Instrument based on Synthesis and Samples + +SMTG_CONSTEXPR const CString kAmbisonics = "Ambisonics"; ///< used for Ambisonics channel (FX or Panner/Mixconverter/Up-Mixer/Down-Mixer when combined with other category) +SMTG_CONSTEXPR const CString kAnalyzer = "Analyzer"; ///< Meter, Scope, FFT-Display, not selectable as insert plug-in +SMTG_CONSTEXPR const CString kNoOfflineProcess = "NoOfflineProcess"; ///< will be NOT used for plug-in offline processing (will work as normal insert plug-in) +SMTG_CONSTEXPR const CString kOnlyARA = "OnlyARA"; ///< used for plug-ins that require ARA to operate (will not work as normal insert plug-in) +SMTG_CONSTEXPR const CString kOnlyOfflineProcess = "OnlyOfflineProcess"; ///< used for plug-in offline processing (will not work as normal insert plug-in) +SMTG_CONSTEXPR const CString kOnlyRealTime = "OnlyRT"; ///< indicates that it supports only realtime process call, no processing faster than realtime +SMTG_CONSTEXPR const CString kSpatial = "Spatial"; ///< used for SurroundPanner +SMTG_CONSTEXPR const CString kSpatialFx = "Spatial|Fx"; ///< used for SurroundPanner and as insert effect +SMTG_CONSTEXPR const CString kUpDownMix = "Up-Downmix"; ///< used for Mixconverter/Up-Mixer/Down-Mixer + +SMTG_CONSTEXPR const CString kMono = "Mono"; ///< used for Mono only plug-in [optional] +SMTG_CONSTEXPR const CString kStereo = "Stereo"; ///< used for Stereo only plug-in [optional] +SMTG_CONSTEXPR const CString kSurround = "Surround"; ///< used for Surround only plug-in [optional] //------------------------------------------------------------------------ /*@}*/ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h index 7bd1a487164d..d7c8925c135c 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h @@ -146,7 +146,14 @@ enum RestartFlags * The host ask the plug-in for the new routing with IComponent::getRoutingInfo, \ref vst3Routing * see IComponent * [SDK 3.6.6] */ - kRoutingInfoChanged = 1 << 9 + kRoutingInfoChanged = 1 << 9, + + /** Key switches has changed (info, count) + * Either the Key switches info, the count of Key switches has changed. + * The host invalidates all caches of Key switches infos and asks the edit controller (IKeyswitchController) for the current ones. + * See IKeyswitchController + * [SDK 3.7.3] */ + kKeyswitchChanged = 1 << 10 }; //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterchanges.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterchanges.h index ce9dec06c642..1d216c1aa324 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterchanges.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterchanges.h @@ -128,7 +128,7 @@ class IParameterChanges : public FUnknown /** Adds a new parameter queue with a given ID at the end of the list, returns it and its index in the parameter changes list. */ - virtual IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID& id, int32& index /*out*/) = 0; + virtual IParamValueQueue* PLUGIN_API addParameterData (const ParamID& id, int32& index /*out*/) = 0; //------------------------------------------------------------------------ static const FUID iid; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterfunctionname.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterfunctionname.h index 8e9a5ab91db9..ca2f2a50e99a 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterfunctionname.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstparameterfunctionname.h @@ -26,7 +26,6 @@ //------------------------------------------------------------------------ namespace Steinberg { namespace Vst { - namespace FunctionNameType { //-------------------------------------------------------------------- const CString kCompGainReduction = "Comp:GainReduction"; /** */ @@ -45,6 +44,12 @@ namespace FunctionNameType { const CString kRandomize = "Randomize"; /** Allow to assign some randomized values to some parameters in a controlled way*/ + /// Panner Type + const CString kPanPosCenterX = "PanPosCenterX"; ///< Gravity point X-axis [0, 1]=>[L-R] (for stereo: middle between left and right) + const CString kPanPosCenterY = "PanPosCenterY"; ///< Gravity point Y-axis [0, 1]=>[Front-Rear] + const CString kPanPosCenterZ = "PanPosCenterZ"; ///< Gravity point Z-axis [0, 1]=>[Bottom-Top] + + } // FunctionNameType //------------------------------------------------------------------------ @@ -55,10 +60,11 @@ namespace FunctionNameType { - [released: 3.7.0] - [optional] -This interface allows the host to get a parameter associated to a specific meaning (a functionName) for a given unit. -The host can use this information, for example, for drawing a Gain Reduction meter in its own UI. -In order to get the plain value of this parameter, the host should use the IEditController::normalizedParamToPlain. -The host can automatically map parameters to dedicated UI controls, such as the wet-dry mix knob or Randomize button. +This interface allows the host to get a parameter associated to a specific meaning (a functionName) +for a given unit. The host can use this information, for example, for drawing a Gain Reduction meter +in its own UI. In order to get the plain value of this parameter, the host should use the +IEditController::normalizedParamToPlain. The host can automatically map parameters to dedicated UI +controls, such as the wet-dry mix knob or Randomize button. \section IParameterFunctionNameExample Example @@ -70,38 +76,39 @@ The host can automatically map parameters to dedicated UI controls, such as the in MyController class declaration class MyController : public Vst::EditController, public Vst::IParameterFunctionName { - ... - tresult PLUGIN_API getParameterIDFromFunctionName (UnitID unitID, FIDString functionName, - Vst::ParamID& paramID) override; - ... - - OBJ_METHODS (MyController, Vst::EditController) - DEFINE_INTERFACES - ... - DEF_INTERFACE (Vst::IParameterFunctionName) - END_DEFINE_INTERFACES (Vst::EditController) - ... + ... + tresult PLUGIN_API getParameterIDFromFunctionName (UnitID unitID, FIDString functionName, + Vst::ParamID& paramID) override; + ... + + OBJ_METHODS (MyController, Vst::EditController) + DEFINE_INTERFACES + ... + DEF_INTERFACE (Vst::IParameterFunctionName) + END_DEFINE_INTERFACES (Vst::EditController) + DELEGATE_REFCOUNT (Vst::EditController) + ... } #include "ivstparameterfunctionname.h" namespace Steinberg { - namespace Vst { - DEF_CLASS_IID (IParameterFunctionName) - } + namespace Vst { + DEF_CLASS_IID (IParameterFunctionName) + } } //------------------------------------------------------------------------ -tresult PLUGIN_API MyController::getParameterIDFromFunctionName (UnitID unitID, FIDString functionName, - Vst::ParamID& paramID) +tresult PLUGIN_API MyController::getParameterIDFromFunctionName (UnitID unitID, FIDString +functionName, Vst::ParamID& paramID) { - using namespace Vst; + using namespace Vst; - paramID = kNoParamId; + paramID = kNoParamId; - if (unitID == kRootUnitId && FIDStringsEqual (functionName, kCompGainReduction)) - paramID = kMyGainReductionId; + if (unitID == kRootUnitId && FIDStringsEqual (functionName, kCompGainReduction)) + paramID = kMyGainReductionId; - return (paramID != kNoParamId) ? kResultOk : kResultFalse; + return (paramID != kNoParamId) ? kResultOk : kResultFalse; } //--- a host implementation example: -------------------- @@ -109,14 +116,15 @@ tresult PLUGIN_API MyController::getParameterIDFromFunctionName (UnitID unitID, FUnknownPtr functionName (mEditController->getIEditController ()); if (functionName) { - Vst::ParamID paramID; - if (functionName->getParameterIDFromFunctionName (Vst::FunctionNameType::kCompGainReduction, paramID) == kResultTrue) - { - // paramID could be cached for performance issue - ParamValue norm = mEditController->getIEditController ()->getParamNormalized (paramID); - ParamValue plain = mEditController->getIEditController ()->normalizedParamToPlain (paramID, norm); - // plain is something like -6 (-6dB) - } + Vst::ParamID paramID; + if (functionName->getParameterIDFromFunctionName (kRootUnitId, + Vst::FunctionNameType::kCompGainReduction, paramID) == kResultTrue) + { + // paramID could be cached for performance issue + ParamValue norm = mEditController->getIEditController ()->getParamNormalized (paramID); + ParamValue plain = mEditController->getIEditController ()->normalizedParamToPlain (paramID, norm); + // plain is something like -6 (-6dB) + } } \endcode */ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstphysicalui.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstphysicalui.h index 7d6ca5b48248..5c1e1d44e1c5 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstphysicalui.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstphysicalui.h @@ -1,169 +1,169 @@ -//------------------------------------------------------------------------ -// Project : VST SDK -// -// Category : Interfaces -// Filename : pluginterfaces/vst/ivstphysicalui.h -// Created by : Steinberg, 06/2018 -// Description : VST Physical User Interface support -// -//----------------------------------------------------------------------------- -// This file is part of a Steinberg SDK. It is subject to the license terms -// in the LICENSE file found in the top-level directory of this distribution -// and at www.steinberg.net/sdklicenses. -// No part of the SDK, including this file, may be copied, modified, propagated, -// or distributed except according to the terms contained in the LICENSE file. -//----------------------------------------------------------------------------- - -#pragma once - -#include "pluginterfaces/vst/ivstnoteexpression.h" - -//------------------------------------------------------------------------ -#include "pluginterfaces/base/falignpush.h" -//------------------------------------------------------------------------ - -//------------------------------------------------------------------------ -namespace Steinberg { -namespace Vst { - -//------------------------------------------------------------------------ -/** \defgroup vst3typedef VST 3 Data Types */ -/*@{*/ -//------------------------------------------------------------------------ -/** Physical UI Type */ -typedef uint32 PhysicalUITypeID; -/*@}*/ - -//------------------------------------------------------------------------ -/** PhysicalUITypeIDs describes the type of Physical UI (PUI) which could be associated to a note -expression. -\see PhysicalUIMap -*/ -enum PhysicalUITypeIDs -{ - /** absolute X position when touching keys of PUIs. Range [0=left, 0.5=middle, 1=right] */ - kPUIXMovement = 0, - /** absolute Y position when touching keys of PUIs. Range [0=bottom/near, 0.5=center, 1=top/far] */ - kPUIYMovement, - /** pressing a key down on keys of PUIs. Range [0=No Pressure, 1=Full Pressure] */ - kPUIPressure, - - kPUITypeCount, ///< count of current defined PUIs - - kInvalidPUITypeID = 0xFFFFFFFF ///< indicates an invalid or not initialized PUI type -}; - -//------------------------------------------------------------------------ -/** PhysicalUIMap describes a mapping of a noteExpression Type to a Physical UI Type. -It is used in PhysicalUIMapList. -\see PhysicalUIMapList -*/ -struct PhysicalUIMap -{ - /** This represents the physical UI. /see PhysicalUITypeIDs, this is set by the caller of - * getPhysicalUIMapping */ - PhysicalUITypeID physicalUITypeID; - - /** This represents the associated noteExpression TypeID to the given physicalUITypeID. This - * will be filled by the plug-in in the call getPhysicalUIMapping, set it to kInvalidTypeID if - * no Note Expression is associated to the given PUI. */ - NoteExpressionTypeID noteExpressionTypeID; -}; - -//------------------------------------------------------------------------ -/** PhysicalUIMapList describes a list of PhysicalUIMap -\see INoteExpressionPhysicalUIMapping -*/ -struct PhysicalUIMapList -{ - /** Count of entries in the map array, set by the caller of getPhysicalUIMapping. */ - uint32 count; - - /** Pointer to a list of PhysicalUIMap containing count entries. */ - PhysicalUIMap* map; -}; - -//------------------------------------------------------------------------ -/** Extended plug-in interface IEditController for note expression event support: Vst::INoteExpressionPhysicalUIMapping -\ingroup vstIPlug vst3611 -- [plug imp] -- [extends IEditController] -- [released: 3.6.11] -- [optional] - -With this plug-in interface, the host can retrieve the preferred physical mapping associated to note -expression supported by the plug-in. -When the mapping changes (for example when switching presets) the plug-in needs -to inform the host about it via \ref IComponentHandler::restartComponent (kNoteExpressionChanged). - -\section INoteExpressionPhysicalUIMappingExample Example - -\code{.cpp} -//------------------------------------------------------------------------ -// here an example of how a VST3 plug-in could support this INoteExpressionPhysicalUIMapping interface. -// we need to define somewhere the iids: - -//in MyController class declaration -class MyController : public Vst::EditController, public Vst::INoteExpressionPhysicalUIMapping -{ - // ... - //--- INoteExpressionPhysicalUIMapping --------------------------------- - tresult PLUGIN_API getPhysicalUIMapping (int32 busIndex, int16 channel, PhysicalUIMapList& list) SMTG_OVERRIDE; - // ... - - OBJ_METHODS (MyController, Vst::EditController) - DEFINE_INTERFACES - // ... - DEF_INTERFACE (Vst::INoteExpressionPhysicalUIMapping) - END_DEFINE_INTERFACES (Vst::EditController) - //... -} - -// In mycontroller.cpp -#include "pluginterfaces/vst/ivstnoteexpression.h" - -namespace Steinberg { - namespace Vst { - DEF_CLASS_IID (INoteExpressionPhysicalUIMapping) - } -} -//------------------------------------------------------------------------ -tresult PLUGIN_API MyController::getPhysicalUIMapping (int32 busIndex, int16 channel, PhysicalUIMapList& list) -{ - if (busIndex == 0 && channel == 0) - { - for (uint32 i = 0; i < list.count; ++i) - { - NoteExpressionTypeID type = kInvalidTypeID; - if (kPUIXMovement == list.map[i].physicalUITypeID) - list.map[i].noteExpressionTypeID = kCustomStart + 1; - else if (kPUIYMovement == list.map[i].physicalUITypeID) - list.map[i].noteExpressionTypeID = kCustomStart + 2; - } - return kResultTrue; - } - return kResultFalse; -} -\endcode -*/ -class INoteExpressionPhysicalUIMapping : public FUnknown -{ -public: - /** Fills the list of mapped [physical UI (in) - note expression (out)] for a given bus index - * and channel. */ - virtual tresult PLUGIN_API getPhysicalUIMapping (int32 busIndex, int16 channel, - PhysicalUIMapList& list) = 0; - -//------------------------------------------------------------------------ - static const FUID iid; -}; - -DECLARE_CLASS_IID (INoteExpressionPhysicalUIMapping, 0xB03078FF, 0x94D24AC8, 0x90CCD303, 0xD4133324) - -//------------------------------------------------------------------------ -} // namespace Vst -} // namespace Steinberg - -//------------------------------------------------------------------------ -#include "pluginterfaces/base/falignpop.h" -//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +// Project : VST SDK +// +// Category : Interfaces +// Filename : pluginterfaces/vst/ivstphysicalui.h +// Created by : Steinberg, 06/2018 +// Description : VST Physical User Interface support +// +//----------------------------------------------------------------------------- +// This file is part of a Steinberg SDK. It is subject to the license terms +// in the LICENSE file found in the top-level directory of this distribution +// and at www.steinberg.net/sdklicenses. +// No part of the SDK, including this file, may be copied, modified, propagated, +// or distributed except according to the terms contained in the LICENSE file. +//----------------------------------------------------------------------------- + +#pragma once + +#include "pluginterfaces/vst/ivstnoteexpression.h" + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpush.h" +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +namespace Steinberg { +namespace Vst { + +//------------------------------------------------------------------------ +/** \defgroup vst3typedef VST 3 Data Types */ +/*@{*/ +//------------------------------------------------------------------------ +/** Physical UI Type */ +typedef uint32 PhysicalUITypeID; +/*@}*/ + +//------------------------------------------------------------------------ +/** PhysicalUITypeIDs describes the type of Physical UI (PUI) which could be associated to a note +expression. +\see PhysicalUIMap +*/ +enum PhysicalUITypeIDs +{ + /** absolute X position when touching keys of PUIs. Range [0=left, 0.5=middle, 1=right] */ + kPUIXMovement = 0, + /** absolute Y position when touching keys of PUIs. Range [0=bottom/near, 0.5=center, 1=top/far] */ + kPUIYMovement, + /** pressing a key down on keys of PUIs. Range [0=No Pressure, 1=Full Pressure] */ + kPUIPressure, + + kPUITypeCount, ///< count of current defined PUIs + + kInvalidPUITypeID = 0xFFFFFFFF ///< indicates an invalid or not initialized PUI type +}; + +//------------------------------------------------------------------------ +/** PhysicalUIMap describes a mapping of a noteExpression Type to a Physical UI Type. +It is used in PhysicalUIMapList. +\see PhysicalUIMapList +*/ +struct PhysicalUIMap +{ + /** This represents the physical UI. /see PhysicalUITypeIDs, this is set by the caller of + * getPhysicalUIMapping */ + PhysicalUITypeID physicalUITypeID; + + /** This represents the associated noteExpression TypeID to the given physicalUITypeID. This + * will be filled by the plug-in in the call getPhysicalUIMapping, set it to kInvalidTypeID if + * no Note Expression is associated to the given PUI. */ + NoteExpressionTypeID noteExpressionTypeID; +}; + +//------------------------------------------------------------------------ +/** PhysicalUIMapList describes a list of PhysicalUIMap +\see INoteExpressionPhysicalUIMapping +*/ +struct PhysicalUIMapList +{ + /** Count of entries in the map array, set by the caller of getPhysicalUIMapping. */ + uint32 count; + + /** Pointer to a list of PhysicalUIMap containing count entries. */ + PhysicalUIMap* map; +}; + +//------------------------------------------------------------------------ +/** Extended plug-in interface IEditController for note expression event support: Vst::INoteExpressionPhysicalUIMapping +\ingroup vstIPlug vst3611 +- [plug imp] +- [extends IEditController] +- [released: 3.6.11] +- [optional] + +With this plug-in interface, the host can retrieve the preferred physical mapping associated to note +expression supported by the plug-in. +When the mapping changes (for example when switching presets) the plug-in needs +to inform the host about it via \ref IComponentHandler::restartComponent (kNoteExpressionChanged). + +\section INoteExpressionPhysicalUIMappingExample Example + +\code{.cpp} +//------------------------------------------------------------------------ +// here an example of how a VST3 plug-in could support this INoteExpressionPhysicalUIMapping interface. +// we need to define somewhere the iids: + +//in MyController class declaration +class MyController : public Vst::EditController, public Vst::INoteExpressionPhysicalUIMapping +{ + // ... + //--- INoteExpressionPhysicalUIMapping --------------------------------- + tresult PLUGIN_API getPhysicalUIMapping (int32 busIndex, int16 channel, PhysicalUIMapList& list) SMTG_OVERRIDE; + // ... + + OBJ_METHODS (MyController, Vst::EditController) + DEFINE_INTERFACES + // ... + DEF_INTERFACE (Vst::INoteExpressionPhysicalUIMapping) + END_DEFINE_INTERFACES (Vst::EditController) + //... +} + +// In mycontroller.cpp +#include "pluginterfaces/vst/ivstnoteexpression.h" + +namespace Steinberg { + namespace Vst { + DEF_CLASS_IID (INoteExpressionPhysicalUIMapping) + } +} +//------------------------------------------------------------------------ +tresult PLUGIN_API MyController::getPhysicalUIMapping (int32 busIndex, int16 channel, PhysicalUIMapList& list) +{ + if (busIndex == 0 && channel == 0) + { + for (uint32 i = 0; i < list.count; ++i) + { + NoteExpressionTypeID type = kInvalidTypeID; + if (kPUIXMovement == list.map[i].physicalUITypeID) + list.map[i].noteExpressionTypeID = kCustomStart + 1; + else if (kPUIYMovement == list.map[i].physicalUITypeID) + list.map[i].noteExpressionTypeID = kCustomStart + 2; + } + return kResultTrue; + } + return kResultFalse; +} +\endcode +*/ +class INoteExpressionPhysicalUIMapping : public FUnknown +{ +public: + /** Fills the list of mapped [physical UI (in) - note expression (out)] for a given bus index + * and channel. */ + virtual tresult PLUGIN_API getPhysicalUIMapping (int32 busIndex, int16 channel, + PhysicalUIMapList& list) = 0; + +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (INoteExpressionPhysicalUIMapping, 0xB03078FF, 0x94D24AC8, 0x90CCD303, 0xD4133324) + +//------------------------------------------------------------------------ +} // namespace Vst +} // namespace Steinberg + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpop.h" +//------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsttestplugprovider.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsttestplugprovider.h index eb9923f5b9fc..ffbcec4987a1 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsttestplugprovider.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsttestplugprovider.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2020, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h index 0daa490a0b15..0d21684fc13f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h @@ -76,6 +76,15 @@ const Speaker kSpeakerACN12 = (Speaker)1 << 46; ///< Ambisonic ACN 12 const Speaker kSpeakerACN13 = (Speaker)1 << 47; ///< Ambisonic ACN 13 const Speaker kSpeakerACN14 = (Speaker)1 << 48; ///< Ambisonic ACN 14 const Speaker kSpeakerACN15 = (Speaker)1 << 49; ///< Ambisonic ACN 15 +const Speaker kSpeakerACN16 = (Speaker)1 << 50; ///< Ambisonic ACN 16 +const Speaker kSpeakerACN17 = (Speaker)1 << 51; ///< Ambisonic ACN 17 +const Speaker kSpeakerACN18 = (Speaker)1 << 52; ///< Ambisonic ACN 18 +const Speaker kSpeakerACN19 = (Speaker)1 << 53; ///< Ambisonic ACN 19 +const Speaker kSpeakerACN20 = (Speaker)1 << 54; ///< Ambisonic ACN 20 +const Speaker kSpeakerACN21 = (Speaker)1 << 55; ///< Ambisonic ACN 21 +const Speaker kSpeakerACN22 = (Speaker)1 << 56; ///< Ambisonic ACN 22 +const Speaker kSpeakerACN23 = (Speaker)1 << 57; ///< Ambisonic ACN 23 +const Speaker kSpeakerACN24 = (Speaker)1 << 58; ///< Ambisonic ACN 24 const Speaker kSpeakerTsl = (Speaker)1 << 24; ///< Top Side Left (Tsl) const Speaker kSpeakerTsr = (Speaker)1 << 25; ///< Top Side Right (Tsr) @@ -103,6 +112,7 @@ namespace SpeakerArr { //------------------------------------------------------------------------ /** Speaker Arrangement Definitions. +* for example: 5.0.5.3 for 5x Middle + 0x LFE + 5x Top + 3x Bottom \ingroup speakerArrangements */ /*@{*/ const SpeakerArrangement kEmpty = 0; ///< empty arrangement @@ -116,45 +126,46 @@ const SpeakerArrangement kStereoTF = kSpeakerTfl | kSpeakerTfr; ///< Tfl Tfr const SpeakerArrangement kStereoTS = kSpeakerTsl | kSpeakerTsr; ///< Tsl Tsr const SpeakerArrangement kStereoTR = kSpeakerTrl | kSpeakerTrr; ///< Trl Trr const SpeakerArrangement kStereoBF = kSpeakerBfl | kSpeakerBfr; ///< Bfl Bfr -const SpeakerArrangement kCineFront = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLc | kSpeakerRc; ///< L R C Lc Rc +/** L R C Lc Rc */ +const SpeakerArrangement kCineFront = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLc | kSpeakerRc; -/** L R C */ +/** L R C */ // 3.0 const SpeakerArrangement k30Cine = kSpeakerL | kSpeakerR | kSpeakerC; -/** L R C Lfe */ -const SpeakerArrangement k31Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe; +/** L R C Lfe */ // 3.1 +const SpeakerArrangement k31Cine = k30Cine | kSpeakerLfe; /** L R S */ const SpeakerArrangement k30Music = kSpeakerL | kSpeakerR | kSpeakerCs; /** L R Lfe S */ -const SpeakerArrangement k31Music = kSpeakerL | kSpeakerR | kSpeakerLfe | kSpeakerCs; -/** L R C S (LCRS) */ +const SpeakerArrangement k31Music = k30Music | kSpeakerLfe; +/** L R C S */ // LCRS const SpeakerArrangement k40Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerCs; -/** L R C Lfe S (LCRS+Lfe) */ -const SpeakerArrangement k41Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerCs; -/** L R Ls Rs (Quadro) */ +/** L R C Lfe S */ // LCRS+Lfe +const SpeakerArrangement k41Cine = k40Cine | kSpeakerLfe; +/** L R Ls Rs */ // 4.0 (Quadro) const SpeakerArrangement k40Music = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs; -/** L R Lfe Ls Rs (Quadro+Lfe) */ -const SpeakerArrangement k41Music = kSpeakerL | kSpeakerR | kSpeakerLfe | kSpeakerLs | kSpeakerRs; -/** L R C Ls Rs */ +/** L R Lfe Ls Rs */ // 4.1 (Quadro+Lfe) +const SpeakerArrangement k41Music = k40Music | kSpeakerLfe; +/** L R C Ls Rs */ // 5.0 (ITU 0+5+0.0 Sound System B) const SpeakerArrangement k50 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs; -/** L R C Lfe Ls Rs */ -const SpeakerArrangement k51 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs; +/** L R C Lfe Ls Rs */ // 5.1 (ITU 0+5+0.1 Sound System B) +const SpeakerArrangement k51 = k50 | kSpeakerLfe; /** L R C Ls Rs Cs */ const SpeakerArrangement k60Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerCs; /** L R C Lfe Ls Rs Cs */ -const SpeakerArrangement k61Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerCs; +const SpeakerArrangement k61Cine = k60Cine | kSpeakerLfe; /** L R Ls Rs Sl Sr */ const SpeakerArrangement k60Music = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr; /** L R Lfe Ls Rs Sl Sr */ -const SpeakerArrangement k61Music = kSpeakerL | kSpeakerR | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr; +const SpeakerArrangement k61Music = k60Music | kSpeakerLfe; /** L R C Ls Rs Lc Rc */ const SpeakerArrangement k70Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc; /** L R C Lfe Ls Rs Lc Rc */ -const SpeakerArrangement k71Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc; +const SpeakerArrangement k71Cine = k70Cine | kSpeakerLfe; const SpeakerArrangement k71CineFullFront = k71Cine; -/** L R C Ls Rs Sl Sr */ +/** L R C Ls Rs Sl Sr */ // (ITU 0+7+0.0 Sound System I) const SpeakerArrangement k70Music = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr; -/** L R C Lfe Ls Rs Sl Sr */ -const SpeakerArrangement k71Music = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr; +/** L R C Lfe Ls Rs Sl Sr */ // (ITU 0+7+0.1 Sound System I) +const SpeakerArrangement k71Music = k70Music | kSpeakerLfe; /** L R C Lfe Ls Rs Lcs Rcs */ const SpeakerArrangement k71CineFullRear = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLcs | kSpeakerRcs; @@ -165,76 +176,110 @@ const SpeakerArrangement k71Proximity = kSpeakerL | kSpeakerR | kSpeakerC | /** L R C Ls Rs Lc Rc Cs */ const SpeakerArrangement k80Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs; /** L R C Lfe Ls Rs Lc Rc Cs */ -const SpeakerArrangement k81Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs; +const SpeakerArrangement k81Cine = k80Cine | kSpeakerLfe; /** L R C Ls Rs Cs Sl Sr */ const SpeakerArrangement k80Music = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerCs | kSpeakerSl | kSpeakerSr; /** L R C Lfe Ls Rs Cs Sl Sr */ -const SpeakerArrangement k81Music = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerCs | kSpeakerSl | kSpeakerSr; +const SpeakerArrangement k81Music = k80Music | kSpeakerLfe; /** L R C Ls Rs Lc Rc Sl Sr */ const SpeakerArrangement k90Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerSl | kSpeakerSr; /** L R C Lfe Ls Rs Lc Rc Sl Sr */ -const SpeakerArrangement k91Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | - kSpeakerSl | kSpeakerSr; +const SpeakerArrangement k91Cine = k90Cine | kSpeakerLfe; /** L R C Ls Rs Lc Rc Cs Sl Sr */ const SpeakerArrangement k100Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs | kSpeakerSl | kSpeakerSr; /** L R C Lfe Ls Rs Lc Rc Cs Sl Sr */ -const SpeakerArrangement k101Cine = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs | - kSpeakerSl | kSpeakerSr; +const SpeakerArrangement k101Cine = k100Cine | kSpeakerLfe; -/** First-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization */ +/** First-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (4 channels) */ const SpeakerArrangement kAmbi1stOrderACN = kSpeakerACN0 | kSpeakerACN1 | kSpeakerACN2 | kSpeakerACN3; -/** Second-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization */ +/** Second-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (9 channels) */ const SpeakerArrangement kAmbi2cdOrderACN = kAmbi1stOrderACN | kSpeakerACN4 | kSpeakerACN5 | kSpeakerACN6 | kSpeakerACN7 | kSpeakerACN8; -/** Third-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization */ +/** Third-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (16 channels) */ const SpeakerArrangement kAmbi3rdOrderACN = kAmbi2cdOrderACN | kSpeakerACN9 | kSpeakerACN10 | kSpeakerACN11 | kSpeakerACN12 | kSpeakerACN13 | kSpeakerACN14 | kSpeakerACN15; - +/** Fourth-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (25 channels) */ +const SpeakerArrangement kAmbi4thOrderACN = kAmbi3rdOrderACN | kSpeakerACN16 | kSpeakerACN17 | kSpeakerACN18 | kSpeakerACN19 | kSpeakerACN20 | + kSpeakerACN21 | kSpeakerACN22 | kSpeakerACN23 | kSpeakerACN24; +/** Fifth-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (36 channels) */ +const SpeakerArrangement kAmbi5thOrderACN = 0x000FFFFFFFFF; +/** Sixth-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (49 channels) */ +const SpeakerArrangement kAmbi6thOrderACN = 0x0001FFFFFFFFFFFF; +/** Seventh-Order with Ambisonic Channel Number (ACN) ordering and SN3D normalization (64 channels) */ +const SpeakerArrangement kAmbi7thOrderACN = 0xFFFFFFFFFFFFFFFF; /*-----------*/ /* 3D formats */ /*-----------*/ /** L R Ls Rs Tfl Tfr Trl Trr */ // 4.0.4 const SpeakerArrangement k80Cube = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | kSpeakerTfl| kSpeakerTfr| kSpeakerTrl | kSpeakerTrr; +const SpeakerArrangement k40_4 = k80Cube; + /** L R C Lfe Ls Rs Cs Tc */ // 6.1.1 const SpeakerArrangement k71CineTopCenter = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerCs | kSpeakerTc; + /** L R C Lfe Ls Rs Cs Tfc */ // 6.1.1 const SpeakerArrangement k71CineCenterHigh = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerCs | kSpeakerTfc; -/** L R C Lfe Ls Rs Tfl Tfr */ // 5.1.2 -const SpeakerArrangement k71CineFrontHigh = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerTfl | kSpeakerTfr; -const SpeakerArrangement k71MPEG3D = k71CineFrontHigh; -/** L R C Lfe Ls Rs Tsl Tsr */ // 5.1.2 -const SpeakerArrangement k71CineSideHigh = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerTsl | kSpeakerTsr; -/** L R Lfe Ls Rs Tfl Tfc Tfr Bfc */ // 4.1.4 +/** L R C Ls Rs Tfl Tfr */ // 5.0.2 (ITU 2+5+0.0 Sound System C) +const SpeakerArrangement k70CineFrontHigh = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerTfl | kSpeakerTfr; +const SpeakerArrangement k70MPEG3D = k70CineFrontHigh; +const SpeakerArrangement k50_2 = k70CineFrontHigh; + +/** L R C Lfe Ls Rs Tfl Tfr */ // 5.1.2 (ITU 2+5+0.1 Sound System C) +const SpeakerArrangement k71CineFrontHigh = k70CineFrontHigh | kSpeakerLfe; +const SpeakerArrangement k71MPEG3D = k71CineFrontHigh; +const SpeakerArrangement k51_2 = k71CineFrontHigh; + +/** L R C Ls Rs Tsl Tsr */ // 5.0.2 (Side) +const SpeakerArrangement k70CineSideHigh = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerTsl | kSpeakerTsr; +const SpeakerArrangement k50_2_TS = k70CineSideHigh; + +/** L R C Lfe Ls Rs Tsl Tsr */ // 5.1.2 (Side) +const SpeakerArrangement k71CineSideHigh = k70CineSideHigh | kSpeakerLfe; +const SpeakerArrangement k51_2_TS = k71CineSideHigh; + +/** L R Lfe Ls Rs Tfl Tfc Tfr Bfc */ // 4.1.3.1 const SpeakerArrangement k81MPEG3D = kSpeakerL | kSpeakerR | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerBfc; +const SpeakerArrangement k41_4_1 = k81MPEG3D; -/** L R C Ls Rs Tfl Tfr Trl Trr */ // 5.0.4 +/** L R C Ls Rs Tfl Tfr Trl Trr */ // 5.0.4 (ITU 4+5+0.0 Sound System D) const SpeakerArrangement k90 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerTfl| kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; const SpeakerArrangement k50_4 = k90; -/** L R C Lfe Ls Rs Tfl Tfr Trl Trr */ // 5.1.4 -const SpeakerArrangement k91 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | - kSpeakerTfl| kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; + +/** L R C Lfe Ls Rs Tfl Tfr Trl Trr */ // 5.1.4 (ITU 4+5+0.1 Sound System D) +const SpeakerArrangement k91 = k90 | kSpeakerLfe; const SpeakerArrangement k51_4 = k91; +/** L R C Ls Rs Tfl Tfr Trl Trr Bfc */ // 5.0.4.1 (ITU 4+5+1.0 Sound System E) +const SpeakerArrangement k50_4_1 = k50_4 | kSpeakerBfc; + +/** L R C Lfe Ls Rs Tfl Tfr Trl Trr Bfc */ // 5.1.4.1 (ITU 4+5+1.1 Sound System E) +const SpeakerArrangement k51_4_1 = k50_4_1 | kSpeakerLfe; + /** L R C Ls Rs Sl Sr Tsl Tsr */ // 7.0.2 const SpeakerArrangement k70_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | kSpeakerTsl | kSpeakerTsr; /** L R C Lfe Ls Rs Sl Sr Tsl Tsr */ // 7.1.2 -const SpeakerArrangement k71_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | - kSpeakerSl | kSpeakerSr | kSpeakerTsl | kSpeakerTsr; +const SpeakerArrangement k71_2 = k70_2 | kSpeakerLfe; const SpeakerArrangement k91Atmos = k71_2; // 9.1 Dolby Atmos (3D) -/** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr */ // 7.0.4 +/** L R C Ls Rs Sl Sr Tfl Tfr Trc */ // 7.0.3 (ITU 3+7+0.0 Sound System F) +const SpeakerArrangement k70_3 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerSl | kSpeakerSr | kSpeakerTfl | kSpeakerTfr | kSpeakerTrc; + +/** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trc Lfe2 */ // 7.2.3 (ITU 3+7+0.2 Sound System F) +const SpeakerArrangement k72_3 = k70_3 | kSpeakerLfe | kSpeakerLfe2; + +/** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr */ // 7.0.4 (ITU 4+7+0.0 Sound System J) const SpeakerArrangement k70_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr */ // 7.1.4 -const SpeakerArrangement k71_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | - kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; +/** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr */ // 7.1.4 (ITU 4+7+0.1 Sound System J) +const SpeakerArrangement k71_4 = k70_4 | kSpeakerLfe; const SpeakerArrangement k111MPEG3D = k71_4; /** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr */ // 7.0.6 @@ -243,19 +288,15 @@ const SpeakerArrangement k70_6 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr; /** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr */ // 7.1.6 -const SpeakerArrangement k71_6 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | - kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | - kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr; +const SpeakerArrangement k71_6 = k70_6 | kSpeakerLfe; -/** L R C Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr */ // 9.0.4 +/** L R C Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr */ // 9.0.4 (ITU 4+9+0.0 Sound System G) const SpeakerArrangement k90_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerSl | kSpeakerSr | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr */ // 9.1.4 -const SpeakerArrangement k91_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | - kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerSl | kSpeakerSr | - kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; +/** L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr */ // 9.1.4 (ITU 4+9+0.1 Sound System G) +const SpeakerArrangement k91_4 = k90_4 | kSpeakerLfe; /** L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr */ // 9.0.6 const SpeakerArrangement k90_6 = kSpeakerL | kSpeakerR | kSpeakerC | @@ -263,53 +304,118 @@ const SpeakerArrangement k90_6 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr; /** L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr */ // 9.1.6 -const SpeakerArrangement k91_6 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | - kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerSl | kSpeakerSr | - kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr; +const SpeakerArrangement k91_6 = k90_6 | kSpeakerLfe; -/** L R C Ls Rs Tc Tfl Tfr Trl Trr */ // 5.0.5 +/** L R C Ls Rs Tc Tfl Tfr Trl Trr */ // 5.0.5 (10.0 Auro-3D) const SpeakerArrangement k100 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerTc | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R C Lfe Ls Rs Tc Tfl Tfr Trl Trr */ // 5.1.5 -const SpeakerArrangement k101 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | - kSpeakerTc | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; +const SpeakerArrangement k50_5 = k100; + +/** L R C Lfe Ls Rs Tc Tfl Tfr Trl Trr */ // 5.1.5 (10.1 Auro-3D) +const SpeakerArrangement k101 = k50_5 | kSpeakerLfe; const SpeakerArrangement k101MPEG3D = k101; +const SpeakerArrangement k51_5 = k101; /** L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Lfe2 */ // 5.2.5 const SpeakerArrangement k102 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerTfl| kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerLfe2; +const SpeakerArrangement k52_5 = k102; -/** L R C Ls Rs Tc Tfl Tfc Tfr Trl Trr */ // 5.0.6 +/** L R C Ls Rs Tc Tfl Tfc Tfr Trl Trr */ // 5.0.6 (11.0 Auro-3D) const SpeakerArrangement k110 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R C Lfe Ls Rs Tc Tfl Tfc Tfr Trl Trr */ // 5.1.6 -const SpeakerArrangement k111 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | - kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; +const SpeakerArrangement k50_6 = k110; + +/** L R C Lfe Ls Rs Tc Tfl Tfc Tfr Trl Trr */ // 5.1.6 (11.1 Auro-3D) +const SpeakerArrangement k111 = k110 | kSpeakerLfe; +const SpeakerArrangement k51_6 = k111; /** L R C Lfe Ls Rs Lc Rc Tfl Tfc Tfr Trl Trr Lfe2 */ // 7.2.5 const SpeakerArrangement k122 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerTfl| kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerLfe2; -/** L R C Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr */ // 7.0.6 +const SpeakerArrangement k72_5 = k122; + +/** L R C Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr */ // 7.0.6 (13.0 Auro-3D) const SpeakerArrangement k130 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R C Lfe Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr */ // 7.1.6 -const SpeakerArrangement k131 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | - kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; -/** L R Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr Brl Brr */ // 6.0.4.4 -const SpeakerArrangement k140 = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | +/** L R C Lfe Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr */ // 7.1.6 (13.1 Auro-3D) +const SpeakerArrangement k131 = k130 | kSpeakerLfe; + +/** L R Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr Brl Brr */ // 6.0.4.4 +const SpeakerArrangement k140 = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerBfl | kSpeakerBfr | kSpeakerBrl | kSpeakerBrr; +const SpeakerArrangement k60_4_4 = k140; -/** L R C Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Tsl Tsr Bfl Bfc Bfr */ // 10.0.9.3 +/** L R C Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Tsl Tsr Bfl Bfc Bfr */ // 10.0.9.3 (ITU 9+10+3.0 Sound System H) const SpeakerArrangement k220 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs | kSpeakerSl | kSpeakerSr | kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrc | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr | kSpeakerBfl| kSpeakerBfc | kSpeakerBfr; +const SpeakerArrangement k100_9_3 = k220; -/** L R C Lfe Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Lfe2 Tsl Tsr Bfl Bfc Bfr */ // 10.2.9.3 +/** L R C Lfe Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Lfe2 Tsl Tsr Bfl Bfc Bfr */ // 10.2.9.3 (ITU 9+10+3.2 Sound System H) const SpeakerArrangement k222 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLfe | kSpeakerLs | kSpeakerRs | kSpeakerLc | kSpeakerRc | kSpeakerCs | kSpeakerSl | kSpeakerSr | kSpeakerTc | kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrc | kSpeakerTrr | kSpeakerLfe2 | kSpeakerTsl | kSpeakerTsr | kSpeakerBfl| kSpeakerBfc | kSpeakerBfr; +const SpeakerArrangement k102_9_3 = k222; + +/** L R C Ls Rs Tfl Tfc Tfr Trl Trr Bfl Bfc Bfr */ // 5.0.5.3 +const SpeakerArrangement k50_5_3 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfc | kSpeakerBfr; + +/** L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Bfl Bfc Bfr */ // 5.1.5.3 +const SpeakerArrangement k51_5_3 = k50_5_3 | kSpeakerLfe; + +/** L R C Ls Rs Tsl Tsr Bfl Bfr */ // 5.0.2.2 +const SpeakerArrangement k50_2_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTsl | kSpeakerTsr | + kSpeakerBfl | kSpeakerBfr; + +/** L R C Ls Rs Tfl Tfr Trl Trr Bfl Bfr */ // 5.0.4.2 +const SpeakerArrangement k50_4_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr; + +/** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr */ // 7.0.4.2 +const SpeakerArrangement k70_4_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | kSpeakerSl | kSpeakerSr | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr; + +/** L R C Ls Rs Tfl Tfc Tfr Trl Trr */ // 5.0.5.0 (Sony 360RA) +const SpeakerArrangement k50_5_Sony = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; + +/** C Sl Sr Cs Tsl Tsr Bsl Bsr */ // 4.0.2.2 (Sony 360RA) +const SpeakerArrangement k40_2_2 = kSpeakerC | kSpeakerSl | kSpeakerSr | kSpeakerCs | + kSpeakerTsl | kSpeakerTsr | + kSpeakerBsl | kSpeakerBsr; + +/** L R Ls Rs Tfl Tfr Trl Trr Bfl Bfr */ // 4.0.4.2 (Sony 360RA) +const SpeakerArrangement k40_4_2 = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr; + +/** L R C Ls Rs Tfl Tfc Tfr Bfl Bfr */ // 5.0.3.2 (Sony 360RA) +const SpeakerArrangement k50_3_2 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | + kSpeakerBfl | kSpeakerBfr; + +/** L R C Tfl Tfc Tfr Trl Trr Bfl Bfr */ // 3.0.5.2 (Sony 360RA) +const SpeakerArrangement k30_5_2 = kSpeakerL | kSpeakerR | kSpeakerC | + kSpeakerTfl | kSpeakerTfc | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr; + +/** L R Ls Rs Tfl Tfr Trl Trr Bfl Bfr Brl Brr */ // 4.0.4.4 (Sony 360RA) +const SpeakerArrangement k40_4_4 = kSpeakerL | kSpeakerR | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr | kSpeakerBrl | kSpeakerBrr; + +/** L R C Ls Rs Tfl Tfr Trl Trr Bfl Bfr Brl Brr */ // 5.0.4.4 (Sony 360RA) +const SpeakerArrangement k50_4_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerLs | kSpeakerRs | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | + kSpeakerBfl | kSpeakerBfr | kSpeakerBrl | kSpeakerBrr; //------------------------------------------------------------------------ /** Speaker Arrangement String Representation. @@ -352,47 +458,69 @@ const CString kString71Music = "7.1"; const CString kString71MusicOld = "7.1 Music (Dolby)"; const CString kString71CineTopCenter = "7.1 Cine Top Center"; const CString kString71CineCenterHigh = "7.1 Cine Center High"; -const CString kString71CineFrontHigh = "7.1 Cine Front High"; -const CString kString71CineSideHigh = "7.1 Cine Side High"; -const CString kString71CineFullRear = "7.1 Cine Full Rear"; -const CString kString71Proximity = "7.1 Proximity"; +const CString kString71CineFullRear = "7.1 Cine Full Rear"; +const CString kString51_2 = "5.1.2"; +const CString kString50_2 = "5.0.2"; +const CString kString50_2TopSide = "5.0.2 Top Side"; +const CString kString51_2TopSide = "5.1.2 Top Side"; +const CString kString71Proximity = "7.1 Proximity"; const CString kString80Cine = "8.0 Cine"; const CString kString80Music = "8.0 Music"; -const CString kString80Cube = "8.0 Cube"; +const CString kString40_4 = "8.0 Cube"; const CString kString81Cine = "8.1 Cine"; const CString kString81Music = "8.1 Music"; const CString kString90Cine = "9.0 Cine"; const CString kString91Cine = "9.1 Cine"; const CString kString100Cine = "10.0 Cine"; const CString kString101Cine = "10.1 Cine"; -const CString kString102 = "10.2 Experimental"; -const CString kString122 = "12.2"; +const CString kString52_5 = "5.2.5"; +const CString kString72_5 = "12.2"; const CString kString50_4 = "5.0.4"; const CString kString51_4 = "5.1.4"; -const CString kString70_2 = "7.0.2"; +const CString kString50_4_1 = "5.0.4.1"; +const CString kString51_4_1 = "5.1.4.1"; +const CString kString70_2 = "7.0.2"; const CString kString71_2 = "7.1.2"; +const CString kString70_3 = "7.0.3"; +const CString kString72_3 = "7.2.3"; const CString kString70_4 = "7.0.4"; const CString kString71_4 = "7.1.4"; -const CString kString70_6 = "7.0.6"; +const CString kString70_6 = "7.0.6"; const CString kString71_6 = "7.1.6"; -const CString kString90_4 = "9.0.4"; +const CString kString90_4 = "9.0.4"; const CString kString91_4 = "9.1.4"; -const CString kString90_6 = "9.0.6"; +const CString kString90_6 = "9.0.6"; const CString kString91_6 = "9.1.6"; -const CString kString100 = "10.0 Auro-3D"; -const CString kString101 = "10.1 Auro-3D"; -const CString kString110 = "11.0 Auro-3D"; -const CString kString111 = "11.1 Auro-3D"; +const CString kString50_5 = "10.0 Auro-3D"; +const CString kString51_5 = "10.1 Auro-3D"; +const CString kString50_6 = "11.0 Auro-3D"; +const CString kString51_6 = "11.1 Auro-3D"; const CString kString130 = "13.0 Auro-3D"; const CString kString131 = "13.1 Auro-3D"; -const CString kString81MPEG = "8.1 MPEG"; -const CString kString140 = "14.0"; +const CString kString41_4_1 = "8.1 MPEG"; +const CString kString60_4_4 = "14.0"; +const CString kString220 = "22.0"; const CString kString222 = "22.2"; -const CString kString220 = "22.0"; +const CString kString50_5_3 = "5.0.5.3"; +const CString kString51_5_3 = "5.1.5.3"; +const CString kString50_2_2 = "5.0.2.2"; +const CString kString50_4_2 = "5.0.4.2"; +const CString kString70_4_2 = "7.0.4.2"; +const CString kString50_5_Sony = "5.0.5 Sony"; +const CString kString40_2_2 = "4.0.3.2"; +const CString kString40_4_2 = "4.0.4.2"; +const CString kString50_3_2 = "5.0.3.2"; +const CString kString30_5_2 = "3.0.5.2"; +const CString kString40_4_4 = "4.0.4.4"; +const CString kString50_4_4 = "5.0.4.4"; + const CString kStringAmbi1stOrder = "1st Order Ambisonics"; const CString kStringAmbi2cdOrder = "2nd Order Ambisonics"; const CString kStringAmbi3rdOrder = "3rd Order Ambisonics"; - +const CString kStringAmbi4thOrder = "4th Order Ambisonics"; +const CString kStringAmbi5thOrder = "5th Order Ambisonics"; +const CString kStringAmbi6thOrder = "6th Order Ambisonics"; +const CString kStringAmbi7thOrder = "7th Order Ambisonics"; /*@}*/ //------------------------------------------------------------------------ @@ -432,21 +560,27 @@ const CString kString80CineS = "L R C Ls Rs Lc Rc Cs"; const CString kString80MusicS = "L R C Ls Rs Cs Sl Sr"; const CString kString81CineS = "L R C LFE Ls Rs Lc Rc Cs"; const CString kString81MusicS = "L R C LFE Ls Rs Cs Sl Sr"; -const CString kString80CubeS = "L R Ls Rs Tfl Tfr Trl Trr"; +const CString kString40_4S = "L R Ls Rs Tfl Tfr Trl Trr"; const CString kString71CineTopCenterS = "L R C LFE Ls Rs Cs Tc"; const CString kString71CineCenterHighS = "L R C LFE Ls Rs Cs Tfc"; -const CString kString71CineFrontHighS = "L R C LFE Ls Rs Tfl Tfl"; -const CString kString71CineSideHighS = "L R C LFE Ls Rs Tsl Tsl"; -const CString kString71CineFullRearS = "L R C LFE Ls Rs Lcs Rcs"; -const CString kString71ProximityS = "L R C LFE Ls Rs Pl Pr"; +const CString kString71CineFullRearS = "L R C LFE Ls Rs Lcs Rcs"; +const CString kString50_2S = "L R C Ls Rs Tfl Tfr"; +const CString kString51_2S = "L R C LFE Ls Rs Tfl Tfr"; +const CString kString50_2TopSideS = "L R C Ls Rs Tsl Tsr"; +const CString kString51_2TopSideS = "L R C LFE Ls Rs Tsl Tsr"; +const CString kString71ProximityS = "L R C LFE Ls Rs Pl Pr"; const CString kString90CineS = "L R C Ls Rs Lc Rc Sl Sr"; -const CString kString91CineS = "L R C Lfe Ls Rs Lc Rc Sl Sr"; +const CString kString91CineS = "L R C LFE Ls Rs Lc Rc Sl Sr"; const CString kString100CineS = "L R C Ls Rs Lc Rc Cs Sl Sr"; -const CString kString101CineS = "L R C Lfe Ls Rs Lc Rc Cs Sl Sr"; +const CString kString101CineS = "L R C LFE Ls Rs Lc Rc Cs Sl Sr"; const CString kString50_4S = "L R C Ls Rs Tfl Tfr Trl Trr"; -const CString kString51_4S = "L R C LFE Ls Rs Tfl Tfr Trl Trr"; +const CString kString51_4S = "L R C LFE Ls Rs Tfl Tfr Trl Trr"; +const CString kString50_4_1S = "L R C Ls Rs Tfl Tfr Trl Trr Bfc"; +const CString kString51_4_1S = "L R C LFE Ls Rs Tfl Tfr Trl Trr Bfc"; const CString kString70_2S = "L R C Ls Rs Sl Sr Tsl Tsr"; const CString kString71_2S = "L R C LFE Ls Rs Sl Sr Tsl Tsr"; +const CString kString70_3S = "L R C Ls Rs Sl Sr Tfl Tfr Trc"; +const CString kString72_3S = "L R C LFE Ls Rs Sl Sr Tfl Tfr Trc LFE2"; const CString kString70_4S = "L R C Ls Rs Sl Sr Tfl Tfr Trl Trr"; const CString kString71_4S = "L R C LFE Ls Rs Sl Sr Tfl Tfr Trl Trr"; const CString kString70_6S = "L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr"; @@ -455,22 +589,38 @@ const CString kString90_4S = "L R C Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr"; const CString kString91_4S = "L R C LFE Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr"; const CString kString90_6S = "L R C Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr"; const CString kString91_6S = "L R C LFE Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr"; -const CString kString100S = "L R C Ls Rs Tc Tfl Tfr Trl Trr"; -const CString kString101S = "L R C LFE Ls Rs Tc Tfl Tfr Trl Trr"; -const CString kString110S = "L R C Ls Rs Tc Tfl Tfc Tfr Trl Trr"; -const CString kString111S = "L R C LFE Ls Rs Tc Tfl Tfc Tfr Trl Trr"; +const CString kString50_5S = "L R C Ls Rs Tc Tfl Tfr Trl Trr"; +const CString kString51_5S = "L R C LFE Ls Rs Tc Tfl Tfr Trl Trr"; +const CString kString50_5_SonyS = "L R C Ls Rs Tfl Tfc Tfr Trl Trr"; +const CString kString50_6S = "L R C Ls Rs Tc Tfl Tfc Tfr Trl Trr"; +const CString kString51_6S = "L R C LFE Ls Rs Tc Tfl Tfc Tfr Trl Trr"; const CString kString130S = "L R C Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr"; const CString kString131S = "L R C LFE Ls Rs Sl Sr Tc Tfl Tfc Tfr Trl Trr"; -const CString kString102S = "L R C LFE Ls Rs Tfl Tfc Tfr Trl Trr LFE2"; -const CString kString122S = "L R C LFE Ls Rs Lc Rc Tfl Tfc Tfr Trl Trr LFE2"; -const CString kString81MPEGS = "L R LFE Ls Rs Tfl Tfc Tfr Bfc"; -const CString kString140S = "L R Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr Brl Brr"; -const CString kString222S = "L R C LFE Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr LFE2 Tsl Tsr Bfl Bfc Bfr"; -const CString kString220S = "L R C Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Tsl Tsr Bfl Bfc Bfr"; - -const CString kStringAmbi1stOrderS = "0 1 2 3"; -const CString kStringAmbi2cdOrderS = "0 1 2 3 4 5 6 7 8"; -const CString kStringAmbi3rdOrderS = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"; +const CString kString52_5S = "L R C LFE Ls Rs Tfl Tfc Tfr Trl Trr LFE2"; +const CString kString72_5S = "L R C LFE Ls Rs Lc Rc Tfl Tfc Tfr Trl Trr LFE2"; +const CString kString41_4_1S = "L R LFE Ls Rs Tfl Tfc Tfr Bfc"; +const CString kString30_5_2S = "L R C Tfl Tfc Tfr Trl Trr Bfl Bfr"; +const CString kString40_2_2S = "C Sl Sr Cs Tfc Tsl Tsr Trc"; +const CString kString40_4_2S = "L R Ls Rs Tfl Tfr Trl Trr Bfl Bfr"; +const CString kString40_4_4S = "L R Ls Rs Tfl Tfr Trl Trr Bfl Bfr Brl Brr"; +const CString kString50_4_4S = "L R C Ls Rs Tfl Tfr Trl Trr Bfl Bfr Brl Brr"; +const CString kString60_4_4S = "L R Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr Brl Brr"; +const CString kString50_5_3S = "L R C Ls Rs Tfl Tfc Tfr Trl Trr Bfl Bfc Bfr"; +const CString kString51_5_3S = "L R C LFE Ls Rs Tfl Tfc Tfr Trl Trr Bfl Bfc Bfr"; +const CString kString50_2_2S = "L R C Ls Rs Tsl Tsr Bfl Bfr"; +const CString kString50_3_2S = "L R C Ls Rs Tfl Tfc Tfr Bfl Bfr"; +const CString kString50_4_2S = "L R C Ls Rs Tfl Tfr Trl Trr Bfl Bfr"; +const CString kString70_4_2S = "L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Bfl Bfr"; +const CString kString222S = "L R C LFE Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr LFE2 Tsl Tsr Bfl Bfc Bfr"; +const CString kString220S = "L R C Ls Rs Lc Rc Cs Sl Sr Tc Tfl Tfc Tfr Trl Trc Trr Tsl Tsr Bfl Bfc Bfr"; + +const CString kStringAmbi1stOrderS = "0 1 2 3"; +const CString kStringAmbi2cdOrderS = "0 1 2 3 4 5 6 7 8"; +const CString kStringAmbi3rdOrderS = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"; +const CString kStringAmbi4thOrderS = "0..24"; +const CString kStringAmbi5thOrderS = "0..35"; +const CString kStringAmbi6thOrderS = "0..48"; +const CString kStringAmbi7thOrderS = "0..63"; /*@}*/ //------------------------------------------------------------------------ @@ -566,8 +716,9 @@ inline bool hasTopSpeakers (const SpeakerArrangement& arr) /** Returns true if arrangement contains bottom (lower layer) speakers */ inline bool hasBottomSpeakers (const SpeakerArrangement& arr) { - if (arr & kSpeakerBfl || arr & kSpeakerBfc || arr & kSpeakerBfl || arr & kSpeakerBfc || - arr & kSpeakerBfr) + if (arr & kSpeakerBfl || arr & kSpeakerBfc || arr & kSpeakerBfr || + arr & kSpeakerBsl || arr & kSpeakerBsr || + arr & kSpeakerBrr || arr & kSpeakerBrl || arr & kSpeakerBrc) return true; return false; } @@ -607,16 +758,39 @@ inline bool is3D (const SpeakerArrangement& arr) } //------------------------------------------------------------------------ -/** Returns true if arrangement is a Auro configuration. */ +/** Returns true if arrangement is a Ambisonic configuration. */ inline bool isAmbisonics (const SpeakerArrangement& arr) { - if (arr == kAmbi1stOrderACN || arr == kAmbi2cdOrderACN || arr == kAmbi3rdOrderACN) + if (arr == kAmbi1stOrderACN || arr == kAmbi2cdOrderACN || arr == kAmbi3rdOrderACN || + arr == kAmbi4thOrderACN || arr == kAmbi5thOrderACN || arr == kAmbi6thOrderACN || + arr == kAmbi7thOrderACN) { return true; } return false; } + +//------------------------------------------------------------------------ +/** Converts a speaker of a Ambisonic order 1 to 4 to a Ambisonic order 7 (5 to 7) (return 0 when out of range).*/ +inline Speaker convertSpeaker_Ambi_1234Order_to_Ambi567Order (Speaker speaker_1234_order) +{ + int32 idx = getSpeakerIndex (speaker_1234_order, kAmbi4thOrderACN); + if (idx < 0) + return 0; + return (Speaker)1 << idx; +} + +//------------------------------------------------------------------------ +/** Converts a speaker of a Ambisonic order 5 to 7 to a Ambisonic order 4 (1 to 4) (return 0 when out of range).*/ +inline Speaker convertSpeaker_Ambi_567Order_to_Ambi1234Order (Speaker speaker_567_order) +{ + int32 idx = getSpeakerIndex (speaker_567_order, kAmbi7thOrderACN); + if (idx < 0) + return 0; + return getSpeaker (kAmbi4thOrderACN, idx); +} + //------------------------------------------------------------------------ /** Returns the speaker arrangement associated to a string representation. Returns kEmpty if no associated arrangement is known. */ @@ -690,20 +864,24 @@ inline SpeakerArrangement getSpeakerArrangementFromString (CString arrStr) return k81Cine; if (!strcmp8 (arrStr, kString81Music)) return k81Music; - if (!strcmp8 (arrStr, kString102)) - return k102; - if (!strcmp8 (arrStr, kString122)) - return k122; - if (!strcmp8 (arrStr, kString80Cube)) - return k80Cube; + if (!strcmp8 (arrStr, kString52_5)) + return k52_5; + if (!strcmp8 (arrStr, kString72_5)) + return k72_5; + if (!strcmp8 (arrStr, kString40_4)) + return k40_4; if (!strcmp8 (arrStr, kString71CineTopCenter)) return k71CineTopCenter; if (!strcmp8 (arrStr, kString71CineCenterHigh)) return k71CineCenterHigh; - if (!strcmp8 (arrStr, kString71CineFrontHigh)) - return k71CineFrontHigh; - if (!strcmp8 (arrStr, kString71CineSideHigh)) - return k71CineSideHigh; + if (!strcmp8 (arrStr, kString50_2)) + return k50_2; + if (!strcmp8 (arrStr, kString51_2)) + return k51_2; + if (!strcmp8 (arrStr, kString50_2TopSide)) + return k50_2_TS; + if (!strcmp8 (arrStr, kString51_2TopSide)) + return k51_2_TS; if (!strcmp8 (arrStr, kString71CineFullRear)) return k71CineFullRear; if (!strcmp8 (arrStr, kString90Cine)) @@ -718,12 +896,20 @@ inline SpeakerArrangement getSpeakerArrangementFromString (CString arrStr) return k50_4; if (!strcmp8 (arrStr, kString51_4)) return k51_4; - if (!strcmp8 (arrStr, kString81MPEG)) - return k81MPEG3D; + if (!strcmp8 (arrStr, kString50_4_1)) + return k50_4_1; + if (!strcmp8 (arrStr, kString51_4_1)) + return k51_4_1; + if (!strcmp8 (arrStr, kString41_4_1)) + return k41_4_1; if (!strcmp8 (arrStr, kString70_2)) return k70_2; if (!strcmp8 (arrStr, kString71_2)) return k71_2; + if (!strcmp8 (arrStr, kString70_3)) + return k70_3; + if (!strcmp8 (arrStr, kString72_3)) + return k72_3; if (!strcmp8 (arrStr, kString70_4)) return k70_4; if (!strcmp8 (arrStr, kString71_4)) @@ -740,30 +926,64 @@ inline SpeakerArrangement getSpeakerArrangementFromString (CString arrStr) return k90_6; if (!strcmp8 (arrStr, kString91_6)) return k91_6; - if (!strcmp8 (arrStr, kString100)) - return k100; - if (!strcmp8 (arrStr, kString101)) - return k101; - if (!strcmp8 (arrStr, kString110)) - return k110; - if (!strcmp8 (arrStr, kString111)) - return k111; + if (!strcmp8 (arrStr, kString50_5)) + return k50_5; + if (!strcmp8 (arrStr, kString51_5)) + return k51_5; + if (!strcmp8 (arrStr, kString50_6)) + return k50_6; + if (!strcmp8 (arrStr, kString51_6)) + return k51_6; if (!strcmp8 (arrStr, kString130)) return k130; if (!strcmp8 (arrStr, kString131)) return k131; - if (!strcmp8 (arrStr, kString140)) - return k140; + if (!strcmp8 (arrStr, kString60_4_4)) + return k60_4_4; if (!strcmp8 (arrStr, kString222)) return k222; if (!strcmp8 (arrStr, kString220)) return k220; + if (!strcmp8 (arrStr, kString50_5_3)) + return k50_5_3; + if (!strcmp8 (arrStr, kString51_5_3)) + return k51_5_3; + if (!strcmp8 (arrStr, kString50_2_2)) + return k50_2_2; + if (!strcmp8 (arrStr, kString50_4_2)) + return k50_4_2; + if (!strcmp8 (arrStr, kString70_4_2)) + return k70_4_2; + + if (!strcmp8 (arrStr, kString50_5_Sony)) + return k50_5_Sony; + if (!strcmp8 (arrStr, kString40_2_2)) + return k40_2_2; + if (!strcmp8 (arrStr, kString40_4_2)) + return k40_4_2; + if (!strcmp8 (arrStr, kString50_3_2)) + return k50_3_2; + if (!strcmp8 (arrStr, kString30_5_2)) + return k30_5_2; + if (!strcmp8 (arrStr, kString40_4_4)) + return k40_4_4; + if (!strcmp8 (arrStr, kString50_4_4)) + return k50_4_4; + if (!strcmp8 (arrStr, kStringAmbi1stOrder)) return kAmbi1stOrderACN; if (!strcmp8 (arrStr, kStringAmbi2cdOrder)) return kAmbi2cdOrderACN; if (!strcmp8 (arrStr, kStringAmbi3rdOrder)) return kAmbi3rdOrderACN; + if (!strcmp8 (arrStr, kStringAmbi4thOrder)) + return kAmbi4thOrderACN; + if (!strcmp8 (arrStr, kStringAmbi5thOrder)) + return kAmbi5thOrderACN; + if (!strcmp8 (arrStr, kStringAmbi6thOrder)) + return kAmbi6thOrderACN; + if (!strcmp8 (arrStr, kStringAmbi7thOrder)) + return kAmbi7thOrderACN; return kEmpty; } @@ -775,6 +995,7 @@ inline CString getSpeakerArrangementString (SpeakerArrangement arr, bool withSpe switch (arr) { case kMono: return withSpeakersName ? kStringMonoS : kStringMono; + //--- Stereo pairs--- case kStereo: return withSpeakersName ? kStringStereoS : kStringStereo; case kStereoSurround: return withSpeakersName ? kStringStereoRS : kStringStereoR; case kStereoCenter: return withSpeakersName ? kStringStereoCS : kStringStereoC; @@ -784,54 +1005,61 @@ inline CString getSpeakerArrangementString (SpeakerArrangement arr, bool withSpe case kStereoTS: return withSpeakersName ? kStringStereoTSS : kStringStereoTS; case kStereoTR: return withSpeakersName ? kStringStereoTRS : kStringStereoTR; case kStereoBF: return withSpeakersName ? kStringStereoBFS : kStringStereoBF; + + //--- --- case kCineFront: return withSpeakersName ? kStringCineFrontS : kStringCineFront; case k30Cine: return withSpeakersName ? kString30CineS : kString30Cine; - case k30Music: return withSpeakersName ? kString30MusicS : kString30Music; case k31Cine: return withSpeakersName ? kString31CineS : kString31Cine; + case k30Music: return withSpeakersName ? kString30MusicS : kString30Music; case k31Music: return withSpeakersName ? kString31MusicS : kString31Music; case k40Cine: return withSpeakersName ? kString40CineS : kString40Cine; - case k40Music: return withSpeakersName ? kString40MusicS : kString40Music; case k41Cine: return withSpeakersName ? kString41CineS : kString41Cine; + case k40Music: return withSpeakersName ? kString40MusicS : kString40Music; case k41Music: return withSpeakersName ? kString41MusicS : kString41Music; case k50: return withSpeakersName ? kString50S : kString50; case k51: return withSpeakersName ? kString51S : kString51; case k60Cine: return withSpeakersName ? kString60CineS : kString60Cine; - case k60Music: return withSpeakersName ? kString60MusicS : kString60Music; case k61Cine: return withSpeakersName ? kString61CineS : kString61Cine; + case k60Music: return withSpeakersName ? kString60MusicS : kString60Music; case k61Music: return withSpeakersName ? kString61MusicS : kString61Music; case k70Cine: return withSpeakersName ? kString70CineS : kString70Cine; - case k70Music: return withSpeakersName ? kString70MusicS : kString70Music; case k71Cine: return withSpeakersName ? kString71CineS : kString71Cine; + case k70Music: return withSpeakersName ? kString70MusicS : kString70Music; case k71Music: return withSpeakersName ? kString71MusicS : kString71Music; case k71Proximity: return withSpeakersName ? kString71ProximityS : kString71Proximity; case k80Cine: return withSpeakersName ? kString80CineS : kString80Cine; - case k80Music: return withSpeakersName ? kString80MusicS : kString80Music; case k81Cine: return withSpeakersName ? kString81CineS : kString81Cine; + case k80Music: return withSpeakersName ? kString80MusicS : kString80Music; case k81Music: return withSpeakersName ? kString81MusicS : kString81Music; - case k81MPEG3D: return withSpeakersName ? kString81MPEGS : kString81MPEG; - case k102: return withSpeakersName ? kString102S : kString102; - case k122: return withSpeakersName ? kString122S : kString122; - case k80Cube: return withSpeakersName ? kString80CubeS : kString80Cube; - case k71CineTopCenter: return withSpeakersName ? kString71CineTopCenterS : kString71CineTopCenter; - case k71CineCenterHigh: return withSpeakersName ? kString71CineCenterHighS : kString71CineCenterHigh; - case k71CineFrontHigh: return withSpeakersName ? kString71CineFrontHighS : kString71CineFrontHigh; - case k71CineSideHigh: return withSpeakersName ? kString71CineSideHighS : kString71CineSideHigh; - case k71CineFullRear: return withSpeakersName ? kString71CineFullRearS : kString71CineFullRear; - case k90Cine: return withSpeakersName ? kString90CineS : kString90Cine; + case k71CineFullRear: return withSpeakersName ? kString71CineFullRearS : kString71CineFullRear; + case k90Cine: return withSpeakersName ? kString90CineS : kString90Cine; case k91Cine: return withSpeakersName ? kString91CineS : kString91Cine; - case k100Cine: return withSpeakersName ? kString100CineS : kString100Cine; + case k100Cine: return withSpeakersName ? kString100CineS : kString100Cine; case k101Cine: return withSpeakersName ? kString101CineS : kString101Cine; - case k100: return withSpeakersName ? kString100S : kString100; - case k101: return withSpeakersName ? kString101S : kString101; - case k110: return withSpeakersName ? kString110S : kString110; - case k111: return withSpeakersName ? kString111S : kString111; + //---With Tops --- + case k71CineTopCenter: return withSpeakersName ? kString71CineTopCenterS : kString71CineTopCenter; + case k71CineCenterHigh: return withSpeakersName ? kString71CineCenterHighS : kString71CineCenterHigh; + case k50_2_TS: return withSpeakersName ? kString50_2TopSideS : kString50_2TopSide; + case k51_2_TS: return withSpeakersName ? kString51_2TopSideS : kString51_2TopSide; + + case k40_4: return withSpeakersName ? kString40_4S : kString40_4; + case k50_2: return withSpeakersName ? kString50_2S : kString50_2; + case k51_2: return withSpeakersName ? kString51_2S : kString51_2; case k50_4: return withSpeakersName ? kString50_4S : kString50_4; case k51_4: return withSpeakersName ? kString51_4S : kString51_4; + case k50_5: return withSpeakersName ? kString50_5S : kString50_5; + case k51_5: return withSpeakersName ? kString51_5S : kString51_5; + case k52_5: return withSpeakersName ? kString52_5S : kString52_5; + case k50_6: return withSpeakersName ? kString50_6S : kString50_6; + case k51_6: return withSpeakersName ? kString51_6S : kString51_6; case k70_2: return withSpeakersName ? kString70_2S : kString70_2; case k71_2: return withSpeakersName ? kString71_2S : kString71_2; + case k70_3: return withSpeakersName ? kString70_3S : kString70_3; + case k72_3: return withSpeakersName ? kString72_3S : kString72_3; case k70_4: return withSpeakersName ? kString70_4S : kString70_4; case k71_4: return withSpeakersName ? kString71_4S : kString71_4; + case k72_5: return withSpeakersName ? kString72_5S : kString72_5; case k70_6: return withSpeakersName ? kString70_6S : kString70_6; case k71_6: return withSpeakersName ? kString71_6S : kString71_6; case k90_4: return withSpeakersName ? kString90_4S : kString90_4; @@ -840,19 +1068,44 @@ inline CString getSpeakerArrangementString (SpeakerArrangement arr, bool withSpe case k91_6: return withSpeakersName ? kString91_6S : kString91_6; case k130: return withSpeakersName ? kString130S : kString130; case k131: return withSpeakersName ? kString131S : kString131; - case k140: return withSpeakersName ? kString140S : kString140; - case k222: return withSpeakersName ? kString222S : kString222; + + //--- With Tops and Bottoms --- + case k41_4_1: return withSpeakersName ? kString41_4_1S : kString41_4_1; + case k50_4_1: return withSpeakersName ? kString50_4_1S : kString50_4_1; + case k51_4_1: return withSpeakersName ? kString51_4_1S : kString51_4_1; + case k50_5_3: return withSpeakersName ? kString50_5_3S : kString50_5_3; + case k51_5_3: return withSpeakersName ? kString51_5_3S : kString51_5_3; + case k50_2_2: return withSpeakersName ? kString50_2_2S : kString50_2_2; + case k50_4_2: return withSpeakersName ? kString50_4_2S : kString50_4_2; + case k60_4_4: return withSpeakersName ? kString60_4_4S : kString60_4_4; + case k70_4_2: return withSpeakersName ? kString70_4_2S : kString70_4_2; + + case k50_5_Sony: return withSpeakersName ? kString50_5_SonyS : kString50_5_Sony; + case k40_2_2: return withSpeakersName ? kString40_2_2S : kString40_2_2; + case k40_4_2: return withSpeakersName ? kString40_4_2S : kString40_4_2; + case k50_3_2: return withSpeakersName ? kString50_3_2S : kString50_3_2; + case k30_5_2: return withSpeakersName ? kString30_5_2S : kString30_5_2; + case k40_4_4: return withSpeakersName ? kString40_4_4S : kString40_4_4; + case k50_4_4: return withSpeakersName ? kString50_4_4S : kString50_4_4; + case k220: return withSpeakersName ? kString220S : kString220; - break; + case k222: return withSpeakersName ? kString222S : kString222; } - + //--- Ambisonics --- if (arr == kAmbi1stOrderACN) return withSpeakersName ? kStringAmbi1stOrderS : kStringAmbi1stOrder; if (arr == kAmbi2cdOrderACN) return withSpeakersName ? kStringAmbi2cdOrderS : kStringAmbi2cdOrder; if (arr == kAmbi3rdOrderACN) return withSpeakersName ? kStringAmbi3rdOrderS : kStringAmbi3rdOrder; - + if (arr == kAmbi4thOrderACN) + return withSpeakersName ? kStringAmbi4thOrderS : kStringAmbi4thOrder; + if (arr == kAmbi5thOrderACN) + return withSpeakersName ? kStringAmbi5thOrderS : kStringAmbi5thOrder; + if (arr == kAmbi6thOrderACN) + return withSpeakersName ? kStringAmbi6thOrderS : kStringAmbi6thOrder; + if (arr == kAmbi7thOrderACN) + return withSpeakersName ? kStringAmbi7thOrderS : kStringAmbi7thOrder; return kStringEmpty; } @@ -955,6 +1208,24 @@ inline CString getSpeakerShortName (const SpeakerArrangement& arr, int32 index) return "14"; if (speaker == kSpeakerACN15) return "15"; + if (speaker == kSpeakerACN16) + return "16"; + if (speaker == kSpeakerACN17) + return "17"; + if (speaker == kSpeakerACN18) + return "18"; + if (speaker == kSpeakerACN19) + return "19"; + if (speaker == kSpeakerACN20) + return "20"; + if (speaker == kSpeakerACN21) + return "21"; + if (speaker == kSpeakerACN22) + return "22"; + if (speaker == kSpeakerACN23) + return "23"; + if (speaker == kSpeakerACN24) + return "24"; if (speaker == kSpeakerTsl) return "Tsl"; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h index 15c1dbe70144..081177fa6879 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h @@ -22,19 +22,25 @@ namespace Steinberg { namespace Vst { //------------------------------------------------------------------------ -/** VST3 SDK Version */ +/** VST 3 SDK Version */ #ifndef kVstVersionString -#define kVstVersionString "VST 3.7.2" ///< SDK version for PClassInfo2 +#define kVstVersionString "VST 3.7.8" ///< SDK version for PClassInfo2 #endif #define kVstVersionMajor 3 #define kVstVersionMinor 7 -#define kVstVersionSub 2 +#define kVstVersionSub 8 #define VST_VERSION ((kVstVersionMajor << 16) | (kVstVersionMinor << 8) | kVstVersionSub) // Versions History which allows to write such code: // #if VST_VERSION >= VST_3_6_5_VERSION +#define VST_3_7_8_VERSION 0x030708 +#define VST_3_7_7_VERSION 0x030707 +#define VST_3_7_6_VERSION 0x030706 +#define VST_3_7_5_VERSION 0x030705 +#define VST_3_7_4_VERSION 0x030704 +#define VST_3_7_3_VERSION 0x030703 #define VST_3_7_2_VERSION 0x030702 #define VST_3_7_1_VERSION 0x030701 #define VST_3_7_0_VERSION 0x030700 @@ -100,6 +106,41 @@ typedef uint64 Speaker; ///< Bit for one speaker /*@}*/ +static SMTG_CONSTEXPR const FIDString SDKVersionString = kVstVersionString; + +static SMTG_CONSTEXPR const uint32 SDKVersionMajor = kVstVersionMajor; +static SMTG_CONSTEXPR const uint32 SDKVersionMinor = kVstVersionMinor; +static SMTG_CONSTEXPR const uint32 SDKVersionSub = kVstVersionSub; + +static SMTG_CONSTEXPR const uint32 SDKVersion = + ((SDKVersionMajor << 16) | (SDKVersionMinor << 8) | SDKVersionSub); + +// Versions History which allows to write such code: +// if constexpr (SDKVersion >= SDKVersion_3_6_5) { ... } +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_7 = VST_3_7_7_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_6 = VST_3_7_6_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_5 = VST_3_7_5_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_4 = VST_3_7_4_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_3 = VST_3_7_3_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_2 = VST_3_7_2_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_1 = VST_3_7_1_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_0 = VST_3_7_0_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_14 = VST_3_6_14_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_13 = VST_3_6_13_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_12 = VST_3_6_12_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_11 = VST_3_6_11_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_10 = VST_3_6_10_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_9 = VST_3_6_9_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_8 = VST_3_6_8_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_7 = VST_3_6_7_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_6 = VST_3_6_6_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_5 = VST_3_6_5_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_6_0 = VST_3_6_0_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_5_0 = VST_3_5_0_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_1_0 = VST_3_1_0_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_0_0 = VST_3_0_0_VERSION; + //------------------------------------------------------------------------ } // namespace Vst } // namespace Steinberg + diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt index d5d3145b1cdb..f9c531e7455a 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt @@ -1,27 +1,27 @@ -//----------------------------------------------------------------------------- -// LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved -//----------------------------------------------------------------------------- -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -// OF THE POSSIBILITY OF SUCH DAMAGE. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md index 587a6aa10b4a..e7c8a937482b 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md @@ -1,18 +1,18 @@ -# Welcome to VST 3 SDK public_sdk - -Here are located: - -- helper classes implementing VST3 Interfaces -- samples of VST3 Hosting and VST3 Plug-Ins -- AAX Wrapper -- AU Wrapper -- AUv3 Wrapper -- VST2 Wrapper -- InterAppAudio - -## License & Usage guidelines - -More details are found at [VST 3 SDK public_sdk License](https://forums.steinberg.net/t/vst-3-sdk-public-sdk-license/695592) - ----- -Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) \ No newline at end of file +# Welcome to VST 3 SDK public_sdk + +Here are located: + +- helper classes implementing **VST 3** Interfaces +- samples of **VST 3** Hosting and **VST 3** plug-ins +- **AAX** Wrapper +- **AU** Wrapper +- **AUv3** Wrapper +- **VST 2** Wrapper +- InterAppAudio + +## License & Usage guidelines + +More details are found at [VST 3 SDK public_sdk License](https://forums.steinberg.net/t/vst-3-sdk-public-sdk-license/695592) + +---- +Return to [VST 3 SDK](https://github.com/steinbergmedia/vst3sdk) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp new file mode 100644 index 000000000000..2d568ae8314b --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp @@ -0,0 +1,439 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfotool +// Filename : public.sdk/samples/vst-utilities/moduleinfotool/main.cpp +// Created by : Steinberg, 12/2021 +// Description : main entry point +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "base/source/fcommandline.h" +#include "pluginterfaces/base/fplatform.h" +#include "pluginterfaces/base/iplugincompatibility.h" +#include "pluginterfaces/vst/vsttypes.h" +#include "public.sdk/source/common/memorystream.h" +#include "public.sdk/source/common/readfile.h" +#include "public.sdk/source/vst/hosting/module.h" +#include "public.sdk/source/vst/moduleinfo/moduleinfocreator.h" +#include "public.sdk/source/vst/moduleinfo/moduleinfoparser.h" +#include "public.sdk/source/vst/utility/stringconvert.h" +#include +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg { +namespace ModuleInfoTool { +namespace { + +//------------------------------------------------------------------------ +constexpr auto BUILD_INFO = "moduleinfotool 1.0.0 [Built " __DATE__ "]"; + +//------------------------------------------------------------------------ +//-- Options +constexpr auto optHelp = "help"; +constexpr auto optCreate = "create"; +constexpr auto optValidate = "validate"; +constexpr auto optModuleVersion = "version"; +constexpr auto optModulePath = "path"; +constexpr auto optInfoPath = "infopath"; +constexpr auto optModuleCompatPath = "compat"; +constexpr auto optOutputPath = "output"; + +//------------------------------------------------------------------------ +void printUsage (std::ostream& s) +{ + s << "Usage:\n"; + s << " moduleinfotool -create -version VERSION -path MODULE_PATH [-compat PATH -output PATH]\n"; + s << " moduleinfotool -validate -path MODULE_PATH [-infopath PATH]\n"; +} + +//------------------------------------------------------------------------ +std::optional openAndParseCompatJSON (const std::string& path) +{ + auto data = readFile (path); + if (data.empty ()) + { + std::cout << "Can not read '" << path << "'\n"; + printUsage (std::cout); + return {}; + } + std::stringstream error; + auto result = ModuleInfoLib::parseCompatibilityJson (data, &error); + if (!result) + { + std::cout << "Can not parse '" << path << "'\n"; + std::cout << error.str (); + printUsage (std::cout); + return {}; + } + return result; +} + +//------------------------------------------------------------------------ +std::optional loadCompatibilityFromModule (const VST3::Hosting::Module& module) +{ + const auto& factory = module.getFactory(); + const auto& infos = factory.classInfos(); + + const auto iter = std::find_if (infos.begin(), infos.end(), [&] (const auto& info) + { + return info.category() == kPluginCompatibilityClass; + }); + + if (iter == infos.end()) + return {}; + + const auto compatibility = factory.createInstance (iter->ID()); + + if (compatibility == nullptr) + return {}; + + Steinberg::MemoryStream stream; + + if (compatibility->getCompatibilityJSON (&stream) != kResultOk) + return {}; + + const std::string_view streamView (stream.getData(), stream.getSize()); + + return ModuleInfoLib::parseCompatibilityJson (streamView, nullptr); +} + +//------------------------------------------------------------------------ +int createJSON (const std::optional& compat, + const std::string& modulePath, const std::string& moduleVersion, + std::ostream& outStream) +{ + std::string errorStr; + auto module = VST3::Hosting::Module::create (modulePath, errorStr); + if (!module) + { + std::cout << errorStr; + return 1; + } + auto moduleInfo = ModuleInfoLib::createModuleInfo (*module, false); + if (compat) + moduleInfo.compatibility = *compat; + else if (auto loaded = loadCompatibilityFromModule (*module)) + moduleInfo.compatibility = *loaded; + + moduleInfo.version = moduleVersion; + + std::stringstream output; + ModuleInfoLib::outputJson (moduleInfo, output); + auto str = output.str (); + outStream << str; + return 0; +} + +//------------------------------------------------------------------------ +struct validate_error : std::exception +{ + validate_error (const std::string& str) : str (str) {} + const char* what () const noexcept override { return str.data (); } + +private: + std::string str; +}; + +//------------------------------------------------------------------------ +void validate (const ModuleInfo& moduleInfo, const VST3::Hosting::Module& module) +{ + auto factory = module.getFactory (); + auto factoryInfo = factory.info (); + auto classInfoList = factory.classInfos (); + auto snapshotList = module.getSnapshots (module.getPath ()); + + if (factoryInfo.vendor () != moduleInfo.factoryInfo.vendor) + throw validate_error ("factoryInfo.vendor different: " + moduleInfo.factoryInfo.vendor); + if (factoryInfo.url () != moduleInfo.factoryInfo.url) + throw validate_error ("factoryInfo.url different: " + moduleInfo.factoryInfo.url); + if (factoryInfo.email () != moduleInfo.factoryInfo.email) + throw validate_error ("factoryInfo.email different: " + moduleInfo.factoryInfo.email); + if (factoryInfo.flags () != moduleInfo.factoryInfo.flags) + throw validate_error ("factoryInfo.flags different: " + + std::to_string (moduleInfo.factoryInfo.flags)); + + for (const auto& ci : moduleInfo.classes) + { + auto cid = VST3::UID::fromString (ci.cid); + if (!cid) + throw validate_error ("could not parse class UID: " + ci.cid); + auto it = std::find_if (classInfoList.begin (), classInfoList.end (), + [&] (const auto& el) { return el.ID () == *cid; }); + if (it == classInfoList.end ()) + throw validate_error ("cannot find CID in class list: " + ci.cid); + if (it->name () != ci.name) + throw validate_error ("class name different: " + ci.name); + if (it->category () != ci.category) + throw validate_error ("class category different: " + ci.category); + if (it->vendor () != ci.vendor) + throw validate_error ("class vendor different: " + ci.vendor); + if (it->version () != ci.version) + throw validate_error ("class version different: " + ci.version); + if (it->sdkVersion () != ci.sdkVersion) + throw validate_error ("class sdkVersion different: " + ci.sdkVersion); + if (it->subCategories () != ci.subCategories) + throw validate_error ("class subCategories different: " /* + ci.subCategories*/); + if (it->cardinality () != ci.cardinality) + throw validate_error ("class cardinality different: " + + std::to_string (ci.cardinality)); + if (it->classFlags () != ci.flags) + throw validate_error ("class flags different: " + std::to_string (ci.flags)); + classInfoList.erase (it); + + auto snapshotListIt = std::find_if (snapshotList.begin (), snapshotList.end (), + [&] (const auto& el) { return el.uid == *cid; }); + if (snapshotListIt == snapshotList.end () && !ci.snapshots.empty ()) + throw validate_error ("cannot find snapshots for: " + ci.cid); + for (const auto& snapshot : ci.snapshots) + { + auto snapshotIt = std::find_if ( + snapshotListIt->images.begin (), snapshotListIt->images.end (), + [&] (const auto& el) { return el.scaleFactor == snapshot.scaleFactor; }); + if (snapshotIt == snapshotListIt->images.end ()) + throw validate_error ("cannot find snapshots for scale factor: " + + std::to_string (snapshot.scaleFactor)); + std::string_view path (snapshotIt->path); + if (path.find (module.getPath ()) == 0) + path.remove_prefix (module.getPath ().size () + 1); + if (path != snapshot.path) + throw validate_error ("cannot find snapshots with path: " + snapshot.path); + snapshotListIt->images.erase (snapshotIt); + } + if (snapshotListIt != snapshotList.end () && !snapshotListIt->images.empty ()) + { + std::string errorStr = "Missing Snapshots in moduleinfo:\n"; + for (const auto& s : snapshotListIt->images) + { + errorStr += s.path + '\n'; + } + throw validate_error (errorStr); + } + if (snapshotListIt != snapshotList.end ()) + snapshotList.erase (snapshotListIt); + } + if (!classInfoList.empty ()) + throw validate_error ("Missing classes in moduleinfo"); + if (!snapshotList.empty ()) + throw validate_error ("Missing snapshots in moduleinfo"); +} + +//------------------------------------------------------------------------ +int validate (const std::string& modulePath, std::string infoJsonPath) +{ + if (infoJsonPath.empty ()) + { + auto path = VST3::Hosting::Module::getModuleInfoPath (modulePath); + if (!path) + { + std::cerr << "Module does not contain a moduleinfo.json: '" << modulePath << "'" + << '\n'; + return 1; + } + infoJsonPath = *path; + } + + auto data = readFile (infoJsonPath); + if (data.empty ()) + { + std::cerr << "Empty or non existing file: '" << infoJsonPath << "'" << '\n'; + printUsage (std::cout); + return 1; + } + auto moduleInfo = ModuleInfoLib::parseJson (data, &std::cerr); + if (moduleInfo) + { + std::string errorStr; + auto module = VST3::Hosting::Module::create (modulePath, errorStr); + if (!module) + { + std::cerr << errorStr; + printUsage (std::cout); + return 1; + } + try + { + validate (*moduleInfo, *module); + } + catch (const std::exception& exc) + { + std::cerr << "Error:\n" << exc.what () << '\n'; + printUsage (std::cout); + return 1; + } + return 0; + } + printUsage (std::cout); + return 1; +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +int run (int argc, char* argv[]) +{ + // parse command line + CommandLine::Descriptions desc; + CommandLine::VariablesMap valueMap; + CommandLine::FilesVector files; + + using Description = CommandLine::Description; + desc.addOptions ( + BUILD_INFO, + { + {optCreate, "Create moduleinfo", Description::kBool}, + {optValidate, "Validate moduleinfo", Description::kBool}, + {optModuleVersion, "Module version", Description::kString}, + {optModulePath, "Path to module", Description::kString}, + {optInfoPath, "Path to moduleinfo.json", Description::kString}, + {optModuleCompatPath, "Path to compatibility.json", Description::kString}, + {optOutputPath, "Write json to file instead of stdout", Description::kString}, + {optHelp, "Print help", Description::kBool}, + }); + CommandLine::parse (argc, argv, desc, valueMap, &files); + + bool isCreate = valueMap.count (optCreate) != 0 && valueMap.count (optModuleVersion) != 0 && + valueMap.count (optModulePath) != 0; + bool isValidate = valueMap.count (optValidate) && valueMap.count (optModulePath) != 0; + + if (valueMap.hasError () || valueMap.count (optHelp) || !(isCreate || isValidate)) + { + std::cout << '\n' << desc << '\n'; + printUsage (std::cout); + return 1; + } + + int result = 1; + + const auto& modulePath = valueMap[optModulePath]; + if (isCreate) + { + auto* outputStream = &std::cout; + std::optional compat; + if (valueMap.count (optModuleCompatPath) != 0) + { + const auto& compatPath = valueMap[optModuleCompatPath]; + compat = openAndParseCompatJSON (compatPath); + if (!compat) + return 1; + } + bool writeToFile = false; + if (valueMap.count (optOutputPath) != 0) + { + writeToFile = true; +#if SMTG_OS_WINDOWS + auto tmp = VST3::StringConvert::convert (valueMap[optOutputPath]); + auto outputFile = reinterpret_cast (tmp.data ()); +#else + auto outputFile = valueMap[optOutputPath]; +#endif + auto ostream = new std::ofstream (outputFile); + + if (ostream->is_open ()) + outputStream = ostream; + else + { + std::cout << "Cannot create output file: " << valueMap[optOutputPath] << '\n'; + return result; + } + } + const auto& moduleVersion = valueMap[optModuleVersion]; + result = createJSON (compat, modulePath, moduleVersion, *outputStream); + if (writeToFile) + delete outputStream; + } + else if (isValidate) + { + std::string moduleInfoJsonPath; + if (valueMap.count (optInfoPath) != 0) + moduleInfoJsonPath = valueMap[optInfoPath]; + result = validate (modulePath, moduleInfoJsonPath); + } + return result; +} + +//------------------------------------------------------------------------ +} // ModuleInfoTool +} // Steinberg + +//------------------------------------------------------------------------ +#if SMTG_OS_WINDOWS +//------------------------------------------------------------------------ +#include +#include + +//------------------------------------------------------------------------ +using Utf8String = std::string; + +//------------------------------------------------------------------------ +using Utf8Args = std::vector; +Utf8Args toUtf8Args (int argc, wchar_t* wargv[]) +{ + Utf8Args utf8Args; + for (int i = 0; i < argc; i++) + { + auto str = reinterpret_cast(wargv[i]); + utf8Args.push_back (VST3::StringConvert::convert (str)); + } + + return utf8Args; +} + +//------------------------------------------------------------------------ +using Utf8ArgPtrs = std::vector; +Utf8ArgPtrs toUtf8ArgPtrs (Utf8Args& utf8Args) +{ + Utf8ArgPtrs utf8ArgPtrs; + for (auto& el : utf8Args) + { + utf8ArgPtrs.push_back (el.data ()); + } + + return utf8ArgPtrs; +} + +//------------------------------------------------------------------------ +int wmain (int argc, wchar_t* wargv[]) +{ + Utf8Args utf8Args = toUtf8Args (argc, wargv); + Utf8ArgPtrs utf8ArgPtrs = toUtf8ArgPtrs (utf8Args); + + char** argv = &(utf8ArgPtrs.at (0)); + return Steinberg::ModuleInfoTool::run (argc, argv); +} +#else +int main (int argc, char* argv[]) +{ + return Steinberg::ModuleInfoTool::run (argc, argv); +} +#endif diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp index 92e82fab22af..5b6c245e000e 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -36,7 +36,7 @@ #include "memorystream.h" #include "pluginterfaces/base/futils.h" -#include +#include namespace Steinberg { diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h index e080c3fae985..489ace5fff65 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp index 1a5ff335d0a6..02dd9fd21b3b 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -51,6 +51,7 @@ CPluginView::CPluginView (const ViewRect* _rect) //------------------------------------------------------------------------ CPluginView::~CPluginView () { + setFrame (nullptr); } //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h index 417c53278adc..ce131b94cb60 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -51,7 +51,7 @@ class CPluginView : public FObject, public IPlugView public: //------------------------------------------------------------------------ CPluginView (const ViewRect* rect = nullptr); - virtual ~CPluginView (); + ~CPluginView () SMTG_OVERRIDE; /** Returns its current frame rectangle. */ const ViewRect& getRect () const { return rect; } @@ -109,7 +109,7 @@ class CPluginView : public FObject, public IPlugView protected: ViewRect rect; void* systemWindow {nullptr}; - IPlugFrame* plugFrame {nullptr}; + IPtr plugFrame; }; } // namespace diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp new file mode 100644 index 000000000000..5f6045770ad5 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : readfile +// Filename : public.sdk/source/common/readfile.cpp +// Created by : Steinberg, 3/2023 +// Description : read file routine +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "readfile.h" +#include "public.sdk/source/vst/utility/stringconvert.h" +#include "pluginterfaces/base/fplatform.h" +#include +#include + +namespace Steinberg { + +//------------------------------------------------------------------------ +std::string readFile (const std::string& path) +{ +#if SMTG_OS_WINDOWS + auto u16Path = VST3::StringConvert::convert (path); + std::ifstream file (reinterpret_cast (u16Path.data ()), + std::ios_base::in | std::ios_base::binary); +#else + std::ifstream file (path, std::ios_base::in | std::ios_base::binary); +#endif + if (!file.is_open ()) + return {}; + +#if SMTG_CPP17 + auto size = file.seekg (0, std::ios_base::end).tellg (); + file.seekg (0, std::ios_base::beg); + std::string data; + data.resize (size); + file.read (data.data (), data.size ()); + if (file.bad ()) + return {}; + return data; +#else + std::stringstream buffer; + buffer << file.rdbuf (); + return buffer.str (); +#endif +} + +//------------------------------------------------------------------------ +} // namespace Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h new file mode 100644 index 000000000000..fdc7105eac04 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Flags : clang-format SMTGSequencer +// Project : VST SDK +// +// Category : readfile +// Filename : public.sdk/source/common/readfile.h +// Created by : Steinberg, 3/2023 +// Description : read file routine +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include + +namespace Steinberg { + +//------------------------------------------------------------------------ +/** Reads entire file content +\ingroup sdkBase + +Returns entire file content at the given path +\endcode +*/ +std::string readFile (const std::string& path); + +//------------------------------------------------------------------------ + +} // namespace Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp index 30a2e31cc959..e04987e16e04 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp @@ -4,37 +4,38 @@ // Category : Helpers // Filename : public.sdk/source/vst/hosting/hostclasses.cpp // Created by : Steinberg, 03/05/2008. -// Description : VST 3 hostclasses, example implementations for IHostApplication, IAttributeList and IMessage +// Description : VST 3 hostclasses, example impl. for IHostApplication, IAttributeList and IMessage // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, +// +// * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation +// this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this +// contributors may be used to endorse or promote products derived from this // software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. //----------------------------------------------------------------------------- #include "hostclasses.h" +#include "public.sdk/source/vst/utility/stringconvert.h" #include @@ -46,31 +47,34 @@ HostApplication::HostApplication () { FUNKNOWN_CTOR - mPlugInterfaceSupport = owned (NEW PlugInterfaceSupport); + mPlugInterfaceSupport = owned (new PlugInterfaceSupport); } //----------------------------------------------------------------------------- tresult PLUGIN_API HostApplication::getName (String128 name) { - String str ("My VST3 HostApplication"); - str.copyTo16 (name, 0, 127); - return kResultTrue; + return VST3::StringConvert::convert ("My VST3 HostApplication", name) ? kResultTrue : + kInternalError; } //----------------------------------------------------------------------------- tresult PLUGIN_API HostApplication::createInstance (TUID cid, TUID _iid, void** obj) { - FUID classID (FUID::fromTUID (cid)); - FUID interfaceID (FUID::fromTUID (_iid)); - if (classID == IMessage::iid && interfaceID == IMessage::iid) + if (FUnknownPrivate::iidEqual (cid, IMessage::iid) && + FUnknownPrivate::iidEqual (_iid, IMessage::iid)) { *obj = new HostMessage; return kResultTrue; } - else if (classID == IAttributeList::iid && interfaceID == IAttributeList::iid) + if (FUnknownPrivate::iidEqual (cid, IAttributeList::iid) && + FUnknownPrivate::iidEqual (_iid, IAttributeList::iid)) { - *obj = new HostAttributeList; - return kResultTrue; + if (auto al = HostAttributeList::make ()) + { + *obj = al.take (); + return kResultTrue; + } + return kOutOfMemory; } *obj = nullptr; return kResultFalse; @@ -106,17 +110,12 @@ uint32 PLUGIN_API HostApplication::release () //----------------------------------------------------------------------------- IMPLEMENT_FUNKNOWN_METHODS (HostMessage, IMessage, IMessage::iid) //----------------------------------------------------------------------------- -HostMessage::HostMessage () : messageId (nullptr), attributeList (nullptr) -{ - FUNKNOWN_CTOR -} +HostMessage::HostMessage () {FUNKNOWN_CTOR} //----------------------------------------------------------------------------- -HostMessage::~HostMessage () +HostMessage::~HostMessage () noexcept { setMessageID (nullptr); - if (attributeList) - attributeList->release (); FUNKNOWN_DTOR } @@ -144,38 +143,51 @@ void PLUGIN_API HostMessage::setMessageID (const char* mid) IAttributeList* PLUGIN_API HostMessage::getAttributes () { if (!attributeList) - attributeList = new HostAttributeList; + attributeList = HostAttributeList::make (); return attributeList; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -class HostAttribute +struct HostAttributeList::Attribute { -public: - enum Type + enum class Type { + kUninitialized, kInteger, kFloat, kString, kBinary }; + Attribute () = default; - HostAttribute (int64 value) : size (0), type (kInteger) { v.intValue = value; } - HostAttribute (double value) : size (0), type (kFloat) { v.floatValue = value; } - /** size is in code unit (count of TChar) */ - HostAttribute (const TChar* value, uint32 sizeInCodeUnit) : size (sizeInCodeUnit), type (kString) + Attribute (int64 value) : type (Type::kInteger) { v.intValue = value; } + Attribute (double value) : type (Type::kFloat) { v.floatValue = value; } + /* size is in code unit (count of TChar) */ + Attribute (const TChar* value, uint32 sizeInCodeUnit) + : size (sizeInCodeUnit), type (Type::kString) { v.stringValue = new TChar[sizeInCodeUnit]; memcpy (v.stringValue, value, sizeInCodeUnit * sizeof (TChar)); } - HostAttribute (const void* value, uint32 sizeInBytes) : size (sizeInBytes), type (kBinary) + Attribute (const void* value, uint32 sizeInBytes) : size (sizeInBytes), type (Type::kBinary) { v.binaryValue = new char[sizeInBytes]; memcpy (v.binaryValue, value, sizeInBytes); } - ~HostAttribute () + Attribute (Attribute&& o) { *this = std::move (o); } + Attribute& operator= (Attribute&& o) + { + v = o.v; + size = o.size; + type = o.type; + o.size = 0; + o.type = Type::kUninitialized; + o.v = {}; + return *this; + } + ~Attribute () noexcept { if (size) delete[] v.binaryValue; @@ -183,7 +195,7 @@ class HostAttribute int64 intValue () const { return v.intValue; } double floatValue () const { return v.floatValue; } - /** sizeInCodeUnit is in code unit (count of TChar) */ + /* sizeInCodeUnit is in code unit (count of TChar) */ const TChar* stringValue (uint32& sizeInCodeUnit) { sizeInCodeUnit = size; @@ -197,7 +209,7 @@ class HostAttribute Type getType () const { return type; } -protected: +private: union v { int64 intValue; @@ -205,58 +217,48 @@ class HostAttribute TChar* stringValue; char* binaryValue; } v; - uint32 size; - Type type; + uint32 size {0}; + Type type {Type::kUninitialized}; }; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- IMPLEMENT_FUNKNOWN_METHODS (HostAttributeList, IAttributeList, IAttributeList::iid) + //----------------------------------------------------------------------------- -HostAttributeList::HostAttributeList () +IPtr HostAttributeList::make () { - FUNKNOWN_CTOR + return owned (new HostAttributeList); } //----------------------------------------------------------------------------- -HostAttributeList::~HostAttributeList () -{ - auto it = list.rbegin (); - while (it != list.rend ()) - { - delete it->second; - it++; - } - FUNKNOWN_DTOR -} +HostAttributeList::HostAttributeList () {FUNKNOWN_CTOR} //----------------------------------------------------------------------------- -void HostAttributeList::removeAttrID (AttrID aid) +HostAttributeList::~HostAttributeList () noexcept { - auto it = list.find (aid); - if (it != list.end ()) - { - delete it->second; - list.erase (it); - } + FUNKNOWN_DTOR } //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::setInt (AttrID aid, int64 value) { - removeAttrID (aid); - list[aid] = new HostAttribute (value); + if (!aid) + return kInvalidArgument; + list[aid] = Attribute (value); return kResultTrue; } //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::getInt (AttrID aid, int64& value) { + if (!aid) + return kInvalidArgument; auto it = list.find (aid); - if (it != list.end () && it->second) + if (it != list.end () && it->second.getType () == Attribute::Type::kInteger) { - value = it->second->intValue (); + value = it->second.intValue (); return kResultTrue; } return kResultFalse; @@ -265,18 +267,21 @@ tresult PLUGIN_API HostAttributeList::getInt (AttrID aid, int64& value) //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::setFloat (AttrID aid, double value) { - removeAttrID (aid); - list[aid] = new HostAttribute (value); + if (!aid) + return kInvalidArgument; + list[aid] = Attribute (value); return kResultTrue; } //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::getFloat (AttrID aid, double& value) { + if (!aid) + return kInvalidArgument; auto it = list.find (aid); - if (it != list.end () && it->second) + if (it != list.end () && it->second.getType () == Attribute::Type::kFloat) { - value = it->second->floatValue (); + value = it->second.floatValue (); return kResultTrue; } return kResultFalse; @@ -285,20 +290,24 @@ tresult PLUGIN_API HostAttributeList::getFloat (AttrID aid, double& value) //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::setString (AttrID aid, const TChar* string) { - removeAttrID (aid); + if (!aid) + return kInvalidArgument; // + 1 for the null-terminate - list[aid] = new HostAttribute (string, String (string).length () + 1); + auto length = tstrlen (string) + 1; + list[aid] = Attribute (string, length); return kResultTrue; } //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::getString (AttrID aid, TChar* string, uint32 sizeInBytes) { + if (!aid) + return kInvalidArgument; auto it = list.find (aid); - if (it != list.end () && it->second) + if (it != list.end () && it->second.getType () == Attribute::Type::kString) { uint32 sizeInCodeUnit = 0; - const TChar* _string = it->second->stringValue (sizeInCodeUnit); + const TChar* _string = it->second.stringValue (sizeInCodeUnit); memcpy (string, _string, std::min (sizeInCodeUnit * sizeof (TChar), sizeInBytes)); return kResultTrue; } @@ -308,22 +317,26 @@ tresult PLUGIN_API HostAttributeList::getString (AttrID aid, TChar* string, uint //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::setBinary (AttrID aid, const void* data, uint32 sizeInBytes) { - removeAttrID (aid); - list[aid] = new HostAttribute (data, sizeInBytes); + if (!aid) + return kInvalidArgument; + list[aid] = Attribute (data, sizeInBytes); return kResultTrue; } //----------------------------------------------------------------------------- tresult PLUGIN_API HostAttributeList::getBinary (AttrID aid, const void*& data, uint32& sizeInBytes) { + if (!aid) + return kInvalidArgument; auto it = list.find (aid); - if (it != list.end () && it->second) + if (it != list.end () && it->second.getType () == Attribute::Type::kBinary) { - data = it->second->binaryValue (sizeInBytes); + data = it->second.binaryValue (sizeInBytes); return kResultTrue; } sizeInBytes = 0; return kResultFalse; } -} -} // namespace + +} // Vst +} // Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h index 7b105a200c5b..4a254cac1649 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h @@ -4,32 +4,32 @@ // Category : Helpers // Filename : public.sdk/source/vst/hosting/hostclasses.h // Created by : Steinberg, 03/05/2008. -// Description : VST 3 hostclasses, example implementations for IHostApplication, IAttributeList and IMessage +// Description : VST 3 hostclasses, example impl. for IHostApplication, IAttributeList and IMessage // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, +// +// * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation +// this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this +// contributors may be used to endorse or promote products derived from this // software without specific prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. //----------------------------------------------------------------------------- @@ -37,9 +37,10 @@ #pragma once #include "public.sdk/source/vst/hosting/pluginterfacesupport.h" -#include "base/source/fstring.h" #include "pluginterfaces/vst/ivsthostapplication.h" #include +#include +#include namespace Steinberg { namespace Vst { @@ -52,64 +53,66 @@ class HostApplication : public IHostApplication { public: HostApplication (); - virtual ~HostApplication () { FUNKNOWN_DTOR } + virtual ~HostApplication () noexcept {FUNKNOWN_DTOR} //--- IHostApplication --------------- - tresult PLUGIN_API getName (String128 name) SMTG_OVERRIDE; - tresult PLUGIN_API createInstance (TUID cid, TUID _iid, void** obj) SMTG_OVERRIDE; + tresult PLUGIN_API getName (String128 name) override; + tresult PLUGIN_API createInstance (TUID cid, TUID _iid, void** obj) override; DECLARE_FUNKNOWN_METHODS PlugInterfaceSupport* getPlugInterfaceSupport () const { return mPlugInterfaceSupport; } -protected: +private: IPtr mPlugInterfaceSupport; }; -class HostAttribute; //------------------------------------------------------------------------ -/** Implementation's example of IAttributeList. +/** Example, ready to use implementation of IAttributeList. \ingroup hostingBase */ -class HostAttributeList : public IAttributeList +class HostAttributeList final : public IAttributeList { public: - HostAttributeList (); - virtual ~HostAttributeList (); + /** make a new attribute list instance */ + static IPtr make (); - tresult PLUGIN_API setInt (AttrID aid, int64 value) SMTG_OVERRIDE; - tresult PLUGIN_API getInt (AttrID aid, int64& value) SMTG_OVERRIDE; - tresult PLUGIN_API setFloat (AttrID aid, double value) SMTG_OVERRIDE; - tresult PLUGIN_API getFloat (AttrID aid, double& value) SMTG_OVERRIDE; - tresult PLUGIN_API setString (AttrID aid, const TChar* string) SMTG_OVERRIDE; - tresult PLUGIN_API getString (AttrID aid, TChar* string, uint32 sizeInBytes) SMTG_OVERRIDE; - tresult PLUGIN_API setBinary (AttrID aid, const void* data, uint32 sizeInBytes) SMTG_OVERRIDE; - tresult PLUGIN_API getBinary (AttrID aid, const void*& data, uint32& sizeInBytes) SMTG_OVERRIDE; + tresult PLUGIN_API setInt (AttrID aid, int64 value) override; + tresult PLUGIN_API getInt (AttrID aid, int64& value) override; + tresult PLUGIN_API setFloat (AttrID aid, double value) override; + tresult PLUGIN_API getFloat (AttrID aid, double& value) override; + tresult PLUGIN_API setString (AttrID aid, const TChar* string) override; + tresult PLUGIN_API getString (AttrID aid, TChar* string, uint32 sizeInBytes) override; + tresult PLUGIN_API setBinary (AttrID aid, const void* data, uint32 sizeInBytes) override; + tresult PLUGIN_API getBinary (AttrID aid, const void*& data, uint32& sizeInBytes) override; + virtual ~HostAttributeList () noexcept; DECLARE_FUNKNOWN_METHODS -protected: - void removeAttrID (AttrID aid); - std::map list; +private: + HostAttributeList (); + + struct Attribute; + std::map list; }; //------------------------------------------------------------------------ -/** Implementation's example of IMessage. +/** Example implementation of IMessage. \ingroup hostingBase */ -class HostMessage : public IMessage +class HostMessage final : public IMessage { public: HostMessage (); - virtual ~HostMessage (); + virtual ~HostMessage () noexcept; - const char* PLUGIN_API getMessageID () SMTG_OVERRIDE; - void PLUGIN_API setMessageID (const char* messageID) SMTG_OVERRIDE; - IAttributeList* PLUGIN_API getAttributes () SMTG_OVERRIDE; + const char* PLUGIN_API getMessageID () override; + void PLUGIN_API setMessageID (const char* messageID) override; + IAttributeList* PLUGIN_API getAttributes () override; DECLARE_FUNKNOWN_METHODS -protected: - char* messageId; - HostAttributeList* attributeList; +private: + char* messageId {nullptr}; + IPtr attributeList; }; //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp new file mode 100644 index 000000000000..9ce5b575222c --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp @@ -0,0 +1,340 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/hosting/module.cpp +// Created by : Steinberg, 08/2016 +// Description : hosting module classes +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "module.h" +#include "public.sdk/source/vst/utility/stringconvert.h" +#include "public.sdk/source/vst/utility/optional.h" +#include +#include + +//------------------------------------------------------------------------ +namespace VST3 { +namespace Hosting { + +//------------------------------------------------------------------------ +FactoryInfo::FactoryInfo (PFactoryInfo&& other) noexcept +{ + *this = std::move (other); +} + +//------------------------------------------------------------------------ +FactoryInfo& FactoryInfo::operator= (FactoryInfo&& other) noexcept +{ + info = std::move (other.info); + other.info = {}; + return *this; +} + +//------------------------------------------------------------------------ +FactoryInfo& FactoryInfo::operator= (PFactoryInfo&& other) noexcept +{ + info = std::move (other); + other = {}; + return *this; +} + +//------------------------------------------------------------------------ +std::string FactoryInfo::vendor () const noexcept +{ + return StringConvert::convert (info.vendor, PFactoryInfo::kNameSize); +} + +//------------------------------------------------------------------------ +std::string FactoryInfo::url () const noexcept +{ + return StringConvert::convert (info.url, PFactoryInfo::kURLSize); +} + +//------------------------------------------------------------------------ +std::string FactoryInfo::email () const noexcept +{ + return StringConvert::convert (info.email, PFactoryInfo::kEmailSize); +} + +//------------------------------------------------------------------------ +Steinberg::int32 FactoryInfo::flags () const noexcept +{ + return info.flags; +} + +//------------------------------------------------------------------------ +bool FactoryInfo::classesDiscardable () const noexcept +{ + return (info.flags & PFactoryInfo::kClassesDiscardable) != 0; +} + +//------------------------------------------------------------------------ +bool FactoryInfo::licenseCheck () const noexcept +{ + return (info.flags & PFactoryInfo::kLicenseCheck) != 0; +} + +//------------------------------------------------------------------------ +bool FactoryInfo::componentNonDiscardable () const noexcept +{ + return (info.flags & PFactoryInfo::kComponentNonDiscardable) != 0; +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +PluginFactory::PluginFactory (const PluginFactoryPtr& factory) noexcept : factory (factory) +{ +} + +//------------------------------------------------------------------------ +void PluginFactory::setHostContext (Steinberg::FUnknown* context) const noexcept +{ + if (auto f = Steinberg::FUnknownPtr (factory)) + f->setHostContext (context); +} + +//------------------------------------------------------------------------ +FactoryInfo PluginFactory::info () const noexcept +{ + Steinberg::PFactoryInfo i; + factory->getFactoryInfo (&i); + return FactoryInfo (std::move (i)); +} + +//------------------------------------------------------------------------ +uint32_t PluginFactory::classCount () const noexcept +{ + auto count = factory->countClasses (); + assert (count >= 0); + return static_cast (count); +} + +//------------------------------------------------------------------------ +PluginFactory::ClassInfos PluginFactory::classInfos () const noexcept +{ + auto count = classCount (); + Optional factoryInfo; + ClassInfos classes; + classes.reserve (count); + auto f3 = Steinberg::FUnknownPtr (factory); + auto f2 = Steinberg::FUnknownPtr (factory); + Steinberg::PClassInfo ci; + Steinberg::PClassInfo2 ci2; + Steinberg::PClassInfoW ci3; + for (uint32_t i = 0; i < count; ++i) + { + if (f3 && f3->getClassInfoUnicode (i, &ci3) == Steinberg::kResultTrue) + classes.emplace_back (ci3); + else if (f2 && f2->getClassInfo2 (i, &ci2) == Steinberg::kResultTrue) + classes.emplace_back (ci2); + else if (factory->getClassInfo (i, &ci) == Steinberg::kResultTrue) + classes.emplace_back (ci); + auto& classInfo = classes.back (); + if (classInfo.vendor ().empty ()) + { + if (!factoryInfo) + factoryInfo = Optional (info ()); + classInfo.get ().vendor = factoryInfo->vendor (); + } + } + return classes; +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +const UID& ClassInfo::ID () const noexcept +{ + return data.classID; +} + +//------------------------------------------------------------------------ +int32_t ClassInfo::cardinality () const noexcept +{ + return data.cardinality; +} + +//------------------------------------------------------------------------ +const std::string& ClassInfo::category () const noexcept +{ + return data.category; +} + +//------------------------------------------------------------------------ +const std::string& ClassInfo::name () const noexcept +{ + return data.name; +} + +//------------------------------------------------------------------------ +const std::string& ClassInfo::vendor () const noexcept +{ + return data.vendor; +} + +//------------------------------------------------------------------------ +const std::string& ClassInfo::version () const noexcept +{ + return data.version; +} + +//------------------------------------------------------------------------ +const std::string& ClassInfo::sdkVersion () const noexcept +{ + return data.sdkVersion; +} + +//------------------------------------------------------------------------ +const ClassInfo::SubCategories& ClassInfo::subCategories () const noexcept +{ + return data.subCategories; +} + +//------------------------------------------------------------------------ +Steinberg::uint32 ClassInfo::classFlags () const noexcept +{ + return data.classFlags; +} + +//------------------------------------------------------------------------ +ClassInfo::ClassInfo (const PClassInfo& info) noexcept +{ + data.classID = info.cid; + data.cardinality = info.cardinality; + data.category = StringConvert::convert (info.category, PClassInfo::kCategorySize); + data.name = StringConvert::convert (info.name, PClassInfo::kNameSize); +} + +//------------------------------------------------------------------------ +ClassInfo::ClassInfo (const PClassInfo2& info) noexcept +{ + data.classID = info.cid; + data.cardinality = info.cardinality; + data.category = StringConvert::convert (info.category, PClassInfo::kCategorySize); + data.name = StringConvert::convert (info.name, PClassInfo::kNameSize); + data.vendor = StringConvert::convert (info.vendor, PClassInfo2::kVendorSize); + data.version = StringConvert::convert (info.version, PClassInfo2::kVersionSize); + data.sdkVersion = StringConvert::convert (info.sdkVersion, PClassInfo2::kVersionSize); + parseSubCategories ( + StringConvert::convert (info.subCategories, PClassInfo2::kSubCategoriesSize)); + data.classFlags = info.classFlags; +} + +//------------------------------------------------------------------------ +ClassInfo::ClassInfo (const PClassInfoW& info) noexcept +{ + data.classID = info.cid; + data.cardinality = info.cardinality; + data.category = StringConvert::convert (info.category, PClassInfo::kCategorySize); + data.name = StringConvert::convert (info.name, PClassInfo::kNameSize); + data.vendor = StringConvert::convert (info.vendor, PClassInfo2::kVendorSize); + data.version = StringConvert::convert (info.version, PClassInfo2::kVersionSize); + data.sdkVersion = StringConvert::convert (info.sdkVersion, PClassInfo2::kVersionSize); + parseSubCategories ( + StringConvert::convert (info.subCategories, PClassInfo2::kSubCategoriesSize)); + data.classFlags = info.classFlags; +} + +//------------------------------------------------------------------------ +void ClassInfo::parseSubCategories (const std::string& str) noexcept +{ + std::stringstream stream (str); + std::string item; + while (std::getline (stream, item, '|')) + data.subCategories.emplace_back (std::move (item)); +} + +//------------------------------------------------------------------------ +std::string ClassInfo::subCategoriesString () const noexcept +{ + std::string result; + if (data.subCategories.empty ()) + return result; + result = data.subCategories[0]; + for (auto index = 1u; index < data.subCategories.size (); ++index) + result += "|" + data.subCategories[index]; + return result; +} + +//------------------------------------------------------------------------ +namespace { + +//------------------------------------------------------------------------ +std::pair rangeOfScaleFactor (const std::string& name) +{ + auto result = std::make_pair (std::string::npos, std::string::npos); + size_t xIndex = name.find_last_of ('x'); + if (xIndex == std::string::npos) + return result; + + size_t indicatorIndex = name.find_last_of ('_'); + if (indicatorIndex == std::string::npos) + return result; + if (xIndex < indicatorIndex) + return result; + result.first = indicatorIndex + 1; + result.second = xIndex; + return result; +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +Optional Module::Snapshot::decodeScaleFactor (const std::string& name) +{ + auto range = rangeOfScaleFactor (name); + if (range.first == std::string::npos || range.second == std::string::npos) + return {}; + std::string tmp (name.data () + range.first, range.second - range.first); + std::istringstream sstream (tmp); + sstream.imbue (std::locale::classic ()); + sstream.precision (static_cast (3)); + double result; + sstream >> result; + return Optional (result); +} + +//------------------------------------------------------------------------ +Optional Module::Snapshot::decodeUID (const std::string& filename) +{ + if (filename.size () < 45) + return {}; + if (filename.find ("_snapshot") != 32) + return {}; + auto uidStr = filename.substr (0, 32); + return UID::fromString (uidStr); +} + +//------------------------------------------------------------------------ +} // Hosting +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h new file mode 100644 index 000000000000..36b3afad2e7c --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h @@ -0,0 +1,214 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/hosting/module.h +// Created by : Steinberg, 08/2016 +// Description : hosting module classes +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "../utility/uid.h" +#include "pluginterfaces/base/ipluginbase.h" +#include +#include + +//------------------------------------------------------------------------ +namespace VST3 { +namespace Hosting { + +//------------------------------------------------------------------------ +class FactoryInfo +{ +public: +//------------------------------------------------------------------------ + using PFactoryInfo = Steinberg::PFactoryInfo; + + FactoryInfo () noexcept {} + ~FactoryInfo () noexcept {} + FactoryInfo (const FactoryInfo&) noexcept = default; + FactoryInfo (PFactoryInfo&&) noexcept; + FactoryInfo (FactoryInfo&&) noexcept = default; + FactoryInfo& operator= (const FactoryInfo&) noexcept = default; + FactoryInfo& operator= (FactoryInfo&&) noexcept; + FactoryInfo& operator= (PFactoryInfo&&) noexcept; + + std::string vendor () const noexcept; + std::string url () const noexcept; + std::string email () const noexcept; + Steinberg::int32 flags () const noexcept; + bool classesDiscardable () const noexcept; + bool licenseCheck () const noexcept; + bool componentNonDiscardable () const noexcept; + + PFactoryInfo& get () noexcept { return info; } +//------------------------------------------------------------------------ +private: + PFactoryInfo info {}; +}; + +//------------------------------------------------------------------------ +class ClassInfo +{ +public: +//------------------------------------------------------------------------ + using SubCategories = std::vector; + using PClassInfo = Steinberg::PClassInfo; + using PClassInfo2 = Steinberg::PClassInfo2; + using PClassInfoW = Steinberg::PClassInfoW; + +//------------------------------------------------------------------------ + ClassInfo () noexcept {} + explicit ClassInfo (const PClassInfo& info) noexcept; + explicit ClassInfo (const PClassInfo2& info) noexcept; + explicit ClassInfo (const PClassInfoW& info) noexcept; + ClassInfo (const ClassInfo&) = default; + ClassInfo& operator= (const ClassInfo&) = default; + ClassInfo (ClassInfo&&) = default; + ClassInfo& operator= (ClassInfo&&) = default; + + const UID& ID () const noexcept; + int32_t cardinality () const noexcept; + const std::string& category () const noexcept; + const std::string& name () const noexcept; + const std::string& vendor () const noexcept; + const std::string& version () const noexcept; + const std::string& sdkVersion () const noexcept; + const SubCategories& subCategories () const noexcept; + std::string subCategoriesString () const noexcept; + Steinberg::uint32 classFlags () const noexcept; + + struct Data + { + UID classID; + int32_t cardinality; + std::string category; + std::string name; + std::string vendor; + std::string version; + std::string sdkVersion; + SubCategories subCategories; + Steinberg::uint32 classFlags = 0; + }; + + Data& get () noexcept { return data; } +//------------------------------------------------------------------------ +private: + void parseSubCategories (const std::string& str) noexcept; + Data data {}; +}; + +//------------------------------------------------------------------------ +class PluginFactory +{ +public: +//------------------------------------------------------------------------ + using ClassInfos = std::vector; + using PluginFactoryPtr = Steinberg::IPtr; + +//------------------------------------------------------------------------ + explicit PluginFactory (const PluginFactoryPtr& factory) noexcept; + + void setHostContext (Steinberg::FUnknown* context) const noexcept; + + FactoryInfo info () const noexcept; + uint32_t classCount () const noexcept; + ClassInfos classInfos () const noexcept; + + template + Steinberg::IPtr createInstance (const UID& classID) const noexcept; + + const PluginFactoryPtr& get () const noexcept { return factory; } +//------------------------------------------------------------------------ +private: + PluginFactoryPtr factory; +}; + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ +class Module +{ +public: +//------------------------------------------------------------------------ + struct Snapshot + { + struct ImageDesc + { + double scaleFactor {1.}; + std::string path; + }; + UID uid; + std::vector images; + + static Optional decodeScaleFactor (const std::string& path); + static Optional decodeUID (const std::string& filename); + }; + + using Ptr = std::shared_ptr; + using PathList = std::vector; + using SnapshotList = std::vector; + +//------------------------------------------------------------------------ + static Ptr create (const std::string& path, std::string& errorDescription); + static PathList getModulePaths (); + static SnapshotList getSnapshots (const std::string& modulePath); + /** get the path to the module info json file if it exists */ + static Optional getModuleInfoPath (const std::string& modulePath); + + const std::string& getName () const noexcept { return name; } + const std::string& getPath () const noexcept { return path; } + const PluginFactory& getFactory () const noexcept { return factory; } + bool isBundle () const noexcept { return hasBundleStructure; } +//------------------------------------------------------------------------ +protected: + virtual ~Module () noexcept = default; + virtual bool load (const std::string& path, std::string& errorDescription) = 0; + + PluginFactory factory {nullptr}; + std::string name; + std::string path; + bool hasBundleStructure {true}; +}; + +//------------------------------------------------------------------------ +template +inline Steinberg::IPtr PluginFactory::createInstance (const UID& classID) const noexcept +{ + T* obj = nullptr; + if (factory->createInstance (classID.data (), T::iid, reinterpret_cast (&obj)) == + Steinberg::kResultTrue) + return Steinberg::owned (obj); + return nullptr; +} + +//------------------------------------------------------------------------ +} // Hosting +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp new file mode 100644 index 000000000000..404054c82851 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp @@ -0,0 +1,369 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/hosting/module_linux.cpp +// Created by : Steinberg, 08/2016 +// Description : hosting module classes (linux implementation) +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "module.h" +#include "../utility/optional.h" +#include "../utility/stringconvert.h" +#include +#include +#include +#include +#include + +#if SMTG_CPP17 + +#if __has_include() +#define USE_EXPERIMENTAL_FS 0 +#elif __has_include() +#define USE_EXPERIMENTAL_FS 1 +#endif + +#else // !SMTG_CPP17 + +#define USE_EXPERIMENTAL_FS 1 + +#endif // SMTG_CPP17 + +#if USE_EXPERIMENTAL_FS == 1 + +#include +namespace filesystem = std::experimental::filesystem; + +#else // USE_FILESYSTEM == 0 + +#include +namespace filesystem = std::filesystem; + +#endif // USE_FILESYSTEM + +//------------------------------------------------------------------------ +extern "C" { +using ModuleEntryFunc = bool (PLUGIN_API*) (void*); +using ModuleExitFunc = bool (PLUGIN_API*) (); +} + +//------------------------------------------------------------------------ +namespace VST3 { +namespace Hosting { + +using Path = filesystem::path; + +//------------------------------------------------------------------------ +namespace { + +//------------------------------------------------------------------------ +Optional getCurrentMachineName () +{ + struct utsname unameData; + + int res = uname (&unameData); + if (res != 0) + return {}; + + return {unameData.machine}; +} + +//------------------------------------------------------------------------ +Optional getApplicationPath () +{ + std::string appPath = ""; + + pid_t pid = getpid (); + char buf[10]; + sprintf (buf, "%d", pid); + std::string _link = "/proc/"; + _link.append (buf); + _link.append ("/exe"); + char proc[1024]; + int ch = readlink (_link.c_str (), proc, 1024); + if (ch == -1) + return {}; + + proc[ch] = 0; + appPath = proc; + std::string::size_type t = appPath.find_last_of ("/"); + appPath = appPath.substr (0, t); + + return Path {appPath}; +} + +//------------------------------------------------------------------------ +class LinuxModule : public Module +{ +public: + template + T getFunctionPointer (const char* name) + { + return reinterpret_cast (dlsym (mModule, name)); + } + + ~LinuxModule () override + { + factory = PluginFactory (nullptr); + + if (mModule) + { + if (auto moduleExit = getFunctionPointer ("ModuleExit")) + moduleExit (); + + dlclose (mModule); + } + } + + static Optional getSOPath (const std::string& inPath) + { + Path modulePath {inPath}; + if (!filesystem::is_directory (modulePath)) + return {}; + + auto stem = modulePath.stem (); + + modulePath /= "Contents"; + if (!filesystem::is_directory (modulePath)) + return {}; + + // use the Machine Hardware Name (from uname cmd-line) as prefix for "-linux" + auto machine = getCurrentMachineName (); + if (!machine) + return {}; + + modulePath /= *machine + "-linux"; + if (!filesystem::is_directory (modulePath)) + return {}; + + stem.replace_extension (".so"); + modulePath /= stem; + return Optional (std::move (modulePath)); + } + + bool load (const std::string& inPath, std::string& errorDescription) override + { + auto modulePath = getSOPath (inPath); + if (!modulePath) + { + errorDescription = inPath + " is not a module directory."; + return false; + } + + mModule = dlopen (reinterpret_cast (modulePath->generic_string ().data ()), + RTLD_LAZY); + if (!mModule) + { + errorDescription = "dlopen failed.\n"; + errorDescription += dlerror (); + return false; + } + // ModuleEntry is mandatory + auto moduleEntry = getFunctionPointer ("ModuleEntry"); + if (!moduleEntry) + { + errorDescription = + "The shared library does not export the required 'ModuleEntry' function"; + return false; + } + // ModuleExit is mandatory + auto moduleExit = getFunctionPointer ("ModuleExit"); + if (!moduleExit) + { + errorDescription = + "The shared library does not export the required 'ModuleExit' function"; + return false; + } + auto factoryProc = getFunctionPointer ("GetPluginFactory"); + if (!factoryProc) + { + errorDescription = + "The shared library does not export the required 'GetPluginFactory' function"; + return false; + } + + if (!moduleEntry (mModule)) + { + errorDescription = "Calling 'ModuleEntry' failed"; + return false; + } + auto f = Steinberg::FUnknownPtr (owned (factoryProc ())); + if (!f) + { + errorDescription = "Calling 'GetPluginFactory' returned nullptr"; + return false; + } + factory = PluginFactory (f); + return true; + } + + void* mModule {nullptr}; +}; + +//------------------------------------------------------------------------ +void findFilesWithExt (const std::string& path, const std::string& ext, Module::PathList& pathList, + bool recursive = true) +{ + try + { + for (auto& p : filesystem::directory_iterator (path)) + { + if (p.path ().extension () == ext) + { + pathList.push_back (p.path ().generic_string ()); + } + else if (recursive && p.status ().type () == filesystem::file_type::directory) + { + findFilesWithExt (p.path (), ext, pathList); + } + } + } + catch (...) + { + } +} + +//------------------------------------------------------------------------ +void findModules (const std::string& path, Module::PathList& pathList) +{ + findFilesWithExt (path, ".vst3", pathList); +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +Module::Ptr Module::create (const std::string& path, std::string& errorDescription) +{ + auto _module = std::make_shared (); + if (_module->load (path, errorDescription)) + { + _module->path = path; + auto it = std::find_if (path.rbegin (), path.rend (), + [] (const std::string::value_type& c) { return c == '/'; }); + if (it != path.rend ()) + _module->name = {it.base (), path.end ()}; + return _module; + } + return nullptr; +} + +//------------------------------------------------------------------------ +Module::PathList Module::getModulePaths () +{ + /* VST3 component locations on linux : + * User privately installed : $HOME/.vst3/ + * Distribution installed : /usr/lib/vst3/ + * Locally installed : /usr/local/lib/vst3/ + * Application : /$APPFOLDER/vst3/ + */ + + const auto systemPaths = {"/usr/lib/vst3/", "/usr/local/lib/vst3/"}; + + PathList list; + if (auto homeDir = getenv ("HOME")) + { + filesystem::path homePath (homeDir); + homePath /= ".vst3"; + findModules (homePath.generic_string (), list); + } + for (auto path : systemPaths) + findModules (path, list); + + // application level + auto appPath = getApplicationPath (); + if (appPath) + { + *appPath /= "vst3"; + findModules (appPath->generic_string (), list); + } + + return list; +} + +//------------------------------------------------------------------------ +Module::SnapshotList Module::getSnapshots (const std::string& modulePath) +{ + SnapshotList result; + filesystem::path path (modulePath); + path /= "Contents"; + path /= "Resources"; + path /= "Snapshots"; + PathList pngList; + findFilesWithExt (path, ".png", pngList, false); + for (auto& png : pngList) + { + filesystem::path p (png); + auto filename = p.filename ().generic_string (); + auto uid = Snapshot::decodeUID (filename); + if (!uid) + continue; + auto scaleFactor = 1.; + if (auto decodedScaleFactor = Snapshot::decodeScaleFactor (filename)) + scaleFactor = *decodedScaleFactor; + + Module::Snapshot::ImageDesc desc; + desc.scaleFactor = scaleFactor; + desc.path = std::move (png); + bool found = false; + for (auto& entry : result) + { + if (entry.uid != *uid) + continue; + found = true; + entry.images.emplace_back (std::move (desc)); + break; + } + if (found) + continue; + Module::Snapshot snapshot; + snapshot.uid = *uid; + snapshot.images.emplace_back (std::move (desc)); + result.emplace_back (std::move (snapshot)); + } + return result; +} + +//------------------------------------------------------------------------ +Optional Module::getModuleInfoPath (const std::string& modulePath) +{ + filesystem::path path (modulePath); + path /= "Contents"; + path /= "Resources"; + path /= "moduleinfo.json"; + if (filesystem::exists (path)) + return {path.generic_string ()}; + return {}; +} + +//------------------------------------------------------------------------ +} // Hosting +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm new file mode 100644 index 000000000000..49a7155543a8 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm @@ -0,0 +1,390 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/hosting/module_mac.mm +// Created by : Steinberg, 08/2016 +// Description : hosting module classes (macOS implementation) +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#import "module.h" + +#import +#import + +#if !__has_feature(objc_arc) +#error this file needs to be compiled with automatic reference counting enabled +#endif + +//------------------------------------------------------------------------ +extern "C" { +typedef bool (*BundleEntryFunc) (CFBundleRef); +typedef bool (*BundleExitFunc) (); +} + +//------------------------------------------------------------------------ +namespace VST3 { +namespace Hosting { + +//------------------------------------------------------------------------ +namespace { + +//------------------------------------------------------------------------ +template +class CFPtr +{ +public: + inline CFPtr (const T& obj = nullptr) : obj (obj) {} + inline CFPtr (CFPtr&& other) { *this = other; } + inline ~CFPtr () + { + if (obj) + CFRelease (obj); + } + + inline CFPtr& operator= (CFPtr&& other) + { + obj = other.obj; + other.obj = nullptr; + return *this; + } + inline CFPtr& operator= (const T& o) + { + if (obj) + CFRelease (obj); + obj = o; + return *this; + } + inline operator T () const { return obj; } // act as T +private: + CFPtr (const CFPtr& other) = delete; + CFPtr& operator= (const CFPtr& other) = delete; + + T obj = nullptr; +}; + +//------------------------------------------------------------------------ +class MacModule : public Module +{ +public: + template + T getFunctionPointer (const char* name) + { + assert (bundle); + CFPtr functionName ( + CFStringCreateWithCString (kCFAllocatorDefault, name, kCFStringEncodingASCII)); + return reinterpret_cast (CFBundleGetFunctionPointerForName (bundle, functionName)); + } + + bool loadInternal (const std::string& path, std::string& errorDescription) + { + CFPtr url (CFURLCreateFromFileSystemRepresentation ( + kCFAllocatorDefault, reinterpret_cast (path.data ()), path.length (), + true)); + if (!url) + return false; + bundle = CFBundleCreate (kCFAllocatorDefault, url); + CFErrorRef error = nullptr; + if (!bundle || !CFBundleLoadExecutableAndReturnError (bundle, &error)) + { + if (error) + { + CFPtr errorString (CFErrorCopyDescription (error)); + if (errorString) + { + auto stringLength = CFStringGetLength (errorString); + auto maxSize = + CFStringGetMaximumSizeForEncoding (stringLength, kCFStringEncodingUTF8); + auto buffer = std::make_unique (maxSize); + if (CFStringGetCString (errorString, buffer.get (), maxSize, + kCFStringEncodingUTF8)) + errorDescription = buffer.get (); + CFRelease (error); + } + } + else + { + errorDescription = "Could not create Bundle for path: " + path; + } + return false; + } + // bundleEntry is mandatory + auto bundleEntry = getFunctionPointer ("bundleEntry"); + if (!bundleEntry) + { + errorDescription = "Bundle does not export the required 'bundleEntry' function"; + return false; + } + // bundleExit is mandatory + auto bundleExit = getFunctionPointer ("bundleExit"); + if (!bundleExit) + { + errorDescription = "Bundle does not export the required 'bundleExit' function"; + return false; + } + auto factoryProc = getFunctionPointer ("GetPluginFactory"); + if (!factoryProc) + { + errorDescription = "Bundle does not export the required 'GetPluginFactory' function"; + return false; + } + if (!bundleEntry (bundle)) + { + errorDescription = "Calling 'bundleEntry' failed"; + return false; + } + auto f = owned (factoryProc ()); + if (!f) + { + errorDescription = "Calling 'GetPluginFactory' returned nullptr"; + return false; + } + factory = PluginFactory (f); + return true; + } + + bool load (const std::string& path, std::string& errorDescription) override + { + if (!path.empty () && path[0] != '/') + { + auto buffer = std::make_unique (PATH_MAX); + auto workDir = getcwd (buffer.get (), PATH_MAX); + if (workDir) + { + std::string wd (workDir); + wd += "/"; + return loadInternal (wd + path, errorDescription); + } + } + return loadInternal (path, errorDescription); + } + + ~MacModule () override + { + factory = PluginFactory (nullptr); + + if (bundle) + { + if (auto bundleExit = getFunctionPointer ("bundleExit")) + bundleExit (); + } + } + + CFPtr bundle; +}; + +//------------------------------------------------------------------------ +void findModulesInDirectory (NSURL* dirUrl, Module::PathList& result) +{ + dirUrl = [dirUrl URLByResolvingSymlinksInPath]; + if (!dirUrl) + return; + NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] + enumeratorAtURL: dirUrl + includingPropertiesForKeys:nil + options:NSDirectoryEnumerationSkipsPackageDescendants + errorHandler:nil]; + for (NSURL* url in enumerator) + { + if ([[[url lastPathComponent] pathExtension] isEqualToString:@"vst3"]) + { + CFPtr archs ( + CFBundleCopyExecutableArchitecturesForURL (static_cast (url))); + if (archs) + result.emplace_back ([url.path UTF8String]); + } + else + { + id resValue; + if (![url getResourceValue:&resValue forKey:NSURLIsSymbolicLinkKey error:nil]) + continue; + if (!static_cast (resValue).boolValue) + continue; + auto resolvedUrl = [url URLByResolvingSymlinksInPath]; + if (![resolvedUrl getResourceValue:&resValue forKey:NSURLIsDirectoryKey error:nil]) + continue; + if (!static_cast (resValue).boolValue) + continue; + findModulesInDirectory (resolvedUrl, result); + } + } +} + +//------------------------------------------------------------------------ +void getModules (NSSearchPathDomainMask domain, Module::PathList& result) +{ + NSURL* libraryUrl = [[NSFileManager defaultManager] URLForDirectory:NSLibraryDirectory + inDomain:domain + appropriateForURL:nil + create:NO + error:nil]; + if (libraryUrl == nil) + return; + NSURL* audioUrl = [libraryUrl URLByAppendingPathComponent:@"Audio"]; + if (audioUrl == nil) + return; + NSURL* plugInsUrl = [audioUrl URLByAppendingPathComponent:@"Plug-Ins"]; + if (plugInsUrl == nil) + return; + NSURL* vst3Url = + [[plugInsUrl URLByAppendingPathComponent:@"VST3"] URLByResolvingSymlinksInPath]; + if (vst3Url == nil) + return; + findModulesInDirectory (vst3Url, result); +} + +//------------------------------------------------------------------------ +void getApplicationModules (Module::PathList& result) +{ + auto bundle = CFBundleGetMainBundle (); + if (!bundle) + return; + auto bundleUrl = static_cast (CFBridgingRelease (CFBundleCopyBundleURL (bundle))); + if (!bundleUrl) + return; + auto resUrl = [bundleUrl URLByAppendingPathComponent:@"Contents"]; + if (!resUrl) + return; + auto vst3Url = [resUrl URLByAppendingPathComponent:@"VST3"]; + if (!vst3Url) + return; + findModulesInDirectory (vst3Url, result); +} + +//------------------------------------------------------------------------ +void getModuleSnapshots (const std::string& path, Module::SnapshotList& result) +{ + auto nsString = [NSString stringWithUTF8String:path.data ()]; + if (!nsString) + return; + auto bundleUrl = [NSURL fileURLWithPath:nsString]; + if (!bundleUrl) + return; + auto urls = [NSBundle URLsForResourcesWithExtension:@"png" + subdirectory:@"Snapshots" + inBundleWithURL:bundleUrl]; + if (!urls || [urls count] == 0) + return; + + for (NSURL* url in urls) + { + std::string fullpath ([[url path] UTF8String]); + std::string filename ([[[url path] lastPathComponent] UTF8String]); + auto uid = Module::Snapshot::decodeUID (filename); + if (!uid) + continue; + + auto scaleFactor = 1.; + if (auto decodedScaleFactor = Module::Snapshot::decodeScaleFactor (filename)) + scaleFactor = *decodedScaleFactor; + + Module::Snapshot::ImageDesc desc; + desc.scaleFactor = scaleFactor; + desc.path = std::move (fullpath); + bool found = false; + for (auto& entry : result) + { + if (entry.uid != *uid) + continue; + found = true; + entry.images.emplace_back (std::move (desc)); + break; + } + if (found) + continue; + Module::Snapshot snapshot; + snapshot.uid = *uid; + snapshot.images.emplace_back (std::move (desc)); + result.emplace_back (std::move (snapshot)); + } +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +Module::Ptr Module::create (const std::string& path, std::string& errorDescription) +{ + auto module = std::make_shared (); + if (module->load (path, errorDescription)) + { + module->path = path; + auto it = std::find_if (path.rbegin (), path.rend (), + [] (const std::string::value_type& c) { return c == '/'; }); + if (it != path.rend ()) + module->name = {it.base (), path.end ()}; + return std::move (module); + } + return nullptr; +} + +//------------------------------------------------------------------------ +Module::PathList Module::getModulePaths () +{ + PathList list; + getModules (NSUserDomainMask, list); + getModules (NSLocalDomainMask, list); + // TODO getModules (NSNetworkDomainMask, list); + getApplicationModules (list); + return list; +} + +//------------------------------------------------------------------------ +Module::SnapshotList Module::getSnapshots (const std::string& modulePath) +{ + SnapshotList list; + getModuleSnapshots (modulePath, list); + return list; +} + +//------------------------------------------------------------------------ +Optional Module::getModuleInfoPath (const std::string& modulePath) +{ + auto nsString = [NSString stringWithUTF8String:modulePath.data ()]; + if (!nsString) + return {}; + auto bundleUrl = [NSURL fileURLWithPath:nsString]; + if (!bundleUrl) + return {}; + auto moduleInfoUrl = [NSBundle URLForResource:@"moduleinfo" + withExtension:@"json" + subdirectory:nullptr + inBundleWithURL:bundleUrl]; + if (!moduleInfoUrl) + return {}; + NSError* error = nil; + if ([moduleInfoUrl checkResourceIsReachableAndReturnError:&error]) + return {std::string (moduleInfoUrl.fileSystemRepresentation)}; + return {}; +} + +//------------------------------------------------------------------------ +} // Hosting +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp new file mode 100644 index 000000000000..77990fdcca3b --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp @@ -0,0 +1,647 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/hosting/module_win32.cpp +// Created by : Steinberg, 08/2016 +// Description : hosting module classes (win32 implementation) +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "../utility/optional.h" +#include "../utility/stringconvert.h" +#include "module.h" + +#include +#include + +#include +#include + +#if SMTG_CPP17 + +#if __has_include() +#define USE_FILESYSTEM 1 +#elif __has_include() +#define USE_FILESYSTEM 0 +#endif + +#else // !SMTG_CPP17 + +#define USE_FILESYSTEM 0 + +#endif // SMTG_CPP17 + +#if USE_FILESYSTEM == 1 + +#include +namespace filesystem = std::filesystem; + +#else // USE_FILESYSTEM == 0 + +// The header is deprecated. It is superseded by the C++17 +// header. You can define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING to silence the +// warning, otherwise the build will fail in VS2019 16.3.0 +#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING +#include +namespace filesystem = std::experimental::filesystem; + +#endif // USE_FILESYSTEM + +#pragma comment(lib, "Shell32") + +//------------------------------------------------------------------------ +extern "C" { +using InitModuleFunc = bool (PLUGIN_API*) (); +using ExitModuleFunc = bool (PLUGIN_API*) (); +} + +//------------------------------------------------------------------------ +namespace VST3 { +namespace Hosting { + +constexpr unsigned long kIPPathNameMax = 1024; + +//------------------------------------------------------------------------ +namespace { + +#define USE_OLE !USE_FILESYSTEM + +// for testing only +#if 0 // DEVELOPMENT +#define LOG_ENABLE 1 +#else +#define LOG_ENABLE 0 +#endif + +#if SMTG_PLATFORM_64 + +#if SMTG_OS_WINDOWS_ARM + +#if SMTG_CPU_ARM_64EC +constexpr auto architectureString = "arm64ec-win"; +constexpr auto architectureX64String = "x86_64-win"; +#else // !SMTG_CPU_ARM_64EC +constexpr auto architectureString = "arm64-win"; +#endif // SMTG_CPU_ARM_64EC + +constexpr auto architectureArm64XString = "arm64x-win"; + +#else // !SMTG_OS_WINDOWS_ARM +constexpr auto architectureString = "x86_64-win"; +#endif // SMTG_OS_WINDOWS_ARM + +#else // !SMTG_PLATFORM_64 + +#if SMTG_OS_WINDOWS_ARM +constexpr auto architectureString = "arm-win"; +#else // !SMTG_OS_WINDOWS_ARM +constexpr auto architectureString = "x86-win"; +#endif // SMTG_OS_WINDOWS_ARM + +#endif // SMTG_PLATFORM_64 + +#if USE_OLE +//------------------------------------------------------------------------ +struct Ole +{ + static Ole& instance () + { + static Ole gInstance; + return gInstance; + } + +private: + Ole () { OleInitialize (nullptr); } + ~Ole () { OleUninitialize (); } +}; +#endif // USE_OLE + +//------------------------------------------------------------------------ +class Win32Module : public Module +{ +public: + template + T getFunctionPointer (const char* name) + { + return reinterpret_cast (GetProcAddress (mModule, name)); + } + + ~Win32Module () override + { + factory = PluginFactory (nullptr); + + if (mModule) + { + // ExitDll is optional + if (auto dllExit = getFunctionPointer ("ExitDll")) + dllExit (); + + FreeLibrary ((HMODULE)mModule); + } + } + + //--- ----------------------------------------------------------------------- + HINSTANCE loadAsPackage (const std::string& inPath, const char* archString = architectureString) + { + filesystem::path p (inPath); + auto filename = p.filename (); + p /= "Contents"; + p /= archString; + p /= filename; + auto wideStr = StringConvert::convert (p.string ()); + HINSTANCE instance = LoadLibraryW (reinterpret_cast (wideStr.data ())); +#if SMTG_CPU_ARM_64EC + if (instance == nullptr) + instance = loadAsPackage (inPath, architectureArm64XString); + if (instance == nullptr) + instance = loadAsPackage (inPath, architectureX64String); +#endif + return instance; + } + + //--- ----------------------------------------------------------------------- + HINSTANCE loadAsDll (const std::string& inPath, std::string& errorDescription) + { + auto wideStr = StringConvert::convert (inPath); + HINSTANCE instance = LoadLibraryW (reinterpret_cast (wideStr.data ())); + if (instance == nullptr) + { + auto lastError = GetLastError (); + LPVOID lpMessageBuffer {nullptr}; + if (FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + nullptr, lastError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&lpMessageBuffer, 0, nullptr) > 0) + { + errorDescription = "LoadLibray failed: " + std::string ((char*)lpMessageBuffer); + LocalFree (lpMessageBuffer); + } + else + { + errorDescription = + "LoadLibrary failed with error number : " + std::to_string (lastError); + } + } + else + { + hasBundleStructure = false; + } + return instance; + } + + //--- ----------------------------------------------------------------------- + bool load (const std::string& inPath, std::string& errorDescription) override + { + // filesystem::u8path is deprecated in C++20 +#if SMTG_CPP20 + const filesystem::path tmp (inPath); +#else + const filesystem::path tmp = filesystem::u8path (inPath); +#endif + if (filesystem::is_directory (tmp)) + { + // try as package (bundle) + mModule = loadAsPackage (inPath); + } + else + { + // try old definition without package + mModule = loadAsDll (inPath, errorDescription); + } + if (mModule == nullptr) + return false; + + auto factoryProc = getFunctionPointer ("GetPluginFactory"); + if (!factoryProc) + { + errorDescription = "The dll does not export the required 'GetPluginFactory' function"; + return false; + } + // InitDll is optional + auto dllEntry = getFunctionPointer ("InitDll"); + if (dllEntry && !dllEntry ()) + { + errorDescription = "Calling 'InitDll' failed"; + return false; + } + auto f = Steinberg::FUnknownPtr (owned (factoryProc ())); + if (!f) + { + errorDescription = "Calling 'GetPluginFactory' returned nullptr"; + return false; + } + factory = PluginFactory (f); + return true; + } + + HINSTANCE mModule {nullptr}; +}; + +//------------------------------------------------------------------------ +bool openVST3Package (const filesystem::path& p, const char* archString, + filesystem::path* result = nullptr) +{ + auto path = p; + path /= "Contents"; + path /= archString; + path /= p.filename (); + auto hFile = CreateFileW (reinterpret_cast (path.c_str ()), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle (hFile); + if (result) + *result = path; + return true; + } + return false; +} + +//------------------------------------------------------------------------ +bool checkVST3Package (const filesystem::path& p, filesystem::path* result = nullptr, + const char* archString = architectureString) +{ + if (openVST3Package (p, archString, result)) + return true; + +#if SMTG_CPU_ARM_64EC + if (openVST3Package (p, architectureArm64XString, result)) + return true; + if (openVST3Package (p, architectureX64String, result)) + return true; +#endif + return false; +} + +//------------------------------------------------------------------------ +bool isFolderSymbolicLink (const filesystem::path& p) +{ +#if USE_FILESYSTEM + if (/*filesystem::exists (p) &&*/ filesystem::is_symlink (p)) + return true; +#else + std::wstring wString = p.generic_wstring (); + auto attrib = GetFileAttributesW (reinterpret_cast (wString.c_str ())); + if (attrib & FILE_ATTRIBUTE_REPARSE_POINT) + { + auto hFile = CreateFileW (reinterpret_cast (wString.c_str ()), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + return true; + CloseHandle (hFile); + } +#endif + return false; +} + +//------------------------------------------------------------------------ +Optional getKnownFolder (REFKNOWNFOLDERID folderID) +{ + PWSTR wideStr {}; + if (FAILED (SHGetKnownFolderPath (folderID, 0, nullptr, &wideStr))) + return {}; + return StringConvert::convert (Steinberg::wscast (wideStr)); +} + +//------------------------------------------------------------------------ +VST3::Optional resolveShellLink (const filesystem::path& p) +{ +#if USE_FILESYSTEM + return {filesystem::read_symlink (p).lexically_normal ()}; +#elif USE_OLE + Ole::instance (); + + IShellLink* shellLink = nullptr; + if (!SUCCEEDED (CoCreateInstance (CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, + IID_IShellLink, reinterpret_cast (&shellLink)))) + return {}; + + IPersistFile* persistFile = nullptr; + if (!SUCCEEDED ( + shellLink->QueryInterface (IID_IPersistFile, reinterpret_cast (&persistFile)))) + return {}; + + if (!SUCCEEDED (persistFile->Load (p.wstring ().data (), STGM_READ))) + return {}; + + if (!SUCCEEDED (shellLink->Resolve (nullptr, MAKELONG (SLR_NO_UI, 500)))) + return {}; + + WCHAR resolvedPath[kIPPathNameMax]; + if (!SUCCEEDED (shellLink->GetPath (resolvedPath, kIPPathNameMax, nullptr, SLGP_SHORTPATH))) + return {}; + + std::wstring longPath; + longPath.resize (kIPPathNameMax); + auto numChars = + GetLongPathNameW (resolvedPath, const_cast (longPath.data ()), kIPPathNameMax); + if (!numChars) + return {}; + longPath.resize (numChars); + + persistFile->Release (); + shellLink->Release (); + + return {filesystem::path (longPath)}; +#else + return {}; +#endif +} + +//------------------------------------------------------------------------ +void addToPathList (Module::PathList& pathList, const std::string& toAdd) +{ +#if LOG_ENABLE + std::cout << "=> add: " << toAdd << "\n"; +#endif + + pathList.push_back (toAdd); +} + +//------------------------------------------------------------------------ +void findFilesWithExt (const filesystem::path& path, const std::string& ext, + Module::PathList& pathList, bool recursive = true) +{ + for (auto& p : filesystem::directory_iterator (path)) + { +#if USE_FILESYSTEM + filesystem::path finalPath (p); + if (isFolderSymbolicLink (p)) + { + if (auto res = resolveShellLink (p)) + { + finalPath = *res; + if (!filesystem::exists (finalPath)) + continue; + } + else + continue; + } + const auto& cpExt = finalPath.extension (); + if (cpExt == ext) + { + filesystem::path result; + if (checkVST3Package (finalPath, &result)) + { + addToPathList (pathList, result.generic_string ()); + continue; + } + } + + if (filesystem::is_directory (finalPath)) + { + if (recursive) + findFilesWithExt (finalPath, ext, pathList, recursive); + } + else if (cpExt == ext) + addToPathList (pathList, finalPath.generic_string ()); +#else + const auto& cp = p.path (); + const auto& cpExt = cp.extension (); + if (cpExt == ext) + { + if ((p.status ().type () == filesystem::file_type::directory) || + isFolderSymbolicLink (p)) + { + filesystem::path result; + if (checkVST3Package (p, &result)) + { + addToPathList (pathList, result.generic_u8string ()); + continue; + } + findFilesWithExt (cp, ext, pathList, recursive); + } + else + addToPathList (pathList, cp.generic_u8string ()); + } + else if (recursive) + { + if (p.status ().type () == filesystem::file_type::directory) + { + findFilesWithExt (cp, ext, pathList, recursive); + } + else if (cpExt == ".lnk") + { + if (auto resolvedLink = resolveShellLink (cp)) + { + if (resolvedLink->extension () == ext) + { + if (filesystem::is_directory (*resolvedLink) || + isFolderSymbolicLink (*resolvedLink)) + { + filesystem::path result; + if (checkVST3Package (*resolvedLink, &result)) + { + addToPathList (pathList, result.generic_u8string ()); + continue; + } + findFilesWithExt (*resolvedLink, ext, pathList, recursive); + } + else + addToPathList (pathList, resolvedLink->generic_u8string ()); + } + else if (filesystem::is_directory (*resolvedLink)) + { + const auto& str = resolvedLink->generic_u8string (); + if (cp.generic_u8string ().compare (0, str.size (), str.data (), + str.size ()) != 0) + findFilesWithExt (*resolvedLink, ext, pathList, recursive); + } + } + } + } +#endif + } +} + +//------------------------------------------------------------------------ +void findModules (const filesystem::path& path, Module::PathList& pathList) +{ + if (filesystem::exists (path)) + findFilesWithExt (path, ".vst3", pathList); +} + +//------------------------------------------------------------------------ +Optional getContentsDirectoryFromModuleExecutablePath ( + const std::string& modulePath) +{ + filesystem::path path (modulePath); + + path = path.parent_path (); + if (path.filename () != architectureString) + return {}; + path = path.parent_path (); + if (path.filename () != "Contents") + return {}; + + return Optional {std::move (path)}; +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +Module::Ptr Module::create (const std::string& path, std::string& errorDescription) +{ + auto _module = std::make_shared (); + if (_module->load (path, errorDescription)) + { + _module->path = path; + auto it = std::find_if (path.rbegin (), path.rend (), + [] (const std::string::value_type& c) { return c == '/'; }); + if (it != path.rend ()) + _module->name = {it.base (), path.end ()}; + return _module; + } + return nullptr; +} + +//------------------------------------------------------------------------ +Module::PathList Module::getModulePaths () +{ + // find plug-ins located in common/VST3 + PathList list; + if (auto knownFolder = getKnownFolder (FOLDERID_UserProgramFilesCommon)) + { + filesystem::path path (*knownFolder); + path.append ("VST3"); +#if LOG_ENABLE + std::cout << "Check folder: " << path << "\n"; +#endif + findModules (path, list); + } + + if (auto knownFolder = getKnownFolder (FOLDERID_ProgramFilesCommon)) + { + filesystem::path path (*knownFolder); + path.append ("VST3"); +#if LOG_ENABLE + std::cout << "Check folder: " << path << "\n"; +#endif + findModules (path, list); + } + + // find plug-ins located in VST3 (application folder) + WCHAR modulePath[kIPPathNameMax]; + GetModuleFileNameW (nullptr, modulePath, kIPPathNameMax); + auto appPath = StringConvert::convert (Steinberg::wscast (modulePath)); + filesystem::path path (appPath); + path = path.parent_path (); + path = path.append ("VST3"); +#if LOG_ENABLE + std::cout << "Check folder: " << path << "\n"; +#endif + findModules (path, list); + + return list; +} + +//------------------------------------------------------------------------ +Optional Module::getModuleInfoPath (const std::string& modulePath) +{ + auto path = getContentsDirectoryFromModuleExecutablePath (modulePath); + if (!path) + { + filesystem::path p; + if (!checkVST3Package ({modulePath}, &p)) + return {}; + p = p.parent_path (); + p = p.parent_path (); + path = Optional {p}; + } + + *path /= "Resources"; + *path /= "moduleinfo.json"; + + if (filesystem::exists (*path)) + { + return {path->generic_string ()}; + } + return {}; +} + +//------------------------------------------------------------------------ +Module::SnapshotList Module::getSnapshots (const std::string& modulePath) +{ + SnapshotList result; + auto path = getContentsDirectoryFromModuleExecutablePath (modulePath); + if (!path) + { + filesystem::path p; + if (!checkVST3Package ({modulePath}, &p)) + return result; + p = p.parent_path (); + p = p.parent_path (); + path = Optional (p); + } + + *path /= "Resources"; + *path /= "Snapshots"; + + if (filesystem::exists (*path) == false) + return result; + + PathList pngList; + findFilesWithExt (*path, ".png", pngList, false); + for (auto& png : pngList) + { + filesystem::path p (png); + auto filename = p.filename ().generic_string (); + auto uid = Snapshot::decodeUID (filename); + if (!uid) + continue; + auto scaleFactor = 1.; + if (auto decodedScaleFactor = Snapshot::decodeScaleFactor (filename)) + scaleFactor = *decodedScaleFactor; + + Module::Snapshot::ImageDesc desc; + desc.scaleFactor = scaleFactor; + desc.path = std::move (png); + bool found = false; + for (auto& entry : result) + { + if (entry.uid != *uid) + continue; + found = true; + entry.images.emplace_back (std::move (desc)); + break; + } + if (found) + continue; + Module::Snapshot snapshot; + snapshot.uid = *uid; + snapshot.images.emplace_back (std::move (desc)); + result.emplace_back (std::move (snapshot)); + } + return result; +} + +//------------------------------------------------------------------------ +} // Hosting +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp index c4d2a665f0e4..adabdb902801 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -43,12 +43,14 @@ #include +//----------------------------------------------------------------------------- namespace Steinberg { namespace Vst { //----------------------------------------------------------------------------- PlugInterfaceSupport::PlugInterfaceSupport () { + FUNKNOWN_CTOR // add minimum set //---VST 3.0.0-------------------------------- @@ -117,9 +119,16 @@ void PlugInterfaceSupport::addPlugInterfaceSupported (const TUID _iid) //----------------------------------------------------------------------------- bool PlugInterfaceSupport::removePlugInterfaceSupported (const TUID _iid) { - return std::remove (mFUIDArray.begin (), mFUIDArray.end (), FUID::fromTUID (_iid)) != - mFUIDArray.end (); + auto uid = FUID::fromTUID (_iid); + auto it = std::find (mFUIDArray.begin (), mFUIDArray.end (), uid); + if (it == mFUIDArray.end ()) + return false; + mFUIDArray.erase (it); + return true; } -} -} // namespace +IMPLEMENT_FUNKNOWN_METHODS (PlugInterfaceSupport, IPlugInterfaceSupport, IPlugInterfaceSupport::iid) + +//----------------------------------------------------------------------------- +} // Vst +} // Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h index ad204b785940..a88cbf6815ab 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -39,19 +39,19 @@ #include "pluginterfaces/vst/ivstpluginterfacesupport.h" #include -#include "base/source/fobject.h" namespace Steinberg { namespace Vst { //------------------------------------------------------------------------ -/** Implementation's example of IPlugInterfaceSupport. +/** Example implementation of IPlugInterfaceSupport. \ingroup hostingBase */ -class PlugInterfaceSupport : public FObject, public IPlugInterfaceSupport +class PlugInterfaceSupport : public IPlugInterfaceSupport { public: PlugInterfaceSupport (); + virtual ~PlugInterfaceSupport () = default; //--- IPlugInterfaceSupport --------- tresult PLUGIN_API isPlugInterfaceSupported (const TUID _iid) SMTG_OVERRIDE; @@ -59,11 +59,7 @@ class PlugInterfaceSupport : public FObject, public IPlugInterfaceSupport void addPlugInterfaceSupported (const TUID _iid); bool removePlugInterfaceSupported (const TUID _iid); - OBJ_METHODS (PlugInterfaceSupport, FObject) - REFCOUNT_METHODS (FObject) - DEFINE_INTERFACES - DEF_INTERFACE (IPlugInterfaceSupport) - END_DEFINE_INTERFACES (FObject) + DECLARE_FUNKNOWN_METHODS private: std::vector mFUIDArray; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md new file mode 100644 index 000000000000..6c93872098a1 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md @@ -0,0 +1,43 @@ + +# ModuleInfoLib + +This is a c++17 library to parse and create the Steinberg moduleinfo.json files. + +## Parsing + +To parse a moduleinfo.json file you need to include the following files to your project: + +* moduleinfoparser.cpp +* moduleinfoparser.h +* moduleinfo.h +* json.h +* jsoncxx.h + +And add a header search path to the root folder of the VST SDK. + +Now to parse a moduleinfo.json file in code you need to read the moduleinfo.json into a memory buffer and call + +``` c++ +auto moduleInfo = ModuleInfoLib::parseCompatibilityJson (std::string_view (buffer, bufferSize), &std::cerr); +``` + +Afterwards if parsing succeeded the moduleInfo optional has a value containing the ModuleInfo. + +## Creating + +The VST3 SDK contains the moduleinfotool utility that can create moduleinfo.json files from VST3 modules. + +To add this capability to your own project you need to link to the sdk_hosting library from the SDK and include the following files to your project: + +* moduleinfocreator.cpp +* moduleinfocreator.h +* moduleinfo.h + +Additionally you need to add the module platform implementation from the hosting directory (module_win32.cpp, module_mac.mm or module_linux.cpp). + +Now you can use the two methods in moduleinfocreator.h to create a moduleinfo.json file: + +``` c++ +auto moduleInfo = ModuleInfoLib::createModuleInfo (module, false); +ModuleInfoLib::outputJson (moduleInfo, std::cout); +``` diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h new file mode 100644 index 000000000000..da8a6ad779e2 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/json.h @@ -0,0 +1,3403 @@ +/* + The latest version of this library is available on GitHub; + https://github.com/sheredom/json.h. +*/ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to . +*/ + +#ifndef SHEREDOM_JSON_H_INCLUDED +#define SHEREDOM_JSON_H_INCLUDED + +#if defined(_MSC_VER) +#pragma warning(push) + +/* disable warning: no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable : 4255) + +/* disable warning: '__cplusplus' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable : 4668) + +/* disable warning: 'bytes padding added after construct' */ +#pragma warning(disable : 4820) +#endif + +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW32__) +#define json_weak __inline +#elif defined(__clang__) || defined(__GNUC__) +#define json_weak __attribute__((weak)) +#else +#error Non clang, non gcc, non MSVC compiler found! +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct json_value_s; +struct json_parse_result_s; + +enum json_parse_flags_e { + json_parse_flags_default = 0, + + /* allow trailing commas in objects and arrays. For example, both [true,] and + {"a" : null,} would be allowed with this option on. */ + json_parse_flags_allow_trailing_comma = 0x1, + + /* allow unquoted keys for objects. For example, {a : null} would be allowed + with this option on. */ + json_parse_flags_allow_unquoted_keys = 0x2, + + /* allow a global unbracketed object. For example, a : null, b : true, c : {} + would be allowed with this option on. */ + json_parse_flags_allow_global_object = 0x4, + + /* allow objects to use '=' instead of ':' between key/value pairs. For + example, a = null, b : true would be allowed with this option on. */ + json_parse_flags_allow_equals_in_object = 0x8, + + /* allow that objects don't have to have comma separators between key/value + pairs. */ + json_parse_flags_allow_no_commas = 0x10, + + /* allow c-style comments (either variants) to be ignored in the input JSON + file. */ + json_parse_flags_allow_c_style_comments = 0x20, + + /* deprecated flag, unused. */ + json_parse_flags_deprecated = 0x40, + + /* record location information for each value. */ + json_parse_flags_allow_location_information = 0x80, + + /* allow strings to be 'single quoted'. */ + json_parse_flags_allow_single_quoted_strings = 0x100, + + /* allow numbers to be hexadecimal. */ + json_parse_flags_allow_hexadecimal_numbers = 0x200, + + /* allow numbers like +123 to be parsed. */ + json_parse_flags_allow_leading_plus_sign = 0x400, + + /* allow numbers like .0123 or 123. to be parsed. */ + json_parse_flags_allow_leading_or_trailing_decimal_point = 0x800, + + /* allow Infinity, -Infinity, NaN, -NaN. */ + json_parse_flags_allow_inf_and_nan = 0x1000, + + /* allow multi line string values. */ + json_parse_flags_allow_multi_line_strings = 0x2000, + + /* allow simplified JSON to be parsed. Simplified JSON is an enabling of a set + of other parsing options. */ + json_parse_flags_allow_simplified_json = + (json_parse_flags_allow_trailing_comma | + json_parse_flags_allow_unquoted_keys | + json_parse_flags_allow_global_object | + json_parse_flags_allow_equals_in_object | + json_parse_flags_allow_no_commas), + + /* allow JSON5 to be parsed. JSON5 is an enabling of a set of other parsing + options. */ + json_parse_flags_allow_json5 = + (json_parse_flags_allow_trailing_comma | + json_parse_flags_allow_unquoted_keys | + json_parse_flags_allow_c_style_comments | + json_parse_flags_allow_single_quoted_strings | + json_parse_flags_allow_hexadecimal_numbers | + json_parse_flags_allow_leading_plus_sign | + json_parse_flags_allow_leading_or_trailing_decimal_point | + json_parse_flags_allow_inf_and_nan | + json_parse_flags_allow_multi_line_strings) +}; + +/* Parse a JSON text file, returning a pointer to the root of the JSON + * structure. json_parse performs 1 call to malloc for the entire encoding. + * Returns 0 if an error occurred (malformed JSON input, or malloc failed). */ +json_weak struct json_value_s *json_parse(const void *src, size_t src_size); + +/* Parse a JSON text file, returning a pointer to the root of the JSON + * structure. json_parse performs 1 call to alloc_func_ptr for the entire + * encoding. Returns 0 if an error occurred (malformed JSON input, or malloc + * failed). If an error occurred, the result struct (if not NULL) will explain + * the type of error, and the location in the input it occurred. If + * alloc_func_ptr is null then malloc is used. */ +json_weak struct json_value_s * +json_parse_ex(const void *src, size_t src_size, size_t flags_bitset, + void *(*alloc_func_ptr)(void *, size_t), void *user_data, + struct json_parse_result_s *result); + +/* Extracts a value and all the data that makes it up into a newly created + * value. json_extract_value performs 1 call to malloc for the entire encoding. + */ +json_weak struct json_value_s * +json_extract_value(const struct json_value_s *value); + +/* Extracts a value and all the data that makes it up into a newly created + * value. json_extract_value performs 1 call to alloc_func_ptr for the entire + * encoding. If alloc_func_ptr is null then malloc is used. */ +json_weak struct json_value_s * +json_extract_value_ex(const struct json_value_s *value, + void *(*alloc_func_ptr)(void *, size_t), void *user_data); + +/* Write out a minified JSON utf-8 string. This string is an encoding of the + * minimal string characters required to still encode the same data. + * json_write_minified performs 1 call to malloc for the entire encoding. Return + * 0 if an error occurred (malformed JSON input, or malloc failed). The out_size + * parameter is optional as the utf-8 string is null terminated. */ +json_weak void *json_write_minified(const struct json_value_s *value, + size_t *out_size); + +/* Write out a pretty JSON utf-8 string. This string is encoded such that the + * resultant JSON is pretty in that it is easily human readable. The indent and + * newline parameters allow a user to specify what kind of indentation and + * newline they want (two spaces / three spaces / tabs? \r, \n, \r\n ?). Both + * indent and newline can be NULL, indent defaults to two spaces (" "), and + * newline defaults to linux newlines ('\n' as the newline character). + * json_write_pretty performs 1 call to malloc for the entire encoding. Return 0 + * if an error occurred (malformed JSON input, or malloc failed). The out_size + * parameter is optional as the utf-8 string is null terminated. */ +json_weak void *json_write_pretty(const struct json_value_s *value, + const char *indent, const char *newline, + size_t *out_size); + +/* Reinterpret a JSON value as a string. Returns null is the value was not a + * string. */ +json_weak struct json_string_s * +json_value_as_string(struct json_value_s *const value); + +/* Reinterpret a JSON value as a number. Returns null is the value was not a + * number. */ +json_weak struct json_number_s * +json_value_as_number(struct json_value_s *const value); + +/* Reinterpret a JSON value as an object. Returns null is the value was not an + * object. */ +json_weak struct json_object_s * +json_value_as_object(struct json_value_s *const value); + +/* Reinterpret a JSON value as an array. Returns null is the value was not an + * array. */ +json_weak struct json_array_s * +json_value_as_array(struct json_value_s *const value); + +/* Whether the value is true. */ +json_weak int json_value_is_true(const struct json_value_s *const value); + +/* Whether the value is false. */ +json_weak int json_value_is_false(const struct json_value_s *const value); + +/* Whether the value is null. */ +json_weak int json_value_is_null(const struct json_value_s *const value); + +/* The various types JSON values can be. Used to identify what a value is. */ +enum json_type_e { + json_type_string, + json_type_number, + json_type_object, + json_type_array, + json_type_true, + json_type_false, + json_type_null +}; + +/* A JSON string value. */ +struct json_string_s { + /* utf-8 string */ + const char *string; + /* The size (in bytes) of the string */ + size_t string_size; +}; + +/* A JSON string value (extended). */ +struct json_string_ex_s { + /* The JSON string this extends. */ + struct json_string_s string; + + /* The character offset for the value in the JSON input. */ + size_t offset; + + /* The line number for the value in the JSON input. */ + size_t line_no; + + /* The row number for the value in the JSON input, in bytes. */ + size_t row_no; +}; + +/* A JSON number value. */ +struct json_number_s { + /* ASCII string containing representation of the number. */ + const char *number; + /* the size (in bytes) of the number. */ + size_t number_size; +}; + +/* an element of a JSON object. */ +struct json_object_element_s { + /* the name of this element. */ + struct json_string_s *name; + /* the value of this element. */ + struct json_value_s *value; + /* the next object element (can be NULL if the last element in the object). */ + struct json_object_element_s *next; +}; + +/* a JSON object value. */ +struct json_object_s { + /* a linked list of the elements in the object. */ + struct json_object_element_s *start; + /* the number of elements in the object. */ + size_t length; +}; + +/* an element of a JSON array. */ +struct json_array_element_s { + /* the value of this element. */ + struct json_value_s *value; + /* the next array element (can be NULL if the last element in the array). */ + struct json_array_element_s *next; +}; + +/* a JSON array value. */ +struct json_array_s { + /* a linked list of the elements in the array. */ + struct json_array_element_s *start; + /* the number of elements in the array. */ + size_t length; +}; + +/* a JSON value. */ +struct json_value_s { + /* a pointer to either a json_string_s, json_number_s, json_object_s, or. */ + /* json_array_s. Should be cast to the appropriate struct type based on what. + */ + /* the type of this value is. */ + void *payload; + /* must be one of json_type_e. If type is json_type_true, json_type_false, or. + */ + /* json_type_null, payload will be NULL. */ + size_t type; +}; + +/* a JSON value (extended). */ +struct json_value_ex_s { + /* the JSON value this extends. */ + struct json_value_s value; + + /* the character offset for the value in the JSON input. */ + size_t offset; + + /* the line number for the value in the JSON input. */ + size_t line_no; + + /* the row number for the value in the JSON input, in bytes. */ + size_t row_no; +}; + +/* a parsing error code. */ +enum json_parse_error_e { + /* no error occurred (huzzah!). */ + json_parse_error_none = 0, + + /* expected either a comma or a closing '}' or ']' to close an object or. */ + /* array! */ + json_parse_error_expected_comma_or_closing_bracket, + + /* colon separating name/value pair was missing! */ + json_parse_error_expected_colon, + + /* expected string to begin with '"'! */ + json_parse_error_expected_opening_quote, + + /* invalid escaped sequence in string! */ + json_parse_error_invalid_string_escape_sequence, + + /* invalid number format! */ + json_parse_error_invalid_number_format, + + /* invalid value! */ + json_parse_error_invalid_value, + + /* reached end of buffer before object/array was complete! */ + json_parse_error_premature_end_of_buffer, + + /* string was malformed! */ + json_parse_error_invalid_string, + + /* a call to malloc, or a user provider allocator, failed. */ + json_parse_error_allocator_failed, + + /* the JSON input had unexpected trailing characters that weren't part of the. + */ + /* JSON value. */ + json_parse_error_unexpected_trailing_characters, + + /* catch-all error for everything else that exploded (real bad chi!). */ + json_parse_error_unknown +}; + +/* error report from json_parse_ex(). */ +struct json_parse_result_s { + /* the error code (one of json_parse_error_e). */ + size_t error; + + /* the character offset for the error in the JSON input. */ + size_t error_offset; + + /* the line number for the error in the JSON input. */ + size_t error_line_no; + + /* the row number for the error, in bytes. */ + size_t error_row_no; +}; + +#ifdef __cplusplus +} /* extern "C". */ +#endif + +#include + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +#define json_uintmax_t unsigned __int64 +#else +#include +#define json_uintmax_t uintmax_t +#endif + +#if defined(_MSC_VER) +#define json_strtoumax _strtoui64 +#else +#define json_strtoumax strtoumax +#endif + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define json_null nullptr +#else +#define json_null 0 +#endif + +#if defined(__clang__) +#pragma clang diagnostic push + +/* we do one big allocation via malloc, then cast aligned slices of this for. */ +/* our structures - we don't have a way to tell the compiler we know what we. */ +/* are doing, so disable the warning instead! */ +#pragma clang diagnostic ignored "-Wcast-align" + +/* We use C style casts everywhere. */ +#pragma clang diagnostic ignored "-Wold-style-cast" + +/* We need long long for strtoull. */ +#pragma clang diagnostic ignored "-Wc++11-long-long" + +/* Who cares if nullptr doesn't work with C++98, we don't use it there! */ +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#elif defined(_MSC_VER) +#pragma warning(push) + +/* disable 'function selected for inline expansion' warning. */ +#pragma warning(disable : 4711) + +/* disable '#pragma warning: there is no warning number' warning. */ +#pragma warning(disable : 4619) + +/* disable 'warning number not a valid compiler warning' warning. */ +#pragma warning(disable : 4616) + +/* disable 'Compiler will insert Spectre mitigation for memory load if + * /Qspectre. */ +/* switch specified' warning. */ +#pragma warning(disable : 5045) +#endif + +struct json_parse_state_s { + const char *src; + size_t size; + size_t offset; + size_t flags_bitset; + char *data; + char *dom; + size_t dom_size; + size_t data_size; + size_t line_no; /* line counter for error reporting. */ + size_t line_offset; /* (offset-line_offset) is the character number (in + bytes). */ + size_t error; +}; + +json_weak int json_hexadecimal_digit(const char c); +int json_hexadecimal_digit(const char c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + if ('a' <= c && c <= 'f') { + return c - 'a' + 10; + } + if ('A' <= c && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +json_weak int json_hexadecimal_value(const char *c, const unsigned long size, + unsigned long *result); +int json_hexadecimal_value(const char *c, const unsigned long size, + unsigned long *result) { + const char *p; + int digit; + + if (size > sizeof(unsigned long) * 2) { + return 0; + } + + *result = 0; + for (p = c; (unsigned long)(p - c) < size; ++p) { + *result <<= 4; + digit = json_hexadecimal_digit(*p); + if (digit < 0 || digit > 15) { + return 0; + } + *result |= (unsigned char)digit; + } + return 1; +} + +json_weak int json_skip_whitespace(struct json_parse_state_s *state); +int json_skip_whitespace(struct json_parse_state_s *state) { + size_t offset = state->offset; + const size_t size = state->size; + const char *const src = state->src; + + /* the only valid whitespace according to ECMA-404 is ' ', '\n', '\r' and + * '\t'. */ + switch (src[offset]) { + default: + return 0; + case ' ': + case '\r': + case '\t': + case '\n': + break; + } + + do { + switch (src[offset]) { + default: + /* Update offset. */ + state->offset = offset; + return 1; + case ' ': + case '\r': + case '\t': + break; + case '\n': + state->line_no++; + state->line_offset = offset; + break; + } + + offset++; + } while (offset < size); + + /* Update offset. */ + state->offset = offset; + return 1; +} + +json_weak int json_skip_c_style_comments(struct json_parse_state_s *state); +int json_skip_c_style_comments(struct json_parse_state_s *state) { + /* do we have a comment?. */ + if ('/' == state->src[state->offset]) { + /* skip '/'. */ + state->offset++; + + if ('/' == state->src[state->offset]) { + /* we had a comment of the form //. */ + + /* skip second '/'. */ + state->offset++; + + while (state->offset < state->size) { + switch (state->src[state->offset]) { + default: + /* skip the character in the comment. */ + state->offset++; + break; + case '\n': + /* if we have a newline, our comment has ended! Skip the newline. */ + state->offset++; + + /* we entered a newline, so move our line info forward. */ + state->line_no++; + state->line_offset = state->offset; + return 1; + } + } + + /* we reached the end of the JSON file! */ + return 1; + } else if ('*' == state->src[state->offset]) { + /* we had a comment in the C-style long form. */ + + /* skip '*'. */ + state->offset++; + + while (state->offset + 1 < state->size) { + if (('*' == state->src[state->offset]) && + ('/' == state->src[state->offset + 1])) { + /* we reached the end of our comment! */ + state->offset += 2; + return 1; + } else if ('\n' == state->src[state->offset]) { + /* we entered a newline, so move our line info forward. */ + state->line_no++; + state->line_offset = state->offset; + } + + /* skip character within comment. */ + state->offset++; + } + + /* Comment wasn't ended correctly which is a failure. */ + return 1; + } + } + + /* we didn't have any comment, which is ok too! */ + return 0; +} + +json_weak int json_skip_all_skippables(struct json_parse_state_s *state); +int json_skip_all_skippables(struct json_parse_state_s *state) { + /* skip all whitespace and other skippables until there are none left. note + * that the previous version suffered from read past errors should. the + * stream end on json_skip_c_style_comments eg. '{"a" ' with comments flag. + */ + + int did_consume = 0; + const size_t size = state->size; + + if (json_parse_flags_allow_c_style_comments & state->flags_bitset) { + do { + if (state->offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + did_consume = json_skip_whitespace(state); + + /* This should really be checked on access, not in front of every call. + */ + if (state->offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + did_consume |= json_skip_c_style_comments(state); + } while (0 != did_consume); + } else { + do { + if (state->offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + did_consume = json_skip_whitespace(state); + } while (0 != did_consume); + } + + if (state->offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + return 0; +} + +json_weak int json_get_value_size(struct json_parse_state_s *state, + int is_global_object); + +json_weak int json_get_string_size(struct json_parse_state_s *state, + size_t is_key); +int json_get_string_size(struct json_parse_state_s *state, size_t is_key) { + size_t offset = state->offset; + const size_t size = state->size; + size_t data_size = 0; + const char *const src = state->src; + const int is_single_quote = '\'' == src[offset]; + const char quote_to_use = is_single_quote ? '\'' : '"'; + const size_t flags_bitset = state->flags_bitset; + unsigned long codepoint; + unsigned long high_surrogate = 0; + + if ((json_parse_flags_allow_location_information & flags_bitset) != 0 && + is_key != 0) { + state->dom_size += sizeof(struct json_string_ex_s); + } else { + state->dom_size += sizeof(struct json_string_s); + } + + if ('"' != src[offset]) { + /* if we are allowed single quoted strings check for that too. */ + if (!((json_parse_flags_allow_single_quoted_strings & flags_bitset) && + is_single_quote)) { + state->error = json_parse_error_expected_opening_quote; + state->offset = offset; + return 1; + } + } + + /* skip leading '"' or '\''. */ + offset++; + + while ((offset < size) && (quote_to_use != src[offset])) { + /* add space for the character. */ + data_size++; + + switch (src[offset]) { + default: + break; + case '\0': + case '\t': + state->error = json_parse_error_invalid_string; + state->offset = offset; + return 1; + } + + if ('\\' == src[offset]) { + /* skip reverse solidus character. */ + offset++; + + if (offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + state->offset = offset; + return 1; + } + + switch (src[offset]) { + default: + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + case '"': + case '\\': + case '/': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + /* all valid characters! */ + offset++; + break; + case 'u': + if (!(offset + 5 < size)) { + /* invalid escaped unicode sequence! */ + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } + + codepoint = 0; + if (!json_hexadecimal_value(&src[offset + 1], 4, &codepoint)) { + /* escaped unicode sequences must contain 4 hexadecimal digits! */ + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } + + /* Valid sequence! + * see: https://en.wikipedia.org/wiki/UTF-8#Invalid_code_points. + * 1 7 U + 0000 U + 007F 0xxxxxxx. + * 2 11 U + 0080 U + 07FF 110xxxxx + * 10xxxxxx. + * 3 16 U + 0800 U + FFFF 1110xxxx + * 10xxxxxx 10xxxxxx. + * 4 21 U + 10000 U + 10FFFF 11110xxx + * 10xxxxxx 10xxxxxx 10xxxxxx. + * Note: the high and low surrogate halves used by UTF-16 (U+D800 + * through U+DFFF) and code points not encodable by UTF-16 (those after + * U+10FFFF) are not legal Unicode values, and their UTF-8 encoding must + * be treated as an invalid byte sequence. */ + + if (high_surrogate != 0) { + /* we previously read the high half of the \uxxxx\uxxxx pair, so now + * we expect the low half. */ + if (codepoint >= 0xdc00 && + codepoint <= 0xdfff) { /* low surrogate range. */ + data_size += 3; + high_surrogate = 0; + } else { + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } + } else if (codepoint <= 0x7f) { + data_size += 0; + } else if (codepoint <= 0x7ff) { + data_size += 1; + } else if (codepoint >= 0xd800 && + codepoint <= 0xdbff) { /* high surrogate range. */ + /* The codepoint is the first half of a "utf-16 surrogate pair". so we + * need the other half for it to be valid: \uHHHH\uLLLL. */ + if (offset + 11 > size || '\\' != src[offset + 5] || + 'u' != src[offset + 6]) { + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } + high_surrogate = codepoint; + } else if (codepoint >= 0xd800 && + codepoint <= 0xdfff) { /* low surrogate range. */ + /* we did not read the other half before. */ + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } else { + data_size += 2; + } + /* escaped codepoints after 0xffff are supported in json through utf-16 + * surrogate pairs: \uD83D\uDD25 for U+1F525. */ + + offset += 5; + break; + } + } else if (('\r' == src[offset]) || ('\n' == src[offset])) { + if (!(json_parse_flags_allow_multi_line_strings & flags_bitset)) { + /* invalid escaped unicode sequence! */ + state->error = json_parse_error_invalid_string_escape_sequence; + state->offset = offset; + return 1; + } + + offset++; + } else { + /* skip character (valid part of sequence). */ + offset++; + } + } + + /* If the offset is equal to the size, we had a non-terminated string! */ + if (offset == size) { + state->error = json_parse_error_premature_end_of_buffer; + state->offset = offset - 1; + return 1; + } + + /* skip trailing '"' or '\''. */ + offset++; + + /* add enough space to store the string. */ + state->data_size += data_size; + + /* one more byte for null terminator ending the string! */ + state->data_size++; + + /* update offset. */ + state->offset = offset; + + return 0; +} + +json_weak int is_valid_unquoted_key_char(const char c); +int is_valid_unquoted_key_char(const char c) { + return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || ('_' == c)); +} + +json_weak int json_get_key_size(struct json_parse_state_s *state); +int json_get_key_size(struct json_parse_state_s *state) { + const size_t flags_bitset = state->flags_bitset; + + if (json_parse_flags_allow_unquoted_keys & flags_bitset) { + size_t offset = state->offset; + const size_t size = state->size; + const char *const src = state->src; + size_t data_size = state->data_size; + + /* if we are allowing unquoted keys, first grok for a quote... */ + if ('"' == src[offset]) { + /* ... if we got a comma, just parse the key as a string as normal. */ + return json_get_string_size(state, 1); + } else if ((json_parse_flags_allow_single_quoted_strings & flags_bitset) && + ('\'' == src[offset])) { + /* ... if we got a comma, just parse the key as a string as normal. */ + return json_get_string_size(state, 1); + } else { + while ((offset < size) && is_valid_unquoted_key_char(src[offset])) { + offset++; + data_size++; + } + + /* one more byte for null terminator ending the string! */ + data_size++; + + if (json_parse_flags_allow_location_information & flags_bitset) { + state->dom_size += sizeof(struct json_string_ex_s); + } else { + state->dom_size += sizeof(struct json_string_s); + } + + /* update offset. */ + state->offset = offset; + + /* update data_size. */ + state->data_size = data_size; + + return 0; + } + } else { + /* we are only allowed to have quoted keys, so just parse a string! */ + return json_get_string_size(state, 1); + } +} + +json_weak int json_get_object_size(struct json_parse_state_s *state, + int is_global_object); +int json_get_object_size(struct json_parse_state_s *state, + int is_global_object) { + const size_t flags_bitset = state->flags_bitset; + const char *const src = state->src; + const size_t size = state->size; + size_t elements = 0; + int allow_comma = 0; + int found_closing_brace = 0; + + if (is_global_object) { + /* if we found an opening '{' of an object, we actually have a normal JSON + * object at the root of the DOM... */ + if (!json_skip_all_skippables(state) && '{' == state->src[state->offset]) { + /* . and we don't actually have a global object after all! */ + is_global_object = 0; + } + } + + if (!is_global_object) { + if ('{' != src[state->offset]) { + state->error = json_parse_error_unknown; + return 1; + } + + /* skip leading '{'. */ + state->offset++; + } + + state->dom_size += sizeof(struct json_object_s); + + if ((state->offset == size) && !is_global_object) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + do { + if (!is_global_object) { + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + if ('}' == src[state->offset]) { + /* skip trailing '}'. */ + state->offset++; + + found_closing_brace = 1; + + /* finished the object! */ + break; + } + } else { + /* we don't require brackets, so that means the object ends when the input + * stream ends! */ + if (json_skip_all_skippables(state)) { + break; + } + } + + /* if we parsed at least once element previously, grok for a comma. */ + if (allow_comma) { + if (',' == src[state->offset]) { + /* skip comma. */ + state->offset++; + allow_comma = 0; + } else if (json_parse_flags_allow_no_commas & flags_bitset) { + /* we don't require a comma, and we didn't find one, which is ok! */ + allow_comma = 0; + } else { + /* otherwise we are required to have a comma, and we found none. */ + state->error = json_parse_error_expected_comma_or_closing_bracket; + return 1; + } + + if (json_parse_flags_allow_trailing_comma & flags_bitset) { + continue; + } else { + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + } + } + + if (json_get_key_size(state)) { + /* key parsing failed! */ + state->error = json_parse_error_invalid_string; + return 1; + } + + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + if (json_parse_flags_allow_equals_in_object & flags_bitset) { + const char current = src[state->offset]; + if ((':' != current) && ('=' != current)) { + state->error = json_parse_error_expected_colon; + return 1; + } + } else { + if (':' != src[state->offset]) { + state->error = json_parse_error_expected_colon; + return 1; + } + } + + /* skip colon. */ + state->offset++; + + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + if (json_get_value_size(state, /* is_global_object = */ 0)) { + /* value parsing failed! */ + return 1; + } + + /* successfully parsed a name/value pair! */ + elements++; + allow_comma = 1; + } while (state->offset < size); + + if ((state->offset == size) && !is_global_object && !found_closing_brace) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + state->dom_size += sizeof(struct json_object_element_s) * elements; + + return 0; +} + +json_weak int json_get_array_size(struct json_parse_state_s *state); +int json_get_array_size(struct json_parse_state_s *state) { + const size_t flags_bitset = state->flags_bitset; + size_t elements = 0; + int allow_comma = 0; + const char *const src = state->src; + const size_t size = state->size; + + if ('[' != src[state->offset]) { + /* expected array to begin with leading '['. */ + state->error = json_parse_error_unknown; + return 1; + } + + /* skip leading '['. */ + state->offset++; + + state->dom_size += sizeof(struct json_array_s); + + while (state->offset < size) { + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + if (']' == src[state->offset]) { + /* skip trailing ']'. */ + state->offset++; + + state->dom_size += sizeof(struct json_array_element_s) * elements; + + /* finished the object! */ + return 0; + } + + /* if we parsed at least once element previously, grok for a comma. */ + if (allow_comma) { + if (',' == src[state->offset]) { + /* skip comma. */ + state->offset++; + allow_comma = 0; + } else if (!(json_parse_flags_allow_no_commas & flags_bitset)) { + state->error = json_parse_error_expected_comma_or_closing_bracket; + return 1; + } + + if (json_parse_flags_allow_trailing_comma & flags_bitset) { + allow_comma = 0; + continue; + } else { + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + } + } + + if (json_get_value_size(state, /* is_global_object = */ 0)) { + /* value parsing failed! */ + return 1; + } + + /* successfully parsed an array element! */ + elements++; + allow_comma = 1; + } + + /* we consumed the entire input before finding the closing ']' of the array! + */ + state->error = json_parse_error_premature_end_of_buffer; + return 1; +} + +json_weak int json_get_number_size(struct json_parse_state_s *state); +int json_get_number_size(struct json_parse_state_s *state) { + const size_t flags_bitset = state->flags_bitset; + size_t offset = state->offset; + const size_t size = state->size; + int had_leading_digits = 0; + const char *const src = state->src; + + state->dom_size += sizeof(struct json_number_s); + + if ((json_parse_flags_allow_hexadecimal_numbers & flags_bitset) && + (offset + 1 < size) && ('0' == src[offset]) && + (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { + /* skip the leading 0x that identifies a hexadecimal number. */ + offset += 2; + + /* consume hexadecimal digits. */ + while ((offset < size) && (('0' <= src[offset] && src[offset] <= '9') || + ('a' <= src[offset] && src[offset] <= 'f') || + ('A' <= src[offset] && src[offset] <= 'F'))) { + offset++; + } + } else { + int found_sign = 0; + int inf_or_nan = 0; + + if ((offset < size) && + (('-' == src[offset]) || + ((json_parse_flags_allow_leading_plus_sign & flags_bitset) && + ('+' == src[offset])))) { + /* skip valid leading '-' or '+'. */ + offset++; + + found_sign = 1; + } + + if (json_parse_flags_allow_inf_and_nan & flags_bitset) { + const char inf[9] = "Infinity"; + const size_t inf_strlen = sizeof(inf) - 1; + const char nan[4] = "NaN"; + const size_t nan_strlen = sizeof(nan) - 1; + + if (offset + inf_strlen < size) { + int found = 1; + size_t i; + for (i = 0; i < inf_strlen; i++) { + if (inf[i] != src[offset + i]) { + found = 0; + break; + } + } + + if (found) { + /* We found our special 'Infinity' keyword! */ + offset += inf_strlen; + + inf_or_nan = 1; + } + } + + if (offset + nan_strlen < size) { + int found = 1; + size_t i; + for (i = 0; i < nan_strlen; i++) { + if (nan[i] != src[offset + i]) { + found = 0; + break; + } + } + + if (found) { + /* We found our special 'NaN' keyword! */ + offset += nan_strlen; + + inf_or_nan = 1; + } + } + } + + if (found_sign && !inf_or_nan && (offset < size) && + !('0' <= src[offset] && src[offset] <= '9')) { + /* check if we are allowing leading '.'. */ + if (!(json_parse_flags_allow_leading_or_trailing_decimal_point & + flags_bitset) || + ('.' != src[offset])) { + /* a leading '-' must be immediately followed by any digit! */ + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + } + } + + if ((offset < size) && ('0' == src[offset])) { + /* skip valid '0'. */ + offset++; + + /* we need to record whether we had any leading digits for checks later. + */ + had_leading_digits = 1; + + if ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { + /* a leading '0' must not be immediately followed by any digit! */ + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + } + } + + /* the main digits of our number next. */ + while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { + offset++; + + /* we need to record whether we had any leading digits for checks later. + */ + had_leading_digits = 1; + } + + if ((offset < size) && ('.' == src[offset])) { + offset++; + + if (!('0' <= src[offset] && src[offset] <= '9')) { + if (!(json_parse_flags_allow_leading_or_trailing_decimal_point & + flags_bitset) || + !had_leading_digits) { + /* a decimal point must be followed by at least one digit. */ + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + } + } + + /* a decimal point can be followed by more digits of course! */ + while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) { + offset++; + } + } + + if ((offset < size) && ('e' == src[offset] || 'E' == src[offset])) { + /* our number has an exponent! Skip 'e' or 'E'. */ + offset++; + + if ((offset < size) && ('-' == src[offset] || '+' == src[offset])) { + /* skip optional '-' or '+'. */ + offset++; + } + + if ((offset < size) && !('0' <= src[offset] && src[offset] <= '9')) { + /* an exponent must have at least one digit! */ + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + } + + /* consume exponent digits. */ + do { + offset++; + } while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')); + } + } + + if (offset < size) { + switch (src[offset]) { + case ' ': + case '\t': + case '\r': + case '\n': + case '}': + case ',': + case ']': + /* all of the above are ok. */ + break; + case '=': + if (json_parse_flags_allow_equals_in_object & flags_bitset) { + break; + } + + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + default: + state->error = json_parse_error_invalid_number_format; + state->offset = offset; + return 1; + } + } + + state->data_size += offset - state->offset; + + /* one more byte for null terminator ending the number string! */ + state->data_size++; + + /* update offset. */ + state->offset = offset; + + return 0; +} + +json_weak int json_get_value_size(struct json_parse_state_s *state, + int is_global_object); +int json_get_value_size(struct json_parse_state_s *state, + int is_global_object) { + const size_t flags_bitset = state->flags_bitset; + const char *const src = state->src; + size_t offset; + const size_t size = state->size; + + if (json_parse_flags_allow_location_information & flags_bitset) { + state->dom_size += sizeof(struct json_value_ex_s); + } else { + state->dom_size += sizeof(struct json_value_s); + } + + if (is_global_object) { + return json_get_object_size(state, /* is_global_object = */ 1); + } else { + if (json_skip_all_skippables(state)) { + state->error = json_parse_error_premature_end_of_buffer; + return 1; + } + + /* can cache offset now. */ + offset = state->offset; + + switch (src[offset]) { + case '"': + return json_get_string_size(state, 0); + case '\'': + if (json_parse_flags_allow_single_quoted_strings & flags_bitset) { + return json_get_string_size(state, 0); + } else { + /* invalid value! */ + state->error = json_parse_error_invalid_value; + return 1; + } + case '{': + return json_get_object_size(state, /* is_global_object = */ 0); + case '[': + return json_get_array_size(state); + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return json_get_number_size(state); + case '+': + if (json_parse_flags_allow_leading_plus_sign & flags_bitset) { + return json_get_number_size(state); + } else { + /* invalid value! */ + state->error = json_parse_error_invalid_number_format; + return 1; + } + case '.': + if (json_parse_flags_allow_leading_or_trailing_decimal_point & + flags_bitset) { + return json_get_number_size(state); + } else { + /* invalid value! */ + state->error = json_parse_error_invalid_number_format; + return 1; + } + default: + if ((offset + 4) <= size && 't' == src[offset + 0] && + 'r' == src[offset + 1] && 'u' == src[offset + 2] && + 'e' == src[offset + 3]) { + state->offset += 4; + return 0; + } else if ((offset + 5) <= size && 'f' == src[offset + 0] && + 'a' == src[offset + 1] && 'l' == src[offset + 2] && + 's' == src[offset + 3] && 'e' == src[offset + 4]) { + state->offset += 5; + return 0; + } else if ((offset + 4) <= size && 'n' == state->src[offset + 0] && + 'u' == state->src[offset + 1] && + 'l' == state->src[offset + 2] && + 'l' == state->src[offset + 3]) { + state->offset += 4; + return 0; + } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && + (offset + 3) <= size && 'N' == src[offset + 0] && + 'a' == src[offset + 1] && 'N' == src[offset + 2]) { + return json_get_number_size(state); + } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && + (offset + 8) <= size && 'I' == src[offset + 0] && + 'n' == src[offset + 1] && 'f' == src[offset + 2] && + 'i' == src[offset + 3] && 'n' == src[offset + 4] && + 'i' == src[offset + 5] && 't' == src[offset + 6] && + 'y' == src[offset + 7]) { + return json_get_number_size(state); + } + + /* invalid value! */ + state->error = json_parse_error_invalid_value; + return 1; + } + } +} + +json_weak void json_parse_value(struct json_parse_state_s *state, + int is_global_object, + struct json_value_s *value); + +json_weak void json_parse_string(struct json_parse_state_s *state, + struct json_string_s *string); +void json_parse_string(struct json_parse_state_s *state, + struct json_string_s *string) { + size_t offset = state->offset; + size_t bytes_written = 0; + const char *const src = state->src; + const char quote_to_use = '\'' == src[offset] ? '\'' : '"'; + char *data = state->data; + unsigned long high_surrogate = 0; + unsigned long codepoint; + + string->string = data; + + /* skip leading '"' or '\''. */ + offset++; + + while (quote_to_use != src[offset]) { + if ('\\' == src[offset]) { + /* skip the reverse solidus. */ + offset++; + + switch (src[offset++]) { + default: + return; /* we cannot ever reach here. */ + case 'u': { + codepoint = 0; + if (!json_hexadecimal_value(&src[offset], 4, &codepoint)) { + return; /* this shouldn't happen as the value was already validated. + */ + } + + offset += 4; + + if (codepoint <= 0x7fu) { + data[bytes_written++] = (char)codepoint; /* 0xxxxxxx. */ + } else if (codepoint <= 0x7ffu) { + data[bytes_written++] = + (char)(0xc0u | (codepoint >> 6)); /* 110xxxxx. */ + data[bytes_written++] = + (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ + } else if (codepoint >= 0xd800 && + codepoint <= 0xdbff) { /* high surrogate. */ + high_surrogate = codepoint; + continue; /* we need the low half to form a complete codepoint. */ + } else if (codepoint >= 0xdc00 && + codepoint <= 0xdfff) { /* low surrogate. */ + /* combine with the previously read half to obtain the complete + * codepoint. */ + const unsigned long surrogate_offset = + 0x10000u - (0xD800u << 10) - 0xDC00u; + codepoint = (high_surrogate << 10) + codepoint + surrogate_offset; + high_surrogate = 0; + data[bytes_written++] = + (char)(0xF0u | (codepoint >> 18)); /* 11110xxx. */ + data[bytes_written++] = + (char)(0x80u | ((codepoint >> 12) & 0x3fu)); /* 10xxxxxx. */ + data[bytes_written++] = + (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */ + data[bytes_written++] = + (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ + } else { + /* we assume the value was validated and thus is within the valid + * range. */ + data[bytes_written++] = + (char)(0xe0u | (codepoint >> 12)); /* 1110xxxx. */ + data[bytes_written++] = + (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */ + data[bytes_written++] = + (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */ + } + } break; + case '"': + data[bytes_written++] = '"'; + break; + case '\\': + data[bytes_written++] = '\\'; + break; + case '/': + data[bytes_written++] = '/'; + break; + case 'b': + data[bytes_written++] = '\b'; + break; + case 'f': + data[bytes_written++] = '\f'; + break; + case 'n': + data[bytes_written++] = '\n'; + break; + case 'r': + data[bytes_written++] = '\r'; + break; + case 't': + data[bytes_written++] = '\t'; + break; + case '\r': + data[bytes_written++] = '\r'; + + /* check if we have a "\r\n" sequence. */ + if ('\n' == src[offset]) { + data[bytes_written++] = '\n'; + offset++; + } + + break; + case '\n': + data[bytes_written++] = '\n'; + break; + } + } else { + /* copy the character. */ + data[bytes_written++] = src[offset++]; + } + } + + /* skip trailing '"' or '\''. */ + offset++; + + /* record the size of the string. */ + string->string_size = bytes_written; + + /* add null terminator to string. */ + data[bytes_written++] = '\0'; + + /* move data along. */ + state->data += bytes_written; + + /* update offset. */ + state->offset = offset; +} + +json_weak void json_parse_key(struct json_parse_state_s *state, + struct json_string_s *string); +void json_parse_key(struct json_parse_state_s *state, + struct json_string_s *string) { + if (json_parse_flags_allow_unquoted_keys & state->flags_bitset) { + const char *const src = state->src; + char *const data = state->data; + size_t offset = state->offset; + + /* if we are allowing unquoted keys, check for quoted anyway... */ + if (('"' == src[offset]) || ('\'' == src[offset])) { + /* ... if we got a quote, just parse the key as a string as normal. */ + json_parse_string(state, string); + } else { + size_t size = 0; + + string->string = state->data; + + while (is_valid_unquoted_key_char(src[offset])) { + data[size++] = src[offset++]; + } + + /* add null terminator to string. */ + data[size] = '\0'; + + /* record the size of the string. */ + string->string_size = size++; + + /* move data along. */ + state->data += size; + + /* update offset. */ + state->offset = offset; + } + } else { + /* we are only allowed to have quoted keys, so just parse a string! */ + json_parse_string(state, string); + } +} + +json_weak void json_parse_object(struct json_parse_state_s *state, + int is_global_object, + struct json_object_s *object); +void json_parse_object(struct json_parse_state_s *state, int is_global_object, + struct json_object_s *object) { + const size_t flags_bitset = state->flags_bitset; + const size_t size = state->size; + const char *const src = state->src; + size_t elements = 0; + int allow_comma = 0; + struct json_object_element_s *previous = json_null; + + if (is_global_object) { + /* if we skipped some whitespace, and then found an opening '{' of an. */ + /* object, we actually have a normal JSON object at the root of the DOM... + */ + if ('{' == src[state->offset]) { + /* . and we don't actually have a global object after all! */ + is_global_object = 0; + } + } + + if (!is_global_object) { + /* skip leading '{'. */ + state->offset++; + } + + (void)json_skip_all_skippables(state); + + /* reset elements. */ + elements = 0; + + while (state->offset < size) { + struct json_object_element_s *element = json_null; + struct json_string_s *string = json_null; + struct json_value_s *value = json_null; + + if (!is_global_object) { + (void)json_skip_all_skippables(state); + + if ('}' == src[state->offset]) { + /* skip trailing '}'. */ + state->offset++; + + /* finished the object! */ + break; + } + } else { + if (json_skip_all_skippables(state)) { + /* global object ends when the file ends! */ + break; + } + } + + /* if we parsed at least one element previously, grok for a comma. */ + if (allow_comma) { + if (',' == src[state->offset]) { + /* skip comma. */ + state->offset++; + allow_comma = 0; + continue; + } + } + + element = (struct json_object_element_s *)state->dom; + + state->dom += sizeof(struct json_object_element_s); + + if (json_null == previous) { + /* this is our first element, so record it in our object. */ + object->start = element; + } else { + previous->next = element; + } + + previous = element; + + if (json_parse_flags_allow_location_information & flags_bitset) { + struct json_string_ex_s *string_ex = + (struct json_string_ex_s *)state->dom; + state->dom += sizeof(struct json_string_ex_s); + + string_ex->offset = state->offset; + string_ex->line_no = state->line_no; + string_ex->row_no = state->offset - state->line_offset; + + string = &(string_ex->string); + } else { + string = (struct json_string_s *)state->dom; + state->dom += sizeof(struct json_string_s); + } + + element->name = string; + + (void)json_parse_key(state, string); + + (void)json_skip_all_skippables(state); + + /* skip colon or equals. */ + state->offset++; + + (void)json_skip_all_skippables(state); + + if (json_parse_flags_allow_location_information & flags_bitset) { + struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom; + state->dom += sizeof(struct json_value_ex_s); + + value_ex->offset = state->offset; + value_ex->line_no = state->line_no; + value_ex->row_no = state->offset - state->line_offset; + + value = &(value_ex->value); + } else { + value = (struct json_value_s *)state->dom; + state->dom += sizeof(struct json_value_s); + } + + element->value = value; + + json_parse_value(state, /* is_global_object = */ 0, value); + + /* successfully parsed a name/value pair! */ + elements++; + allow_comma = 1; + } + + /* if we had at least one element, end the linked list. */ + if (previous) { + previous->next = json_null; + } + + if (0 == elements) { + object->start = json_null; + } + + object->length = elements; +} + +json_weak void json_parse_array(struct json_parse_state_s *state, + struct json_array_s *array); +void json_parse_array(struct json_parse_state_s *state, + struct json_array_s *array) { + const char *const src = state->src; + const size_t size = state->size; + size_t elements = 0; + int allow_comma = 0; + struct json_array_element_s *previous = json_null; + + /* skip leading '['. */ + state->offset++; + + (void)json_skip_all_skippables(state); + + /* reset elements. */ + elements = 0; + + do { + struct json_array_element_s *element = json_null; + struct json_value_s *value = json_null; + + (void)json_skip_all_skippables(state); + + if (']' == src[state->offset]) { + /* skip trailing ']'. */ + state->offset++; + + /* finished the array! */ + break; + } + + /* if we parsed at least one element previously, grok for a comma. */ + if (allow_comma) { + if (',' == src[state->offset]) { + /* skip comma. */ + state->offset++; + allow_comma = 0; + continue; + } + } + + element = (struct json_array_element_s *)state->dom; + + state->dom += sizeof(struct json_array_element_s); + + if (json_null == previous) { + /* this is our first element, so record it in our array. */ + array->start = element; + } else { + previous->next = element; + } + + previous = element; + + if (json_parse_flags_allow_location_information & state->flags_bitset) { + struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom; + state->dom += sizeof(struct json_value_ex_s); + + value_ex->offset = state->offset; + value_ex->line_no = state->line_no; + value_ex->row_no = state->offset - state->line_offset; + + value = &(value_ex->value); + } else { + value = (struct json_value_s *)state->dom; + state->dom += sizeof(struct json_value_s); + } + + element->value = value; + + json_parse_value(state, /* is_global_object = */ 0, value); + + /* successfully parsed an array element! */ + elements++; + allow_comma = 1; + } while (state->offset < size); + + /* end the linked list. */ + if (previous) { + previous->next = json_null; + } + + if (0 == elements) { + array->start = json_null; + } + + array->length = elements; +} + +json_weak void json_parse_number(struct json_parse_state_s *state, + struct json_number_s *number); +void json_parse_number(struct json_parse_state_s *state, + struct json_number_s *number) { + const size_t flags_bitset = state->flags_bitset; + size_t offset = state->offset; + const size_t size = state->size; + size_t bytes_written = 0; + const char *const src = state->src; + char *data = state->data; + + number->number = data; + + if (json_parse_flags_allow_hexadecimal_numbers & flags_bitset) { + if (('0' == src[offset]) && + (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) { + /* consume hexadecimal digits. */ + while ((offset < size) && + (('0' <= src[offset] && src[offset] <= '9') || + ('a' <= src[offset] && src[offset] <= 'f') || + ('A' <= src[offset] && src[offset] <= 'F') || + ('x' == src[offset]) || ('X' == src[offset]))) { + data[bytes_written++] = src[offset++]; + } + } + } + + while (offset < size) { + int end = 0; + + switch (src[offset]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + case 'e': + case 'E': + case '+': + case '-': + data[bytes_written++] = src[offset++]; + break; + default: + end = 1; + break; + } + + if (0 != end) { + break; + } + } + + if (json_parse_flags_allow_inf_and_nan & flags_bitset) { + const size_t inf_strlen = 8; /* = strlen("Infinity");. */ + const size_t nan_strlen = 3; /* = strlen("NaN");. */ + + if (offset + inf_strlen < size) { + if ('I' == src[offset]) { + size_t i; + /* We found our special 'Infinity' keyword! */ + for (i = 0; i < inf_strlen; i++) { + data[bytes_written++] = src[offset++]; + } + } + } + + if (offset + nan_strlen < size) { + if ('N' == src[offset]) { + size_t i; + /* We found our special 'NaN' keyword! */ + for (i = 0; i < nan_strlen; i++) { + data[bytes_written++] = src[offset++]; + } + } + } + } + + /* record the size of the number. */ + number->number_size = bytes_written; + /* add null terminator to number string. */ + data[bytes_written++] = '\0'; + /* move data along. */ + state->data += bytes_written; + /* update offset. */ + state->offset = offset; +} + +json_weak void json_parse_value(struct json_parse_state_s *state, + int is_global_object, + struct json_value_s *value); +void json_parse_value(struct json_parse_state_s *state, int is_global_object, + struct json_value_s *value) { + const size_t flags_bitset = state->flags_bitset; + const char *const src = state->src; + const size_t size = state->size; + size_t offset; + + (void)json_skip_all_skippables(state); + + /* cache offset now. */ + offset = state->offset; + + if (is_global_object) { + value->type = json_type_object; + value->payload = state->dom; + state->dom += sizeof(struct json_object_s); + json_parse_object(state, /* is_global_object = */ 1, + (struct json_object_s *)value->payload); + } else { + switch (src[offset]) { + case '"': + case '\'': + value->type = json_type_string; + value->payload = state->dom; + state->dom += sizeof(struct json_string_s); + json_parse_string(state, (struct json_string_s *)value->payload); + break; + case '{': + value->type = json_type_object; + value->payload = state->dom; + state->dom += sizeof(struct json_object_s); + json_parse_object(state, /* is_global_object = */ 0, + (struct json_object_s *)value->payload); + break; + case '[': + value->type = json_type_array; + value->payload = state->dom; + state->dom += sizeof(struct json_array_s); + json_parse_array(state, (struct json_array_s *)value->payload); + break; + case '-': + case '+': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + value->type = json_type_number; + value->payload = state->dom; + state->dom += sizeof(struct json_number_s); + json_parse_number(state, (struct json_number_s *)value->payload); + break; + default: + if ((offset + 4) <= size && 't' == src[offset + 0] && + 'r' == src[offset + 1] && 'u' == src[offset + 2] && + 'e' == src[offset + 3]) { + value->type = json_type_true; + value->payload = json_null; + state->offset += 4; + } else if ((offset + 5) <= size && 'f' == src[offset + 0] && + 'a' == src[offset + 1] && 'l' == src[offset + 2] && + 's' == src[offset + 3] && 'e' == src[offset + 4]) { + value->type = json_type_false; + value->payload = json_null; + state->offset += 5; + } else if ((offset + 4) <= size && 'n' == src[offset + 0] && + 'u' == src[offset + 1] && 'l' == src[offset + 2] && + 'l' == src[offset + 3]) { + value->type = json_type_null; + value->payload = json_null; + state->offset += 4; + } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && + (offset + 3) <= size && 'N' == src[offset + 0] && + 'a' == src[offset + 1] && 'N' == src[offset + 2]) { + value->type = json_type_number; + value->payload = state->dom; + state->dom += sizeof(struct json_number_s); + json_parse_number(state, (struct json_number_s *)value->payload); + } else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) && + (offset + 8) <= size && 'I' == src[offset + 0] && + 'n' == src[offset + 1] && 'f' == src[offset + 2] && + 'i' == src[offset + 3] && 'n' == src[offset + 4] && + 'i' == src[offset + 5] && 't' == src[offset + 6] && + 'y' == src[offset + 7]) { + value->type = json_type_number; + value->payload = state->dom; + state->dom += sizeof(struct json_number_s); + json_parse_number(state, (struct json_number_s *)value->payload); + } + break; + } + } +} + +struct json_value_s * +json_parse_ex(const void *src, size_t src_size, size_t flags_bitset, + void *(*alloc_func_ptr)(void *user_data, size_t size), + void *user_data, struct json_parse_result_s *result) { + struct json_parse_state_s state; + void *allocation; + struct json_value_s *value; + size_t total_size; + int input_error; + + if (result) { + result->error = json_parse_error_none; + result->error_offset = 0; + result->error_line_no = 0; + result->error_row_no = 0; + } + + if (json_null == src) { + /* invalid src pointer was null! */ + return json_null; + } + + state.src = (const char *)src; + state.size = src_size; + state.offset = 0; + state.line_no = 1; + state.line_offset = 0; + state.error = json_parse_error_none; + state.dom_size = 0; + state.data_size = 0; + state.flags_bitset = flags_bitset; + + input_error = json_get_value_size( + &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset)); + + if (0 == input_error) { + json_skip_all_skippables(&state); + + if (state.offset != state.size) { + /* our parsing didn't have an error, but there are characters remaining in + * the input that weren't part of the JSON! */ + + state.error = json_parse_error_unexpected_trailing_characters; + input_error = 1; + } + } + + if (input_error) { + /* parsing value's size failed (most likely an invalid JSON DOM!). */ + if (result) { + result->error = state.error; + result->error_offset = state.offset; + result->error_line_no = state.line_no; + result->error_row_no = state.offset - state.line_offset; + } + return json_null; + } + + /* our total allocation is the combination of the dom and data sizes (we. */ + /* first encode the structure of the JSON, and then the data referenced by. */ + /* the JSON values). */ + total_size = state.dom_size + state.data_size; + + if (json_null == alloc_func_ptr) { + allocation = malloc(total_size); + } else { + allocation = alloc_func_ptr(user_data, total_size); + } + + if (json_null == allocation) { + /* malloc failed! */ + if (result) { + result->error = json_parse_error_allocator_failed; + result->error_offset = 0; + result->error_line_no = 0; + result->error_row_no = 0; + } + + return json_null; + } + + /* reset offset so we can reuse it. */ + state.offset = 0; + + /* reset the line information so we can reuse it. */ + state.line_no = 1; + state.line_offset = 0; + + state.dom = (char *)allocation; + state.data = state.dom + state.dom_size; + + if (json_parse_flags_allow_location_information & state.flags_bitset) { + struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state.dom; + state.dom += sizeof(struct json_value_ex_s); + + value_ex->offset = state.offset; + value_ex->line_no = state.line_no; + value_ex->row_no = state.offset - state.line_offset; + + value = &(value_ex->value); + } else { + value = (struct json_value_s *)state.dom; + state.dom += sizeof(struct json_value_s); + } + + json_parse_value( + &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset), + value); + + return (struct json_value_s *)allocation; +} + +struct json_value_s *json_parse(const void *src, size_t src_size) { + return json_parse_ex(src, src_size, json_parse_flags_default, json_null, + json_null, json_null); +} + +struct json_extract_result_s { + size_t dom_size; + size_t data_size; +}; + +struct json_value_s *json_extract_value(const struct json_value_s *value) { + return json_extract_value_ex(value, json_null, json_null); +} + +json_weak struct json_extract_result_s +json_extract_get_number_size(const struct json_number_s *const number); +json_weak struct json_extract_result_s +json_extract_get_string_size(const struct json_string_s *const string); +json_weak struct json_extract_result_s +json_extract_get_object_size(const struct json_object_s *const object); +json_weak struct json_extract_result_s +json_extract_get_array_size(const struct json_array_s *const array); +json_weak struct json_extract_result_s +json_extract_get_value_size(const struct json_value_s *const value); + +struct json_extract_result_s +json_extract_get_number_size(const struct json_number_s *const number) { + struct json_extract_result_s result; + result.dom_size = sizeof(struct json_number_s); + result.data_size = number->number_size; + return result; +} + +struct json_extract_result_s +json_extract_get_string_size(const struct json_string_s *const string) { + struct json_extract_result_s result; + result.dom_size = sizeof(struct json_string_s); + result.data_size = string->string_size + 1; + return result; +} + +struct json_extract_result_s +json_extract_get_object_size(const struct json_object_s *const object) { + struct json_extract_result_s result; + size_t i; + const struct json_object_element_s *element = object->start; + + result.dom_size = sizeof(struct json_object_s) + + (sizeof(struct json_object_element_s) * object->length); + result.data_size = 0; + + for (i = 0; i < object->length; i++) { + const struct json_extract_result_s string_result = + json_extract_get_string_size(element->name); + const struct json_extract_result_s value_result = + json_extract_get_value_size(element->value); + + result.dom_size += string_result.dom_size; + result.data_size += string_result.data_size; + + result.dom_size += value_result.dom_size; + result.data_size += value_result.data_size; + + element = element->next; + } + + return result; +} + +struct json_extract_result_s +json_extract_get_array_size(const struct json_array_s *const array) { + struct json_extract_result_s result; + size_t i; + const struct json_array_element_s *element = array->start; + + result.dom_size = sizeof(struct json_array_s) + + (sizeof(struct json_array_element_s) * array->length); + result.data_size = 0; + + for (i = 0; i < array->length; i++) { + const struct json_extract_result_s value_result = + json_extract_get_value_size(element->value); + + result.dom_size += value_result.dom_size; + result.data_size += value_result.data_size; + + element = element->next; + } + + return result; +} + +struct json_extract_result_s +json_extract_get_value_size(const struct json_value_s *const value) { + struct json_extract_result_s result = {0, 0}; + + switch (value->type) { + default: + break; + case json_type_object: + result = json_extract_get_object_size( + (const struct json_object_s *)value->payload); + break; + case json_type_array: + result = json_extract_get_array_size( + (const struct json_array_s *)value->payload); + break; + case json_type_number: + result = json_extract_get_number_size( + (const struct json_number_s *)value->payload); + break; + case json_type_string: + result = json_extract_get_string_size( + (const struct json_string_s *)value->payload); + break; + } + + result.dom_size += sizeof(struct json_value_s); + + return result; +} + +struct json_extract_state_s { + char *dom; + char *data; +}; + +json_weak void json_extract_copy_value(struct json_extract_state_s *const state, + const struct json_value_s *const value); +void json_extract_copy_value(struct json_extract_state_s *const state, + const struct json_value_s *const value) { + struct json_string_s *string; + struct json_number_s *number; + struct json_object_s *object; + struct json_array_s *array; + struct json_value_s *new_value; + + memcpy(state->dom, value, sizeof(struct json_value_s)); + new_value = (struct json_value_s *)state->dom; + state->dom += sizeof(struct json_value_s); + new_value->payload = state->dom; + + if (json_type_string == value->type) { + memcpy(state->dom, value->payload, sizeof(struct json_string_s)); + string = (struct json_string_s *)state->dom; + state->dom += sizeof(struct json_string_s); + + memcpy(state->data, string->string, string->string_size + 1); + string->string = state->data; + state->data += string->string_size + 1; + } else if (json_type_number == value->type) { + memcpy(state->dom, value->payload, sizeof(struct json_number_s)); + number = (struct json_number_s *)state->dom; + state->dom += sizeof(struct json_number_s); + + memcpy(state->data, number->number, number->number_size); + number->number = state->data; + state->data += number->number_size; + } else if (json_type_object == value->type) { + struct json_object_element_s *element; + size_t i; + + memcpy(state->dom, value->payload, sizeof(struct json_object_s)); + object = (struct json_object_s *)state->dom; + state->dom += sizeof(struct json_object_s); + + element = object->start; + object->start = (struct json_object_element_s *)state->dom; + + for (i = 0; i < object->length; i++) { + struct json_value_s *previous_value; + struct json_object_element_s *previous_element; + + memcpy(state->dom, element, sizeof(struct json_object_element_s)); + element = (struct json_object_element_s *)state->dom; + state->dom += sizeof(struct json_object_element_s); + + string = element->name; + memcpy(state->dom, string, sizeof(struct json_string_s)); + string = (struct json_string_s *)state->dom; + state->dom += sizeof(struct json_string_s); + element->name = string; + + memcpy(state->data, string->string, string->string_size + 1); + string->string = state->data; + state->data += string->string_size + 1; + + previous_value = element->value; + element->value = (struct json_value_s *)state->dom; + json_extract_copy_value(state, previous_value); + + previous_element = element; + element = element->next; + + if (element) { + previous_element->next = (struct json_object_element_s *)state->dom; + } + } + } else if (json_type_array == value->type) { + struct json_array_element_s *element; + size_t i; + + memcpy(state->dom, value->payload, sizeof(struct json_array_s)); + array = (struct json_array_s *)state->dom; + state->dom += sizeof(struct json_array_s); + + element = array->start; + array->start = (struct json_array_element_s *)state->dom; + + for (i = 0; i < array->length; i++) { + struct json_value_s *previous_value; + struct json_array_element_s *previous_element; + + memcpy(state->dom, element, sizeof(struct json_array_element_s)); + element = (struct json_array_element_s *)state->dom; + state->dom += sizeof(struct json_array_element_s); + + previous_value = element->value; + element->value = (struct json_value_s *)state->dom; + json_extract_copy_value(state, previous_value); + + previous_element = element; + element = element->next; + + if (element) { + previous_element->next = (struct json_array_element_s *)state->dom; + } + } + } +} + +struct json_value_s *json_extract_value_ex(const struct json_value_s *value, + void *(*alloc_func_ptr)(void *, + size_t), + void *user_data) { + void *allocation; + struct json_extract_result_s result; + struct json_extract_state_s state; + size_t total_size; + + if (json_null == value) { + /* invalid value was null! */ + return json_null; + } + + result = json_extract_get_value_size(value); + total_size = result.dom_size + result.data_size; + + if (json_null == alloc_func_ptr) { + allocation = malloc(total_size); + } else { + allocation = alloc_func_ptr(user_data, total_size); + } + + state.dom = (char *)allocation; + state.data = state.dom + result.dom_size; + + json_extract_copy_value(&state, value); + + return (struct json_value_s *)allocation; +} + +struct json_string_s *json_value_as_string(struct json_value_s *const value) { + if (value->type != json_type_string) { + return json_null; + } + + return (struct json_string_s *)value->payload; +} + +struct json_number_s *json_value_as_number(struct json_value_s *const value) { + if (value->type != json_type_number) { + return json_null; + } + + return (struct json_number_s *)value->payload; +} + +struct json_object_s *json_value_as_object(struct json_value_s *const value) { + if (value->type != json_type_object) { + return json_null; + } + + return (struct json_object_s *)value->payload; +} + +struct json_array_s *json_value_as_array(struct json_value_s *const value) { + if (value->type != json_type_array) { + return json_null; + } + + return (struct json_array_s *)value->payload; +} + +int json_value_is_true(const struct json_value_s *const value) { + return value->type == json_type_true; +} + +int json_value_is_false(const struct json_value_s *const value) { + return value->type == json_type_false; +} + +int json_value_is_null(const struct json_value_s *const value) { + return value->type == json_type_null; +} + +json_weak int +json_write_minified_get_value_size(const struct json_value_s *value, + size_t *size); + +json_weak int json_write_get_number_size(const struct json_number_s *number, + size_t *size); +int json_write_get_number_size(const struct json_number_s *number, + size_t *size) { + json_uintmax_t parsed_number; + size_t i; + + if (number->number_size >= 2) { + switch (number->number[1]) { + default: + break; + case 'x': + case 'X': + /* the number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal + * so we have to do extra work to convert it to a non-hexadecimal for JSON + * output. */ + parsed_number = json_strtoumax(number->number, json_null, 0); + + i = 0; + + while (0 != parsed_number) { + parsed_number /= 10; + i++; + } + + *size += i; + return 0; + } + } + + /* check to see if the number has leading/trailing decimal point. */ + i = 0; + + /* skip any leading '+' or '-'. */ + if ((i < number->number_size) && + (('+' == number->number[i]) || ('-' == number->number[i]))) { + i++; + } + + /* check if we have infinity. */ + if ((i < number->number_size) && ('I' == number->number[i])) { + const char *inf = "Infinity"; + size_t k; + + for (k = i; k < number->number_size; k++) { + const char c = *inf++; + + /* Check if we found the Infinity string! */ + if ('\0' == c) { + break; + } else if (c != number->number[k]) { + break; + } + } + + if ('\0' == *inf) { + /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */ + *size += 22; + + /* if we had a leading '-' we need to record it in the JSON output. */ + if ('-' == number->number[0]) { + *size += 1; + } + } + + return 0; + } + + /* check if we have nan. */ + if ((i < number->number_size) && ('N' == number->number[i])) { + const char *nan = "NaN"; + size_t k; + + for (k = i; k < number->number_size; k++) { + const char c = *nan++; + + /* Check if we found the NaN string! */ + if ('\0' == c) { + break; + } else if (c != number->number[k]) { + break; + } + } + + if ('\0' == *nan) { + /* NaN becomes 1 because JSON can't support it. */ + *size += 1; + + return 0; + } + } + + /* if we had a leading decimal point. */ + if ((i < number->number_size) && ('.' == number->number[i])) { + /* 1 + because we had a leading decimal point. */ + *size += 1; + goto cleanup; + } + + for (; i < number->number_size; i++) { + const char c = number->number[i]; + if (!('0' <= c && c <= '9')) { + break; + } + } + + /* if we had a trailing decimal point. */ + if ((i + 1 == number->number_size) && ('.' == number->number[i])) { + /* 1 + because we had a trailing decimal point. */ + *size += 1; + goto cleanup; + } + +cleanup: + *size += number->number_size; /* the actual string of the number. */ + + /* if we had a leading '+' we don't record it in the JSON output. */ + if ('+' == number->number[0]) { + *size -= 1; + } + + return 0; +} + +json_weak int json_write_get_string_size(const struct json_string_s *string, + size_t *size); +int json_write_get_string_size(const struct json_string_s *string, + size_t *size) { + size_t i; + for (i = 0; i < string->string_size; i++) { + switch (string->string[i]) { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + *size += 2; + break; + default: + *size += 1; + break; + } + } + + *size += 2; /* need to encode the surrounding '"' characters. */ + + return 0; +} + +json_weak int +json_write_minified_get_array_size(const struct json_array_s *array, + size_t *size); +int json_write_minified_get_array_size(const struct json_array_s *array, + size_t *size) { + struct json_array_element_s *element; + + *size += 2; /* '[' and ']'. */ + + if (1 < array->length) { + *size += array->length - 1; /* ','s seperate each element. */ + } + + for (element = array->start; json_null != element; element = element->next) { + if (json_write_minified_get_value_size(element->value, size)) { + /* value was malformed! */ + return 1; + } + } + + return 0; +} + +json_weak int +json_write_minified_get_object_size(const struct json_object_s *object, + size_t *size); +int json_write_minified_get_object_size(const struct json_object_s *object, + size_t *size) { + struct json_object_element_s *element; + + *size += 2; /* '{' and '}'. */ + + *size += object->length; /* ':'s seperate each name/value pair. */ + + if (1 < object->length) { + *size += object->length - 1; /* ','s seperate each element. */ + } + + for (element = object->start; json_null != element; element = element->next) { + if (json_write_get_string_size(element->name, size)) { + /* string was malformed! */ + return 1; + } + + if (json_write_minified_get_value_size(element->value, size)) { + /* value was malformed! */ + return 1; + } + } + + return 0; +} + +json_weak int +json_write_minified_get_value_size(const struct json_value_s *value, + size_t *size); +int json_write_minified_get_value_size(const struct json_value_s *value, + size_t *size) { + switch (value->type) { + default: + /* unknown value type found! */ + return 1; + case json_type_number: + return json_write_get_number_size((struct json_number_s *)value->payload, + size); + case json_type_string: + return json_write_get_string_size((struct json_string_s *)value->payload, + size); + case json_type_array: + return json_write_minified_get_array_size( + (struct json_array_s *)value->payload, size); + case json_type_object: + return json_write_minified_get_object_size( + (struct json_object_s *)value->payload, size); + case json_type_true: + *size += 4; /* the string "true". */ + return 0; + case json_type_false: + *size += 5; /* the string "false". */ + return 0; + case json_type_null: + *size += 4; /* the string "null". */ + return 0; + } +} + +json_weak char *json_write_minified_value(const struct json_value_s *value, + char *data); + +json_weak char *json_write_number(const struct json_number_s *number, + char *data); +char *json_write_number(const struct json_number_s *number, char *data) { + json_uintmax_t parsed_number, backup; + size_t i; + + if (number->number_size >= 2) { + switch (number->number[1]) { + default: + break; + case 'x': + case 'X': + /* The number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal + * so we have to do extra work to convert it to a non-hexadecimal for JSON + * output. */ + parsed_number = json_strtoumax(number->number, json_null, 0); + + /* We need a copy of parsed number twice, so take a backup of it. */ + backup = parsed_number; + + i = 0; + + while (0 != parsed_number) { + parsed_number /= 10; + i++; + } + + /* Restore parsed_number to its original value stored in the backup. */ + parsed_number = backup; + + /* Now use backup to take a copy of i, or the length of the string. */ + backup = i; + + do { + *(data + i - 1) = '0' + (char)(parsed_number % 10); + parsed_number /= 10; + i--; + } while (0 != parsed_number); + + data += backup; + + return data; + } + } + + /* check to see if the number has leading/trailing decimal point. */ + i = 0; + + /* skip any leading '-'. */ + if ((i < number->number_size) && + (('+' == number->number[i]) || ('-' == number->number[i]))) { + i++; + } + + /* check if we have infinity. */ + if ((i < number->number_size) && ('I' == number->number[i])) { + const char *inf = "Infinity"; + size_t k; + + for (k = i; k < number->number_size; k++) { + const char c = *inf++; + + /* Check if we found the Infinity string! */ + if ('\0' == c) { + break; + } else if (c != number->number[k]) { + break; + } + } + + if ('\0' == *inf++) { + const char *dbl_max; + + /* if we had a leading '-' we need to record it in the JSON output. */ + if ('-' == number->number[0]) { + *data++ = '-'; + } + + /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */ + for (dbl_max = "1.7976931348623158e308"; '\0' != *dbl_max; dbl_max++) { + *data++ = *dbl_max; + } + + return data; + } + } + + /* check if we have nan. */ + if ((i < number->number_size) && ('N' == number->number[i])) { + const char *nan = "NaN"; + size_t k; + + for (k = i; k < number->number_size; k++) { + const char c = *nan++; + + /* Check if we found the NaN string! */ + if ('\0' == c) { + break; + } else if (c != number->number[k]) { + break; + } + } + + if ('\0' == *nan++) { + /* NaN becomes 0 because JSON can't support it. */ + *data++ = '0'; + return data; + } + } + + /* if we had a leading decimal point. */ + if ((i < number->number_size) && ('.' == number->number[i])) { + i = 0; + + /* skip any leading '+'. */ + if ('+' == number->number[i]) { + i++; + } + + /* output the leading '-' if we had one. */ + if ('-' == number->number[i]) { + *data++ = '-'; + i++; + } + + /* insert a '0' to fix the leading decimal point for JSON output. */ + *data++ = '0'; + + /* and output the rest of the number as normal. */ + for (; i < number->number_size; i++) { + *data++ = number->number[i]; + } + + return data; + } + + for (; i < number->number_size; i++) { + const char c = number->number[i]; + if (!('0' <= c && c <= '9')) { + break; + } + } + + /* if we had a trailing decimal point. */ + if ((i + 1 == number->number_size) && ('.' == number->number[i])) { + i = 0; + + /* skip any leading '+'. */ + if ('+' == number->number[i]) { + i++; + } + + /* output the leading '-' if we had one. */ + if ('-' == number->number[i]) { + *data++ = '-'; + i++; + } + + /* and output the rest of the number as normal. */ + for (; i < number->number_size; i++) { + *data++ = number->number[i]; + } + + /* insert a '0' to fix the trailing decimal point for JSON output. */ + *data++ = '0'; + + return data; + } + + i = 0; + + /* skip any leading '+'. */ + if ('+' == number->number[i]) { + i++; + } + + for (; i < number->number_size; i++) { + *data++ = number->number[i]; + } + + return data; +} + +json_weak char *json_write_string(const struct json_string_s *string, + char *data); +char *json_write_string(const struct json_string_s *string, char *data) { + size_t i; + + *data++ = '"'; /* open the string. */ + + for (i = 0; i < string->string_size; i++) { + switch (string->string[i]) { + case '"': + *data++ = '\\'; /* escape the control character. */ + *data++ = '"'; + break; + case '\\': + *data++ = '\\'; /* escape the control character. */ + *data++ = '\\'; + break; + case '\b': + *data++ = '\\'; /* escape the control character. */ + *data++ = 'b'; + break; + case '\f': + *data++ = '\\'; /* escape the control character. */ + *data++ = 'f'; + break; + case '\n': + *data++ = '\\'; /* escape the control character. */ + *data++ = 'n'; + break; + case '\r': + *data++ = '\\'; /* escape the control character. */ + *data++ = 'r'; + break; + case '\t': + *data++ = '\\'; /* escape the control character. */ + *data++ = 't'; + break; + default: + *data++ = string->string[i]; + break; + } + } + + *data++ = '"'; /* close the string. */ + + return data; +} + +json_weak char *json_write_minified_array(const struct json_array_s *array, + char *data); +char *json_write_minified_array(const struct json_array_s *array, char *data) { + struct json_array_element_s *element = json_null; + + *data++ = '['; /* open the array. */ + + for (element = array->start; json_null != element; element = element->next) { + if (element != array->start) { + *data++ = ','; /* ','s seperate each element. */ + } + + data = json_write_minified_value(element->value, data); + + if (json_null == data) { + /* value was malformed! */ + return json_null; + } + } + + *data++ = ']'; /* close the array. */ + + return data; +} + +json_weak char *json_write_minified_object(const struct json_object_s *object, + char *data); +char *json_write_minified_object(const struct json_object_s *object, + char *data) { + struct json_object_element_s *element = json_null; + + *data++ = '{'; /* open the object. */ + + for (element = object->start; json_null != element; element = element->next) { + if (element != object->start) { + *data++ = ','; /* ','s seperate each element. */ + } + + data = json_write_string(element->name, data); + + if (json_null == data) { + /* string was malformed! */ + return json_null; + } + + *data++ = ':'; /* ':'s seperate each name/value pair. */ + + data = json_write_minified_value(element->value, data); + + if (json_null == data) { + /* value was malformed! */ + return json_null; + } + } + + *data++ = '}'; /* close the object. */ + + return data; +} + +json_weak char *json_write_minified_value(const struct json_value_s *value, + char *data); +char *json_write_minified_value(const struct json_value_s *value, char *data) { + switch (value->type) { + default: + /* unknown value type found! */ + return json_null; + case json_type_number: + return json_write_number((struct json_number_s *)value->payload, data); + case json_type_string: + return json_write_string((struct json_string_s *)value->payload, data); + case json_type_array: + return json_write_minified_array((struct json_array_s *)value->payload, + data); + case json_type_object: + return json_write_minified_object((struct json_object_s *)value->payload, + data); + case json_type_true: + data[0] = 't'; + data[1] = 'r'; + data[2] = 'u'; + data[3] = 'e'; + return data + 4; + case json_type_false: + data[0] = 'f'; + data[1] = 'a'; + data[2] = 'l'; + data[3] = 's'; + data[4] = 'e'; + return data + 5; + case json_type_null: + data[0] = 'n'; + data[1] = 'u'; + data[2] = 'l'; + data[3] = 'l'; + return data + 4; + } +} + +void *json_write_minified(const struct json_value_s *value, size_t *out_size) { + size_t size = 0; + char *data = json_null; + char *data_end = json_null; + + if (json_null == value) { + return json_null; + } + + if (json_write_minified_get_value_size(value, &size)) { + /* value was malformed! */ + return json_null; + } + + size += 1; /* for the '\0' null terminating character. */ + + data = (char *)malloc(size); + + if (json_null == data) { + /* malloc failed! */ + return json_null; + } + + data_end = json_write_minified_value(value, data); + + if (json_null == data_end) { + /* bad chi occurred! */ + free(data); + return json_null; + } + + /* null terminated the string. */ + *data_end = '\0'; + + if (json_null != out_size) { + *out_size = size; + } + + return data; +} + +json_weak int json_write_pretty_get_value_size(const struct json_value_s *value, + size_t depth, size_t indent_size, + size_t newline_size, + size_t *size); + +json_weak int json_write_pretty_get_array_size(const struct json_array_s *array, + size_t depth, size_t indent_size, + size_t newline_size, + size_t *size); +int json_write_pretty_get_array_size(const struct json_array_s *array, + size_t depth, size_t indent_size, + size_t newline_size, size_t *size) { + struct json_array_element_s *element; + + *size += 1; /* '['. */ + + if (0 < array->length) { + /* if we have any elements we need to add a newline after our '['. */ + *size += newline_size; + + *size += array->length - 1; /* ','s seperate each element. */ + + for (element = array->start; json_null != element; + element = element->next) { + /* each element gets an indent. */ + *size += (depth + 1) * indent_size; + + if (json_write_pretty_get_value_size(element->value, depth + 1, + indent_size, newline_size, size)) { + /* value was malformed! */ + return 1; + } + + /* each element gets a newline too. */ + *size += newline_size; + } + + /* since we wrote out some elements, need to add a newline and indentation. + */ + /* to the trailing ']'. */ + *size += depth * indent_size; + } + + *size += 1; /* ']'. */ + + return 0; +} + +json_weak int +json_write_pretty_get_object_size(const struct json_object_s *object, + size_t depth, size_t indent_size, + size_t newline_size, size_t *size); +int json_write_pretty_get_object_size(const struct json_object_s *object, + size_t depth, size_t indent_size, + size_t newline_size, size_t *size) { + struct json_object_element_s *element; + + *size += 1; /* '{'. */ + + if (0 < object->length) { + *size += newline_size; /* need a newline next. */ + + *size += object->length - 1; /* ','s seperate each element. */ + + for (element = object->start; json_null != element; + element = element->next) { + /* each element gets an indent and newline. */ + *size += (depth + 1) * indent_size; + *size += newline_size; + + if (json_write_get_string_size(element->name, size)) { + /* string was malformed! */ + return 1; + } + + *size += 3; /* seperate each name/value pair with " : ". */ + + if (json_write_pretty_get_value_size(element->value, depth + 1, + indent_size, newline_size, size)) { + /* value was malformed! */ + return 1; + } + } + + *size += depth * indent_size; + } + + *size += 1; /* '}'. */ + + return 0; +} + +json_weak int json_write_pretty_get_value_size(const struct json_value_s *value, + size_t depth, size_t indent_size, + size_t newline_size, + size_t *size); +int json_write_pretty_get_value_size(const struct json_value_s *value, + size_t depth, size_t indent_size, + size_t newline_size, size_t *size) { + switch (value->type) { + default: + /* unknown value type found! */ + return 1; + case json_type_number: + return json_write_get_number_size((struct json_number_s *)value->payload, + size); + case json_type_string: + return json_write_get_string_size((struct json_string_s *)value->payload, + size); + case json_type_array: + return json_write_pretty_get_array_size( + (struct json_array_s *)value->payload, depth, indent_size, newline_size, + size); + case json_type_object: + return json_write_pretty_get_object_size( + (struct json_object_s *)value->payload, depth, indent_size, + newline_size, size); + case json_type_true: + *size += 4; /* the string "true". */ + return 0; + case json_type_false: + *size += 5; /* the string "false". */ + return 0; + case json_type_null: + *size += 4; /* the string "null". */ + return 0; + } +} + +json_weak char *json_write_pretty_value(const struct json_value_s *value, + size_t depth, const char *indent, + const char *newline, char *data); + +json_weak char *json_write_pretty_array(const struct json_array_s *array, + size_t depth, const char *indent, + const char *newline, char *data); +char *json_write_pretty_array(const struct json_array_s *array, size_t depth, + const char *indent, const char *newline, + char *data) { + size_t k, m; + struct json_array_element_s *element; + + *data++ = '['; /* open the array. */ + + if (0 < array->length) { + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + + for (element = array->start; json_null != element; + element = element->next) { + if (element != array->start) { + *data++ = ','; /* ','s seperate each element. */ + + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + } + + for (k = 0; k < depth + 1; k++) { + for (m = 0; '\0' != indent[m]; m++) { + *data++ = indent[m]; + } + } + + data = json_write_pretty_value(element->value, depth + 1, indent, newline, + data); + + if (json_null == data) { + /* value was malformed! */ + return json_null; + } + } + + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + + for (k = 0; k < depth; k++) { + for (m = 0; '\0' != indent[m]; m++) { + *data++ = indent[m]; + } + } + } + + *data++ = ']'; /* close the array. */ + + return data; +} + +json_weak char *json_write_pretty_object(const struct json_object_s *object, + size_t depth, const char *indent, + const char *newline, char *data); +char *json_write_pretty_object(const struct json_object_s *object, size_t depth, + const char *indent, const char *newline, + char *data) { + size_t k, m; + struct json_object_element_s *element; + + *data++ = '{'; /* open the object. */ + + if (0 < object->length) { + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + + for (element = object->start; json_null != element; + element = element->next) { + if (element != object->start) { + *data++ = ','; /* ','s seperate each element. */ + + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + } + + for (k = 0; k < depth + 1; k++) { + for (m = 0; '\0' != indent[m]; m++) { + *data++ = indent[m]; + } + } + + data = json_write_string(element->name, data); + + if (json_null == data) { + /* string was malformed! */ + return json_null; + } + + /* " : "s seperate each name/value pair. */ + *data++ = ' '; + *data++ = ':'; + *data++ = ' '; + + data = json_write_pretty_value(element->value, depth + 1, indent, newline, + data); + + if (json_null == data) { + /* value was malformed! */ + return json_null; + } + } + + for (k = 0; '\0' != newline[k]; k++) { + *data++ = newline[k]; + } + + for (k = 0; k < depth; k++) { + for (m = 0; '\0' != indent[m]; m++) { + *data++ = indent[m]; + } + } + } + + *data++ = '}'; /* close the object. */ + + return data; +} + +json_weak char *json_write_pretty_value(const struct json_value_s *value, + size_t depth, const char *indent, + const char *newline, char *data); +char *json_write_pretty_value(const struct json_value_s *value, size_t depth, + const char *indent, const char *newline, + char *data) { + switch (value->type) { + default: + /* unknown value type found! */ + return json_null; + case json_type_number: + return json_write_number((struct json_number_s *)value->payload, data); + case json_type_string: + return json_write_string((struct json_string_s *)value->payload, data); + case json_type_array: + return json_write_pretty_array((struct json_array_s *)value->payload, depth, + indent, newline, data); + case json_type_object: + return json_write_pretty_object((struct json_object_s *)value->payload, + depth, indent, newline, data); + case json_type_true: + data[0] = 't'; + data[1] = 'r'; + data[2] = 'u'; + data[3] = 'e'; + return data + 4; + case json_type_false: + data[0] = 'f'; + data[1] = 'a'; + data[2] = 'l'; + data[3] = 's'; + data[4] = 'e'; + return data + 5; + case json_type_null: + data[0] = 'n'; + data[1] = 'u'; + data[2] = 'l'; + data[3] = 'l'; + return data + 4; + } +} + +void *json_write_pretty(const struct json_value_s *value, const char *indent, + const char *newline, size_t *out_size) { + size_t size = 0; + size_t indent_size = 0; + size_t newline_size = 0; + char *data = json_null; + char *data_end = json_null; + + if (json_null == value) { + return json_null; + } + + if (json_null == indent) { + indent = " "; /* default to two spaces. */ + } + + if (json_null == newline) { + newline = "\n"; /* default to linux newlines. */ + } + + while ('\0' != indent[indent_size]) { + ++indent_size; /* skip non-null terminating characters. */ + } + + while ('\0' != newline[newline_size]) { + ++newline_size; /* skip non-null terminating characters. */ + } + + if (json_write_pretty_get_value_size(value, 0, indent_size, newline_size, + &size)) { + /* value was malformed! */ + return json_null; + } + + size += 1; /* for the '\0' null terminating character. */ + + data = (char *)malloc(size); + + if (json_null == data) { + /* malloc failed! */ + return json_null; + } + + data_end = json_write_pretty_value(value, 0, indent, newline, data); + + if (json_null == data_end) { + /* bad chi occurred! */ + free(data); + return json_null; + } + + /* null terminated the string. */ + *data_end = '\0'; + + if (json_null != out_size) { + *out_size = size; + } + + return data; +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif /* SHEREDOM_JSON_H_INCLUDED. */ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h new file mode 100644 index 000000000000..979c2f8527e4 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h @@ -0,0 +1,427 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : +// Filename : public.sdk/source/vst/moduleinfo/jsoncxx.h +// Created by : Steinberg, 12/2021 +// Description : +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "json.h" +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) || __has_include() +#include +#define SMTG_HAS_CHARCONV +#endif + +//------------------------------------------------------------------------ +namespace JSON { +namespace Detail { + +//------------------------------------------------------------------------ +template +struct Base +{ + explicit Base (JsonT* o) : object_ (o) {} + explicit Base (const Base& o) : object_ (o.object_) {} + + Base& operator= (const Base& o) = default; + + operator JsonT* () const { return object_; } + JsonT* jsonValue () const { return object_; } + +protected: + Base () : object_ (nullptr) {} + + JsonT* object_; +}; + +//------------------------------------------------------------------------ +template +struct Iterator +{ + explicit Iterator (JsonElement el) : el (el) {} + + bool operator== (const Iterator& other) const { return other.el == el; } + bool operator!= (const Iterator& other) const { return other.el != el; } + + const JsonElement& operator* () const { return el; } + const JsonElement& operator-> () const { return el; } + + Iterator& operator++ () + { + if (el) + el = el.next (); + return *this; + } + + Iterator operator++ (int) + { + auto it = Iterator (el); + operator++ (); + return it; + } + +private: + JsonElement el; +}; + +//------------------------------------------------------------------------ +} // Detail + +struct Object; +struct Array; +struct String; +struct Number; +struct Boolean; + +//------------------------------------------------------------------------ +enum class Type +{ + Object, + Array, + String, + Number, + True, + False, + Null, +}; + +//------------------------------------------------------------------------ +struct SourceLocation +{ + size_t offset; + size_t line; + size_t row; +}; + +//------------------------------------------------------------------------ +struct Value : Detail::Base +{ + using Detail::Base::Base; + using VariantT = std::variant; + + std::optional asObject () const; + std::optional asArray () const; + std::optional asString () const; + std::optional asNumber () const; + std::optional asBoolean () const; + std::optional asNull () const; + + VariantT asVariant () const; + Type type () const; + + SourceLocation getSourceLocation () const; +}; + +//------------------------------------------------------------------------ +struct Boolean +{ + Boolean (size_t type) : value (type == json_type_true) {} + + operator bool () const { return value; } + +private: + bool value; +}; + +//------------------------------------------------------------------------ +struct String : Detail::Base +{ + using Detail::Base::Base; + + std::string_view text () const { return {jsonValue ()->string, jsonValue ()->string_size}; } + + SourceLocation getSourceLocation () const; +}; + +//------------------------------------------------------------------------ +struct Number : Detail::Base +{ + using Detail::Base::Base; + + std::string_view text () const { return {jsonValue ()->number, jsonValue ()->number_size}; } + + std::optional getInteger () const; + std::optional getDouble () const; +}; + +//------------------------------------------------------------------------ +struct ObjectElement : Detail::Base +{ + using Detail::Base::Base; + + String name () const { return String (jsonValue ()->name); } + Value value () const { return Value (jsonValue ()->value); } + + ObjectElement next () const { return ObjectElement (jsonValue ()->next); } +}; + +//------------------------------------------------------------------------ +struct Object : Detail::Base +{ + using Detail::Base::Base; + using Iterator = Detail::Iterator; + + size_t size () const { return jsonValue ()->length; } + + Iterator begin () const { return Iterator (ObjectElement (jsonValue ()->start)); } + Iterator end () const { return Iterator (ObjectElement (nullptr)); } +}; + +//------------------------------------------------------------------------ +struct ArrayElement : Detail::Base +{ + using Detail::Base::Base; + + Value value () const { return Value (jsonValue ()->value); } + + ArrayElement next () const { return ArrayElement (jsonValue ()->next); } +}; + +//------------------------------------------------------------------------ +struct Array : Detail::Base +{ + using Detail::Base::Base; + using Iterator = Detail::Iterator; + + size_t size () const { return jsonValue ()->length; } + + Iterator begin () const { return Iterator (ArrayElement (jsonValue ()->start)); } + Iterator end () const { return Iterator (ArrayElement (nullptr)); } +}; + +//------------------------------------------------------------------------ +struct Document : Value +{ + static std::variant parse (std::string_view data) + { + auto allocate = [] (void*, size_t allocSize) { return std::malloc (allocSize); }; + json_parse_result_s parse_result {}; + auto value = json_parse_ex (data.data (), data.size (), + json_parse_flags_allow_json5 | + json_parse_flags_allow_location_information, + allocate, nullptr, &parse_result); + if (value) + return Document (value); + return parse_result; + } + ~Document () noexcept + { + if (object_) + std::free (object_); + } + + Document (Document&& doc) noexcept { *this = std::move (doc); } + Document& operator= (Document&& doc) noexcept + { + std::swap (object_, doc.object_); + return *this; + } + +private: + using Value::Value; +}; + +//------------------------------------------------------------------------ +inline std::optional Value::asObject () const +{ + if (type () != Type::Object) + return {}; + return Object (json_value_as_object (jsonValue ())); +} + +//------------------------------------------------------------------------ +inline std::optional Value::asArray () const +{ + if (type () != Type::Array) + return {}; + return Array (json_value_as_array (jsonValue ())); +} + +//------------------------------------------------------------------------ +inline std::optional Value::asString () const +{ + if (type () != Type::String) + return {}; + return String (json_value_as_string (jsonValue ())); +} + +//------------------------------------------------------------------------ +inline std::optional Value::asNumber () const +{ + if (type () != Type::Number) + return {}; + return Number (json_value_as_number (jsonValue ())); +} + +//------------------------------------------------------------------------ +inline std::optional Value::asBoolean () const +{ + if (type () == Type::True || type () == Type::False) + return Boolean (jsonValue ()->type); + return {}; +} + +//------------------------------------------------------------------------ +inline std::optional Value::asNull () const +{ + if (type () != Type::Null) + return {}; + return nullptr; +} + +//------------------------------------------------------------------------ +inline Type Value::type () const +{ + switch (jsonValue ()->type) + { + case json_type_string: return Type::String; + case json_type_number: return Type::Number; + case json_type_object: return Type::Object; + case json_type_array: return Type::Array; + case json_type_true: return Type::True; + case json_type_false: return Type::False; + case json_type_null: return Type::Null; + } + assert (false); + return Type::Null; +} + +//------------------------------------------------------------------------ +inline Value::VariantT Value::asVariant () const +{ + switch (type ()) + { + case Type::String: return *asString (); + case Type::Number: return *asNumber (); + case Type::Object: return *asObject (); + case Type::Array: return *asArray (); + case Type::True: return *asBoolean (); + case Type::False: return *asBoolean (); + case Type::Null: return *asNull (); + } + assert (false); + return nullptr; +} + +//------------------------------------------------------------------------ +inline SourceLocation Value::getSourceLocation () const +{ + auto exValue = reinterpret_cast (jsonValue ()); + return {exValue->offset, exValue->line_no, exValue->row_no}; +} + +//------------------------------------------------------------------------ +inline SourceLocation String::getSourceLocation () const +{ + auto exValue = reinterpret_cast (jsonValue ()); + return {exValue->offset, exValue->line_no, exValue->row_no}; +} + +//------------------------------------------------------------------------ +inline std::optional Number::getInteger () const +{ +#if defined(SMTG_HAS_CHARCONV) + int64_t result {0}; + auto res = std::from_chars (jsonValue ()->number, + jsonValue ()->number + jsonValue ()->number_size, result); + if (res.ec == std::errc ()) + return result; + return {}; +#else + int64_t result {0}; + std::string str (jsonValue ()->number, jsonValue ()->number + jsonValue ()->number_size); + if (std::sscanf (str.data (), "%lld", &result) != 1) + return {}; + return result; +#endif +} + +//------------------------------------------------------------------------ +inline std::optional Number::getDouble () const +{ +#if 1 // clang still has no floting point from_chars version + size_t ctrl {0}; + auto result = std::stod (std::string (jsonValue ()->number, jsonValue ()->number_size), &ctrl); + if (ctrl > 0) + return result; +#else + double result {0.}; + auto res = std::from_chars (jsonValue ()->number, + jsonValue ()->number + jsonValue ()->number_size, result); + if (res.ec == std::errc ()) + return result; +#endif + return {}; +} + +//------------------------------------------------------------------------ +inline std::string_view errorToString (json_parse_error_e error) +{ + switch (error) + { + case json_parse_error_e::json_parse_error_none: return {}; + case json_parse_error_e::json_parse_error_expected_comma_or_closing_bracket: + return "json_parse_error_expected_comma_or_closing_bracket"; + case json_parse_error_e::json_parse_error_expected_colon: + return "json_parse_error_expected_colon"; + case json_parse_error_e::json_parse_error_expected_opening_quote: + return "json_parse_error_expected_opening_quote"; + case json_parse_error_e::json_parse_error_invalid_string_escape_sequence: + return "json_parse_error_invalid_string_escape_sequence"; + case json_parse_error_e::json_parse_error_invalid_number_format: + return "json_parse_error_invalid_number_format"; + case json_parse_error_e::json_parse_error_invalid_value: + return "json_parse_error_invalid_value"; + case json_parse_error_e::json_parse_error_premature_end_of_buffer: + return "json_parse_error_premature_end_of_buffer"; + case json_parse_error_e::json_parse_error_invalid_string: + return "json_parse_error_invalid_string"; + case json_parse_error_e::json_parse_error_allocator_failed: + return "json_parse_error_allocator_failed"; + case json_parse_error_e::json_parse_error_unexpected_trailing_characters: + return "json_parse_error_unexpected_trailing_characters"; + case json_parse_error_e::json_parse_error_unknown: return "json_parse_error_unknown"; + } + return {}; +} + +//------------------------------------------------------------------------ +} // JSON diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h new file mode 100644 index 000000000000..81b93f74beb1 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h @@ -0,0 +1,100 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfo +// Filename : public.sdk/source/vst/moduleinfo/moduleinfo.h +// Created by : Steinberg, 12/2021 +// Description : +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg { + +//------------------------------------------------------------------------ +struct ModuleInfo +{ +//------------------------------------------------------------------------ + struct FactoryInfo + { + std::string vendor; + std::string url; + std::string email; + int32_t flags {0}; + }; + +//------------------------------------------------------------------------ + struct Snapshot + { + double scaleFactor {1.}; + std::string path; + }; + using SnapshotList = std::vector; + +//------------------------------------------------------------------------ + struct ClassInfo + { + std::string cid; + std::string category; + std::string name; + std::string vendor; + std::string version; + std::string sdkVersion; + std::vector subCategories; + SnapshotList snapshots; + int32_t cardinality {0x7FFFFFFF}; + uint32_t flags {0}; + }; + +//------------------------------------------------------------------------ + struct Compatibility + { + std::string newCID; + std::vector oldCID; + }; + + using ClassList = std::vector; + using CompatibilityList = std::vector; + + std::string name; + std::string version; + FactoryInfo factoryInfo; + ClassList classes; + CompatibilityList compatibility; +}; + +//------------------------------------------------------------------------ +} // Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp new file mode 100644 index 000000000000..8f12829c7d9d --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp @@ -0,0 +1,309 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfo +// Filename : public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp +// Created by : Steinberg, 12/2021 +// Description : utility functions to create moduleinfo json files +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "moduleinfocreator.h" +#include "jsoncxx.h" +#include +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg::ModuleInfoLib { +using namespace VST3; +namespace { + +//------------------------------------------------------------------------ +struct JSON5Writer +{ +private: + std::ostream& stream; + bool beautify; + bool lastIsComma {false}; + int32_t intend {0}; + + void doBeautify () + { + if (beautify) + { + stream << '\n'; + for (int i = 0; i < intend; ++i) + stream << " "; + } + } + + void writeComma () + { + if (lastIsComma) + return; + stream << ","; + lastIsComma = true; + } + void startObject () + { + stream << "{"; + ++intend; + lastIsComma = false; + } + void endObject () + { + --intend; + doBeautify (); + stream << "}"; + lastIsComma = false; + } + void startArray () + { + stream << "["; + ++intend; + lastIsComma = false; + } + void endArray () + { + --intend; + doBeautify (); + stream << "]"; + lastIsComma = false; + } + +public: + JSON5Writer (std::ostream& stream, bool beautify = true) : stream (stream), beautify (beautify) + { + } + + void string (std::string_view str) + { + stream << "\"" << str << "\""; + lastIsComma = false; + } + + void boolean (bool val) + { + stream << (val ? "true" : "false"); + lastIsComma = false; + } + + template + void value (ValueT val) + { + stream << val; + lastIsComma = false; + } + + template + void object (Proc proc) + { + startObject (); + proc (); + endObject (); + } + + template + void array (Iterator begin, Iterator end, Proc proc) + { + startArray (); + while (begin != end) + { + doBeautify (); + proc (begin); + ++begin; + writeComma (); + } + endArray (); + } + + template + void keyValue (std::string_view key, Proc proc) + { + doBeautify (); + string (key); + stream << ": "; + proc (); + writeComma (); + } +}; + +//------------------------------------------------------------------------ +void writeSnapshots (const ModuleInfo::SnapshotList& snapshots, JSON5Writer& w) +{ + w.keyValue ("Snapshots", [&] () { + w.array (snapshots.begin (), snapshots.end (), [&] (const auto& el) { + w.object ([&] () { + w.keyValue ("Scale Factor", [&] () { w.value (el->scaleFactor); }); + w.keyValue ("Path", [&] () { w.string (el->path); }); + }); + }); + }); +} + +//------------------------------------------------------------------------ +void writeClassInfo (const ModuleInfo::ClassInfo& cls, JSON5Writer& w) +{ + w.keyValue ("CID", [&] () { w.string (cls.cid); }); + w.keyValue ("Category", [&] () { w.string (cls.category); }); + w.keyValue ("Name", [&] () { w.string (cls.name); }); + w.keyValue ("Vendor", [&] () { w.string (cls.vendor); }); + w.keyValue ("Version", [&] () { w.string (cls.version); }); + w.keyValue ("SDKVersion", [&] () { w.string (cls.sdkVersion); }); + const auto& sc = cls.subCategories; + if (!sc.empty ()) + { + w.keyValue ("Sub Categories", [&] () { + w.array (sc.begin (), sc.end (), [&] (const auto& cat) { w.string (*cat); }); + }); + } + w.keyValue ("Class Flags", [&] () { w.value (cls.flags); }); + w.keyValue ("Cardinality", [&] () { w.value (cls.cardinality); }); + writeSnapshots (cls.snapshots, w); +} + +//------------------------------------------------------------------------ +void writePluginCompatibility (const ModuleInfo::CompatibilityList& compat, JSON5Writer& w) +{ + if (compat.empty ()) + return; + w.keyValue ("Compatibility", [&] () { + w.array (compat.begin (), compat.end (), [&] (auto& el) { + w.object ([&] () { + w.keyValue ("New", [&] () { w.string (el->newCID); }); + w.keyValue ("Old", [&] () { + w.array (el->oldCID.begin (), el->oldCID.end (), + [&] (auto& oldEl) { w.string (*oldEl); }); + }); + }); + }); + }); +} + +//------------------------------------------------------------------------ +void writeFactoryInfo (const ModuleInfo::FactoryInfo& fi, JSON5Writer& w) +{ + w.keyValue ("Factory Info", [&] () { + w.object ([&] () { + w.keyValue ("Vendor", [&] () { w.string (fi.vendor); }); + w.keyValue ("URL", [&] () { w.string (fi.url); }); + w.keyValue ("E-Mail", [&] () { w.string (fi.email); }); + w.keyValue ("Flags", [&] () { + w.object ([&] () { + w.keyValue ("Unicode", + [&] () { w.boolean (fi.flags & PFactoryInfo::kUnicode); }); + w.keyValue ("Classes Discardable", [&] () { + w.boolean (fi.flags & PFactoryInfo::kClassesDiscardable); + }); + w.keyValue ("Component Non Discardable", [&] () { + w.boolean (fi.flags & PFactoryInfo::kComponentNonDiscardable); + }); + }); + }); + }); + }); +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +ModuleInfo createModuleInfo (const VST3::Hosting::Module& module, bool includeDiscardableClasses) +{ + ModuleInfo info; + + const auto& factory = module.getFactory (); + auto factoryInfo = factory.info (); + + info.name = module.getName (); + auto pos = info.name.find_last_of ('.'); + if (pos != std::string::npos) + info.name.erase (pos); + + info.factoryInfo.vendor = factoryInfo.vendor (); + info.factoryInfo.url = factoryInfo.url (); + info.factoryInfo.email = factoryInfo.email (); + info.factoryInfo.flags = factoryInfo.flags (); + + if (factoryInfo.classesDiscardable () == false || + (factoryInfo.classesDiscardable () && includeDiscardableClasses)) + { + auto snapshots = VST3::Hosting::Module::getSnapshots (module.getPath ()); + for (const auto& ci : factory.classInfos ()) + { + ModuleInfo::ClassInfo classInfo; + classInfo.cid = ci.ID ().toString (); + classInfo.category = ci.category (); + classInfo.name = ci.name (); + classInfo.vendor = ci.vendor (); + classInfo.version = ci.version (); + classInfo.sdkVersion = ci.sdkVersion (); + classInfo.subCategories = ci.subCategories (); + classInfo.cardinality = ci.cardinality (); + classInfo.flags = ci.classFlags (); + auto snapshotIt = std::find_if (snapshots.begin (), snapshots.end (), + [&] (const auto& el) { return el.uid == ci.ID (); }); + if (snapshotIt != snapshots.end ()) + { + for (auto& s : snapshotIt->images) + { + std::string_view path (s.path); + if (path.find (module.getPath ()) == 0) + path.remove_prefix (module.getPath ().size () + 1); + classInfo.snapshots.emplace_back ( + ModuleInfo::Snapshot {s.scaleFactor, {path.data (), path.size ()}}); + } + snapshots.erase (snapshotIt); + } + info.classes.emplace_back (std::move (classInfo)); + } + } + return info; +} + +//------------------------------------------------------------------------ +void outputJson (const ModuleInfo& info, std::ostream& output) +{ + JSON5Writer w (output); + w.object ([&] () { + w.keyValue ("Name", [&] () { w.string (info.name); }); + w.keyValue ("Version", [&] () { w.string (info.version); }); + writeFactoryInfo (info.factoryInfo, w); + writePluginCompatibility (info.compatibility, w); + w.keyValue ("Classes", [&] () { + w.array (info.classes.begin (), info.classes.end (), + [&] (const auto& cls) { w.object ([&] () { writeClassInfo (*cls, w); }); }); + }); + }); +} + +//------------------------------------------------------------------------ +} // Steinberg::ModuleInfoLib diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h new file mode 100644 index 000000000000..f28716ae2a31 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfo +// Filename : public.sdk/source/vst/moduleinfo/moduleinfocreator.h +// Created by : Steinberg, 12/2021 +// Description : utility functions to create moduleinfo json files +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "moduleinfo.h" +#include "public.sdk/source/vst/hosting/module.h" +#include +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg::ModuleInfoLib { + +//------------------------------------------------------------------------ +/** create a ModuleInfo from a module + * + * @param module module to create the module info from + * @param includeDiscardableClasses if true adds the current available classes to the module info + * @return a ModuleInfo struct with the classes and factory info of the module + */ +ModuleInfo createModuleInfo (const VST3::Hosting::Module& module, bool includeDiscardableClasses); + +//------------------------------------------------------------------------ +/** output the ModuleInfo as json to the stream + * + * @param info module info + * @param output output stream + */ +void outputJson (const ModuleInfo& info, std::ostream& output); + +//------------------------------------------------------------------------ +} // Steinberg::ModuelInfoLib diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp new file mode 100644 index 000000000000..0d09d2bb0c1d --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp @@ -0,0 +1,537 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfo +// Filename : public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp +// Created by : Steinberg, 01/2022 +// Description : utility functions to parse moduleinfo json files +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "moduleinfoparser.h" +#include "jsoncxx.h" +#include "pluginterfaces/base/ipluginbase.h" +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg::ModuleInfoLib { +namespace { + +//------------------------------------------------------------------------ +void printJsonParseError (json_parse_result_s& parseResult, std::ostream& errorOut) +{ + errorOut << "error : " + << JSON::errorToString (static_cast (parseResult.error)) << '\n'; + errorOut << "offset : " << parseResult.error_offset << '\n'; + errorOut << "line no: " << parseResult.error_line_no << '\n'; + errorOut << "row no : " << parseResult.error_row_no << '\n'; +} + +//------------------------------------------------------------------------ +struct parse_error : std::exception +{ + parse_error (const std::string& str, const JSON::Value& value) + : str (str), location (value.getSourceLocation ()) + { + addLocation (location); + } + parse_error (const std::string& str, const JSON::String& value) + : str (str), location (value.getSourceLocation ()) + { + addLocation (location); + } + const char* what () const noexcept override { return str.data (); } + +private: + void addLocation (const JSON::SourceLocation& loc) + { + str += '\n'; + str += "offset:"; + str += std::to_string (loc.offset); + str += '\n'; + str += "line:"; + str += std::to_string (loc.line); + str += '\n'; + str += "row:"; + str += std::to_string (loc.row); + str += '\n'; + } + + std::string str; + JSON::SourceLocation location; +}; + +//------------------------------------------------------------------------ +struct ModuleInfoJsonParser +{ + ModuleInfoJsonParser () = default; + + std::string_view getText (const JSON::Value& value) const + { + if (auto str = value.asString ()) + return str->text (); + throw parse_error ("Expect a String here", value); + } + + template + T getInteger (const JSON::Value& value) const + { + if (auto number = value.asNumber ()) + { + if (auto result = number->getInteger ()) + { + if (result > static_cast (std::numeric_limits::max ()) || + result < static_cast (std::numeric_limits::min ())) + throw parse_error ("Value is out of range here", value); + return static_cast (*result); + } + throw parse_error ("Expect an Integer here", value); + } + throw parse_error ("Expect a Number here", value); + } + + double getDouble (const JSON::Value& value) const + { + if (auto number = value.asNumber ()) + { + if (auto result = number->getDouble ()) + return *result; + throw parse_error ("Expect a Double here", value); + } + throw parse_error ("Expect a Number here", value); + } + + void parseFactoryInfo (const JSON::Value& value) + { + enum ParsedBits + { + Vendor = 1 << 0, + URL = 1 << 1, + EMail = 1 << 2, + Flags = 1 << 3, + }; + uint32_t parsed {0}; + if (auto obj = value.asObject ()) + { + for (const auto& el : *obj) + { + auto elementName = el.name ().text (); + if (elementName == "Vendor") + { + if (parsed & ParsedBits::Vendor) + throw parse_error ("Only one 'Vendor' key allowed", el.name ()); + parsed |= ParsedBits::Vendor; + info.factoryInfo.vendor = getText (el.value ()); + } + else if (elementName == "URL") + { + if (parsed & ParsedBits::URL) + throw parse_error ("Only one 'URL' key allowed", el.name ()); + parsed |= ParsedBits::URL; + info.factoryInfo.url = getText (el.value ()); + } + else if (elementName == "E-Mail") + { + if (parsed & ParsedBits::EMail) + throw parse_error ("Only one 'E-Mail' key allowed", el.name ()); + parsed |= ParsedBits::EMail; + info.factoryInfo.email = getText (el.value ()); + } + else if (elementName == "Flags") + { + if (parsed & ParsedBits::Flags) + throw parse_error ("Only one 'Flags' key allowed", el.name ()); + auto flags = el.value ().asObject (); + if (!flags) + throw parse_error ("Expect 'Flags' to be a JSON Object", el.name ()); + for (const auto& flag : *flags) + { + auto flagName = flag.name ().text (); + auto flagValue = flag.value ().asBoolean (); + if (!flagValue) + throw parse_error ("Flag must be a boolean", flag.value ()); + if (flagName == "Classes Discardable") + { + if (*flagValue) + info.factoryInfo.flags |= PFactoryInfo::kClassesDiscardable; + } + else if (flagName == "Component Non Discardable") + { + if (*flagValue) + info.factoryInfo.flags |= PFactoryInfo::kComponentNonDiscardable; + } + else if (flagName == "Unicode") + { + if (*flagValue) + info.factoryInfo.flags |= PFactoryInfo::kUnicode; + } + else + throw parse_error ("Unknown flag", flag.name ()); + } + parsed |= ParsedBits::Flags; + } + } + } + if (!(parsed & ParsedBits::Vendor)) + throw std::logic_error ("Missing 'Vendor' in Factory Info"); + if (!(parsed & ParsedBits::URL)) + throw std::logic_error ("Missing 'URL' in Factory Info"); + if (!(parsed & ParsedBits::EMail)) + throw std::logic_error ("Missing 'EMail' in Factory Info"); + if (!(parsed & ParsedBits::Flags)) + throw std::logic_error ("Missing 'Flags' in Factory Info"); + } + + void parseClasses (const JSON::Value& value) + { + enum ParsedBits + { + CID = 1 << 0, + Category = 1 << 1, + Name = 1 << 2, + Vendor = 1 << 3, + Version = 1 << 4, + SDKVersion = 1 << 5, + SubCategories = 1 << 6, + ClassFlags = 1 << 7, + Snapshots = 1 << 8, + Cardinality = 1 << 9, + }; + + auto array = value.asArray (); + if (!array) + throw parse_error ("Expect Classes Array", value); + for (const auto& classInfoEl : *array) + { + auto classInfo = classInfoEl.value ().asObject (); + if (!classInfo) + throw parse_error ("Expect Class Object", classInfoEl.value ()); + + ModuleInfo::ClassInfo ci {}; + + uint32_t parsed {0}; + + for (const auto& el : *classInfo) + { + auto elementName = el.name ().text (); + if (elementName == "CID") + { + if (parsed & ParsedBits::CID) + throw parse_error ("Only one 'CID' key allowed", el.name ()); + ci.cid = getText (el.value ()); + parsed |= ParsedBits::CID; + } + else if (elementName == "Category") + { + if (parsed & ParsedBits::Category) + throw parse_error ("Only one 'Category' key allowed", el.name ()); + ci.category = getText (el.value ()); + parsed |= ParsedBits::Category; + } + else if (elementName == "Name") + { + if (parsed & ParsedBits::Name) + throw parse_error ("Only one 'Name' key allowed", el.name ()); + ci.name = getText (el.value ()); + parsed |= ParsedBits::Name; + } + else if (elementName == "Vendor") + { + if (parsed & ParsedBits::Vendor) + throw parse_error ("Only one 'Vendor' key allowed", el.name ()); + ci.vendor = getText (el.value ()); + parsed |= ParsedBits::Vendor; + } + else if (elementName == "Version") + { + if (parsed & ParsedBits::Version) + throw parse_error ("Only one 'Version' key allowed", el.name ()); + ci.version = getText (el.value ()); + parsed |= ParsedBits::Version; + } + else if (elementName == "SDKVersion") + { + if (parsed & ParsedBits::SDKVersion) + throw parse_error ("Only one 'SDKVersion' key allowed", el.name ()); + ci.sdkVersion = getText (el.value ()); + parsed |= ParsedBits::SDKVersion; + } + else if (elementName == "Sub Categories") + { + if (parsed & ParsedBits::SubCategories) + throw parse_error ("Only one 'Sub Categories' key allowed", el.name ()); + auto subCatArr = el.value ().asArray (); + if (!subCatArr) + throw parse_error ("Expect Array here", el.value ()); + for (const auto& catEl : *subCatArr) + { + auto cat = getText (catEl.value ()); + ci.subCategories.emplace_back (cat); + } + parsed |= ParsedBits::SubCategories; + } + else if (elementName == "Class Flags") + { + if (parsed & ParsedBits::ClassFlags) + throw parse_error ("Only one 'Class Flags' key allowed", el.name ()); + ci.flags = getInteger (el.value ()); + parsed |= ParsedBits::ClassFlags; + } + else if (elementName == "Cardinality") + { + if (parsed & ParsedBits::Cardinality) + throw parse_error ("Only one 'Cardinality' key allowed", el.name ()); + ci.cardinality = getInteger (el.value ()); + parsed |= ParsedBits::Cardinality; + } + else if (elementName == "Snapshots") + { + if (parsed & ParsedBits::Snapshots) + throw parse_error ("Only one 'Snapshots' key allowed", el.name ()); + auto snapArr = el.value ().asArray (); + if (!snapArr) + throw parse_error ("Expect Array here", el.value ()); + for (const auto& snapEl : *snapArr) + { + auto snap = snapEl.value ().asObject (); + if (!snap) + throw parse_error ("Expect Object here", snapEl.value ()); + ModuleInfo::Snapshot snapshot; + for (const auto& spEl : *snap) + { + auto spElName = spEl.name ().text (); + if (spElName == "Path") + snapshot.path = getText (spEl.value ()); + else if (spElName == "Scale Factor") + snapshot.scaleFactor = getDouble (spEl.value ()); + else + throw parse_error ("Unexpected key", spEl.name ()); + } + if (snapshot.scaleFactor == 0. || snapshot.path.empty ()) + throw parse_error ("Missing Snapshot keys", snapEl.value ()); + ci.snapshots.emplace_back (std::move (snapshot)); + } + parsed |= ParsedBits::Snapshots; + } + else + throw parse_error ("Unexpected key", el.name ()); + } + if (!(parsed & ParsedBits::CID)) + throw parse_error ("'CID' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::Category)) + throw parse_error ("'Category' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::Name)) + throw parse_error ("'Name' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::Vendor)) + throw parse_error ("'Vendor' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::Version)) + throw parse_error ("'Version' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::SDKVersion)) + throw parse_error ("'SDK Version' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::ClassFlags)) + throw parse_error ("'Class Flags' key missing", classInfoEl.value ()); + if (!(parsed & ParsedBits::Cardinality)) + throw parse_error ("'Cardinality' key missing", classInfoEl.value ()); + info.classes.emplace_back (std::move (ci)); + } + } + + void parseCompatibility (const JSON::Value& value) + { + auto arr = value.asArray (); + if (!arr) + throw parse_error ("Expect Array here", value); + for (const auto& el : *arr) + { + auto obj = el.value ().asObject (); + if (!obj) + throw parse_error ("Expect Object here", el.value ()); + + ModuleInfo::Compatibility compat; + for (const auto& objEl : *obj) + { + auto elementName = objEl.name ().text (); + if (elementName == "New") + compat.newCID = getText (objEl.value ()); + else if (elementName == "Old") + { + auto oldElArr = objEl.value ().asArray (); + if (!oldElArr) + throw parse_error ("Expect Array here", objEl.value ()); + for (const auto& old : *oldElArr) + { + compat.oldCID.emplace_back (getText (old.value ())); + } + } + } + if (compat.newCID.empty ()) + throw parse_error ("Expect New CID here", el.value ()); + if (compat.oldCID.empty ()) + throw parse_error ("Expect Old CID here", el.value ()); + info.compatibility.emplace_back (std::move (compat)); + } + } + + void parse (const JSON::Document& doc) + { + auto docObj = doc.asObject (); + if (!docObj) + throw parse_error ("Unexpected", doc); + + enum ParsedBits + { + Name = 1 << 0, + Version = 1 << 1, + FactoryInfo = 1 << 2, + Compatibility = 1 << 3, + Classes = 1 << 4, + }; + + uint32_t parsed {0}; + for (const auto& el : *docObj) + { + auto elementName = el.name ().text (); + if (elementName == "Name") + { + if (parsed & ParsedBits::Name) + throw parse_error ("Only one 'Name' key allowed", el.name ()); + parsed |= ParsedBits::Name; + info.name = getText (el.value ()); + } + else if (elementName == "Version") + { + if (parsed & ParsedBits::Version) + throw parse_error ("Only one 'Version' key allowed", el.name ()); + parsed |= ParsedBits::Version; + info.version = getText (el.value ()); + } + else if (elementName == "Factory Info") + { + if (parsed & ParsedBits::FactoryInfo) + throw parse_error ("Only one 'Factory Info' key allowed", el.name ()); + parseFactoryInfo (el.value ()); + parsed |= ParsedBits::FactoryInfo; + } + else if (elementName == "Compatibility") + { + if (parsed & ParsedBits::Compatibility) + throw parse_error ("Only one 'Compatibility' key allowed", el.name ()); + parseCompatibility (el.value ()); + parsed |= ParsedBits::Compatibility; + } + else if (elementName == "Classes") + { + if (parsed & ParsedBits::Classes) + throw parse_error ("Only one 'Classes' key allowed", el.name ()); + parseClasses (el.value ()); + parsed |= ParsedBits::Classes; + } + else + { + throw parse_error ("Unexpected JSON Token", el.name ()); + } + } + if (!(parsed & ParsedBits::Name)) + throw std::logic_error ("'Name' key missing"); + if (!(parsed & ParsedBits::Version)) + throw std::logic_error ("'Version' key missing"); + if (!(parsed & ParsedBits::FactoryInfo)) + throw std::logic_error ("'Factory Info' key missing"); + if (!(parsed & ParsedBits::Classes)) + throw std::logic_error ("'Classes' key missing"); + } + + ModuleInfo&& takeInfo () { return std::move (info); } + +private: + ModuleInfo info; +}; + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +std::optional parseJson (std::string_view jsonData, std::ostream* optErrorOutput) +{ + auto docVar = JSON::Document::parse (jsonData); + if (auto res = std::get_if (&docVar)) + { + if (optErrorOutput) + printJsonParseError (*res, *optErrorOutput); + return {}; + } + auto doc = std::get_if (&docVar); + assert (doc); + try + { + ModuleInfoJsonParser parser; + parser.parse (*doc); + return parser.takeInfo (); + } + catch (std::exception& error) + { + if (optErrorOutput) + *optErrorOutput << error.what () << '\n'; + return {}; + } + // unreachable +} + +//------------------------------------------------------------------------ +std::optional parseCompatibilityJson (std::string_view jsonData, + std::ostream* optErrorOutput) +{ + auto docVar = JSON::Document::parse (jsonData); + if (auto res = std::get_if (&docVar)) + { + if (optErrorOutput) + printJsonParseError (*res, *optErrorOutput); + return {}; + } + auto doc = std::get_if (&docVar); + assert (doc); + try + { + ModuleInfoJsonParser parser; + parser.parseCompatibility (*doc); + return parser.takeInfo ().compatibility; + } + catch (std::exception& error) + { + if (optErrorOutput) + *optErrorOutput << error.what () << '\n'; + return {}; + } + // unreachable +} + +//------------------------------------------------------------------------ +} // Steinberg::ModuelInfoLib diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h new file mode 100644 index 000000000000..9b426da3c94e --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// Flags : clang-format SMTGSequencer +// +// Category : moduleinfo +// Filename : public.sdk/source/vst/moduleinfo/moduleinfoparser.h +// Created by : Steinberg, 01/2022 +// Description : utility functions to parse moduleinfo json files +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "moduleinfo.h" +#include +#include +#include + +//------------------------------------------------------------------------ +namespace Steinberg::ModuleInfoLib { + +//------------------------------------------------------------------------ +/** parse a json formatted string to a ModuleInfo struct + * + * @param jsonData a string view to a json formatted string + * @param optErrorOutput optional error output stream where to print parse error + * @return ModuleInfo if parsing succeeded + */ +std::optional parseJson (std::string_view jsonData, std::ostream* optErrorOutput); + +//------------------------------------------------------------------------ +/** parse a json formatted string to a ModuleInfo::CompatibilityList + * + * @param jsonData a string view to a json formatted string + * @param optErrorOutput optional error output stream where to print parse error + * @return ModuleInfo::CompatibilityList if parsing succeeded + */ +std::optional parseCompatibilityJson (std::string_view jsonData, + std::ostream* optErrorOutput); + +//------------------------------------------------------------------------ +} // Steinberg::ModuelInfoLib diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h new file mode 100644 index 000000000000..7ea6a3c37328 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/utility/optional.h +// Created by : Steinberg, 08/2016 +// Description : optional helper +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include + +//------------------------------------------------------------------------ +namespace VST3 { + +//------------------------------------------------------------------------ +template +struct Optional +{ + Optional () noexcept : valid (false) {} + explicit Optional (const T& v) noexcept : _value (v), valid (true) {} + Optional (T&& v) noexcept : _value (std::move (v)), valid (true) {} + + Optional (Optional&& other) noexcept { *this = std::move (other); } + Optional& operator= (Optional&& other) noexcept + { + valid = other.valid; + _value = std::move (other._value); + return *this; + } + + explicit operator bool () const noexcept + { + setValidationChecked (); + return valid; + } + + const T& operator* () const noexcept + { + checkValid (); + return _value; + } + + const T* operator-> () const noexcept + { + checkValid (); + return &_value; + } + + T& operator* () noexcept + { + checkValid (); + return _value; + } + + T* operator-> () noexcept + { + checkValid (); + return &_value; + } + + T&& value () noexcept + { + checkValid (); + return move (_value); + } + + const T& value () const noexcept + { + checkValid (); + return _value; + } + + void swap (T& other) noexcept + { + checkValid (); + auto tmp = std::move (other); + other = std::move (_value); + _value = std::move (tmp); + } + +private: + T _value {}; + bool valid; + +#if !defined(NDEBUG) + mutable bool validationChecked {false}; +#endif + + void setValidationChecked () const + { +#if !defined(NDEBUG) + validationChecked = true; +#endif + } + void checkValid () const + { +#if !defined(NDEBUG) + assert (validationChecked); +#endif + } +}; + +//------------------------------------------------------------------------ +} diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp new file mode 100644 index 000000000000..6bc7f3aa7c85 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp @@ -0,0 +1,148 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/utility/stringconvert.cpp +// Created by : Steinberg, 11/2014 +// Description : c++11 unicode string convert functions +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#include "stringconvert.h" +#include +#include +#include + +//------------------------------------------------------------------------ +namespace VST3 { +namespace StringConvert { + +//------------------------------------------------------------------------ +namespace { + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#define USE_WCHAR_AS_UTF16TYPE +using UTF16Type = wchar_t; +#else +using UTF16Type = char16_t; +#endif + +using Converter = std::wstring_convert, UTF16Type>; + +//------------------------------------------------------------------------ +Converter& converter () +{ + static Converter conv; + return conv; +} + +//------------------------------------------------------------------------ +} // anonymous + +//------------------------------------------------------------------------ +std::u16string convert (const std::string& utf8Str) +{ +#if defined(USE_WCHAR_AS_UTF16TYPE) + auto wstr = converter ().from_bytes (utf8Str); + return {wstr.data (), wstr.data () + wstr.size ()}; +#else + return converter ().from_bytes (utf8Str); +#endif +} + +//------------------------------------------------------------------------ +bool convert (const std::string& utf8Str, Steinberg::Vst::String128 str) +{ + return convert (utf8Str, str, 128); +} + +//------------------------------------------------------------------------ +bool convert (const std::string& utf8Str, Steinberg::Vst::TChar* str, uint32_t maxCharacters) +{ + auto ucs2 = convert (utf8Str); + if (ucs2.length () < maxCharacters) + { + ucs2.copy (reinterpret_cast (str), ucs2.length ()); + str[ucs2.length ()] = 0; + return true; + } + return false; +} + +//------------------------------------------------------------------------ +std::string convert (const Steinberg::Vst::TChar* str) +{ + return converter ().to_bytes (reinterpret_cast (str)); +} + +//------------------------------------------------------------------------ +std::string convert (const Steinberg::Vst::TChar* str, uint32_t max) +{ + std::string result; + if (str) + { + Steinberg::Vst::TChar tmp[2] {}; + for (uint32_t i = 0; i < max; ++i, ++str) + { + tmp[0] = *str; + if (tmp[0] == 0) + break; + result += convert (tmp); + } + } + return result; +} + +//------------------------------------------------------------------------ +std::string convert (const std::u16string& str) +{ + return converter ().to_bytes (reinterpret_cast (str.data ()), + reinterpret_cast (str.data () + str.size ())); +} + +//------------------------------------------------------------------------ +std::string convert (const char* str, uint32_t max) +{ + std::string result; + if (str) + { + result.reserve (max); + for (uint32_t i = 0; i < max; ++i, ++str) + { + if (*str == 0) + break; + result += *str; + } + } + return result; +} + +//------------------------------------------------------------------------ +} // String +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h new file mode 100644 index 000000000000..d2d4678a742a --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/utility/stringconvert.h +// Created by : Steinberg, 11/2014 +// Description : c++11 unicode string convert functions +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "pluginterfaces/vst/vsttypes.h" +#include + +//------------------------------------------------------------------------ +namespace VST3 { +namespace StringConvert { + +//------------------------------------------------------------------------ +/** + * convert an UTF-8 string to an UTF-16 string + * + * @param utf8Str UTF-8 string + * + * @return UTF-16 string + */ +extern std::u16string convert (const std::string& utf8Str); + +//------------------------------------------------------------------------ +/** + * convert an UTF-8 string to an UTF-16 string buffer with max 127 characters + * + * @param utf8Str UTF-8 string + * @param str UTF-16 string buffer + * + * @return true on success + */ +extern bool convert (const std::string& utf8Str, Steinberg::Vst::String128 str); + +//------------------------------------------------------------------------ +/** + * convert an UTF-8 string to an UTF-16 string buffer + * + * @param utf8Str UTF-8 string + * @param str UTF-16 string buffer + * @param maxCharacters max characters that fit into str + * + * @return true on success + */ +extern bool convert (const std::string& utf8Str, Steinberg::Vst::TChar* str, + uint32_t maxCharacters); + +//------------------------------------------------------------------------ +/** + * convert an UTF-16 string buffer to an UTF-8 string + * + * @param str UTF-16 string buffer + * + * @return UTF-8 string + */ +extern std::string convert (const Steinberg::Vst::TChar* str); + +//------------------------------------------------------------------------ +/** + * convert an UTF-16 string buffer to an UTF-8 string + * + * @param str UTF-16 string buffer + * @param max maximum characters in str + * + * @return UTF-8 string + */ +extern std::string convert (const Steinberg::Vst::TChar* str, uint32_t max); + +//------------------------------------------------------------------------ +/** + * convert an UTF-16 string to an UTF-8 string + * + * @param str UTF-16 string + * + * @return UTF-8 string + */ +extern std::string convert (const std::u16string& str); + +//------------------------------------------------------------------------ +/** + * convert a ASCII string buffer to an UTF-8 string + * + * @param str ASCII string buffer + * @param max maximum characters in str + * + * @return UTF-8 string + */ +extern std::string convert (const char* str, uint32_t max); + +//------------------------------------------------------------------------ +} // StringConvert + +//------------------------------------------------------------------------ +inline const Steinberg::Vst::TChar* toTChar (const std::u16string& str) +{ + return reinterpret_cast (str.data ()); +} + +//------------------------------------------------------------------------ +/** + * convert an number to an UTF-16 string + * + * @param value number + * + * @return UTF-16 string + */ +template +std::u16string toString (NumberT value) +{ + auto u8str = std::to_string (value); + return StringConvert::convert (u8str); +} + +//------------------------------------------------------------------------ +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h new file mode 100644 index 000000000000..2f8ed8b33592 --- /dev/null +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h @@ -0,0 +1,294 @@ +//----------------------------------------------------------------------------- +// Project : VST SDK +// +// Category : Helpers +// Filename : public.sdk/source/vst/utility/uid.h +// Created by : Steinberg, 08/2016 +// Description : UID +// +//----------------------------------------------------------------------------- +// LICENSE +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- + +#pragma once + +#include "optional.h" +#include "pluginterfaces/base/funknown.h" +#include + +//------------------------------------------------------------------------ +namespace VST3 { + +//------------------------------------------------------------------------ +struct UID +{ +#if defined(SMTG_OS_WINDOWS) && SMTG_OS_WINDOWS == 1 + static constexpr bool defaultComFormat = true; +#else + static constexpr bool defaultComFormat = false; +#endif + + using TUID = Steinberg::TUID; + + constexpr UID () noexcept = default; + UID (uint32_t l1, uint32_t l2, uint32_t l3, uint32_t l4, bool comFormat = defaultComFormat) + noexcept; + UID (const TUID& uid) noexcept; + UID (const UID& uid) noexcept; + UID& operator= (const UID& uid) noexcept; + UID& operator= (const TUID& uid) noexcept; + + constexpr const TUID& data () const noexcept; + constexpr size_t size () const noexcept; + + std::string toString (bool comFormat = defaultComFormat) const noexcept; + + template + static Optional fromString (const StringT& str, + bool comFormat = defaultComFormat) noexcept; + + static UID fromTUID (const TUID _uid) noexcept; +//------------------------------------------------------------------------ +private: + Steinberg::TUID _data {}; + + struct GUID + { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; + }; +}; + +//------------------------------------------------------------------------ +inline bool operator== (const UID& uid1, const UID& uid2) +{ + const uint64_t* p1 = reinterpret_cast (uid1.data ()); + const uint64_t* p2 = reinterpret_cast (uid2.data ()); + return p1[0] == p2[0] && p1[1] == p2[1]; +} + +//------------------------------------------------------------------------ +inline bool operator!= (const UID& uid1, const UID& uid2) +{ + return !(uid1 == uid2); +} + +//------------------------------------------------------------------------ +inline bool operator< (const UID& uid1, const UID& uid2) +{ + const uint64_t* p1 = reinterpret_cast (uid1.data ()); + const uint64_t* p2 = reinterpret_cast (uid2.data ()); + return (p1[0] < p2[0]) && (p1[1] < p2[1]); +} + +//------------------------------------------------------------------------ +inline UID::UID (uint32_t l1, uint32_t l2, uint32_t l3, uint32_t l4, bool comFormat) noexcept +{ + if (comFormat) + { + _data[0] = static_cast ((l1 & 0x000000FF)); + _data[1] = static_cast ((l1 & 0x0000FF00) >> 8); + _data[2] = static_cast ((l1 & 0x00FF0000) >> 16); + _data[3] = static_cast ((l1 & 0xFF000000) >> 24); + _data[4] = static_cast ((l2 & 0x00FF0000) >> 16); + _data[5] = static_cast ((l2 & 0xFF000000) >> 24); + _data[6] = static_cast ((l2 & 0x000000FF)); + _data[7] = static_cast ((l2 & 0x0000FF00) >> 8); + _data[8] = static_cast ((l3 & 0xFF000000) >> 24); + _data[9] = static_cast ((l3 & 0x00FF0000) >> 16); + _data[10] = static_cast ((l3 & 0x0000FF00) >> 8); + _data[11] = static_cast ((l3 & 0x000000FF)); + _data[12] = static_cast ((l4 & 0xFF000000) >> 24); + _data[13] = static_cast ((l4 & 0x00FF0000) >> 16); + _data[14] = static_cast ((l4 & 0x0000FF00) >> 8); + _data[15] = static_cast ((l4 & 0x000000FF)); + } + else + { + _data[0] = static_cast ((l1 & 0xFF000000) >> 24); + _data[1] = static_cast ((l1 & 0x00FF0000) >> 16); + _data[2] = static_cast ((l1 & 0x0000FF00) >> 8); + _data[3] = static_cast ((l1 & 0x000000FF)); + _data[4] = static_cast ((l2 & 0xFF000000) >> 24); + _data[5] = static_cast ((l2 & 0x00FF0000) >> 16); + _data[6] = static_cast ((l2 & 0x0000FF00) >> 8); + _data[7] = static_cast ((l2 & 0x000000FF)); + _data[8] = static_cast ((l3 & 0xFF000000) >> 24); + _data[9] = static_cast ((l3 & 0x00FF0000) >> 16); + _data[10] = static_cast ((l3 & 0x0000FF00) >> 8); + _data[11] = static_cast ((l3 & 0x000000FF)); + _data[12] = static_cast ((l4 & 0xFF000000) >> 24); + _data[13] = static_cast ((l4 & 0x00FF0000) >> 16); + _data[14] = static_cast ((l4 & 0x0000FF00) >> 8); + _data[15] = static_cast ((l4 & 0x000000FF)); + } +} + +//------------------------------------------------------------------------ +inline UID::UID (const TUID& uid) noexcept +{ + *this = uid; +} + +//------------------------------------------------------------------------ +inline UID::UID (const UID& uid) noexcept +{ + *this = uid; +} + +//------------------------------------------------------------------------ +inline UID& UID::operator= (const UID& uid) noexcept +{ + *this = uid.data (); + return *this; +} + +//------------------------------------------------------------------------ +inline UID& UID::operator= (const TUID& uid) noexcept +{ + uint64_t* p1 = reinterpret_cast (_data); + const uint64_t* p2 = reinterpret_cast (uid); + p1[0] = p2[0]; + p1[1] = p2[1]; + return *this; +} + +//------------------------------------------------------------------------ +inline constexpr auto UID::data () const noexcept -> const TUID& +{ + return _data; +} + +//------------------------------------------------------------------------ +inline constexpr size_t UID::size () const noexcept +{ + return sizeof (TUID); +} + +//------------------------------------------------------------------------ +inline std::string UID::toString (bool comFormat) const noexcept +{ + std::string result; + result.reserve (32); + if (comFormat) + { + const auto& g = reinterpret_cast (_data); + + char tmp[21] {}; + snprintf (tmp, 21, "%08X%04X%04X", g->Data1, g->Data2, g->Data3); + result = tmp; + + for (uint32_t i = 0; i < 8; ++i) + { + char s[3] {}; + snprintf (s, 3, "%02X", g->Data4[i]); + result += s; + } + } + else + { + for (uint32_t i = 0; i < 16; ++i) + { + char s[3] {}; + snprintf (s, 3, "%02X", static_cast (_data[i])); + result += s; + } + } + return result; +} + +//------------------------------------------------------------------------ +template +inline Optional UID::fromString (const StringT& str, bool comFormat) noexcept +{ + if (str.length () != 32) + return {}; + // TODO: this is a copy from FUID. there are no input validation checks !!! + if (comFormat) + { + TUID uid {}; + GUID g; + char s[33]; + + strcpy (s, str.data ()); + s[8] = 0; + sscanf (s, "%x", &g.Data1); + strcpy (s, str.data () + 8); + s[4] = 0; + sscanf (s, "%hx", &g.Data2); + strcpy (s, str.data () + 12); + s[4] = 0; + sscanf (s, "%hx", &g.Data3); + + memcpy (uid, &g, 8); + + for (uint32_t i = 8; i < 16; ++i) + { + char s2[3] {}; + s2[0] = str[i * 2]; + s2[1] = str[i * 2 + 1]; + + int32_t d = 0; + sscanf (s2, "%2x", &d); + uid[i] = static_cast (d); + } + return {uid}; + } + else + { + TUID uid {}; + for (uint32_t i = 0; i < 16; ++i) + { + char s[3] {}; + s[0] = str[i * 2]; + s[1] = str[i * 2 + 1]; + + int32_t d = 0; + sscanf (s, "%2x", &d); + uid[i] = static_cast (d); + } + return {uid}; + } +} + +//------------------------------------------------------------------------ +inline UID UID::fromTUID (const TUID _uid) noexcept +{ + UID result; + + uint64_t* p1 = reinterpret_cast (result._data); + const uint64_t* p2 = reinterpret_cast (_uid); + p1[0] = p2[0]; + p1[1] = p2[1]; + + return result; +} + +//------------------------------------------------------------------------ +} // VST3 diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp index 2615b875b4a2..8f6ff44fc82f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -50,7 +50,8 @@ Bus::Bus (const TChar* _name, BusType _busType, int32 _flags) //------------------------------------------------------------------------ bool Bus::getInfo (BusInfo& info) { - name.copyTo16 (info.name, 0, str16BufferSize (info.name) - 1); + memset (info.name, 0, sizeof (String128)); + name.copy (info.name, 128); info.busType = busType; info.flags = flags; return true; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h index c3c3c217c86e..f1e7ad4b06be 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -37,10 +37,13 @@ #pragma once #include "base/source/fobject.h" -#include "base/source/fstring.h" #include "pluginterfaces/vst/ivstcomponent.h" #include "pluginterfaces/vst/ivstaudioprocessor.h" +#include +#if SMTG_CPP_17 +#include +#endif #include //------------------------------------------------------------------------ @@ -64,8 +67,13 @@ class Bus: public FObject /** Activates the bus. */ void setActive (TBool state) { active = state; } +#if SMTG_CPP_17 /** Sets a new name for this bus. */ - void setName (String newName) { name = newName; } + void setName (std::u16string_view newName) { name = newName; } +#else + /** Sets a new name for this bus. */ + void setName (const std::u16string& newName) { name = newName; } +#endif /** Sets a new busType for this bus. */ void setBusType (BusType newBusType) { busType = newBusType; } @@ -79,7 +87,7 @@ class Bus: public FObject OBJ_METHODS (Vst::Bus, FObject) //------------------------------------------------------------------------ protected: - String name; ///< name + std::u16string name; ///< name BusType busType; ///< kMain or kAux, see \ref BusTypes int32 flags; ///< flags, see \ref BusInfo::BusFlags TBool active; ///< activation state diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp index 0c46feb3ab16..57e03d081508 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -70,7 +70,7 @@ BusList* Component::getBusList (MediaType type, BusDirection dir) { if (type == kAudio) return dir == kInput ? &audioInputs : &audioOutputs; - else if (type == kEvent) + if (type == kEvent) return dir == kInput ? &eventInputs : &eventOutputs; return nullptr; } diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h index 7994534aaf6f..a1009d48716f 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -59,6 +59,7 @@ class Component : public ComponentBase, public IComponent //---Internal Methods------- /** Sets the controller Class ID associated to its component. */ void setControllerClass (const FUID& cid) { controllerClass = cid; } + void setControllerClass (const TUID& cid) { controllerClass = FUID::fromTUID (cid); } /** Removes all Audio Busses. */ tresult removeAudioBusses (); diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp index 4d2443c9a635..c82ac39cde15 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -159,7 +159,7 @@ tresult ComponentBase::sendTextMessage (const char8* text) const } //------------------------------------------------------------------------ -tresult ComponentBase::sendMessageID (const char* messageID) const +tresult ComponentBase::sendMessageID (const char8* messageID) const { if (auto msg = owned (allocateMessage ())) { diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h index 64474bddeefc..e71b857be923 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp index a88483c038f8..4342c7b21c75 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -48,7 +48,7 @@ KnobMode EditController::hostKnobMode = kCircularMode; //------------------------------------------------------------------------ // EditController Implementation //------------------------------------------------------------------------ -EditController::EditController () : componentHandler (nullptr), componentHandler2 (nullptr) +EditController::EditController () { } @@ -63,17 +63,8 @@ tresult PLUGIN_API EditController::terminate () { parameters.removeAll (); - if (componentHandler) - { - componentHandler->release (); - componentHandler = nullptr; - } - - if (componentHandler2) - { - componentHandler2->release (); - componentHandler2 = nullptr; - } + componentHandler.reset (); + componentHandler2.reset (); return ComponentBase::terminate (); } @@ -189,25 +180,11 @@ tresult PLUGIN_API EditController::setComponentHandler (IComponentHandler* newHa return kResultTrue; } - if (componentHandler) - { - componentHandler->release (); - } - componentHandler = newHandler; - if (componentHandler) - { - componentHandler->addRef (); - } + componentHandler2.reset (); - // try to get the extended version - if (componentHandler2) - { - componentHandler2->release (); - componentHandler2 = nullptr; - } - - if (newHandler) + // try to get the extended version + if (newHandler) { newHandler->queryInterface (IComponentHandler2::iid, (void**)&componentHandler2); } @@ -302,10 +279,6 @@ tresult EditController::requestOpenEditor (FIDString name) EditorView::EditorView (EditController* _controller, ViewRect* size) : CPluginView (size), controller (_controller) { - if (controller) - { - controller->addRef (); - } } //------------------------------------------------------------------------ @@ -314,7 +287,7 @@ EditorView::~EditorView () if (controller) { controller->editorDestroyed (this); - controller->release (); + controller = nullptr; } } @@ -340,7 +313,7 @@ void EditorView::removedFromParent () //------------------------------------------------------------------------ // EditControllerEx1 implementation //------------------------------------------------------------------------ -EditControllerEx1::EditControllerEx1 () : selectedUnit (kRootUnitId) +EditControllerEx1::EditControllerEx1 () { UpdateHandler::instance (); } @@ -376,6 +349,8 @@ bool EditControllerEx1::addUnit (Unit* unit) //------------------------------------------------------------------------ tresult PLUGIN_API EditControllerEx1::getUnitInfo (int32 unitIndex, UnitInfo& info /*out*/) { + if (unitIndex < 0 || unitIndex >= static_cast (units.size ())) + return kResultFalse; if (Unit* unit = units.at (unitIndex)) { info = unit->getInfo (); @@ -586,9 +561,10 @@ tresult ProgramList::getProgramInfo (int32 programIndex, CString attributeId, StringMap::const_iterator it = programInfos[programIndex].find (attributeId); if (it != programInfos[programIndex].end ()) { - if (!it->second.isEmpty ()) + if (!it->second.empty ()) { - it->second.copyTo16 (value, 0, 128); + memset (value, 0, sizeof (String128)); + it->second.copy (value, 128); return kResultTrue; } } @@ -601,7 +577,8 @@ tresult ProgramList::getProgramName (int32 programIndex, String128 name /*out*/) { if (programIndex >= 0 && programIndex < static_cast (programNames.size ())) { - programNames.at (programIndex).copyTo16 (name, 0, 128); + memset (name, 0, sizeof (String128)); + programNames.at (programIndex).copy (name, 128); return kResultTrue; } return kResultFalse; @@ -633,7 +610,7 @@ Parameter* ProgramList::getParameter () unitId); for (const auto& programName : programNames) { - listParameter->appendString (programName); + listParameter->appendString (programName.data ()); } parameter = listParameter; } @@ -711,7 +688,8 @@ tresult ProgramListWithPitchNames::getPitchName (int32 programIndex, int16 midiP PitchNameMap::const_iterator it = pitchNames[programIndex].find (midiPitch); if (it != pitchNames[programIndex].end ()) { - it->second.copyTo16 (name, 0, 128); + memset (name, 0, sizeof (String128)); + it->second.copy (name, 128); return kResultTrue; } } diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h index d6727842a05a..9fcb0e692206 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -39,13 +39,13 @@ #include "public.sdk/source/vst/vstcomponentbase.h" #include "public.sdk/source/vst/vstparameters.h" #include "public.sdk/source/common/pluginview.h" -#include "base/source/fstring.h" #include "pluginterfaces/vst/ivsteditcontroller.h" #include "pluginterfaces/vst/ivstunits.h" -#include #include +#include +#include //------------------------------------------------------------------------ namespace Steinberg { @@ -125,8 +125,8 @@ class EditController : public ComponentBase, public IEditController, public IEdi REFCOUNT_METHODS (ComponentBase) //------------------------------------------------------------------------ protected: - IComponentHandler* componentHandler; - IComponentHandler2* componentHandler2; + IPtr componentHandler; + IPtr componentHandler2; ParameterContainer parameters; @@ -153,7 +153,7 @@ class EditorView : public CPluginView //------------------------------------------------------------------------ protected: - EditController* controller; + IPtr controller; }; //------------------------------------------------------------------------ @@ -241,8 +241,8 @@ class ProgramList : public FObject OBJ_METHODS (ProgramList, FObject) //------------------------------------------------------------------------ protected: - using StringMap = std::map; - using StringVector = std::vector; + using StringMap = std::map; + using StringVector = std::vector; using ProgramInfoVector = std::vector; ProgramListInfo info; UnitID unitId; @@ -275,7 +275,7 @@ class ProgramListWithPitchNames : public ProgramList OBJ_METHODS (ProgramListWithPitchNames, ProgramList) protected: - using PitchNameMap = std::map; + using PitchNameMap = std::map; using PitchNamesVector = std::vector; PitchNamesVector pitchNames; }; @@ -366,7 +366,7 @@ class EditControllerEx1 : public EditController, public IUnitInfo UnitVector units; ProgramListVector programLists; ProgramIndexMap programIndexMap; - UnitID selectedUnit; + UnitID selectedUnit {kRootUnitId}; }; //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp index aa06547135c7..c5ad8b08fd93 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -36,6 +36,7 @@ #include "pluginterfaces/base/funknown.h" +#include "pluginterfaces/base/iplugincompatibility.h" #include "pluginterfaces/vst/ivstaudioprocessor.h" #include "pluginterfaces/vst/ivstautomationstate.h" #include "pluginterfaces/vst/ivstchannelcontextinfo.h" @@ -58,86 +59,87 @@ //------------------------------------------------------------------------ namespace Steinberg { -namespace Vst { //----VST 3.0-------------------------------- -DEF_CLASS_IID (IComponent) -DEF_CLASS_IID (IAudioProcessor) -DEF_CLASS_IID (IUnitData) -DEF_CLASS_IID (IProgramListData) +DEF_CLASS_IID (Vst::IComponent) +DEF_CLASS_IID (Vst::IAudioProcessor) +DEF_CLASS_IID (Vst::IUnitData) +DEF_CLASS_IID (Vst::IProgramListData) -DEF_CLASS_IID (IEditController) -DEF_CLASS_IID (IUnitInfo) +DEF_CLASS_IID (Vst::IEditController) +DEF_CLASS_IID (Vst::IUnitInfo) -DEF_CLASS_IID (IConnectionPoint) +DEF_CLASS_IID (Vst::IConnectionPoint) -DEF_CLASS_IID (IComponentHandler) -DEF_CLASS_IID (IUnitHandler) +DEF_CLASS_IID (Vst::IComponentHandler) +DEF_CLASS_IID (Vst::IUnitHandler) -DEF_CLASS_IID (IParamValueQueue) -DEF_CLASS_IID (IParameterChanges) +DEF_CLASS_IID (Vst::IParamValueQueue) +DEF_CLASS_IID (Vst::IParameterChanges) -DEF_CLASS_IID (IEventList) -DEF_CLASS_IID (IMessage) +DEF_CLASS_IID (Vst::IEventList) +DEF_CLASS_IID (Vst::IMessage) -DEF_CLASS_IID (IHostApplication) -DEF_CLASS_IID (IAttributeList) +DEF_CLASS_IID (Vst::IHostApplication) +DEF_CLASS_IID (Vst::IAttributeList) //----VST 3.0.1-------------------------------- -DEF_CLASS_IID (IMidiMapping) +DEF_CLASS_IID (Vst::IMidiMapping) //----VST 3.0.2-------------------------------- -DEF_CLASS_IID (IParameterFinder) +DEF_CLASS_IID (Vst::IParameterFinder) //----VST 3.1---------------------------------- -DEF_CLASS_IID (IComponentHandler2) -DEF_CLASS_IID (IEditController2) -DEF_CLASS_IID (IAudioPresentationLatency) -DEF_CLASS_IID (IVst3ToVst2Wrapper) -DEF_CLASS_IID (IVst3ToAUWrapper) +DEF_CLASS_IID (Vst::IComponentHandler2) +DEF_CLASS_IID (Vst::IEditController2) +DEF_CLASS_IID (Vst::IAudioPresentationLatency) +DEF_CLASS_IID (Vst::IVst3ToVst2Wrapper) +DEF_CLASS_IID (Vst::IVst3ToAUWrapper) //----VST 3.5---------------------------------- -DEF_CLASS_IID (INoteExpressionController) -DEF_CLASS_IID (IKeyswitchController) -DEF_CLASS_IID (IContextMenuTarget) -DEF_CLASS_IID (IContextMenu) -DEF_CLASS_IID (IComponentHandler3) -DEF_CLASS_IID (IEditControllerHostEditing) -DEF_CLASS_IID (IXmlRepresentationController) +DEF_CLASS_IID (Vst::INoteExpressionController) +DEF_CLASS_IID (Vst::IKeyswitchController) +DEF_CLASS_IID (Vst::IContextMenuTarget) +DEF_CLASS_IID (Vst::IContextMenu) +DEF_CLASS_IID (Vst::IComponentHandler3) +DEF_CLASS_IID (Vst::IEditControllerHostEditing) +DEF_CLASS_IID (Vst::IXmlRepresentationController) //----VST 3.6---------------------------------- -DEF_CLASS_IID (IInterAppAudioHost) -DEF_CLASS_IID (IInterAppAudioConnectionNotification) -DEF_CLASS_IID (IInterAppAudioPresetManager) -DEF_CLASS_IID (IStreamAttributes) +DEF_CLASS_IID (Vst::IInterAppAudioHost) +DEF_CLASS_IID (Vst::IInterAppAudioConnectionNotification) +DEF_CLASS_IID (Vst::IInterAppAudioPresetManager) +DEF_CLASS_IID (Vst::IStreamAttributes) //----VST 3.6.5-------------------------------- -DEF_CLASS_IID (ChannelContext::IInfoListener) -DEF_CLASS_IID (IPrefetchableSupport) -DEF_CLASS_IID (IUnitHandler2) -DEF_CLASS_IID (IAutomationState) +DEF_CLASS_IID (Vst::ChannelContext::IInfoListener) +DEF_CLASS_IID (Vst::IPrefetchableSupport) +DEF_CLASS_IID (Vst::IUnitHandler2) +DEF_CLASS_IID (Vst::IAutomationState) //----VST 3.6.8-------------------------------- -DEF_CLASS_IID (IComponentHandlerBusActivation) -DEF_CLASS_IID (IVst3ToAAXWrapper) +DEF_CLASS_IID (Vst::IComponentHandlerBusActivation) +DEF_CLASS_IID (Vst::IVst3ToAAXWrapper) //----VST 3.6.11-------------------------------- -DEF_CLASS_IID (INoteExpressionPhysicalUIMapping) +DEF_CLASS_IID (Vst::INoteExpressionPhysicalUIMapping) //----VST 3.6.12-------------------------------- -DEF_CLASS_IID (IMidiLearn) -DEF_CLASS_IID (IPlugInterfaceSupport) -DEF_CLASS_IID (IVst3WrapperMPESupport) +DEF_CLASS_IID (Vst::IMidiLearn) +DEF_CLASS_IID (Vst::IPlugInterfaceSupport) +DEF_CLASS_IID (Vst::IVst3WrapperMPESupport) //----VST 3.6.13-------------------------------- -DEF_CLASS_IID (ITestPlugProvider) +DEF_CLASS_IID (Vst::ITestPlugProvider) //----VST 3.7----------------------------------- -DEF_CLASS_IID (IParameterFunctionName) -DEF_CLASS_IID (IProcessContextRequirements) -DEF_CLASS_IID (IProgress) -DEF_CLASS_IID (ITestPlugProvider2) +DEF_CLASS_IID (Vst::IParameterFunctionName) +DEF_CLASS_IID (Vst::IProcessContextRequirements) +DEF_CLASS_IID (Vst::IProgress) +DEF_CLASS_IID (Vst::ITestPlugProvider2) + + +//----VST 3.7.5--------------------------------- +DEF_CLASS_IID (IPluginCompatibility) -//------------------------------------------------------------------------ -} // Vst } // Steinberg diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp index 400f6e356a30..dd0835167dfd 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -45,14 +45,13 @@ namespace Vst { //------------------------------------------------------------------------ // Parameter Implementation //------------------------------------------------------------------------ -Parameter::Parameter () : valueNormalized (0.), precision (4) +Parameter::Parameter () { - info = {}; } //------------------------------------------------------------------------ Parameter::Parameter (const ParameterInfo& info) -: info (info), valueNormalized (info.defaultNormalizedValue), precision (4) +: info (info), valueNormalized (info.defaultNormalizedValue) { } @@ -60,10 +59,7 @@ Parameter::Parameter (const ParameterInfo& info) Parameter::Parameter (const TChar* title, ParamID tag, const TChar* units, ParamValue defaultValueNormalized, int32 stepCount, int32 flags, UnitID unitID, const TChar* shortTitle) -: precision (4) { - info = {}; - UString (info.title, str16BufferSize (String128)).assign (title); if (units) UString (info.units, str16BufferSize (String128)).assign (units); @@ -302,7 +298,7 @@ bool StringListParameter::replaceString (int32 index, const String128 string) //------------------------------------------------------------------------ void StringListParameter::toString (ParamValue _valueNormalized, String128 string) const { - int32 index = (int32)toPlain (_valueNormalized); + int32 index = static_cast (toPlain (_valueNormalized)); if (const TChar* valueString = strings.at (index)) { UString (string, str16BufferSize (String128)).assign (valueString); @@ -345,7 +341,7 @@ ParamValue StringListParameter::toNormalized (ParamValue plainValue) const //------------------------------------------------------------------------ // ParameterContainer Implementation //------------------------------------------------------------------------ -ParameterContainer::ParameterContainer () : params (nullptr) +ParameterContainer::ParameterContainer () { } @@ -389,6 +385,14 @@ Parameter* ParameterContainer::addParameter (const ParameterInfo& info) return nullptr; } +//------------------------------------------------------------------------ +Parameter* ParameterContainer::getParameterByIndex (int32 index) const +{ + if (!params || index < 0 || index >= static_cast (params->size ())) + return nullptr; + return params->at (index); +} + //------------------------------------------------------------------------ Parameter* ParameterContainer::getParameter (ParamID tag) const { diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h index 51d1b4ab212c..88742e20ce46 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -98,9 +98,9 @@ class Parameter : public FObject OBJ_METHODS (Parameter, FObject) //------------------------------------------------------------------------ protected: - ParameterInfo info; - ParamValue valueNormalized; - int32 precision; + ParameterInfo info {0}; + ParamValue valueNormalized {0.}; + int32 precision {4}; }; //------------------------------------------------------------------------ @@ -212,7 +212,7 @@ class ParameterContainer int32 getParameterCount () const { return params ? static_cast (params->size ()) : 0; } /** Gets parameter by index. */ - Parameter* getParameterByIndex (int32 index) const { return params ? params->at (index) : nullptr; } + Parameter* getParameterByIndex (int32 index) const; /** Removes all parameters. */ void removeAll () @@ -231,7 +231,7 @@ class ParameterContainer protected: using ParameterPtrVector = std::vector>; using IndexMap = std::map; - ParameterPtrVector* params; + ParameterPtrVector* params {nullptr}; IndexMap id2index; }; diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp index 1adb8e49d73d..3a47c175c10e 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -35,10 +35,8 @@ //----------------------------------------------------------------------------- #include "vstpresetfile.h" - #include - namespace Steinberg { namespace Vst { @@ -178,7 +176,7 @@ bool PresetFile::loadPreset (IBStream* stream, const FUID& classID, IComponent* } //------------------------------------------------------------------------ -PresetFile::PresetFile (IBStream* stream) : stream (stream), entryCount (0) +PresetFile::PresetFile (IBStream* stream) : stream (stream) { memset (entries, 0, sizeof (entries)); @@ -490,13 +488,12 @@ bool PresetFile::storeComponentState (IBStream* componentStream) bool PresetFile::restoreComponentState (IComponent* component) { const Entry* e = getEntry (kComponentState); - if (e) - { - auto* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size); - FReleaser readOnlyBStreamReleaser (readOnlyBStream); - return verify (component->setState (readOnlyBStream)); - } - return false; + if (!e) + return false; + + auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size)); + return verify (component->setState (readOnlyBStream)); + } //------------------------------------------------------------------------ @@ -505,8 +502,7 @@ bool PresetFile::restoreComponentState (IEditController* editController) const Entry* e = getEntry (kComponentState); if (e) { - auto* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size); - FReleaser readOnlyBStreamReleaser (readOnlyBStream); + auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size)); return verify (editController->setComponentState (readOnlyBStream)); } return false; @@ -546,8 +542,7 @@ bool PresetFile::restoreControllerState (IEditController* editController) const Entry* e = getEntry (kControllerState); if (e) { - auto* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size); - FReleaser readOnlyBStreamReleaser (readOnlyBStream); + auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size)); return verify (editController->setState (readOnlyBStream)); } return false; @@ -603,9 +598,8 @@ bool PresetFile::restoreProgramData (IProgramListData* programListData, return false; int32 alreadyRead = sizeof (int32); - auto* readOnlyBStream = - new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead); - FReleaser readOnlyBStreamReleaser (readOnlyBStream); + auto readOnlyBStream = owned ( + new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead)); return programListData && verify (programListData->setProgramData ( savedProgramListID, programIndex, readOnlyBStream)); } @@ -639,9 +633,8 @@ bool PresetFile::restoreProgramData (IUnitData* unitData, UnitID* unitId) return false; int32 alreadyRead = sizeof (int32); - auto* readOnlyBStream = - new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead); - FReleaser readOnlyStreamReleaser (readOnlyBStream); + auto readOnlyBStream = owned ( + new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead)); return (unitData && verify (unitData->setUnitData (savedUnitID, readOnlyBStream))); } } @@ -662,9 +655,8 @@ bool PresetFile::restoreProgramData (IUnitInfo* unitInfo, int32 unitProgramListI return false; int32 alreadyRead = sizeof (int32); - auto* readOnlyBStream = - new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead); - FReleaser readOnlyStreamReleaser (readOnlyBStream); + auto readOnlyBStream = owned ( + new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead)); return (unitInfo && unitInfo->setUnitProgramData (unitProgramListID, programIndex, readOnlyBStream)); } @@ -788,7 +780,7 @@ tresult PLUGIN_API ReadOnlyBStream::read (void* buffer, int32 numBytes, int32* n if (!sourceStream) return kNotInitialized; - int32 maxBytesToRead = (int32) (sectionSize - seekPosition); + int32 maxBytesToRead = static_cast (sectionSize - seekPosition); if (numBytes > maxBytesToRead) numBytes = maxBytesToRead; if (numBytes <= 0) diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h index c68da25171e2..2a9f83fce58c 100644 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h +++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2021, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved //----------------------------------------------------------------------------- // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: @@ -124,7 +124,7 @@ class PresetFile TSize size; }; - IBStream* getStream () { return stream; } ///< Returns the associated stream. + IBStream* getStream () const { return stream; } ///< Returns the associated stream. const FUID& getClassID () const { return classID; } ///< Returns the associated classID (component ID: Processor part (not the controller!)). void setClassID (const FUID& uid) { classID = uid; }///< Sets the associated classID (component ID: Processor part (not the controller!)). @@ -223,7 +223,7 @@ class PresetFile FUID classID; ///< classID is the FUID of the component (processor) part enum { kMaxEntries = 128 }; Entry entries[kMaxEntries]; - int32 entryCount; + int32 entryCount {0}; }; //------------------------------------------------------------------------ diff --git a/modules/juce_audio_processors/format_types/juce_ARAHosting.h b/modules/juce_audio_processors/format_types/juce_ARAHosting.h index 08862331a2af..9da806df080a 100644 --- a/modules/juce_audio_processors/format_types/juce_ARAHosting.h +++ b/modules/juce_audio_processors/format_types/juce_ARAHosting.h @@ -107,6 +107,8 @@ struct ConversionFunctions when the lifetime of the helper class object ends. You shouldn't use this class directly but instead inherit from the helper classes. + + @tags{ARA} */ template class ManagedARAHandle @@ -279,6 +281,8 @@ class AudioModification : public ManagedARAHandle= __IPHONE_15_0) \ + || (JUCE_MAC && defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0) + #define JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED 1 +#else + #define JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED 0 +#endif + +#include + +#if JUCE_APPLE_MIDI_EVENT_LIST_SUPPORTED + #include +#endif + namespace juce { @@ -359,7 +373,10 @@ struct AudioUnitHelpers } auto layout = processor.getBusesLayout(); - auto maxNumChanToCheckFor = 9; + + // The 'standard' layout with the most channels defined is AudioChannelSet::create9point1point6(). + // This value should be updated if larger standard channel layouts are added in the future. + constexpr auto maxNumChanToCheckFor = 16; auto defaultInputs = processor.getChannelCountOfBus (true, 0); auto defaultOutputs = processor.getChannelCountOfBus (false, 0); diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index ef7b30ad05ff..6540a882130e 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -42,9 +42,8 @@ #include -#include -#include -#include +#include +#include #include "juce_AU_Shared.h" namespace juce @@ -507,40 +506,16 @@ static bool hasARAExtension ([[maybe_unused]] AudioUnit audioUnit) static void createAudioUnit (VersionedAudioComponent versionedComponent, AudioUnitCreationCallback callback) { - struct AUAsyncInitializationCallback - { - typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus); - - explicit AUAsyncInitializationCallback (AudioUnitCreationCallback inOriginalCallback) - : originalCallback (std::move (inOriginalCallback)) - { - block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); - } - - AUCompletionCallbackBlock getBlock() noexcept { return block; } - - void completion (AudioComponentInstance audioUnit, OSStatus err) - { - originalCallback (audioUnit, err); - - delete this; - } - - double sampleRate; - int framesPerBuffer; - AudioUnitCreationCallback originalCallback; - - ObjCBlock block; - }; - - auto callbackBlock = new AUAsyncInitializationCallback (std::move (callback)); - if (versionedComponent.isAUv3) { if (@available (macOS 10.11, *)) { - AudioComponentInstantiate (versionedComponent.audioComponent, kAudioComponentInstantiation_LoadOutOfProcess, - callbackBlock->getBlock()); + AudioComponentInstantiate (versionedComponent.audioComponent, + kAudioComponentInstantiation_LoadOutOfProcess, + ^(AudioComponentInstance audioUnit, OSStatus err) + { + callback (audioUnit, err); + }); return; } @@ -548,7 +523,7 @@ void completion (AudioComponentInstance audioUnit, OSStatus err) AudioComponentInstance audioUnit; auto err = AudioComponentInstanceNew (versionedComponent.audioComponent, &audioUnit); - callbackBlock->completion (err != noErr ? nullptr : audioUnit, err); + callback (err != noErr ? nullptr : audioUnit, err); } struct AudioComponentResult @@ -1272,7 +1247,7 @@ void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast (i), &sampleRate, &sampleRateSize); - if (sampleRate != sr) + if (! approximatelyEqual (sampleRate, sr)) { if (isAUv3) // setting kAudioUnitProperty_SampleRate fails on AUv3s { @@ -2616,9 +2591,6 @@ void updateBypass (bool processBlockBypassedCalled) { addAndMakeVisible (wrapper); - viewControllerCallback = - CreateObjCBlock (this, &AudioUnitPluginWindowCocoa::requestViewControllerCallback); - setOpaque (true); setVisible (true); setSize (100, 100); @@ -2674,7 +2646,6 @@ void childBoundsChanged (Component*) override AudioUnitFormatHelpers::AutoResizingNSViewComponent wrapper; typedef void (^ViewControllerCallbackBlock)(AUViewControllerBase *); - ObjCBlock viewControllerCallback; bool waitingForViewCallback = false; @@ -2728,12 +2699,9 @@ bool createView ([[maybe_unused]] bool createGenericViewIfNeeded) && dataSize == sizeof (ViewControllerCallbackBlock)) { waitingForViewCallback = true; - ViewControllerCallbackBlock callback; - callback = viewControllerCallback; - - ViewControllerCallbackBlock* info = &callback; + auto callback = ^(AUViewControllerBase* controller) { this->requestViewControllerCallback (controller); }; - if (noErr == AudioUnitSetProperty (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, 0, info, dataSize)) + if (noErr == AudioUnitSetProperty (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, 0, &callback, dataSize)) return true; waitingForViewCallback = false; @@ -2771,7 +2739,7 @@ void requestViewControllerCallback (AUViewControllerBase* controller) if (@available (macOS 10.11, *)) size = [controller preferredContentSize]; - if (size.width == 0 || size.height == 0) + if (approximatelyEqual (size.width, 0.0) || approximatelyEqual (size.height, 0.0)) size = controller.view.frame.size; return CGSizeMake (jmax ((CGFloat) 20.0f, size.width), diff --git a/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp index 6121dd84e828..275f2be8a878 100644 --- a/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp @@ -457,7 +457,7 @@ class LADSPAPluginInstance final : public AudioPluginInstance { const ScopedLock sl (pluginInstance.lock); - if (paramValue.unscaled != newValue) + if (! approximatelyEqual (paramValue.unscaled, newValue)) paramValue = ParameterValue (getNewParamScaled (interface->PortRangeHints [paramID], newValue), newValue); } } diff --git a/modules/juce_audio_processors/format_types/juce_LV2PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_LV2PluginFormat.cpp index 4ef7f4b3b5f1..b4f358812e20 100644 --- a/modules/juce_audio_processors/format_types/juce_LV2PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_LV2PluginFormat.cpp @@ -28,7 +28,7 @@ #include "juce_LV2Common.h" #include "juce_LV2Resources.h" -#include +#include #include @@ -2579,15 +2579,8 @@ class UiInstanceArgs File bundlePath; URL pluginUri; - auto withBundlePath (File v) const noexcept { return with (&UiInstanceArgs::bundlePath, std::move (v)); } - auto withPluginUri (URL v) const noexcept { return with (&UiInstanceArgs::pluginUri, std::move (v)); } - -private: - template - UiInstanceArgs with (Member UiInstanceArgs::* member, Member value) const noexcept - { - return juce::lv2_host::with (*this, member, std::move (value)); - } + auto withBundlePath (File v) const noexcept { return withMember (*this, &UiInstanceArgs::bundlePath, std::move (v)); } + auto withPluginUri (URL v) const noexcept { return withMember (*this, &UiInstanceArgs::pluginUri, std::move (v)); } }; static File bundlePathFromUri (const char* uri) @@ -2614,7 +2607,7 @@ class UiInstance mLV2_UI__floatProtocol (map.map (LV2_UI__floatProtocol)), mLV2_ATOM__atomTransfer (map.map (LV2_ATOM__atomTransfer)), mLV2_ATOM__eventTransfer (map.map (LV2_ATOM__eventTransfer)), - instance (makeInstance (args.pluginUri, args.bundlePath, features)), + instance (makeInstance (args, features)), idleCallback (getExtensionData (world, LV2_UI__idleInterface)) { jassert (descriptor != nullptr); @@ -2682,14 +2675,14 @@ class UiInstance using Instance = std::unique_ptr; using Idle = int (*) (LV2UI_Handle); - Instance makeInstance (const URL& pluginUri, const File& bundlePath, const LV2_Feature* const* features) + Instance makeInstance (const UiInstanceArgs& args, const LV2_Feature* const* features) { if (descriptor->get() == nullptr) return { nullptr, [] (LV2UI_Handle) {} }; return Instance { descriptor->get()->instantiate (descriptor->get(), - pluginUri.toString (false).toRawUTF8(), - File::addTrailingSeparator (bundlePath.getFullPathName()).toRawUTF8(), + args.pluginUri.toString (true).toRawUTF8(), + File::addTrailingSeparator (args.bundlePath.getFullPathName()).toRawUTF8(), writeFunction, this, &widget, @@ -3287,7 +3280,7 @@ class ConfiguredEditorComponent : public Component, { if (auto* r = ref.getComponent()) { - if (std::exchange (r->nativeScaleFactor, platformScale) == platformScale) + if (approximatelyEqual (std::exchange (r->nativeScaleFactor, platformScale), platformScale)) return; r->nativeScaleFactor = platformScale; diff --git a/modules/juce_audio_processors/format_types/juce_LV2SupportLibs.cpp b/modules/juce_audio_processors/format_types/juce_LV2SupportLibs.cpp index bc81cdb6f4d5..4c63da5c8a11 100644 --- a/modules/juce_audio_processors/format_types/juce_LV2SupportLibs.cpp +++ b/modules/juce_audio_processors/format_types/juce_LV2SupportLibs.cpp @@ -31,6 +31,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc99-extensions", "-Wdeprecated-declarations", "-Wextra-semi", "-Wfloat-conversion", + "-Wfloat-equal", + "-Wformat-overflow", "-Wimplicit-float-conversion", "-Wimplicit-int-conversion", "-Wmicrosoft-include", @@ -114,3 +116,6 @@ using namespace Utils; #pragma pop_macro ("nil") } // extern "C" + +JUCE_END_IGNORE_WARNINGS_MSVC +JUCE_END_IGNORE_WARNINGS_GCC_LIKE diff --git a/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp b/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp index 90efcc5821c8..a65a0d59ecb0 100644 --- a/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp +++ b/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp @@ -29,7 +29,7 @@ namespace juce JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) -class LegacyAudioParameter : public AudioProcessorParameter +class LegacyAudioParameter : public HostedAudioProcessorParameter { public: LegacyAudioParameter (AudioProcessor& audioProcessorToUse, int audioParameterIndex) @@ -54,7 +54,7 @@ class LegacyAudioParameter : public AudioProcessorParameter bool isMetaParameter() const override { return processor->isMetaParameter (parameterIndex); } Category getCategory() const override { return processor->getParameterCategory (parameterIndex); } String getCurrentValueAsText() const override { return processor->getParameterText (parameterIndex); } - String getParamID() const { return processor->getParameterID (parameterIndex); } + String getParameterID() const override { return processor->getParameterID (parameterIndex); } //============================================================================== float getValueForText (const String&) const override @@ -101,12 +101,12 @@ class LegacyAudioParameter : public AudioProcessorParameter static String getParamID (const AudioProcessorParameter* param, bool forceLegacyParamIDs) noexcept { if (auto* legacy = dynamic_cast (param)) - return forceLegacyParamIDs ? String (legacy->parameterIndex) : legacy->getParamID(); + return forceLegacyParamIDs ? String (legacy->parameterIndex) : legacy->getParameterID(); - if (auto* paramWithID = dynamic_cast (param)) + if (auto* paramWithID = dynamic_cast (param)) { if (! forceLegacyParamIDs) - return paramWithID->paramID; + return paramWithID->getParameterID(); } if (param != nullptr) diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index cf7f2a81437c..9043a0d77766 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -197,7 +197,7 @@ static inline Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg return arrangement; } -static Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept +static std::optional getSpeakerType (const AudioChannelSet& set, AudioChannelSet::ChannelType type) noexcept { switch (type) { @@ -241,6 +241,15 @@ static Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, Audio case AudioChannelSet::ambisonicACN13: return Steinberg::Vst::kSpeakerACN13; case AudioChannelSet::ambisonicACN14: return Steinberg::Vst::kSpeakerACN14; case AudioChannelSet::ambisonicACN15: return Steinberg::Vst::kSpeakerACN15; + case AudioChannelSet::ambisonicACN16: return Steinberg::Vst::kSpeakerACN16; + case AudioChannelSet::ambisonicACN17: return Steinberg::Vst::kSpeakerACN17; + case AudioChannelSet::ambisonicACN18: return Steinberg::Vst::kSpeakerACN18; + case AudioChannelSet::ambisonicACN19: return Steinberg::Vst::kSpeakerACN19; + case AudioChannelSet::ambisonicACN20: return Steinberg::Vst::kSpeakerACN20; + case AudioChannelSet::ambisonicACN21: return Steinberg::Vst::kSpeakerACN21; + case AudioChannelSet::ambisonicACN22: return Steinberg::Vst::kSpeakerACN22; + case AudioChannelSet::ambisonicACN23: return Steinberg::Vst::kSpeakerACN23; + case AudioChannelSet::ambisonicACN24: return Steinberg::Vst::kSpeakerACN24; case AudioChannelSet::topSideLeft: return Steinberg::Vst::kSpeakerTsl; case AudioChannelSet::topSideRight: return Steinberg::Vst::kSpeakerTsr; case AudioChannelSet::bottomFrontLeft: return Steinberg::Vst::kSpeakerBfl; @@ -254,15 +263,6 @@ static Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, Audio case AudioChannelSet::discreteChannel0: return Steinberg::Vst::kSpeakerM; - case AudioChannelSet::ambisonicACN16: - case AudioChannelSet::ambisonicACN17: - case AudioChannelSet::ambisonicACN18: - case AudioChannelSet::ambisonicACN19: - case AudioChannelSet::ambisonicACN20: - case AudioChannelSet::ambisonicACN21: - case AudioChannelSet::ambisonicACN22: - case AudioChannelSet::ambisonicACN23: - case AudioChannelSet::ambisonicACN24: case AudioChannelSet::ambisonicACN25: case AudioChannelSet::ambisonicACN26: case AudioChannelSet::ambisonicACN27: @@ -274,17 +274,44 @@ static Steinberg::Vst::Speaker getSpeakerType (const AudioChannelSet& set, Audio case AudioChannelSet::ambisonicACN33: case AudioChannelSet::ambisonicACN34: case AudioChannelSet::ambisonicACN35: + case AudioChannelSet::ambisonicACN36: + case AudioChannelSet::ambisonicACN37: + case AudioChannelSet::ambisonicACN38: + case AudioChannelSet::ambisonicACN39: + case AudioChannelSet::ambisonicACN40: + case AudioChannelSet::ambisonicACN41: + case AudioChannelSet::ambisonicACN42: + case AudioChannelSet::ambisonicACN43: + case AudioChannelSet::ambisonicACN44: + case AudioChannelSet::ambisonicACN45: + case AudioChannelSet::ambisonicACN46: + case AudioChannelSet::ambisonicACN47: + case AudioChannelSet::ambisonicACN48: + case AudioChannelSet::ambisonicACN49: + case AudioChannelSet::ambisonicACN50: + case AudioChannelSet::ambisonicACN51: + case AudioChannelSet::ambisonicACN52: + case AudioChannelSet::ambisonicACN53: + case AudioChannelSet::ambisonicACN54: + case AudioChannelSet::ambisonicACN55: + case AudioChannelSet::ambisonicACN56: + case AudioChannelSet::ambisonicACN57: + case AudioChannelSet::ambisonicACN58: + case AudioChannelSet::ambisonicACN59: + case AudioChannelSet::ambisonicACN60: + case AudioChannelSet::ambisonicACN61: + case AudioChannelSet::ambisonicACN62: + case AudioChannelSet::ambisonicACN63: case AudioChannelSet::wideLeft: case AudioChannelSet::wideRight: case AudioChannelSet::unknown: break; } - auto channelIndex = static_cast (type) - (static_cast (AudioChannelSet::discreteChannel0) + 6ull); - return (1ull << (channelIndex + 33ull /* last speaker in vst layout + 1 */)); + return {}; } -static AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArrangement arr, Steinberg::Vst::Speaker type) noexcept +static std::optional getChannelType (Steinberg::Vst::SpeakerArrangement arr, Steinberg::Vst::Speaker type) noexcept { switch (type) { @@ -324,6 +351,15 @@ static AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArran case Steinberg::Vst::kSpeakerACN13: return AudioChannelSet::ambisonicACN13; case Steinberg::Vst::kSpeakerACN14: return AudioChannelSet::ambisonicACN14; case Steinberg::Vst::kSpeakerACN15: return AudioChannelSet::ambisonicACN15; + case Steinberg::Vst::kSpeakerACN16: return AudioChannelSet::ambisonicACN16; + case Steinberg::Vst::kSpeakerACN17: return AudioChannelSet::ambisonicACN17; + case Steinberg::Vst::kSpeakerACN18: return AudioChannelSet::ambisonicACN18; + case Steinberg::Vst::kSpeakerACN19: return AudioChannelSet::ambisonicACN19; + case Steinberg::Vst::kSpeakerACN20: return AudioChannelSet::ambisonicACN20; + case Steinberg::Vst::kSpeakerACN21: return AudioChannelSet::ambisonicACN21; + case Steinberg::Vst::kSpeakerACN22: return AudioChannelSet::ambisonicACN22; + case Steinberg::Vst::kSpeakerACN23: return AudioChannelSet::ambisonicACN23; + case Steinberg::Vst::kSpeakerACN24: return AudioChannelSet::ambisonicACN24; case Steinberg::Vst::kSpeakerTsl: return AudioChannelSet::topSideLeft; case Steinberg::Vst::kSpeakerTsr: return AudioChannelSet::topSideRight; case Steinberg::Vst::kSpeakerLcs: return AudioChannelSet::leftSurroundRear; @@ -340,12 +376,7 @@ static AudioChannelSet::ChannelType getChannelType (Steinberg::Vst::SpeakerArran case Steinberg::Vst::kSpeakerBrr: return AudioChannelSet::bottomRearRight; } - auto channelType = BigInteger (static_cast (type)).findNextSetBit (0); - - // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum - jassert (channelType >= 33); - - return static_cast (static_cast (AudioChannelSet::discreteChannel0) + 6 + (channelType - 33)); + return {}; } namespace detail @@ -394,6 +425,8 @@ namespace detail { k70_6, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, // The VST3 layout uses 'left/right' and 'left-of-center/right-of-center', but the JUCE layout uses 'left/right' and 'wide-left/wide-right'. + { k91_4, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } }, + { k90_4, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } }, { k91_6, { X::wideLeft, X::wideRight, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, { k90_6, { X::wideLeft, X::wideRight, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::left, X::right, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, }; @@ -406,7 +439,7 @@ namespace detail inline bool isLayoutTableValid() { for (const auto& item : detail::layoutTable) - if ((size_t) countNumberOfBits (item.arrangement) != item.channelOrder.size()) + if ((size_t) countNumberOfBits ((uint64) item.arrangement) != item.channelOrder.size()) return false; std::set arrangements; @@ -423,7 +456,7 @@ inline bool isLayoutTableValid() }); } -static Array getSpeakerOrder (Steinberg::Vst::SpeakerArrangement arr) +static std::optional> getSpeakerOrder (Steinberg::Vst::SpeakerArrangement arr) { using namespace Steinberg::Vst; using namespace Steinberg::Vst::SpeakerArr; @@ -445,12 +478,34 @@ static Array getSpeakerOrder (Steinberg::Vst::Spea result.ensureStorageAllocated (channels); for (auto i = 0; i < channels; ++i) - result.add (getChannelType (arr, getSpeaker (arr, i))); + if (const auto t = getChannelType (arr, getSpeaker (arr, i))) + result.add (*t); + + if (getChannelCount (arr) == result.size()) + return result; - return result; + return {}; } -static Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const AudioChannelSet& channels) noexcept +struct Ambisonics +{ + struct Mapping + { + Steinberg::Vst::SpeakerArrangement arrangement; + AudioChannelSet channelSet; + }; + + inline static const Mapping mappings[] + { + { Steinberg::Vst::SpeakerArr::kAmbi5thOrderACN, AudioChannelSet::ambisonic (5) }, + { Steinberg::Vst::SpeakerArr::kAmbi6thOrderACN, AudioChannelSet::ambisonic (6) }, + { Steinberg::Vst::SpeakerArr::kAmbi7thOrderACN, AudioChannelSet::ambisonic (7) }, + }; + + Ambisonics() = delete; +}; + +static std::optional getVst3SpeakerArrangement (const AudioChannelSet& channels) noexcept { using namespace Steinberg::Vst::SpeakerArr; @@ -458,6 +513,10 @@ static Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const Audio std::call_once (detail::layoutTableCheckedFlag, [] { jassert (isLayoutTableValid()); }); #endif + for (const auto& mapping : Ambisonics::mappings) + if (channels == mapping.channelSet) + return mapping.arrangement; + const auto channelSetMatches = [&channels] (const auto& layoutPair) { return AudioChannelSet::channelSetWithChannels (layoutPair.channelOrder) == channels; @@ -470,21 +529,28 @@ static Steinberg::Vst::SpeakerArrangement getVst3SpeakerArrangement (const Audio Steinberg::Vst::SpeakerArrangement result = 0; for (const auto& type : channels.getChannelTypes()) - result |= getSpeakerType (channels, type); + if (const auto t = getSpeakerType (channels, type)) + result |= *t; - return result; + if (getChannelCount (result) == channels.size()) + return result; + + return {}; } -inline AudioChannelSet getChannelSetForSpeakerArrangement (Steinberg::Vst::SpeakerArrangement arr) noexcept +inline std::optional getChannelSetForSpeakerArrangement (Steinberg::Vst::SpeakerArrangement arr) noexcept { using namespace Steinberg::Vst::SpeakerArr; - const auto result = AudioChannelSet::channelSetWithChannels (getSpeakerOrder (arr)); + for (const auto& mapping : Ambisonics::mappings) + if (arr == mapping.arrangement) + return mapping.channelSet; - // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum - jassert (result.size() == getChannelCount (arr)); + if (const auto order = getSpeakerOrder (arr)) + return AudioChannelSet::channelSetWithChannels (*order); - return result; + // VST3 <-> JUCE layout conversion error: report this bug to the JUCE forum + return {}; } //============================================================================== @@ -522,7 +588,21 @@ struct ChannelMapping */ static std::vector makeChannelIndices (const AudioChannelSet& juceArrangement) { - const auto order = getSpeakerOrder (getVst3SpeakerArrangement (juceArrangement)); + const auto order = [&] + { + const auto fallback = juceArrangement.getChannelTypes(); + const auto vst3Arrangement = getVst3SpeakerArrangement (juceArrangement); + + if (! vst3Arrangement.has_value()) + return fallback; + + const auto reordered = getSpeakerOrder (*vst3Arrangement); + + if (! reordered.has_value() || AudioChannelSet::channelSetWithChannels (*reordered) != juceArrangement) + return fallback; + + return *reordered; + }(); std::vector result; @@ -613,7 +693,9 @@ static int countValidBuses (Steinberg::Vst::AudioBusBuffers* buffers, int32 num) })); } -template +enum class Direction { input, output }; + +template static bool validateLayouts (Iterator first, Iterator last, const std::vector& map) { if ((size_t) std::distance (first, last) > map.size()) @@ -623,12 +705,24 @@ static bool validateLayouts (Iterator first, Iterator last, const std::vector{}, *it); - const auto anyChannelIsNull = std::any_of (busPtr, busPtr + it->numChannels, [] (auto* ptr) { return ptr == nullptr; }); + auto& bus = *it; + auto** busPtr = getAudioBusPointer (detail::Tag{}, bus); + const auto expectedJuceChannels = (int) mapIterator->size(); + const auto actualVstChannels = (int) bus.numChannels; + const auto limit = jmin (expectedJuceChannels, actualVstChannels); + const auto anyChannelIsNull = std::any_of (busPtr, busPtr + limit, [] (auto* ptr) { return ptr == nullptr; }); + constexpr auto isInput = direction == Direction::input; + + const auto channelCountIsUsable = isInput ? expectedJuceChannels <= actualVstChannels + : actualVstChannels <= expectedJuceChannels; // Null channels are allowed if the bus is inactive - if (mapIterator->isHostActive() && (anyChannelIsNull || (int) mapIterator->size() != it->numChannels)) + if (mapIterator->isHostActive() && (anyChannelIsNull || ! channelCountIsUsable)) return false; + + // If this is hit, the destination bus has fewer channels than the source bus. + // As a result, some channels will 'go missing', and channel layouts may be invalid. + jassert (actualVstChannels == expectedJuceChannels); } // If the host didn't provide the full complement of buses, it must be because the other @@ -669,10 +763,10 @@ class ClientBufferMapperData // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here const auto vstInputs = countValidBuses (data.inputs, data.numInputs); - if (! validateLayouts (data.inputs, data.inputs + vstInputs, inputMap)) + if (! validateLayouts (data.inputs, data.inputs + vstInputs, inputMap)) return getBlankBuffer (usedChannels, (int) data.numSamples); - setUpInputChannels (data, (size_t) vstInputs, scratchBuffer, inputMap, channels); + setUpInputChannels (data, (size_t) vstInputs, scratchBuffer, inputMap, channels); setUpOutputChannels (scratchBuffer, outputMap, channels); const auto channelPtr = channels.empty() ? scratchBuffer.getArrayOfWritePointers() @@ -690,7 +784,7 @@ class ClientBufferMapperData { for (size_t busIndex = 0; busIndex < map.size(); ++busIndex) { - const auto mapping = map[busIndex]; + const auto& mapping = map[busIndex]; if (! mapping.isClientActive()) continue; @@ -702,7 +796,12 @@ class ClientBufferMapperData if (mapping.isHostActive() && busIndex < vstInputs) { - auto** busPtr = getAudioBusPointer (detail::Tag{}, data.inputs[busIndex]); + auto& bus = data.inputs[busIndex]; + + // Every JUCE channel must have a VST3 channel counterpart + jassert (mapping.size() <= static_cast (bus.numChannels)); + + auto** busPtr = getAudioBusPointer (detail::Tag{}, bus); for (size_t channelIndex = 0; channelIndex < mapping.size(); ++channelIndex) { @@ -921,7 +1020,7 @@ class ClientRemappedBuffer // WaveLab workaround: This host may report the wrong number of inputs/outputs so re-count here const auto vstOutputs = (size_t) countValidBuses (data.outputs, data.numOutputs); - if (validateLayouts (data.outputs, data.outputs + vstOutputs, *outputMap)) + if (validateLayouts (data.outputs, data.outputs + vstOutputs, *outputMap)) copyToHostOutputBuses (vstOutputs); else clearHostOutputBuses (vstOutputs); @@ -940,9 +1039,12 @@ class ClientRemappedBuffer { auto& bus = data.outputs[i]; + // Every VST3 channel must have a JUCE channel counterpart + jassert (static_cast (bus.numChannels) <= mapping.size()); + if (mapping.isClientActive()) { - for (size_t j = 0; j < mapping.size(); ++j) + for (size_t j = 0; j < static_cast (bus.numChannels); ++j) { auto* hostChannel = getAudioBusPointer (detail::Tag{}, bus)[j]; const auto juceChannel = juceBusOffset + (size_t) mapping.getJuceChannelForVst3Channel ((int) j); @@ -951,7 +1053,7 @@ class ClientRemappedBuffer } else { - for (size_t j = 0; j < mapping.size(); ++j) + for (size_t j = 0; j < static_cast (bus.numChannels); ++j) { auto* hostChannel = getAudioBusPointer (detail::Tag{}, bus)[j]; FloatVectorOperations::clear (hostChannel, (size_t) data.numSamples); diff --git a/modules/juce_audio_processors/format_types/juce_VST3Headers.h b/modules/juce_audio_processors/format_types/juce_VST3Headers.h index cd757c396218..eb715c60d2af 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Headers.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Headers.h @@ -32,44 +32,49 @@ // Wow, those Steinberg guys really don't worry too much about compiler warnings. JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC (0, 4505 4702 6011 6031 6221 6386 6387 6330 6001 28199) -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", - "-Wnon-virtual-dtor", - "-Wdeprecated", - "-Wreorder", - "-Wunsequenced", - "-Wint-to-pointer-cast", - "-Wunused-parameter", +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-W#warnings", + "-Wcast-align", + "-Wclass-memaccess", + "-Wcomma", "-Wconversion", - "-Woverloaded-virtual", - "-Wshadow", - "-Wdeprecated-register", - "-Wunused-function", - "-Wsign-conversion", - "-Wsign-compare", + "-Wcpp", "-Wdelete-non-virtual-dtor", + "-Wdeprecated", + "-Wdeprecated-copy-dtor", "-Wdeprecated-declarations", + "-Wdeprecated-register", + "-Wextra", "-Wextra-semi", - "-Wmissing-braces", - "-Wswitch-default", - "-Wshadow-field", - "-Wpragma-pack", - "-Wcomma", - "-Wzero-as-null-pointer-constant", - "-Winconsistent-missing-destructor-override", - "-Wcast-align", + "-Wfloat-equal", + "-Wformat", + "-Wformat-truncation=", + "-Wformat=", "-Wignored-qualifiers", + "-Winconsistent-missing-destructor-override", + "-Wint-to-pointer-cast", + "-Wlogical-op-parentheses", + "-Wmaybe-uninitialized", + "-Wmissing-braces", "-Wmissing-field-initializers", - "-Wformat=", - "-Wformat", - "-Wpedantic", - "-Wextra", - "-Wclass-memaccess", "-Wmissing-prototypes", + "-Wnon-virtual-dtor", + "-Woverloaded-virtual", + "-Wparentheses", + "-Wpedantic", + "-Wpragma-pack", + "-Wredundant-decls", + "-Wreorder", + "-Wshadow", + "-Wshadow-field", + "-Wsign-compare", + "-Wsign-conversion", + "-Wswitch-default", "-Wtype-limits", - "-Wcpp", - "-W#warnings", - "-Wmaybe-uninitialized", - "-Wunused-but-set-variable") + "-Wunsequenced", + "-Wunused-but-set-variable", + "-Wunused-function", + "-Wunused-parameter", + "-Wzero-as-null-pointer-constant") #undef DEVELOPMENT #define DEVELOPMENT 0 // This avoids a Clang warning in Steinberg code about unused values @@ -87,6 +92,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", #include #include #include + #include #include #include #include @@ -107,6 +113,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", #include #include #include + #include #include #include @@ -115,6 +122,10 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", // needed for VST_VERSION #include + #ifndef NOMINMAX + #define NOMINMAX // Some of the steinberg sources don't set this before including windows.h + #endif + #include #include #include @@ -137,6 +148,11 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", #include #endif +#pragma push_macro ("True") +#undef True +#pragma push_macro ("False") +#undef False + #include #include #include @@ -144,18 +160,24 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-dtor", #include #include #include - #include #include + #include #include #include - #include + #include + #include + #include + #include #include - #include #include #include + #include + #include #include #include - #include + +#pragma pop_macro ("True") +#pragma pop_macro ("False") #if VST_VERSION >= 0x03060c // 3.6.12 #include diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 7865d50bdad1..e049cc9d6ca4 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -94,7 +94,6 @@ static int warnOnFailureIfImplemented (int result) noexcept #define warnOnFailureIfImplemented(x) x #endif -enum class Direction { input, output }; enum class MediaKind { audio, event }; static Vst::MediaType toVstType (MediaKind x) { return x == MediaKind::audio ? Vst::kAudio : Vst::kEvent; } @@ -189,6 +188,66 @@ static void fillDescriptionWith (PluginDescription& description, ObjectType& obj description.manufacturerName = toString (object.vendor).trim(); } +static std::vector createPluginDescriptions (const File& pluginFile, const Steinberg::ModuleInfo& info) +{ + std::vector result; + + const auto araMainFactoryClassNames = [&] + { + std::unordered_set factories; + + #if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) + for (const auto& c : info.classes) + if (c.category == kARAMainFactoryClass) + factories.insert (CharPointer_UTF8 (c.name.c_str())); + #endif + + return factories; + }(); + + for (const auto& c : info.classes) + { + if (c.category != kVstAudioEffectClass) + continue; + + PluginDescription description; + + description.fileOrIdentifier = pluginFile.getFullPathName(); + description.lastFileModTime = pluginFile.getLastModificationTime(); + description.lastInfoUpdateTime = Time::getCurrentTime(); + description.manufacturerName = CharPointer_UTF8 (info.factoryInfo.vendor.c_str()); + description.name = CharPointer_UTF8 (info.name.c_str()); + description.descriptiveName = CharPointer_UTF8 (info.name.c_str()); + description.pluginFormatName = "VST3"; + description.numInputChannels = 0; + description.numOutputChannels = 0; + description.hasARAExtension = araMainFactoryClassNames.find (description.name) != araMainFactoryClassNames.end(); + + const auto uid = VST3::UID::fromString (c.cid); + + if (! uid) + continue; + + description.deprecatedUid = getHashForRange (uid->data()); + description.uniqueId = getHashForRange (getNormalisedTUID (uid->data())); + + StringArray categories; + + for (const auto& category : c.subCategories) + categories.add (CharPointer_UTF8 (category.c_str())); + + description.category = categories.joinIntoString ("|"); + + description.isInstrument = std::any_of (c.subCategories.begin(), + c.subCategories.end(), + [] (const auto& subcategory) { return subcategory == "Instrument"; }); + + result.push_back (description); + } + + return result; +} + static void createPluginDescription (PluginDescription& description, const File& pluginFile, const String& company, const String& name, const PClassInfo& info, PClassInfo2* info2, PClassInfoW* infoW, @@ -377,7 +436,7 @@ struct VST3HostContext : public Vst::IComponentHandler, // From VST V3.0.0 //============================================================================== tresult PLUGIN_API requestOpenEditor ([[maybe_unused]] FIDString name) override { - jassertfalse; + // This request cannot currently be surfaced in the JUCE public API return kResultFalse; } @@ -814,26 +873,49 @@ struct VST3HostContext : public Vst::IComponentHandler, // From VST V3.0.0 }; //============================================================================== -struct DescriptionFactory +struct DescriptionLister { - DescriptionFactory (VST3HostContext* host, IPluginFactory* pluginFactory) - : vst3HostContext (host), factory (pluginFactory) + static std::vector tryLoadFast (const File& file, const File& moduleinfo) { - jassert (pluginFactory != nullptr); + if (! moduleinfo.existsAsFile()) + return {}; + + MemoryBlock mb; + + if (! moduleinfo.loadFileAsData (mb)) + return {}; + + const std::string_view blockAsStringView (static_cast (mb.getData()), mb.getSize()); + const auto parsed = Steinberg::ModuleInfoLib::parseJson (blockAsStringView, nullptr); + + if (! parsed) + return {}; + + return createPluginDescriptions (file, *parsed); } - virtual ~DescriptionFactory() {} + static std::vector findDescriptionsFast (const File& file) + { + const auto moduleinfoNewLocation = file.getChildFile ("Contents").getChildFile ("Resources").getChildFile ("moduleinfo.json"); + + if (const auto loaded = tryLoadFast (file, moduleinfoNewLocation); ! loaded.empty()) + return loaded; + + return tryLoadFast (file, file.getChildFile ("Contents").getChildFile ("moduleinfo.json")); + } - Result findDescriptionsAndPerform (const File& file) + static std::vector findDescriptionsSlow (VST3HostContext& host, + IPluginFactory& factory, + const File& file) { + std::vector result; + StringArray foundNames; PFactoryInfo factoryInfo; - factory->getFactoryInfo (&factoryInfo); + factory.getFactoryInfo (&factoryInfo); auto companyName = toString (factoryInfo.vendor).trim(); - Result result (Result::ok()); - - auto numClasses = factory->countClasses(); + auto numClasses = factory.countClasses(); // Every ARA::IMainFactory must have a matching Steinberg::IComponent. // The match is determined by the two classes having the same name. @@ -843,7 +925,7 @@ struct DescriptionFactory for (Steinberg::int32 i = 0; i < numClasses; ++i) { PClassInfo info; - factory->getClassInfo (i, &info); + factory.getClassInfo (i, &info); if (std::strcmp (info.category, kARAMainFactoryClass) == 0) araMainFactoryClassNames.insert (info.name); } @@ -852,7 +934,7 @@ struct DescriptionFactory for (Steinberg::int32 i = 0; i < numClasses; ++i) { PClassInfo info; - factory->getClassInfo (i, &info); + factory.getClassInfo (i, &info); if (std::strcmp (info.category, kVstAudioEffectClass) != 0) continue; @@ -869,13 +951,13 @@ struct DescriptionFactory VSTComSmartPtr pf2; VSTComSmartPtr pf3; - if (pf2.loadFrom (factory)) + if (pf2.loadFrom (&factory)) { info2.reset (new PClassInfo2()); pf2->getClassInfo2 (i, info2.get()); } - if (pf3.loadFrom (factory)) + if (pf3.loadFrom (&factory)) { infoW.reset (new PClassInfoW()); pf3->getClassInfoUnicode (i, infoW.get()); @@ -889,9 +971,9 @@ struct DescriptionFactory { VSTComSmartPtr component; - if (component.loadFrom (factory, info.cid)) + if (component.loadFrom (&factory, info.cid)) { - if (component->initialize (vst3HostContext->getFUnknown()) == kResultOk) + if (component->initialize (host.getFUnknown()) == kResultOk) { auto numInputs = getNumSingleDirectionChannelsFor (component, Direction::input); auto numOutputs = getNumSingleDirectionChannelsFor (component, Direction::output); @@ -916,41 +998,11 @@ struct DescriptionFactory desc.hasARAExtension = true; if (desc.uniqueId != 0) - result = performOnDescription (desc); - - if (result.failed()) - break; + result.push_back (desc); } return result; } - - virtual Result performOnDescription (PluginDescription&) = 0; - -private: - VSTComSmartPtr vst3HostContext; - VSTComSmartPtr factory; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DescriptionFactory) -}; - -struct DescriptionLister : public DescriptionFactory -{ - DescriptionLister (VST3HostContext* host, IPluginFactory* pluginFactory) - : DescriptionFactory (host, pluginFactory) - { - } - - Result performOnDescription (PluginDescription& desc) - { - list.add (new PluginDescription (desc)); - return Result::ok(); - } - - OwnedArray list; - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DescriptionLister) }; //============================================================================== @@ -1357,9 +1409,11 @@ struct VST3ModuleHandle : public ReferenceCountedObject if (std::strcmp (info.category, kVstAudioEffectClass) != 0) continue; + const auto uniqueId = getHashForRange (getNormalisedTUID (info.cid)); + const auto deprecatedUid = getHashForRange (info.cid); + if (toString (info.name).trim() == description.name - && (getHashForRange (getNormalisedTUID (info.cid)) == description.uniqueId - || getHashForRange (info.cid) == description.deprecatedUid)) + && (uniqueId == description.uniqueId || deprecatedUid == description.deprecatedUid)) { name = description.name; return true; @@ -1442,9 +1496,10 @@ static std::shared_ptr getARAFactory (VST3ModuleHandle& m } //============================================================================== -struct VST3PluginWindow : public AudioProcessorEditor, - private ComponentMovementWatcher, - private IPlugFrame +struct VST3PluginWindow final : public AudioProcessorEditor, + private ComponentMovementWatcher, + private ComponentBoundsConstrainer, + private IPlugFrame { VST3PluginWindow (AudioPluginInstance* owner, IPlugView* pluginView) : AudioProcessorEditor (owner), @@ -1457,12 +1512,15 @@ struct VST3PluginWindow : public AudioProcessorEditor, setSize (10, 10); setOpaque (true); setVisible (true); + setConstrainer (this); warnOnFailure (view->setFrame (this)); view->queryInterface (Steinberg::IPlugViewContentScaleSupport::iid, (void**) &scaleInterface); setContentScaleFactor(); resizeToFit(); + + setResizable (view->canResize() == kResultTrue, false); } ~VST3PluginWindow() override @@ -1528,6 +1586,19 @@ struct VST3PluginWindow : public AudioProcessorEditor, bool keyPressed (const KeyPress& /*key*/) override { return true; } private: + void checkBounds (Rectangle& bounds, + const Rectangle&, + const Rectangle&, + bool, + bool, + bool, + bool) override + { + auto rect = componentToVST3Rect (bounds); + view->checkSizeConstraint (&rect); + bounds = vst3ToComponentRect (rect); + } + //============================================================================== void componentPeerChanged() override {} @@ -2173,7 +2244,7 @@ class ParameterChanges : public Vst::IParameterChanges for (const auto* item : queues) { auto* ptr = item->ptr.get(); - callback (ptr->getParameterIndex(), ptr->get()); + callback (ptr->getParameterIndex(), ptr->getParameterId(), ptr->get()); } } @@ -2459,34 +2530,33 @@ class VST3PluginInstance final : public AudioPluginInstance return module != nullptr ? module->getName() : String(); } - void repopulateArrangements (Array& inputArrangements, Array& outputArrangements) const + std::vector getActualArrangements (bool isInput) const { - inputArrangements.clearQuick(); - outputArrangements.clearQuick(); + std::vector result; - auto numInputAudioBuses = getBusCount (true); - auto numOutputAudioBuses = getBusCount (false); + const auto numBuses = getBusCount (isInput); - for (int i = 0; i < numInputAudioBuses; ++i) - inputArrangements.add (getArrangementForBus (processor, true, i)); + for (auto i = 0; i < numBuses; ++i) + result.push_back (getArrangementForBus (processor, isInput, i)); - for (int i = 0; i < numOutputAudioBuses; ++i) - outputArrangements.add (getArrangementForBus (processor, false, i)); + return result; } - void processorLayoutsToArrangements (Array& inputArrangements, Array& outputArrangements) + std::optional> busLayoutsToArrangements (bool isInput) const { - inputArrangements.clearQuick(); - outputArrangements.clearQuick(); + std::vector result; - auto numInputBuses = getBusCount (true); - auto numOutputBuses = getBusCount (false); + const auto numBuses = getBusCount (isInput); - for (int i = 0; i < numInputBuses; ++i) - inputArrangements.add (getVst3SpeakerArrangement (getBus (true, i)->getLastEnabledLayout())); + for (auto i = 0; i < numBuses; ++i) + { + if (const auto arr = getVst3SpeakerArrangement (getBus (isInput, i)->getLastEnabledLayout())) + result.push_back (*arr); + else + return {}; + } - for (int i = 0; i < numOutputBuses; ++i) - outputArrangements.add (getVst3SpeakerArrangement (getBus (false, i)->getLastEnabledLayout())); + return result; } void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override @@ -2500,7 +2570,7 @@ class VST3PluginInstance final : public AudioPluginInstance // Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins: if (isActive - && getSampleRate() == newSampleRate + && approximatelyEqual (getSampleRate(), newSampleRate) && getBlockSize() == estimatedSamplesPerBlock) return; @@ -2521,21 +2591,21 @@ class VST3PluginInstance final : public AudioPluginInstance holder->initialise(); - Array inputArrangements, outputArrangements; - processorLayoutsToArrangements (inputArrangements, outputArrangements); + auto inArrangements = busLayoutsToArrangements (true) .value_or (std::vector{}); + auto outArrangements = busLayoutsToArrangements (false).value_or (std::vector{}); // Some plug-ins will crash if you pass a nullptr to setBusArrangements! SpeakerArrangement nullArrangement = {}; - auto* inputArrangementData = inputArrangements.isEmpty() ? &nullArrangement : inputArrangements.getRawDataPointer(); - auto* outputArrangementData = outputArrangements.isEmpty() ? &nullArrangement : outputArrangements.getRawDataPointer(); + auto* inData = inArrangements .empty() ? &nullArrangement : inArrangements .data(); + auto* outData = outArrangements.empty() ? &nullArrangement : outArrangements.data(); - warnOnFailure (processor->setBusArrangements (inputArrangementData, inputArrangements.size(), - outputArrangementData, outputArrangements.size())); + warnOnFailure (processor->setBusArrangements (inData, static_cast (inArrangements .size()), + outData, static_cast (outArrangements.size()))); - Array actualInArr, actualOutArr; - repopulateArrangements (actualInArr, actualOutArr); + const auto inArrActual = getActualArrangements (true); + const auto outArrActual = getActualArrangements (false); - jassert (actualInArr == inputArrangements && actualOutArr == outputArrangements); + jassert (inArrActual == inArrangements && outArrActual == outArrangements); // Needed for having the same sample rate in processBlock(); some plugins need this! setRateAndBufferSizeDetails (newSampleRate, estimatedSamplesPerBlock); @@ -2683,9 +2753,12 @@ class VST3PluginInstance final : public AudioPluginInstance processor->process (data); - outputParameterChanges->forEach ([&] (Steinberg::int32 index, float value) + outputParameterChanges->forEach ([&] (Steinberg::int32 index, Vst::ParamID id, float value) { - parameterDispatcher.push (index, value); + cachedParamValues.setWithoutNotifying (index, value); + + if (auto* param = getParameterForID (id)) + param->setValueWithoutUpdatingProcessor (value); }); midiMessages.clear(); @@ -2707,9 +2780,8 @@ class VST3PluginInstance final : public AudioPluginInstance // not much we can do to check the layout while the audio processor is running // Let's at least check if it is a VST3 compatible layout - for (int dir = 0; dir < 2; ++dir) + for (const auto isInput : { true, false }) { - bool isInput = (dir == 0); auto n = getBusCount (isInput); for (int i = 0; i < n; ++i) @@ -2722,9 +2794,8 @@ class VST3PluginInstance final : public AudioPluginInstance bool syncBusLayouts (const BusesLayout& layouts) const { - for (int dir = 0; dir < 2; ++dir) + for (const auto isInput : { true, false }) { - bool isInput = (dir == 0); auto n = getBusCount (isInput); const Vst::BusDirection vstDir = (isInput ? Vst::kInput : Vst::kOutput); @@ -2737,34 +2808,49 @@ class VST3PluginInstance final : public AudioPluginInstance } } - Array inputArrangements, outputArrangements; - - for (int i = 0; i < layouts.inputBuses.size(); ++i) + const auto getPotentialArrangements = [&] (bool isInput) -> std::optional> { - const auto& requested = layouts.getChannelSet (true, i); - inputArrangements.add (getVst3SpeakerArrangement (requested.isDisabled() ? getBus (true, i)->getLastEnabledLayout() : requested)); - } + std::vector result; + + for (int i = 0; i < layouts.getBuses (isInput).size(); ++i) + { + const auto& requested = layouts.getChannelSet (isInput, i); + + if (const auto arr = getVst3SpeakerArrangement (requested.isDisabled() ? getBus (isInput, i)->getLastEnabledLayout() : requested)) + result.push_back (*arr); + else + return {}; + } - for (int i = 0; i < layouts.outputBuses.size(); ++i) + return result; + }; + + auto inArrangements = getPotentialArrangements (true); + auto outArrangements = getPotentialArrangements (false); + + if (! inArrangements.has_value() || ! outArrangements.has_value()) { - const auto& requested = layouts.getChannelSet (false, i); - outputArrangements.add (getVst3SpeakerArrangement (requested.isDisabled() ? getBus (false, i)->getLastEnabledLayout() : requested)); + // This bus layout can't be represented as a VST3 speaker arrangement + return false; } + auto& inputArrangements = *inArrangements; + auto& outputArrangements = *outArrangements; + // Some plug-ins will crash if you pass a nullptr to setBusArrangements! Vst::SpeakerArrangement nullArrangement = {}; - auto* inputArrangementData = inputArrangements.isEmpty() ? &nullArrangement : inputArrangements.getRawDataPointer(); - auto* outputArrangementData = outputArrangements.isEmpty() ? &nullArrangement : outputArrangements.getRawDataPointer(); + auto* inputArrangementData = inputArrangements .empty() ? &nullArrangement : inputArrangements .data(); + auto* outputArrangementData = outputArrangements.empty() ? &nullArrangement : outputArrangements.data(); - if (processor->setBusArrangements (inputArrangementData, inputArrangements.size(), - outputArrangementData, outputArrangements.size()) != kResultTrue) + if (processor->setBusArrangements (inputArrangementData, static_cast (inputArrangements .size()), + outputArrangementData, static_cast (outputArrangements.size())) != kResultTrue) return false; // check if the layout matches the request - Array actualIn, actualOut; - repopulateArrangements (actualIn, actualOut); + const auto inArrActual = getActualArrangements (true); + const auto outArrActual = getActualArrangements (false); - return (actualIn == inputArrangements && actualOut == outputArrangements); + return (inArrActual == inputArrangements && outArrActual == outputArrangements); } bool canApplyBusesLayout (const BusesLayout& layouts) const override @@ -3007,7 +3093,7 @@ class VST3PluginInstance final : public AudioPluginInstance { if (componentStream != nullptr) { - int64 result; + Steinberg::int64 result; componentStream->seek (0, IBStream::kIBSeekSet, &result); setComponentStateAndResetParameters (*componentStream); } @@ -3368,9 +3454,8 @@ class VST3PluginInstance final : public AudioPluginInstance VSTComSmartPtr processor; processor.loadFrom (component.get()); - for (int dirIdx = 0; dirIdx < 2; ++dirIdx) + for (const auto isInput : { true, false }) { - const bool isInput = (dirIdx == 0); const Vst::BusDirection dir = (isInput ? Vst::kInput : Vst::kOutput); const int numBuses = component->getBusCount (Vst::kAudio, dir); @@ -3386,7 +3471,8 @@ class VST3PluginInstance final : public AudioPluginInstance Vst::SpeakerArrangement arr; if (processor != nullptr && processor->getBusArrangement (dir, i, arr) == kResultOk) - layout = getChannelSetForSpeakerArrangement (arr); + if (const auto set = getChannelSetForSpeakerArrangement (arr)) + layout = *set; busProperties.addBus (isInput, toString (info.name), layout, (info.flags & Vst::BusInfo::kDefaultActive) != 0); @@ -3418,7 +3504,7 @@ class VST3PluginInstance final : public AudioPluginInstance // call was processBlockBypassed, otherwise do nothing if (processBlockBypassedCalled) { - if (bypassParam != nullptr && (bypassParam->getValue() == 0.0f || ! lastProcessBlockCallWasBypass)) + if (bypassParam != nullptr && (approximatelyEqual (bypassParam->getValue(), 0.0f) || ! lastProcessBlockCallWasBypass)) bypassParam->setValue (1.0f); } else @@ -3604,7 +3690,7 @@ tresult VST3HostContext::performEdit (Vst::ParamID paramID, Vst::ParamValue valu param->setValueNotifyingHost ((float) valueNormalised); // did the plug-in already update the parameter internally - if (plugin->editController->getParamNormalized (paramID) != (float) valueNormalised) + if (! approximatelyEqual (plugin->editController->getParamNormalized (paramID), valueNormalised)) return plugin->editController->setParamNormalized (paramID, valueNormalised); return kResultTrue; @@ -3777,7 +3863,18 @@ bool VST3PluginFormat::setStateFromVSTPresetFile (AudioPluginInstance* api, cons void VST3PluginFormat::findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) { - if (fileMightContainThisPluginType (fileOrIdentifier)) + if (! fileMightContainThisPluginType (fileOrIdentifier)) + return; + + if (const auto fast = DescriptionLister::findDescriptionsFast (File (fileOrIdentifier)); ! fast.empty()) + { + for (const auto& d : fast) + results.add (new PluginDescription (d)); + + return; + } + + for (const auto& file : getLibraryPaths (fileOrIdentifier)) { /** Since there is no apparent indication if a VST3 plugin is a shell or not, @@ -3785,21 +3882,16 @@ void VST3PluginFormat::findAllTypesForFile (OwnedArray& resul for every housed plugin. */ - VSTComSmartPtr pluginFactory (DLLHandleCache::getInstance()->findOrCreateHandle (fileOrIdentifier) - .getPluginFactory()); + VSTComSmartPtr pluginFactory (DLLHandleCache::getInstance()->findOrCreateHandle (file) + .getPluginFactory()); - if (pluginFactory != nullptr) - { - VSTComSmartPtr host (new VST3HostContext()); - DescriptionLister lister (host, pluginFactory); - lister.findDescriptionsAndPerform (File (fileOrIdentifier)); + if (pluginFactory == nullptr) + continue; - results.addCopiesOf (lister.list); - } - else - { - jassertfalse; - } + VSTComSmartPtr host (new VST3HostContext()); + + for (const auto& d : DescriptionLister::findDescriptionsSlow (*host, *pluginFactory, File (file))) + results.add (new PluginDescription (d)); } } @@ -3820,13 +3912,12 @@ void VST3PluginFormat::createARAFactoryAsync (const PluginDescription& descripti } static std::unique_ptr createVST3Instance (VST3PluginFormat& format, - const PluginDescription& description) + const PluginDescription& description, + const File& file) { if (! format.fileMightContainThisPluginType (description.fileOrIdentifier)) return nullptr; - const File file { description.fileOrIdentifier }; - struct ScopedWorkingDirectory { ~ScopedWorkingDirectory() { previousWorkingDirectory.setAsCurrentWorkingDirectory(); } @@ -3854,15 +3945,33 @@ static std::unique_ptr createVST3Instance (VST3PluginFormat return instance; } +StringArray VST3PluginFormat::getLibraryPaths (const String& fileOrIdentifier) +{ + #if JUCE_WINDOWS + if (! File (fileOrIdentifier).existsAsFile()) + { + StringArray files; + recursiveFileSearch (files, fileOrIdentifier, true); + return files; + } + #endif + + return { fileOrIdentifier }; +} + void VST3PluginFormat::createPluginInstance (const PluginDescription& description, double, int, PluginCreationCallback callback) { - auto result = createVST3Instance (*this, description); - - const auto errorMsg = result == nullptr ? TRANS ("Unable to load XXX plug-in file").replace ("XXX", "VST-3") - : String(); + for (const auto& file : getLibraryPaths (description.fileOrIdentifier)) + { + if (auto result = createVST3Instance (*this, description, file)) + { + callback (std::move (result), {}); + return; + } + } - callback (std::move (result), errorMsg); + callback (nullptr, TRANS ("Unable to load XXX plug-in file").replace ("XXX", "VST-3")); } bool VST3PluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const @@ -3874,12 +3983,7 @@ bool VST3PluginFormat::fileMightContainThisPluginType (const String& fileOrIdent { auto f = File::createFileWithoutCheckingPath (fileOrIdentifier); - return f.hasFileExtension (".vst3") - #if JUCE_MAC || JUCE_LINUX || JUCE_BSD - && f.exists(); - #else - && f.existsAsFile(); - #endif + return f.hasFileExtension (".vst3") && f.exists(); } String VST3PluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h index d192029eb4ec..d76a15cf0674 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h @@ -76,6 +76,7 @@ class JUCE_API VST3PluginFormat : public AudioPluginFormat int initialBufferSize, PluginCreationCallback) override; bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const override; void recursiveFileSearch (StringArray&, const File&, bool recursive); + StringArray getLibraryPaths (const String&); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginFormat) }; diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp index 305a705cba04..27c10a2d58b2 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp @@ -550,6 +550,23 @@ class VST3PluginFormatTests : public UnitTest expect (clientBuffers[3].channelBuffers64[0] == nullptr); } } + + beginTest ("Speaker layout conversions"); + { + using namespace Steinberg::Vst::SpeakerArr; + + for (const auto& [channelSet, arr] : { std::tuple (AudioChannelSet::ambisonic (1), kAmbi1stOrderACN), + std::tuple (AudioChannelSet::ambisonic (2), kAmbi2cdOrderACN), + std::tuple (AudioChannelSet::ambisonic (3), kAmbi3rdOrderACN), + std::tuple (AudioChannelSet::ambisonic (4), kAmbi4thOrderACN), + std::tuple (AudioChannelSet::ambisonic (5), kAmbi5thOrderACN), + std::tuple (AudioChannelSet::ambisonic (6), kAmbi6thOrderACN), + std::tuple (AudioChannelSet::ambisonic (7), kAmbi7thOrderACN), }) + { + expect (getVst3SpeakerArrangement (channelSet) == arr); + expect (channelSet == getChannelSetForSpeakerArrangement (arr)); + } + } } private: @@ -584,7 +601,7 @@ class VST3PluginFormatTests : public UnitTest bool allMatch (int channel, float value) const { const auto& buf = buffers[(size_t) channel]; - return std::all_of (buf.begin(), buf.end(), [&] (auto x) { return x == value; }); + return std::all_of (buf.begin(), buf.end(), [&] (auto x) { return exactlyEqual (x, value); }); } bool isClear (int channel) const @@ -607,13 +624,13 @@ class VST3PluginFormatTests : public UnitTest static bool channelStartsWithValue (Steinberg::Vst::AudioBusBuffers& bus, size_t index, float value) { - return bus.channelBuffers32[index][0] == value; + return exactlyEqual (bus.channelBuffers32[index][0], value); } static bool allMatch (const AudioBuffer& buf, int index, float value) { const auto* ptr = buf.getReadPointer (index); - return std::all_of (ptr, ptr + buf.getNumSamples(), [&] (auto x) { return x == value; }); + return std::all_of (ptr, ptr + buf.getNumSamples(), [&] (auto x) { return exactlyEqual (x, value); }); } struct MultiBusBuffers diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 1f38a2a9eee5..893d244f1272 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -904,7 +904,7 @@ struct VSTPluginInstance final : public AudioPluginInstance, { const ScopedLock sl (pluginInstance.lock); - if (effect->getParameter (effect, getParameterIndex()) != newValue) + if (! approximatelyEqual (effect->getParameter (effect, getParameterIndex()), newValue)) effect->setParameter (effect, getParameterIndex(), newValue); } } @@ -2004,7 +2004,7 @@ struct VSTPluginInstance final : public AudioPluginInstance, void setValue (float newValue) override { - currentValue = (newValue != 0.0f); + currentValue = (! approximatelyEqual (newValue, 0.0f)); if (parent.vstSupportsBypass) parent.dispatch (Vst2::effSetBypass, 0, currentValue ? 1 : 0, nullptr, 0.0f); @@ -2028,7 +2028,7 @@ struct VSTPluginInstance final : public AudioPluginInstance, float getValue() const override { return currentValue; } float getDefaultValue() const override { return 0.0f; } String getName (int /*maximumStringLength*/) const override { return "Bypass"; } - String getText (float value, int) const override { return (value != 0.0f ? TRANS("On") : TRANS("Off")); } + String getText (float value, int) const override { return (! approximatelyEqual (value, 0.0f) ? TRANS("On") : TRANS("Off")); } bool isAutomatable() const override { return true; } bool isDiscrete() const override { return true; } bool isBoolean() const override { return true; } @@ -2740,7 +2740,7 @@ struct VSTPluginInstance final : public AudioPluginInstance, { if (processBlockBypassedCalled) { - if (bypassParam->getValue() == 0.0f || ! lastProcessBlockCallWasBypass) + if (approximatelyEqual (bypassParam->getValue(), 0.0f) || ! lastProcessBlockCallWasBypass) bypassParam->setValue (1.0f); } else @@ -2805,13 +2805,14 @@ struct VSTPluginWindow : public AudioProcessorEditor, ~VSTPluginWindow() override { + activeVSTWindows.removeFirstMatchingValue (this); + closePluginWindow(); #if JUCE_MAC cocoaWrapper.reset(); #endif - activeVSTWindows.removeFirstMatchingValue (this); plugin.editorBeingDeleted (this); } @@ -3037,8 +3038,8 @@ struct VSTPluginWindow : public AudioProcessorEditor, void broughtToFront() override { - activeVSTWindows.removeFirstMatchingValue (this); - activeVSTWindows.add (this); + if (activeVSTWindows.removeFirstMatchingValue (this) != -1) + activeVSTWindows.add (this); #if JUCE_MAC dispatch (Vst2::effEditTop, 0, 0, nullptr, 0); diff --git a/modules/juce_audio_processors/juce_audio_processors.cpp b/modules/juce_audio_processors/juce_audio_processors.cpp index 8bbc3a36d115..27ed7c32907d 100644 --- a/modules/juce_audio_processors/juce_audio_processors.cpp +++ b/modules/juce_audio_processors/juce_audio_processors.cpp @@ -43,7 +43,9 @@ //============================================================================== #if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_VST3) && (JUCE_LINUX || JUCE_BSD) + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wvariadic-macros") #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #include #include #undef KeyPress @@ -220,7 +222,8 @@ struct NSViewComponentWithParent : public NSViewComponent, #include "utilities/juce_AudioProcessorValueTreeState.cpp" #include "utilities/juce_PluginHostType.cpp" #include "utilities/juce_NativeScaleFactorNotifier.cpp" -#include "utilities/juce_VSTCallbackHandler.cpp" +#include "utilities/juce_AAXClientExtensions.cpp" +#include "utilities/juce_VST2ClientExtensions.cpp" #include "utilities/ARA/juce_ARA_utils.cpp" #include "format_types/juce_LV2PluginFormat.cpp" diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index aa618eeb712b..87d4c7be81da 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -35,7 +35,7 @@ ID: juce_audio_processors vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE audio processor classes description: Classes for loading and playing VST, AU, LADSPA, or internally-generated audio processors. website: http://www.juce.com/juce @@ -130,7 +130,8 @@ #endif //============================================================================== -#include "utilities/juce_VSTCallbackHandler.h" +#include "utilities/juce_AAXClientExtensions.h" +#include "utilities/juce_VST2ClientExtensions.h" #include "utilities/juce_VST3ClientExtensions.h" #include "utilities/juce_NativeScaleFactorNotifier.h" #include "format_types/juce_ARACommon.h" diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp index f5815241ec08..7ea8d23bcc07 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp @@ -437,18 +437,20 @@ void AudioProcessor::validateParameter (AudioProcessorParameter* param) See the documentation for AudioProcessorParameter(int) for more information. */ #if JucePlugin_Build_AU - jassert (wrapperType == wrapperType_Undefined || param->getVersionHint() != 0); + static std::once_flag flag; + if (wrapperType != wrapperType_Undefined && param->getVersionHint() == 0) + std::call_once (flag, [] { jassertfalse; }); #endif } void AudioProcessor::checkForDuplicateTrimmedParamID ([[maybe_unused]] AudioProcessorParameter* param) { #if JUCE_DEBUG && ! JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING - if (auto* withID = dynamic_cast (param)) + if (auto* withID = dynamic_cast (param)) { constexpr auto maximumSafeAAXParameterIdLength = 31; - const auto paramID = withID->paramID; + const auto paramID = withID->getParameterID(); // If you hit this assertion, a parameter name is too long to be supported // by the AAX plugin format. @@ -476,9 +478,9 @@ void AudioProcessor::checkForDuplicateTrimmedParamID ([[maybe_unused]] AudioProc void AudioProcessor::checkForDuplicateParamID ([[maybe_unused]] AudioProcessorParameter* param) { #if JUCE_DEBUG - if (auto* withID = dynamic_cast (param)) + if (auto* withID = dynamic_cast (param)) { - auto insertResult = paramIDs.insert (withID->paramID); + auto insertResult = paramIDs.insert (withID->getParameterID()); // If you hit this assertion then the parameter ID is not unique jassert (insertResult.second); @@ -1152,7 +1154,7 @@ void AudioProcessor::Bus::updateChannelCount() noexcept void AudioProcessor::BusesProperties::addBus (bool isInput, const String& name, const AudioChannelSet& dfltLayout, bool isActivatedByDefault) { - jassert (dfltLayout.size() != 0); + jassert (! dfltLayout.isDisabled()); BusProperties props; @@ -1181,55 +1183,6 @@ AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withOutput (con return retval; } -//============================================================================== -int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, - const AudioChannelSet& mainOutputLayout, - const bool idForAudioSuite) const -{ - int uniqueFormatId = 0; - - for (int dir = 0; dir < 2; ++dir) - { - const bool isInput = (dir == 0); - auto& set = (isInput ? mainInputLayout : mainOutputLayout); - int aaxFormatIndex = 0; - - const AudioChannelSet sets[] - { - AudioChannelSet::disabled(), - AudioChannelSet::mono(), - AudioChannelSet::stereo(), - AudioChannelSet::createLCR(), - AudioChannelSet::createLCRS(), - AudioChannelSet::quadraphonic(), - AudioChannelSet::create5point0(), - AudioChannelSet::create5point1(), - AudioChannelSet::create6point0(), - AudioChannelSet::create6point1(), - AudioChannelSet::create7point0(), - AudioChannelSet::create7point1(), - AudioChannelSet::create7point0SDDS(), - AudioChannelSet::create7point1SDDS(), - AudioChannelSet::create7point0point2(), - AudioChannelSet::create7point1point2(), - AudioChannelSet::ambisonic (1), - AudioChannelSet::ambisonic (2), - AudioChannelSet::ambisonic (3) - }; - - const auto index = (int) std::distance (std::begin (sets), std::find (std::begin (sets), std::end (sets), set)); - - if (index != numElementsInArray (sets)) - aaxFormatIndex = index; - else - jassertfalse; - - uniqueFormatId = (uniqueFormatId << 8) | aaxFormatIndex; - } - - return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId; -} - //============================================================================== const char* AudioProcessor::getWrapperTypeDescription (AudioProcessor::WrapperType type) noexcept { @@ -1248,6 +1201,63 @@ const char* AudioProcessor::getWrapperTypeDescription (AudioProcessor::WrapperTy } } +//============================================================================== +VST2ClientExtensions* AudioProcessor::getVST2ClientExtensions() +{ + if (auto* extensions = dynamic_cast (this)) + { + // To silence this jassert there are two options: + // + // 1. - Override AudioProcessor::getVST2ClientExtensions() and + // return the "this" pointer. + // + // - This option has the advantage of being quick and easy, + // and avoids the above dynamic_cast. + // + // 2. - Create a new object that inherits from VST2ClientExtensions. + // + // - Port your existing functionality from the AudioProcessor + // to the new object. + // + // - Return a pointer to the object in AudioProcessor::getVST2ClientExtensions(). + // + // - This option has the advantage of allowing you to break + // up your AudioProcessor into smaller composable objects. + jassertfalse; + return extensions; + } + + return nullptr; +} + +VST3ClientExtensions* AudioProcessor::getVST3ClientExtensions() +{ + if (auto* extensions = dynamic_cast (this)) + { + // To silence this jassert there are two options: + // + // 1. - Override AudioProcessor::getVST3ClientExtensions() and + // return the "this" pointer. + // + // - This option has the advantage of being quick and easy, + // and avoids the above dynamic_cast. + // + // 2. - Create a new object that inherits from VST3ClientExtensions. + // + // - Port your existing functionality from the AudioProcessor + // to the new object. + // + // - Return a pointer to the object in AudioProcessor::getVST3ClientExtensions(). + // + // - This option has the advantage of allowing you to break + // up your AudioProcessor into smaller composable objects. + jassertfalse; + return extensions; + } + + return nullptr; +} + //============================================================================== JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) @@ -1412,8 +1422,8 @@ const String AudioProcessor::getParameterName (int index) String AudioProcessor::getParameterID (int index) { // Don't use getParamChecked here, as this must also work for legacy plug-ins - if (auto* p = dynamic_cast (getParameters()[index])) - return p->paramID; + if (auto* p = dynamic_cast (getParameters()[index])) + return p->getParameterID(); return String (index); } diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index b0acefa92734..db98f02a7133 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -40,9 +40,11 @@ namespace juce plugin, you should implement a global function called createPluginFilter() which creates and returns a new instance of your subclass. + @see AAXClientExtensions, VST2ClientExtensions, VST3ClientExtensions + @tags{Audio} */ -class JUCE_API AudioProcessor +class JUCE_API AudioProcessor : private AAXClientExtensions { protected: struct BusesProperties; @@ -309,29 +311,37 @@ class JUCE_API AudioProcessor */ struct BusesLayout { + private: + template + static auto& getBuses (This& t, bool isInput) { return isInput ? t.inputBuses : t.outputBuses; } + + public: /** An array containing the list of input buses that this processor supports. */ Array inputBuses; /** An array containing the list of output buses that this processor supports. */ Array outputBuses; + auto& getBuses (bool isInput) const { return getBuses (*this, isInput); } + auto& getBuses (bool isInput) { return getBuses (*this, isInput); } + /** Get the number of channels of a particular bus */ int getNumChannels (bool isInput, int busIndex) const noexcept { - auto& bus = (isInput ? inputBuses : outputBuses); + auto& bus = getBuses (isInput); return isPositiveAndBelow (busIndex, bus.size()) ? bus.getReference (busIndex).size() : 0; } /** Get the channel set of a particular bus */ AudioChannelSet& getChannelSet (bool isInput, int busIndex) noexcept { - return (isInput ? inputBuses : outputBuses).getReference (busIndex); + return getBuses (isInput).getReference (busIndex); } /** Get the channel set of a particular bus */ AudioChannelSet getChannelSet (bool isInput, int busIndex) const noexcept { - return (isInput ? inputBuses : outputBuses)[busIndex]; + return getBuses (isInput)[busIndex]; } /** Get the input channel layout on the main bus. */ @@ -1168,18 +1178,30 @@ class JUCE_API AudioProcessor void setRateAndBufferSizeDetails (double sampleRate, int blockSize) noexcept; //============================================================================== - /** AAX plug-ins need to report a unique "plug-in id" for every audio layout - configuration that your AudioProcessor supports on the main bus. Override this - function if you want your AudioProcessor to use a custom "plug-in id" (for example - to stay backward compatible with older versions of JUCE). - - The default implementation will compute a unique integer from the input and output - layout and add this value to the 4 character code 'jcaa' (for native AAX) or 'jyaa' - (for AudioSuite plug-ins). - */ - virtual int32 getAAXPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, - const AudioChannelSet& mainOutputLayout, - bool idForAudioSuite) const; + /** Returns a reference to an object that implements AAX specific information regarding + this AudioProcessor. + */ + virtual AAXClientExtensions& getAAXClientExtensions() { return *this; } + + /** Returns a non-owning pointer to an object that implements VST2 specific information + regarding this AudioProcessor. + + By default, for backwards compatibility, this will attempt to dynamic-cast this + AudioProcessor to VST2ClientExtensions. + It is recommended to override this function to return a pointer directly to an object + of the correct type in order to avoid this dynamic cast. + */ + virtual VST2ClientExtensions* getVST2ClientExtensions(); + + /** Returns a non-owning pointer to an object that implements VST3 specific information + regarding this AudioProcessor. + + By default, for backwards compatibility, this will attempt to dynamic-cast this + AudioProcessor to VST3ClientExtensions. + It is recommended to override this function to return a pointer directly to an object + of the correct type in order to avoid this dynamic cast. + */ + virtual VST3ClientExtensions* getVST3ClientExtensions(); //============================================================================== /** Some plug-ins support sharing response curve data with the host so that it can diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp index 7b20407cca61..0d3104c1ab5c 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp @@ -225,4 +225,16 @@ ComponentPeer* AudioProcessorEditor::createNewPeer ([[maybe_unused]] int styleFl return Component::createNewPeer (styleFlags, nativeWindow); } +bool AudioProcessorEditor::wantsLayerBackedView() const +{ + #if JUCE_MODULE_AVAILABLE_juce_opengl && JUCE_MAC + if (@available (macOS 10.14, *)) + return true; + + return false; + #else + return true; + #endif +} + } // namespace juce diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h index df43af64212c..3bc5e3ac4d9a 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h @@ -206,6 +206,23 @@ class JUCE_API AudioProcessorEditor : public Component */ std::unique_ptr resizableCorner; + /** The plugin wrapper will call this function to decide whether to use a layer-backed view to + host the editor on macOS and iOS. + + Layer-backed views generally provide better performance, and are recommended in most + situations. However, on older macOS versions (confirmed on 10.12 and 10.13), displaying an + OpenGL context inside a layer-backed view can lead to deadlocks, so it is recommended to + avoid layer-backed views when using OpenGL on these OS versions. + + The default behaviour of this function is to return false if and only if the juce_opengl + module is present and the current platform is macOS 10.13 or earlier. + + You may want to override this behaviour if your plugin has an option to enable and disable + OpenGL rendering. If you know your plugin editor will never use OpenGL rendering, you can + set this function to return true in all situations. + */ + virtual bool wantsLayerBackedView() const; + private: //============================================================================== struct AudioProcessorEditorListener : public ComponentListener diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp index 5e615433abcd..ea9b8968aef4 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp @@ -139,6 +139,15 @@ class Connections using Connection = AudioProcessorGraph::Connection; using NodeAndChannel = AudioProcessorGraph::NodeAndChannel; +private: + static auto equalRange (const std::set& pins, const NodeID node) + { + return std::equal_range (pins.cbegin(), pins.cend(), node, ImplicitNode::compare); + } + + using Map = std::map>; + +public: static constexpr auto midiChannelIndex = AudioProcessorGraph::midiChannelIndex; bool addConnection (const Nodes& n, const Connection& c) @@ -179,7 +188,7 @@ class Connections for (auto& pair : sourcesForDestination) { - const auto range = std::equal_range (pair.second.cbegin(), pair.second.cend(), n, ImplicitNode::compare); + const auto range = equalRange (pair.second, n); result |= range.first != range.second; pair.second.erase (range.first, range.second); } @@ -231,8 +240,8 @@ class Connections return std::any_of (matchingDestinations.first, matchingDestinations.second, [srcID] (const auto& pair) { - const auto iter = std::lower_bound (pair.second.cbegin(), pair.second.cend(), srcID, ImplicitNode::compare); - return iter != pair.second.cend() && iter->nodeID == srcID; + const auto [begin, end] = equalRange (pair.second, srcID); + return begin != end; }); } @@ -276,9 +285,44 @@ class Connections bool operator== (const Connections& other) const { return sourcesForDestination == other.sourcesForDestination; } bool operator!= (const Connections& other) const { return sourcesForDestination != other.sourcesForDestination; } -private: - using Map = std::map>; + class DestinationsForSources + { + public: + explicit DestinationsForSources (Map m) : map (std::move (m)) {} + + bool isSourceConnectedToDestinationNodeIgnoringChannel (const NodeAndChannel& source, NodeID dest, int channel) const + { + if (const auto destIter = map.find (source); destIter != map.cend()) + { + const auto [begin, end] = equalRange (destIter->second, dest); + return std::any_of (begin, end, [&] (const NodeAndChannel& nodeAndChannel) + { + return nodeAndChannel != NodeAndChannel { dest, channel }; + }); + } + + return false; + } + + private: + Map map; + }; + + /* Reverses the graph, to allow fast lookup by source. + This is expensive, don't call this more than necessary! + */ + auto getDestinationsForSources() const + { + Map destinationsForSources; + + for (const auto& [destination, sources] : sourcesForDestination) + for (const auto& source : sources) + destinationsForSources[source].insert (destination); + return DestinationsForSources (std::move (destinationsForSources)); + } + +private: struct SearchState { std::set visited; @@ -351,14 +395,14 @@ class NodeStates /* Called from prepareToPlay and releaseResources with the PrepareSettings that should be used next time the graph is rebuilt. */ - void setState (Optional newSettings) + void setState (std::optional newSettings) { const std::lock_guard lock (mutex); next = newSettings; } /* Call from the audio thread only. */ - Optional getLastRequestedSettings() const { return next; } + std::optional getLastRequestedSettings() const { return next; } /* Call from the main thread only! @@ -375,7 +419,7 @@ class NodeStates Returns the settings that were applied to the nodes. */ - Optional applySettings (const Nodes& n) + std::optional applySettings (const Nodes& n) { const auto settingsChanged = [this] { @@ -411,7 +455,7 @@ class NodeStates preparedNodes.clear(); } - if (current.hasValue()) + if (current.has_value()) { for (const auto& node : n.getNodes()) { @@ -430,10 +474,24 @@ class NodeStates return current; } + /* Call from the main thread to indicate that a node has been removed from the graph. + */ + void removeNode (const NodeID n) + { + preparedNodes.erase (n); + } + + /* Call from the main thread to indicate that all nodes have been removed from the graph. + */ + void clear() + { + preparedNodes.clear(); + } + private: std::mutex mutex; std::set preparedNodes; - Optional current, next; + std::optional current, next; }; //============================================================================== @@ -442,8 +500,17 @@ struct GraphRenderSequence { using Node = AudioProcessorGraph::Node; + struct GlobalIO + { + AudioBuffer& audioIn; + AudioBuffer& audioOut; + MidiBuffer& midiIn; + MidiBuffer& midiOut; + }; + struct Context { + GlobalIO globalIO; AudioPlayHead* audioPlayHead; int numSamples; }; @@ -482,7 +549,12 @@ struct GraphRenderSequence currentMidiOutputBuffer.clear(); { - const Context context { audioPlayHead, numSamples }; + const Context context { { *currentAudioInputBuffer, + currentAudioOutputBuffer, + *currentMidiInputBuffer, + currentMidiOutputBuffer }, + audioPlayHead, + numSamples }; for (const auto& op : renderOps) op->process (context); @@ -690,7 +762,30 @@ struct GraphRenderSequence int totalNumChans, int midiBuffer) { - renderOps.push_back (std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer)); + auto op = [&]() -> std::unique_ptr + { + if (auto* ioNode = dynamic_cast (node->getProcessor())) + { + switch (ioNode->getType()) + { + case AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode: + return std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer); + + case AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode: + return std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer); + + case AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode: + return std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer); + + case AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode: + return std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer); + } + } + + return std::make_unique (node, audioChannelsUsed, totalNumChans, midiBuffer); + }(); + + renderOps.push_back (std::move (op)); } void prepareBuffers (int blockSize) @@ -738,12 +833,12 @@ struct GraphRenderSequence virtual void process (const Context&) = 0; }; - struct ProcessOp : public RenderOp + struct NodeOp : public RenderOp { - ProcessOp (const Node::Ptr& n, - const Array& audioChannelsUsed, - int totalNumChans, - int midiBufferIndex) + NodeOp (const Node::Ptr& n, + const Array& audioChannelsUsed, + int totalNumChans, + int midiBufferIndex) : node (n), processor (*n->getProcessor()), audioChannelsToUse (audioChannelsUsed), @@ -754,7 +849,7 @@ struct GraphRenderSequence audioChannelsToUse.add (0); } - void prepare (FloatType* const* renderBuffer, MidiBuffer* buffers) override + void prepare (FloatType* const* renderBuffer, MidiBuffer* buffers) final { for (size_t i = 0; i < audioChannels.size(); ++i) audioChannels[i] = renderBuffer[audioChannelsToUse.getUnchecked ((int) i)]; @@ -762,7 +857,7 @@ struct GraphRenderSequence midiBuffer = buffers + midiBufferToUse; } - void process (const Context& c) override + void process (const Context& c) final { processor.setPlayHead (c.audioPlayHead); @@ -777,64 +872,140 @@ struct GraphRenderSequence AudioBuffer buffer { audioChannels.data(), numAudioChannels, c.numSamples }; - const ScopedLock lock (processor.getCallbackLock()); - if (processor.isSuspended()) + { buffer.clear(); + } else - callProcess (buffer, *midiBuffer); + { + const auto bypass = node->isBypassed() && processor.getBypassParameter() == nullptr; + processWithBuffer (c.globalIO, bypass, buffer, *midiBuffer); + } + } + + virtual void processWithBuffer (const GlobalIO&, bool bypass, AudioBuffer& audio, MidiBuffer& midi) = 0; + + const Node::Ptr node; + AudioProcessor& processor; + MidiBuffer* midiBuffer = nullptr; + + Array audioChannelsToUse; + std::vector audioChannels; + const int midiBufferToUse; + }; + + struct ProcessOp : public NodeOp + { + using NodeOp::NodeOp; + + void processWithBuffer (const GlobalIO&, bool bypass, AudioBuffer& audio, MidiBuffer& midi) final + { + callProcess (bypass, audio, midi); } - void callProcess (AudioBuffer& buffer, MidiBuffer& midi) + void callProcess (bool bypass, AudioBuffer& buffer, MidiBuffer& midi) { - if (processor.isUsingDoublePrecision()) + if (this->processor.isUsingDoublePrecision()) { tempBufferDouble.makeCopyOf (buffer, true); - process (*node, tempBufferDouble, midi); + processImpl (bypass, this->processor, tempBufferDouble, midi); buffer.makeCopyOf (tempBufferDouble, true); } else { - process (*node, buffer, midi); + processImpl (bypass, this->processor, buffer, midi); } } - void callProcess (AudioBuffer& buffer, MidiBuffer& midi) + void callProcess (bool bypass, AudioBuffer& buffer, MidiBuffer& midi) { - if (processor.isUsingDoublePrecision()) + if (this->processor.isUsingDoublePrecision()) { - process (*node, buffer, midi); + processImpl (bypass, this->processor, buffer, midi); } else { tempBufferFloat.makeCopyOf (buffer, true); - process (*node, tempBufferFloat, midi); + processImpl (bypass, this->processor, tempBufferFloat, midi); buffer.makeCopyOf (tempBufferFloat, true); } } template - static void process (const Node& node, AudioBuffer& audio, MidiBuffer& midi) + static void processImpl (bool bypass, AudioProcessor& p, AudioBuffer& audio, MidiBuffer& midi) { - if (node.isBypassed() && node.getProcessor()->getBypassParameter() == nullptr) - node.getProcessor()->processBlockBypassed (audio, midi); + if (bypass) + p.processBlockBypassed (audio, midi); else - node.getProcessor()->processBlock (audio, midi); + p.processBlock (audio, midi); } - const Node::Ptr node; - AudioProcessor& processor; - MidiBuffer* midiBuffer = nullptr; - - Array audioChannelsToUse; - std::vector audioChannels; AudioBuffer tempBufferFloat, tempBufferDouble; - const int midiBufferToUse; + }; + + struct MidiInOp : public NodeOp + { + using NodeOp::NodeOp; + + void processWithBuffer (const GlobalIO& g, bool bypass, AudioBuffer& audio, MidiBuffer& midi) final + { + if (! bypass) + midi.addEvents (g.midiIn, 0, audio.getNumSamples(), 0); + } + }; + + struct MidiOutOp : public NodeOp + { + using NodeOp::NodeOp; + + void processWithBuffer (const GlobalIO& g, bool bypass, AudioBuffer& audio, MidiBuffer& midi) final + { + if (! bypass) + g.midiOut.addEvents (midi, 0, audio.getNumSamples(), 0); + } + }; + + struct AudioInOp : public NodeOp + { + using NodeOp::NodeOp; + + void processWithBuffer (const GlobalIO& g, bool bypass, AudioBuffer& audio, MidiBuffer&) final + { + if (bypass) + return; + + for (int i = jmin (g.audioIn.getNumChannels(), audio.getNumChannels()); --i >= 0;) + audio.copyFrom (i, 0, g.audioIn, i, 0, audio.getNumSamples()); + } + }; + + struct AudioOutOp : public NodeOp + { + using NodeOp::NodeOp; + + void processWithBuffer (const GlobalIO& g, bool bypass, AudioBuffer& audio, MidiBuffer&) final + { + if (bypass) + return; + + for (int i = jmin (g.audioOut.getNumChannels(), audio.getNumChannels()); --i >= 0;) + g.audioOut.addFrom (i, 0, audio, i, 0, audio.getNumSamples()); + } }; std::vector> renderOps; }; +//============================================================================== +struct SequenceAndLatency +{ + using RenderSequenceVariant = std::variant, + GraphRenderSequence>; + + RenderSequenceVariant sequence; + int latencySamples = 0; +}; + //============================================================================== class RenderSequenceBuilder { @@ -846,19 +1017,12 @@ class RenderSequenceBuilder static constexpr auto midiChannelIndex = AudioProcessorGraph::midiChannelIndex; - template - static auto build (const Nodes& n, const Connections& c) + template + static SequenceAndLatency build (const Nodes& n, const Connections& c) { - RenderSequence sequence; + GraphRenderSequence sequence; const RenderSequenceBuilder builder (n, c, sequence); - - struct SequenceAndLatency - { - RenderSequence sequence; - int latencySamples = 0; - }; - - return SequenceAndLatency { std::move (sequence), builder.totalLatency }; + return { std::move (sequence), builder.totalLatency }; } private: @@ -961,6 +1125,7 @@ class RenderSequenceBuilder //============================================================================== template int findBufferForInputAudioChannel (const Connections& c, + const Connections::DestinationsForSources& reversed, RenderSequence& sequence, Node& node, const int inputChan, @@ -998,7 +1163,7 @@ class RenderSequenceBuilder jassert (bufIndex >= 0); } - if (inputChan < numOuts && isBufferNeededLater (c, ourRenderingIndex, inputChan, src)) + if (inputChan < numOuts && isBufferNeededLater (reversed, ourRenderingIndex, inputChan, src)) { // can't mess up this channel because it's needed later by another node, // so we need to use a copy of it.. @@ -1025,7 +1190,7 @@ class RenderSequenceBuilder { auto sourceBufIndex = getBufferContaining (src); - if (sourceBufIndex >= 0 && ! isBufferNeededLater (c, ourRenderingIndex, inputChan, src)) + if (sourceBufIndex >= 0 && ! isBufferNeededLater (reversed, ourRenderingIndex, inputChan, src)) { // we've found one of our input chans that can be re-used.. reusableInputIndex = i; @@ -1079,7 +1244,7 @@ class RenderSequenceBuilder if (nodeDelay < maxLatency) { - if (! isBufferNeededLater (c, ourRenderingIndex, inputChan, src)) + if (! isBufferNeededLater (reversed, ourRenderingIndex, inputChan, src)) { sequence.addDelayChannelOp (srcIndex, maxLatency - nodeDelay); } @@ -1105,6 +1270,7 @@ class RenderSequenceBuilder template int findBufferForInputMidiChannel (const Connections& c, + const Connections::DestinationsForSources& reversed, RenderSequence& sequence, Node& node, int ourRenderingIndex) @@ -1131,7 +1297,7 @@ class RenderSequenceBuilder if (midiBufferToUse >= 0) { - if (isBufferNeededLater (c, ourRenderingIndex, midiChannelIndex, src)) + if (isBufferNeededLater (reversed, ourRenderingIndex, midiChannelIndex, src)) { // can't mess up this channel because it's needed later by another node, so we // need to use a copy of it.. @@ -1160,7 +1326,7 @@ class RenderSequenceBuilder auto sourceBufIndex = getBufferContaining (src); if (sourceBufIndex >= 0 - && ! isBufferNeededLater (c, ourRenderingIndex, midiChannelIndex, src)) + && ! isBufferNeededLater (reversed, ourRenderingIndex, midiChannelIndex, src)) { // we've found one of our input buffers that can be re-used.. reusableInputIndex = i; @@ -1209,6 +1375,7 @@ class RenderSequenceBuilder template void createRenderingOpsForNode (const Connections& c, + const Connections::DestinationsForSources& reversed, RenderSequence& sequence, Node& node, const int ourRenderingIndex) @@ -1225,6 +1392,7 @@ class RenderSequenceBuilder { // get a list of all the inputs to this node auto index = findBufferForInputAudioChannel (c, + reversed, sequence, node, inputChan, @@ -1247,7 +1415,7 @@ class RenderSequenceBuilder audioBuffers.getReference (index).channel = { node.nodeID, outputChan }; } - auto midiBufferToUse = findBufferForInputMidiChannel (c, sequence, node, ourRenderingIndex); + auto midiBufferToUse = findBufferForInputMidiChannel (c, reversed, sequence, node, ourRenderingIndex); if (processor.producesMidi()) midiBuffers.getReference (midiBufferToUse).channel = { node.nodeID, midiChannelIndex }; @@ -1286,7 +1454,7 @@ class RenderSequenceBuilder return -1; } - void markAnyUnusedBuffersAsFree (const Connections& c, + void markAnyUnusedBuffersAsFree (const Connections::DestinationsForSources& c, Array& buffers, const int stepIndex) { @@ -1295,34 +1463,25 @@ class RenderSequenceBuilder b.setFree(); } - bool isBufferNeededLater (const Connections& c, - int stepIndexToSearchFrom, - int inputChannelOfIndexToIgnore, - NodeAndChannel output) const + bool isBufferNeededLater (const Connections::DestinationsForSources& c, + const int stepIndexToSearchFrom, + const int inputChannelOfIndexToIgnore, + const NodeAndChannel output) const { - while (stepIndexToSearchFrom < orderedNodes.size()) - { - auto* node = orderedNodes.getUnchecked (stepIndexToSearchFrom); - - if (output.isMIDI()) - { - if (inputChannelOfIndexToIgnore != midiChannelIndex - && c.isConnected ({ { output.nodeID, midiChannelIndex }, - { node->nodeID, midiChannelIndex } })) - return true; - } - else - { - for (int i = 0; i < node->getProcessor()->getTotalNumInputChannels(); ++i) - if (i != inputChannelOfIndexToIgnore && c.isConnected ({ output, { node->nodeID, i } })) - return true; - } + if (orderedNodes.size() <= stepIndexToSearchFrom) + return false; - inputChannelOfIndexToIgnore = -1; - ++stepIndexToSearchFrom; + if (c.isSourceConnectedToDestinationNodeIgnoringChannel (output, + orderedNodes.getUnchecked (stepIndexToSearchFrom)->nodeID, + inputChannelOfIndexToIgnore)) + { + return true; } - return false; + return std::any_of (orderedNodes.begin() + stepIndexToSearchFrom + 1, orderedNodes.end(), [&] (const auto* node) + { + return c.isSourceConnectedToDestinationNodeIgnoringChannel (output, node->nodeID, -1); + }); } template @@ -1332,11 +1491,13 @@ class RenderSequenceBuilder audioBuffers.add (AssignedBuffer::createReadOnlyEmpty()); // first buffer is read-only zeros midiBuffers .add (AssignedBuffer::createReadOnlyEmpty()); + const auto reversed = c.getDestinationsForSources(); + for (int i = 0; i < orderedNodes.size(); ++i) { - createRenderingOpsForNode (c, sequence, *orderedNodes.getUnchecked (i), i); - markAnyUnusedBuffersAsFree (c, audioBuffers, i); - markAnyUnusedBuffersAsFree (c, midiBuffers, i); + createRenderingOpsForNode (c, reversed, sequence, *orderedNodes.getUnchecked (i), i); + markAnyUnusedBuffersAsFree (reversed, audioBuffers, i); + markAnyUnusedBuffersAsFree (reversed, midiBuffers, i); } sequence.numBuffersNeeded = audioBuffers.size(); @@ -1356,95 +1517,77 @@ class RenderSequence public: using AudioGraphIOProcessor = AudioProcessorGraph::AudioGraphIOProcessor; - RenderSequence (PrepareSettings s, const Nodes& n, const Connections& c) - : RenderSequence (s, - RenderSequenceBuilder::build> (n, c), - RenderSequenceBuilder::build> (n, c)) + RenderSequence (const PrepareSettings s, const Nodes& n, const Connections& c) + : RenderSequence (s, s.precision == AudioProcessor::ProcessingPrecision::singlePrecision + ? RenderSequenceBuilder::build (n, c) + : RenderSequenceBuilder::build (n, c)) { } - void process (AudioBuffer& audio, MidiBuffer& midi, AudioPlayHead* playHead) + template + void process (AudioBuffer& audio, MidiBuffer& midi, AudioPlayHead* playHead) { - renderSequenceF.perform (audio, midi, playHead); + if (auto* s = std::get_if> (&sequence.sequence)) + s->perform (audio, midi, playHead); + else + jassertfalse; // Not prepared for this audio format! } - void process (AudioBuffer& audio, MidiBuffer& midi, AudioPlayHead* playHead) - { - renderSequenceD.perform (audio, midi, playHead); - } + int getLatencySamples() const { return sequence.latencySamples; } + PrepareSettings getSettings() const { return settings; } - void processIO (AudioGraphIOProcessor& io, AudioBuffer& audio, MidiBuffer& midi) +private: + template + static void visitRenderSequence (This& t, Callback&& callback) { - processIOBlock (io, renderSequenceF, audio, midi); + if (auto* sequence = std::get_if> (&t.sequence.sequence)) return callback (*sequence); + if (auto* sequence = std::get_if> (&t.sequence.sequence)) return callback (*sequence); + jassertfalse; } - void processIO (AudioGraphIOProcessor& io, AudioBuffer& audio, MidiBuffer& midi) + RenderSequence (const PrepareSettings s, SequenceAndLatency&& built) + : settings (s), sequence (std::move (built)) { - processIOBlock (io, renderSequenceD, audio, midi); + visitRenderSequence (*this, [&] (auto& seq) { seq.prepareBuffers (settings.blockSize); }); } - int getLatencySamples() const { return latencySamples; } - PrepareSettings getSettings() const { return settings; } - -private: - template - static void processIOBlock (AudioGraphIOProcessor& io, - SequenceType& sequence, - AudioBuffer& buffer, - MidiBuffer& midiMessages) - { - switch (io.getType()) - { - case AudioGraphIOProcessor::audioOutputNode: - { - auto&& currentAudioOutputBuffer = sequence.currentAudioOutputBuffer; - - for (int i = jmin (currentAudioOutputBuffer.getNumChannels(), buffer.getNumChannels()); --i >= 0;) - currentAudioOutputBuffer.addFrom (i, 0, buffer, i, 0, buffer.getNumSamples()); - - break; - } - - case AudioGraphIOProcessor::audioInputNode: - { - auto* currentInputBuffer = sequence.currentAudioInputBuffer; - - for (int i = jmin (currentInputBuffer->getNumChannels(), buffer.getNumChannels()); --i >= 0;) - buffer.copyFrom (i, 0, *currentInputBuffer, i, 0, buffer.getNumSamples()); + PrepareSettings settings; + SequenceAndLatency sequence; +}; - break; - } +//============================================================================== +/* Holds information about a particular graph configuration, without sharing ownership of any + graph nodes. Can be checked for equality with other RenderSequenceSignature instances to see + whether two graph configurations match. +*/ +class RenderSequenceSignature +{ + auto tie() const { return std::tie (settings, connections, nodes); } - case AudioGraphIOProcessor::midiOutputNode: - sequence.currentMidiOutputBuffer.addEvents (midiMessages, 0, buffer.getNumSamples(), 0); - break; +public: + RenderSequenceSignature (const PrepareSettings s, const Nodes& n, const Connections& c) + : settings (s), connections (c), nodes (getNodeMap (n)) {} - case AudioGraphIOProcessor::midiInputNode: - midiMessages.addEvents (*sequence.currentMidiInputBuffer, 0, buffer.getNumSamples(), 0); - break; + bool operator== (const RenderSequenceSignature& other) const { return tie() == other.tie(); } + bool operator!= (const RenderSequenceSignature& other) const { return tie() != other.tie(); } - default: - break; - } - } +private: + using NodeMap = std::map; - template - RenderSequence (PrepareSettings s, Float f, Double d) - : settings (s), - renderSequenceF (std::move (f.sequence)), - renderSequenceD (std::move (d.sequence)), - latencySamples (f.latencySamples) + static NodeMap getNodeMap (const Nodes& n) { - jassert (f.latencySamples == d.latencySamples); + const auto& nodeRefs = n.getNodes(); + NodeMap result; + + for (const auto& node : nodeRefs) + result.emplace (node->nodeID, node->getProcessor()->getBusesLayout()); - renderSequenceF.prepareBuffers (settings.blockSize); - renderSequenceD.prepareBuffers (settings.blockSize); + return result; } PrepareSettings settings; - GraphRenderSequence renderSequenceF; - GraphRenderSequence renderSequenceD; - int latencySamples = 0; + Connections connections; + NodeMap nodes; }; //============================================================================== @@ -1475,7 +1618,7 @@ class RenderSequenceExchange : private Timer isNew = true; } - /** Call from the audio thread only. */ + /* Call from the audio thread only. */ void updateAudioThreadState() { const SpinLock::ScopedTryLockType lock (mutex); @@ -1488,7 +1631,7 @@ class RenderSequenceExchange : private Timer } } - /** Call from the audio thread only. */ + /* Call from the audio thread only. */ RenderSequence* getAudioThreadState() const { return audioThreadState.get(); } private: @@ -1534,17 +1677,11 @@ bool AudioProcessorGraph::Connection::operator< (const Connection& other) const } //============================================================================== -class AudioProcessorGraph::Pimpl : public AsyncUpdater +class AudioProcessorGraph::Pimpl { public: explicit Pimpl (AudioProcessorGraph& o) : owner (&o) {} - ~Pimpl() override - { - cancelPendingUpdate(); - clear (UpdateKind::sync); - } - const auto& getNodes() const { return nodes.getNodes(); } void clear (UpdateKind updateKind) @@ -1554,6 +1691,7 @@ class AudioProcessorGraph::Pimpl : public AsyncUpdater nodes = Nodes{}; connections = Connections{}; + nodeStates.clear(); topologyChanged (updateKind); } @@ -1592,6 +1730,7 @@ class AudioProcessorGraph::Pimpl : public AsyncUpdater { connections.disconnectNode (nodeID); auto result = nodes.removeNode (nodeID); + nodeStates.removeNode (nodeID); topologyChanged (updateKind); return result; } @@ -1687,6 +1826,17 @@ class AudioProcessorGraph::Pimpl : public AsyncUpdater topologyChanged (UpdateKind::sync); } + void rebuild (UpdateKind updateKind) + { + if (updateKind == UpdateKind::none) + return; + + if (updateKind == UpdateKind::sync && MessageManager::getInstance()->isThisTheMessageThread()) + handleAsyncUpdate(); + else + updater.triggerAsyncUpdate(); + } + void reset() { for (auto* n : getNodes()) @@ -1743,36 +1893,41 @@ class AudioProcessorGraph::Pimpl : public AsyncUpdater void topologyChanged (UpdateKind updateKind) { owner->sendChangeMessage(); - - if (updateKind == UpdateKind::sync && MessageManager::getInstance()->isThisTheMessageThread()) - handleAsyncUpdate(); - else - triggerAsyncUpdate(); + rebuild (updateKind); } - void handleAsyncUpdate() override + void handleAsyncUpdate() { if (const auto newSettings = nodeStates.applySettings (nodes)) { for (const auto node : nodes.getNodes()) setParentGraph (node->getProcessor()); - auto sequence = std::make_unique (*newSettings, nodes, connections); - owner->setLatencySamples (sequence->getLatencySamples()); - renderSequenceExchange.set (std::move (sequence)); + const RenderSequenceSignature newSignature (*newSettings, nodes, connections); + + if (std::exchange (lastBuiltSequence, newSignature) != newSignature) + { + auto sequence = std::make_unique (*newSettings, nodes, connections); + owner->setLatencySamples (sequence->getLatencySamples()); + renderSequenceExchange.set (std::move (sequence)); + } } else { + lastBuiltSequence.reset(); renderSequenceExchange.set (nullptr); } } + AudioProcessorGraph* owner = nullptr; Nodes nodes; Connections connections; NodeStates nodeStates; RenderSequenceExchange renderSequenceExchange; NodeID lastNodeID; + std::optional lastBuiltSequence; + LockingAsyncUpdater updater { [this] { handleAsyncUpdate(); } }; }; //============================================================================== @@ -1799,6 +1954,7 @@ AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (NodeID x) const bool AudioProcessorGraph::disconnectNode (NodeID nodeID, UpdateKind updateKind) { return pimpl->disconnectNode (nodeID, updateKind); } void AudioProcessorGraph::releaseResources() { return pimpl->releaseResources(); } bool AudioProcessorGraph::removeIllegalConnections (UpdateKind updateKind) { return pimpl->removeIllegalConnections (updateKind); } +void AudioProcessorGraph::rebuild() { return pimpl->rebuild (UpdateKind::sync); } void AudioProcessorGraph::reset() { return pimpl->reset(); } bool AudioProcessorGraph::canConnect (const Connection& c) const { return pimpl->canConnect (c); } bool AudioProcessorGraph::isConnected (const Connection& c) const noexcept { return pimpl->isConnected (c); } @@ -1892,20 +2048,16 @@ bool AudioProcessorGraph::AudioGraphIOProcessor::supportsDoublePrecisionProcessi return true; } -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) +void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer&, MidiBuffer&) { - jassert (graph != nullptr); - - if (auto* state = graph->pimpl->getAudioThreadState()) - state->processIO (*this, buffer, midiMessages); + // The graph should never call this! + jassertfalse; } -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) +void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioBuffer&, MidiBuffer&) { - jassert (graph != nullptr); - - if (auto* state = graph->pimpl->getAudioThreadState()) - state->processIO (*this, buffer, midiMessages); + // The graph should never call this! + jassertfalse; } double AudioProcessorGraph::AudioGraphIOProcessor::getTailLengthSeconds() const @@ -1943,15 +2095,15 @@ void AudioProcessorGraph::AudioGraphIOProcessor::setParentGraph (AudioProcessorG { graph = newGraph; - if (graph != nullptr) - { - setPlayConfigDetails (type == audioOutputNode ? graph->getTotalNumOutputChannels() : 0, - type == audioInputNode ? graph->getTotalNumInputChannels() : 0, - getSampleRate(), - getBlockSize()); + if (graph == nullptr) + return; - updateHostDisplay(); - } + setPlayConfigDetails (type == audioOutputNode ? newGraph->getTotalNumOutputChannels() : 0, + type == audioInputNode ? newGraph->getTotalNumInputChannels() : 0, + getSampleRate(), + getBlockSize()); + + updateHostDisplay(); } //============================================================================== @@ -2058,6 +2210,36 @@ class AudioProcessorGraphTests : public UnitTest expect (graph.isAnInputTo (*nodes[nodes.size() - 1], *node)); } } + + beginTest ("large render sequence can be built"); + { + AudioProcessorGraph graph; + + std::vector nodeIDs; + + constexpr auto numNodes = 1000; + constexpr auto numChannels = 100; + + for (auto i = 0; i < numNodes; ++i) + { + nodeIDs.push_back (graph.addNode (BasicProcessor::make (BasicProcessor::getMultichannelProperties (numChannels), + MidiIn::yes, + MidiOut::yes))->nodeID); + } + + for (auto it = nodeIDs.begin(); it != std::prev (nodeIDs.end()); ++it) + for (auto channel = 0; channel < numChannels; ++channel) + expect (graph.addConnection ({ { it[0], channel }, { it[1], channel } })); + + const auto b = std::chrono::steady_clock::now(); + graph.prepareToPlay (44100.0, 512); + const auto e = std::chrono::steady_clock::now(); + const auto duration = std::chrono::duration_cast (e - b).count(); + + // No test here, but older versions of the graph would take forever to complete building + // this graph, so we just want to make sure that we finish the test without timing out. + logMessage ("render sequence built in " + String (duration) + " ms"); + } } private: @@ -2102,10 +2284,16 @@ class AudioProcessorGraphTests : public UnitTest static BusesProperties getStereoProperties() { - return BusesProperties().withInput ("in", AudioChannelSet::stereo()) + return BusesProperties().withInput ("in", AudioChannelSet::stereo()) .withOutput ("out", AudioChannelSet::stereo()); } + static BusesProperties getMultichannelProperties (int numChannels) + { + return BusesProperties().withInput ("in", AudioChannelSet::discreteChannels (numChannels)) + .withOutput ("out", AudioChannelSet::discreteChannels (numChannels)); + } + private: MidiIn midiIn; MidiOut midiOut; diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h index 8190d754d4d0..b6b6054678e3 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h @@ -127,7 +127,7 @@ class JUCE_API AudioProcessorGraph : public AudioProcessor, if (processor != nullptr) { if (auto* bypassParam = processor->getBypassParameter()) - return (bypassParam->getValue() != 0.0f); + return ! approximatelyEqual (bypassParam->getValue(), 0.0f); } return bypassed; @@ -210,8 +210,11 @@ class JUCE_API AudioProcessorGraph : public AudioProcessor, */ enum class UpdateKind { - sync, ///< Indicates that the graph should be rebuilt immediately after modification. - async ///< Indicates that the graph rebuild should be deferred. + sync, ///< Graph should be rebuilt immediately after modification. + async, ///< Graph rebuild should be delayed. If you make several changes to the graph + ///< inside the same call stack, these changes will be applied in one go. + none ///< Graph should not be rebuilt automatically. Use rebuild() to trigger a graph + ///< rebuild. }; //============================================================================== @@ -312,6 +315,14 @@ class JUCE_API AudioProcessorGraph : public AudioProcessor, */ bool removeIllegalConnections (UpdateKind = UpdateKind::sync); + /** Rebuilds the graph if necessary. + + This function will only ever rebuild the graph on the main thread. If this function is + called from another thread, the rebuild request will be dispatched asynchronously to the + main thread. + */ + void rebuild(); + //============================================================================== /** A special type of AudioProcessor that can live inside an AudioProcessorGraph in order to use the audio that comes into and out of the graph itself. diff --git a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp index d153c3d28912..7e32b8b776cb 100644 --- a/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp +++ b/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp @@ -293,7 +293,7 @@ class ChoiceParameterComponent : public ParameterComponent index = roundToInt (getParameter().getValue() * (float) (parameterValues.size() - 1)); } - box.setSelectedItemIndex (index); + box.setSelectedItemIndex (index, dontSendNotification); } void boxChanged() @@ -378,7 +378,7 @@ class SliderParameterComponent : public ParameterComponent { auto newVal = (float) slider.getValue(); - if (getParameter().getValue() != newVal) + if (! approximatelyEqual (getParameter().getValue(), newVal)) { if (! isDragging) getParameter().beginChangeGesture(); diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp index 6af4db764055..af4e0013fce5 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp @@ -64,7 +64,7 @@ class PluginListComponent::TableModel : public TableListBoxModel if (columnId == nameCol) text = list.getBlacklistedFiles() [row - list.getNumTypes()]; else if (columnId == descCol) - text = TRANS("Deactivated after failing to initialise correctly"); + text = TRANS ("Deactivated after failing to initialise correctly"); } else { @@ -155,11 +155,11 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, Kno TableHeaderComponent& header = table.getHeader(); - header.addColumn (TRANS("Name"), TableModel::nameCol, 200, 100, 700, TableHeaderComponent::defaultFlags | TableHeaderComponent::sortedForwards); - header.addColumn (TRANS("Format"), TableModel::typeCol, 80, 80, 80, TableHeaderComponent::notResizable); - header.addColumn (TRANS("Category"), TableModel::categoryCol, 100, 100, 200); - header.addColumn (TRANS("Manufacturer"), TableModel::manufacturerCol, 200, 100, 300); - header.addColumn (TRANS("Description"), TableModel::descCol, 300, 100, 500, TableHeaderComponent::notSortable); + header.addColumn (TRANS ("Name"), TableModel::nameCol, 200, 100, 700, TableHeaderComponent::defaultFlags | TableHeaderComponent::sortedForwards); + header.addColumn (TRANS ("Format"), TableModel::typeCol, 80, 80, 80, TableHeaderComponent::notResizable); + header.addColumn (TRANS ("Category"), TableModel::categoryCol, 100, 100, 200); + header.addColumn (TRANS ("Manufacturer"), TableModel::manufacturerCol, 200, 100, 300); + header.addColumn (TRANS ("Description"), TableModel::descCol, 300, 100, 500, TableHeaderComponent::notSortable); table.setHeaderHeight (22); table.setRowHeight (20); @@ -289,7 +289,7 @@ void PluginListComponent::removePluginItem (int index) PopupMenu PluginListComponent::createOptionsMenu() { PopupMenu menu; - menu.addItem (PopupMenu::Item (TRANS("Clear list")) + menu.addItem (PopupMenu::Item (TRANS ("Clear list")) .setAction ([this] { list.clear(); })); menu.addSeparator(); @@ -306,18 +306,18 @@ PopupMenu PluginListComponent::createOptionsMenu() menu.addSeparator(); - menu.addItem (PopupMenu::Item (TRANS("Remove selected plug-in from list")) + menu.addItem (PopupMenu::Item (TRANS ("Remove selected plug-in from list")) .setEnabled (table.getNumSelectedRows() > 0) .setAction ([this] { removeSelectedPlugins(); })); - menu.addItem (PopupMenu::Item (TRANS("Remove any plug-ins whose files no longer exist")) + menu.addItem (PopupMenu::Item (TRANS ("Remove any plug-ins whose files no longer exist")) .setAction ([this] { removeMissingPlugins(); })); menu.addSeparator(); auto selectedRow = table.getSelectedRow(); - menu.addItem (PopupMenu::Item (TRANS("Show folder containing selected plug-in")) + menu.addItem (PopupMenu::Item (TRANS ("Show folder containing selected plug-in")) .setEnabled (canShowFolderForPlugin (list, selectedRow)) .setAction ([this, selectedRow] { showFolderForPlugin (list, selectedRow); })); @@ -337,10 +337,10 @@ PopupMenu PluginListComponent::createMenuForRow (int rowNumber) if (rowNumber >= 0 && rowNumber < tableModel->getNumRows()) { - menu.addItem (PopupMenu::Item (TRANS("Remove plug-in from list")) + menu.addItem (PopupMenu::Item (TRANS ("Remove plug-in from list")) .setAction ([this, rowNumber] { removePluginItem (rowNumber); })); - menu.addItem (PopupMenu::Item (TRANS("Show folder containing plug-in")) + menu.addItem (PopupMenu::Item (TRANS ("Show folder containing plug-in")) .setEnabled (canShowFolderForPlugin (list, rowNumber)) .setAction ([this, rowNumber] { showFolderForPlugin (list, rowNumber); })); } @@ -391,7 +391,7 @@ class PluginListComponent::Scanner : private Timer formatToScan (format), filesOrIdentifiersToScan (filesOrIdentifiers), propertiesToUse (properties), - pathChooserWindow (TRANS("Select folders to scan..."), String(), MessageBoxIconType::NoIcon), + pathChooserWindow (TRANS ("Select folders to scan..."), String(), MessageBoxIconType::NoIcon), progressWindow (title, text, MessageBoxIconType::NoIcon), numThreads (threads), allowAsync (allowPluginsWhichRequireAsynchronousInstantiation) @@ -417,8 +417,8 @@ class PluginListComponent::Scanner : private Timer pathList.setPath (path); pathChooserWindow.addCustomComponent (&pathList); - pathChooserWindow.addButton (TRANS("Scan"), 1, KeyPress (KeyPress::returnKey)); - pathChooserWindow.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); + pathChooserWindow.addButton (TRANS ("Scan"), 1, KeyPress (KeyPress::returnKey)); + pathChooserWindow.addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey)); pathChooserWindow.enterModalState (true, ModalCallbackFunction::forComponent (startScanCallback, @@ -455,6 +455,7 @@ class PluginListComponent::Scanner : private Timer std::atomic finished { false }; std::unique_ptr pool; std::set initiallyBlacklistedFiles; + ScopedMessageBox messageBox; static void startScanCallback (int result, AlertWindow* alert, Scanner* scanner) { @@ -472,22 +473,27 @@ class PluginListComponent::Scanner : private Timer { for (int i = 0; i < pathList.getPath().getNumPaths(); ++i) { - auto f = pathList.getPath()[i]; + auto f = pathList.getPath().getRawString (i); - if (isStupidPath (f)) + if (File::isAbsolutePath (f) && isStupidPath (File (f))) { - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - TRANS("Plugin Scanning"), - TRANS("If you choose to scan folders that contain non-plugin files, " - "then scanning may take a long time, and can cause crashes when " - "attempting to load unsuitable files.") - + newLine - + TRANS ("Are you sure you want to scan the folder \"XYZ\"?") - .replace ("XYZ", f.getFullPathName()), - TRANS ("Scan"), - String(), - nullptr, - ModalCallbackFunction::create (warnAboutStupidPathsCallback, this)); + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + TRANS ("Plugin Scanning"), + TRANS ("If you choose to scan folders that contain non-plugin files, " + "then scanning may take a long time, and can cause crashes when " + "attempting to load unsuitable files.") + + newLine + + TRANS ("Are you sure you want to scan the folder \"XYZ\"?") + .replace ("XYZ", f), + TRANS ("Scan")); + messageBox = AlertWindow::showScopedAsync (options, [this] (int result) + { + if (result != 0) + startScan(); + else + finishedScan(); + }); + return; } } @@ -524,14 +530,6 @@ class PluginListComponent::Scanner : private Timer return false; } - static void warnAboutStupidPathsCallback (int result, Scanner* scanner) - { - if (result != 0) - scanner->startScan(); - else - scanner->finishedScan(); - } - void startScan() { pathChooserWindow.setVisible (false); @@ -549,13 +547,13 @@ class PluginListComponent::Scanner : private Timer propertiesToUse->saveIfNeeded(); } - progressWindow.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); + progressWindow.addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey)); progressWindow.addProgressBarComponent (progress); progressWindow.enterModalState(); if (numThreads > 0) { - pool.reset (new ThreadPool (numThreads)); + pool.reset (new ThreadPool (ThreadPoolOptions{}.withNumberOfThreads (numThreads))); for (int i = numThreads; --i >= 0;) pool->addJob (new ScanJob (*this), true); @@ -599,7 +597,7 @@ class PluginListComponent::Scanner : private Timer if (finished) finishedScan(); else - progressWindow.setMessage (TRANS("Testing") + ":\n\n" + pluginBeingScanned); + progressWindow.setMessage (TRANS ("Testing") + ":\n\n" + pluginBeingScanned); } bool doNextScan() @@ -639,8 +637,8 @@ void PluginListComponent::scanFor (AudioPluginFormat& format) void PluginListComponent::scanFor (AudioPluginFormat& format, const StringArray& filesOrIdentifiersToScan) { currentScanner.reset (new Scanner (*this, format, filesOrIdentifiersToScan, propertiesToUse, allowAsync, numThreads, - dialogTitle.isNotEmpty() ? dialogTitle : TRANS("Scanning for plug-ins..."), - dialogText.isNotEmpty() ? dialogText : TRANS("Searching for all possible plug-in files..."))); + dialogTitle.isNotEmpty() ? dialogTitle : TRANS ("Scanning for plug-ins..."), + dialogText.isNotEmpty() ? dialogText : TRANS ("Searching for all possible plug-in files..."))); } bool PluginListComponent::isScanning() const noexcept @@ -672,9 +670,12 @@ void PluginListComponent::scanFinished (const StringArray& failedFiles, currentScanner.reset(); // mustn't delete this before using the failed files array if (! warnings.isEmpty()) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::InfoIcon, - TRANS("Scan complete"), - warnings.joinIntoString ("\n\n")); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::InfoIcon, + TRANS ("Scan complete"), + warnings.joinIntoString ("\n\n")); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } } } // namespace juce diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.h b/modules/juce_audio_processors/scanning/juce_PluginListComponent.h index 42f7433c954a..96c375025862 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.h +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.h @@ -130,6 +130,8 @@ class JUCE_API PluginListComponent : public Component, class Scanner; std::unique_ptr currentScanner; + ScopedMessageBox messageBox; + void scanFinished (const StringArray&, const std::vector&); void updateList(); void removeMissingPlugins(); diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp index 6e819cda74f6..5c505e1f44de 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.cpp @@ -114,6 +114,9 @@ class ARADocumentControllerSpecialisation::ARADocumentControllerImpl : public A ARA::PlugIn::ContentReader* doCreatePlaybackRegionContentReader (ARA::PlugIn::PlaybackRegion* playbackRegion, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range) noexcept override; + void doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion, + ARA::ARATimeDuration* headTime, + ARA::ARATimeDuration* tailTime) noexcept override; //============================================================================== // ARAAudioSource analysis @@ -659,6 +662,13 @@ ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::ARADocumentCont return specialisation->doCreatePlaybackRegionContentReader (playbackRegion, type, range); } +void ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion, + ARA::ARATimeDuration* headTime, + ARA::ARATimeDuration* tailTime) noexcept +{ + specialisation->doGetPlaybackRegionHeadAndTailTime (playbackRegion, headTime, tailTime); +} + bool ARADocumentControllerSpecialisation::ARADocumentControllerImpl::doIsAudioSourceContentAnalysisIncomplete (const ARA::PlugIn::AudioSource* audioSource, ARA::ARAContentType type) noexcept { @@ -915,6 +925,14 @@ ARA::PlugIn::ContentReader* ARADocumentControllerSpecialisation::doCreatePlaybac return nullptr; } +void ARADocumentControllerSpecialisation::doGetPlaybackRegionHeadAndTailTime ([[maybe_unused]] const ARA::PlugIn::PlaybackRegion* playbackRegion, + ARA::ARATimeDuration* headTime, + ARA::ARATimeDuration* tailTime) +{ + *headTime = 0.0; + *tailTime = 0.0; +} + bool ARADocumentControllerSpecialisation::doIsAudioSourceContentAnalysisIncomplete ([[maybe_unused]] const ARA::PlugIn::AudioSource* audioSource, [[maybe_unused]] ARA::ARAContentType type) { diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.h b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.h index 8b04fbb0ca0d..c9e315f17548 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.h +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARADocumentController.h @@ -282,6 +282,15 @@ class ARADocumentControllerSpecialisation : public ARADocument::Listener, ARA::ARAContentType type, const ARA::ARAContentTimeRange* range); + /** Override to implement getPlaybackRegionHeadAndTailTime(). + + This function is called within + ARA::PlugIn::DocumentControllerDelegate::doGetPlaybackRegionHeadAndTailTime. + */ + virtual void doGetPlaybackRegionHeadAndTailTime (const ARA::PlugIn::PlaybackRegion* playbackRegion, + ARA::ARATimeDuration* headTime, + ARA::ARATimeDuration* tailTime); + //============================================================================== // ARAAudioSource analysis diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARAModelObjects.cpp b/modules/juce_audio_processors/utilities/ARA/juce_ARAModelObjects.cpp index 3db14330272b..c2c175017eef 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARAModelObjects.cpp +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARAModelObjects.cpp @@ -91,7 +91,7 @@ double ARARegionSequence::getCommonSampleRate() const const auto range = getPlaybackRegions(); const auto sampleRate = range.size() > 0 ? getSampleRate (range.front()) : 0.0; - if (std::any_of (range.begin(), range.end(), [&] (auto& x) { return getSampleRate (x) != sampleRate; })) + if (std::any_of (range.begin(), range.end(), [&] (auto& x) { return ! exactlyEqual (getSampleRate (x), sampleRate); })) return 0.0; return sampleRate; diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARA_utils.h b/modules/juce_audio_processors/utilities/ARA/juce_ARA_utils.h index e30cbbe3d008..8f2357e5645d 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARA_utils.h +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARA_utils.h @@ -27,7 +27,8 @@ // Include ARA SDK headers JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wgnu-zero-variadic-macro-arguments", - "-Wunused-parameter") + "-Wunused-parameter", + "-Wfloat-equal") JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387) #include diff --git a/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp b/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp new file mode 100644 index 000000000000..9596d006194e --- /dev/null +++ b/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.cpp @@ -0,0 +1,299 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce +{ + +class AAXPluginId +{ +public: + static std::optional create (std::array letters) + { + std::array indices{}; + + for (size_t i = 0; i < letters.size(); ++i) + { + if (const auto index = findIndexOfChar (letters[i])) + indices[i] = *index; + else + return std::nullopt; + } + + return AAXPluginId { std::move (indices) }; + } + + std::optional withIncrementedLetter (size_t index, size_t increment) const + { + if (indices.size() <= index) + return std::nullopt; + + auto copy = *this; + copy.indices[index] += increment; + + if ((size_t) std::size (validChars) <= copy.indices[index]) + return std::nullopt; + + return copy; + } + + int32 getPluginId() const + { + int32 result = 0; + + for (size_t i = 0; i < indices.size(); ++i) + result |= static_cast (validChars[indices[i]]) << (8 * (indices.size() - 1 - i)); + + return result; + } + + static std::optional findIndexOfChar (char c) + { + const auto ptr = std::find (std::begin (validChars), std::end (validChars), c); + return ptr != std::end (validChars) ? std::make_optional (std::distance (std::begin (validChars), ptr)) + : std::nullopt; + } + +private: + static inline constexpr char validChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + explicit AAXPluginId (std::array indicesIn) + : indices (std::move (indicesIn)) + {} + + std::array indices; +}; + +static const AudioChannelSet channelSets[] { AudioChannelSet::disabled(), + AudioChannelSet::mono(), + AudioChannelSet::stereo(), + AudioChannelSet::createLCR(), + AudioChannelSet::createLCRS(), + AudioChannelSet::quadraphonic(), + AudioChannelSet::create5point0(), + AudioChannelSet::create5point1(), + AudioChannelSet::create6point0(), + AudioChannelSet::create6point1(), + AudioChannelSet::create7point0(), + AudioChannelSet::create7point1(), + AudioChannelSet::create7point0SDDS(), + AudioChannelSet::create7point1SDDS(), + AudioChannelSet::create7point0point2(), + AudioChannelSet::create7point1point2(), + AudioChannelSet::ambisonic (1), + AudioChannelSet::ambisonic (2), + AudioChannelSet::ambisonic (3), + AudioChannelSet::create5point0point2(), + AudioChannelSet::create5point1point2(), + AudioChannelSet::create5point0point4(), + AudioChannelSet::create5point1point4(), + AudioChannelSet::create7point0point4(), + AudioChannelSet::create7point1point4(), + AudioChannelSet::create7point0point6(), + AudioChannelSet::create7point1point6(), + AudioChannelSet::create9point0point4(), + AudioChannelSet::create9point1point4(), + AudioChannelSet::create9point0point6(), + AudioChannelSet::create9point1point6(), + AudioChannelSet::ambisonic (4), + AudioChannelSet::ambisonic (5), + AudioChannelSet::ambisonic (6), + AudioChannelSet::ambisonic (7) }; + +int32 AAXClientExtensions::getPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, + const AudioChannelSet& mainOutputLayout, + bool idForAudioSuite) const +{ + auto pluginId = [&] + { + auto opt = idForAudioSuite ? AAXPluginId::create ({ 'j', 'y', 'a', 'a' }) + : AAXPluginId::create ({ 'j', 'c', 'a', 'a' }); + jassert (opt.has_value()); + return *opt; + }(); + + for (const auto& [channelSet, indexToModify] : { std::tuple (&mainInputLayout, (size_t) 2), + std::tuple (&mainOutputLayout, (size_t) 3) }) + { + const auto increment = (size_t) std::distance (std::begin (channelSets), + std::find (std::begin (channelSets), + std::end (channelSets), + *channelSet)); + + if (auto modifiedPluginIdOpt = pluginId.withIncrementedLetter (indexToModify, increment); + increment < (size_t) std::size (channelSets) && modifiedPluginIdOpt.has_value()) + { + pluginId = *modifiedPluginIdOpt; + } + else + { + jassertfalse; + } + } + + return pluginId.getPluginId(); +} + +String AAXClientExtensions::getPageFileName() const +{ + #ifdef JucePlugin_AAXPageTableFile + JUCE_COMPILER_WARNING ("JucePlugin_AAXPageTableFile is deprecated, instead implement AAXClientExtensions::getPageFileName()") + return JucePlugin_AAXPageTableFile; + #else + return {}; + #endif +} + +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +static std::array toCharArray (int32 identifier) +{ + std::array result; + + for (size_t i = 0; i < result.size(); ++i) + result[i] = static_cast ((identifier >> (i * 8)) & 0xff); + + return result; +} + +static bool isValidAAXPluginId (int32 pluginId) +{ + const auto chars = toCharArray (pluginId); + + return std::all_of (std::begin (chars), + std::end (chars), + [] (const auto& c) + { + return AAXPluginId::findIndexOfChar (c).has_value(); + }); +} + +static int32 getPluginIDForMainBusConfigJuce705 (const AudioChannelSet& mainInputLayout, + const AudioChannelSet& mainOutputLayout, + bool idForAudioSuite) +{ + int uniqueFormatId = 0; + + for (int dir = 0; dir < 2; ++dir) + { + const bool isInput = (dir == 0); + auto& set = (isInput ? mainInputLayout : mainOutputLayout); + int aaxFormatIndex = 0; + + const AudioChannelSet sets[] + { + AudioChannelSet::disabled(), + AudioChannelSet::mono(), + AudioChannelSet::stereo(), + AudioChannelSet::createLCR(), + AudioChannelSet::createLCRS(), + AudioChannelSet::quadraphonic(), + AudioChannelSet::create5point0(), + AudioChannelSet::create5point1(), + AudioChannelSet::create6point0(), + AudioChannelSet::create6point1(), + AudioChannelSet::create7point0(), + AudioChannelSet::create7point1(), + AudioChannelSet::create7point0SDDS(), + AudioChannelSet::create7point1SDDS(), + AudioChannelSet::create7point0point2(), + AudioChannelSet::create7point1point2(), + AudioChannelSet::ambisonic (1), + AudioChannelSet::ambisonic (2), + AudioChannelSet::ambisonic (3), + AudioChannelSet::create5point0point2(), + AudioChannelSet::create5point1point2(), + AudioChannelSet::create5point0point4(), + AudioChannelSet::create5point1point4(), + AudioChannelSet::create7point0point4(), + AudioChannelSet::create7point1point4(), + AudioChannelSet::create7point0point6(), + AudioChannelSet::create7point1point6(), + AudioChannelSet::create9point0point4(), + AudioChannelSet::create9point1point4(), + AudioChannelSet::create9point0point6(), + AudioChannelSet::create9point1point6(), + AudioChannelSet::ambisonic (4), + AudioChannelSet::ambisonic (5), + AudioChannelSet::ambisonic (6), + AudioChannelSet::ambisonic (7) + }; + + const auto index = (int) std::distance (std::begin (sets), std::find (std::begin (sets), std::end (sets), set)); + + if (index != (int) std::size (sets)) + aaxFormatIndex = index; + else + jassertfalse; + + uniqueFormatId = (uniqueFormatId << 8) | aaxFormatIndex; + } + + return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId; +} + +class AAXClientExtensionsTests : public UnitTest +{ +public: + AAXClientExtensionsTests() + : UnitTest ("AAXClientExtensionsTests", UnitTestCategories::audioProcessors) + {} + + void runTest() override + { + AAXClientExtensions extensions; + + beginTest ("Previously valid PluginIds should be unchanged"); + { + for (const auto& input : channelSets) + for (const auto& output : channelSets) + for (const auto idForAudioSuite : { false, true }) + if (const auto oldId = getPluginIDForMainBusConfigJuce705 (input, output, idForAudioSuite); isValidAAXPluginId (oldId)) + expect (extensions.getPluginIDForMainBusConfig (input, output, idForAudioSuite) == oldId); + } + + beginTest ("Valid, unique PluginIds should be generated for all configurations"); + { + std::set pluginIds; + + for (const auto& input : channelSets) + for (const auto& output : channelSets) + for (const auto idForAudioSuite : { false, true }) + pluginIds.insert (extensions.getPluginIDForMainBusConfig (input, output, idForAudioSuite)); + + for (auto identifier : pluginIds) + expect (isValidAAXPluginId (identifier)); + + expect (pluginIds.size() == square (std::size (channelSets)) * 2); + } + } +}; + +static AAXClientExtensionsTests aaxClientExtensionsTests; + +#endif + +} // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h b/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h new file mode 100644 index 000000000000..870ab966fd3e --- /dev/null +++ b/modules/juce_audio_processors/utilities/juce_AAXClientExtensions.h @@ -0,0 +1,83 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce +{ + +/** + An interface to allow an AudioProcessor to implement extended AAX-specific functionality. + + To use this class, create an object that inherits from it, implement the methods, then return + a pointer to the object in your AudioProcessor `getAAXClientExtensions()` method. + + @see AudioProcessor, VST2ClientExtensions, VST3ClientExtensions + + @tags{Audio} +*/ +struct AAXClientExtensions +{ + virtual ~AAXClientExtensions() = default; + + /** AAX plug-ins need to report a unique "plug-in id" for every audio layout + configuration that your AudioProcessor supports on the main bus. Override this + function if you want your AudioProcessor to use a custom "plug-in id" (for example + to stay backward compatible with older versions of JUCE). + + The default implementation will compute a unique integer from the input and output + layout and add this value to the 4 character code 'jcaa' (for native AAX) or 'jyaa' + (for AudioSuite plug-ins). + */ + virtual int32 getPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout, + const AudioChannelSet& mainOutputLayout, + bool idForAudioSuite) const; + + /** Returns an optional filename (including extension) for a page file to be used. + + A page file allows an AAX plugin to specify how its parameters are displayed on + various control surfaces. For more information read the Page Table Guide in the + AAX SDK documentation. + + By default this file will be searched for in `*.aaxplugin/Contents/Resources`. + + @see getPageFileSearchPath + */ + virtual String getPageFileName() const; + + /** Optionally returns a search path for finding a page table file. + + This can be useful for specifying a location outside the plugin bundle so users can + make changes to a page table file without breaking any code signatures. + + If this function returns a default-constructed File, then a default location will be used. + The AAX SDK states this location will be `*.aaxplugin/Contents/Resources`. + + @note The returned path should be an absolute path to a directory. + + @see getPageFileName + */ + virtual File getPageFileSearchPath() const { return {}; } +}; + +} // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h index f16945f77996..6caa41775615 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterBool.h @@ -29,6 +29,8 @@ namespace juce /** Properties of an AudioParameterBool. @see AudioParameterBool(), RangedAudioParameterAttributes() + + @tags{Audio} */ class AudioParameterBoolAttributes : public RangedAudioParameterAttributes {}; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h index f3fdd2d641e1..6940a57d0050 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h @@ -29,6 +29,8 @@ namespace juce /** Properties of an AudioParameterChoice. @see AudioParameterChoice(), RangedAudioParameterAttributes() + + @tags{Audio} */ class AudioParameterChoiceAttributes : public RangedAudioParameterAttributes {}; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp index a9f84d3a6923..5ac42137c369 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.cpp @@ -44,7 +44,7 @@ AudioParameterFloat::AudioParameterFloat (const ParameterID& idToUse, { int numDecimalPlaces = 7; - if (range.interval != 0.0f) + if (! approximatelyEqual (range.interval, 0.0f)) { if (approximatelyEqual (std::abs (range.interval - std::floor (range.interval)), 0.0f)) return 0; @@ -95,7 +95,7 @@ void AudioParameterFloat::valueChanged (float) {} AudioParameterFloat& AudioParameterFloat::operator= (float newValue) { - if (value != newValue) + if (! approximatelyEqual ((float) value, newValue)) setValueNotifyingHost (convertTo0to1 (newValue)); return *this; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h index c6adbe78f68a..c785f340e245 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterFloat.h @@ -29,6 +29,8 @@ namespace juce /** Properties of an AudioParameterFloat. @see AudioParameterFloat(), RangedAudioParameterAttributes() + + @tags{Audio} */ class AudioParameterFloatAttributes : public RangedAudioParameterAttributes {}; diff --git a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h index 965dac6a40a1..87036c24ab15 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h +++ b/modules/juce_audio_processors/utilities/juce_AudioParameterInt.h @@ -29,6 +29,8 @@ namespace juce /** Properties of an AudioParameterInt. @see AudioParameterInt(), RangedAudioParameterAttributes() + + @tags{Audio} */ class AudioParameterIntAttributes : public RangedAudioParameterAttributes {}; diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h b/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h index 15f7882c9ff8..c5a622d26941 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorParameterWithID.h @@ -28,6 +28,8 @@ namespace juce /** Combines a parameter ID and a version hint. + + @tags{Audio} */ class ParameterID { @@ -62,6 +64,8 @@ class ParameterID /** An instance of this class may be passed to the constructor of an AudioProcessorParameterWithID to set optional characteristics of that parameter. + + @tags{Audio} */ class AudioProcessorParameterWithIDAttributes { diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp index 7e75bc145886..fa9f91ab996e 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp @@ -52,13 +52,11 @@ bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return void AudioProcessorValueTreeState::Parameter::valueChanged (float newValue) { - if (lastValue == newValue) + if (approximatelyEqual ((float) lastValue, newValue)) return; lastValue = newValue; - - if (onValueChanged != nullptr) - onValueChanged(); + NullCheckedInvocation::invoke (onValueChanged); } //============================================================================== @@ -93,10 +91,8 @@ class AudioProcessorValueTreeState::ParameterAdapter : private AudioProcessorP void setDenormalisedValue (float value) { - if (value == unnormalisedValue) - return; - - setNormalisedValue (normalise (value)); + if (! approximatelyEqual (value, (float) unnormalisedValue)) + setNormalisedValue (normalise (value)); } float getDenormalisedValueForText (const String& text) const @@ -119,9 +115,9 @@ class AudioProcessorValueTreeState::ParameterAdapter : private AudioProcessorP if (! needsUpdate.compare_exchange_strong (needsUpdateTestValue, false)) return false; - if (auto valueProperty = tree.getPropertyPointer (key)) + if (auto* valueProperty = tree.getPropertyPointer (key)) { - if ((float) *valueProperty != unnormalisedValue) + if (! approximatelyEqual ((float) *valueProperty, unnormalisedValue.load())) { ScopedValueSetter svs (ignoreParameterChangedCallbacks, true); tree.setProperty (key, unnormalisedValue.load(), um); @@ -144,7 +140,7 @@ class AudioProcessorValueTreeState::ParameterAdapter : private AudioProcessorP { const auto newValue = denormalise (parameter.getValue()); - if (unnormalisedValue == newValue && ! listenersNeedCalling) + if (! listenersNeedCalling && approximatelyEqual ((float) unnormalisedValue, newValue)) return; unnormalisedValue = newValue; diff --git a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h index a6e0de39476c..83d93962eba3 100644 --- a/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h +++ b/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h @@ -32,6 +32,8 @@ namespace juce AudioParameterFloatAttributes. @see AudioParameterFloatAttributes, RangedAudioParameterAttributes + + @tags{Audio} */ class AudioProcessorValueTreeStateParameterAttributes { diff --git a/modules/juce_audio_processors/utilities/juce_NativeScaleFactorNotifier.h b/modules/juce_audio_processors/utilities/juce_NativeScaleFactorNotifier.h index a755fb2def13..597513eef0ed 100644 --- a/modules/juce_audio_processors/utilities/juce_NativeScaleFactorNotifier.h +++ b/modules/juce_audio_processors/utilities/juce_NativeScaleFactorNotifier.h @@ -31,6 +31,8 @@ namespace juce This is used in the VST and VST3 wrappers to ensure that the editor's scale is kept in sync with the scale of its containing component. + + @tags{GUI} */ class NativeScaleFactorNotifier : private ComponentMovementWatcher, private ComponentPeer::ScaleFactorListener diff --git a/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp b/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp index 73edfe010a75..3c092a16ec51 100644 --- a/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp +++ b/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp @@ -84,7 +84,7 @@ void ParameterAttachment::callIfParameterValueChanged (float newDenormalisedValu { const auto newValue = normalise (newDenormalisedValue); - if (parameter.getValue() != newValue) + if (! approximatelyEqual (parameter.getValue(), newValue)) callback (newValue); } diff --git a/modules/juce_audio_processors/utilities/juce_PluginHostType.cpp b/modules/juce_audio_processors/utilities/juce_PluginHostType.cpp index 78f7ea2346ca..b74874a60161 100644 --- a/modules/juce_audio_processors/utilities/juce_PluginHostType.cpp +++ b/modules/juce_audio_processors/utilities/juce_PluginHostType.cpp @@ -119,6 +119,7 @@ const char* PluginHostType::getHostDescription() const noexcept case pluginval: return "pluginval"; case MergingPyramix: return "Pyramix"; case MuseReceptorGeneric: return "Muse Receptor"; + case Maschine: return "NI Maschine"; case Reaper: return "Reaper"; case Reason: return "Reason"; case Renoise: return "Renoise"; @@ -213,6 +214,7 @@ PluginHostType::HostType PluginHostType::getHostType() if (hostFilename.containsIgnoreCase ("OsxFL")) return FruityLoops; if (hostFilename.containsIgnoreCase ("pluginval")) return pluginval; if (hostFilename.containsIgnoreCase ("AudioPluginHost")) return JUCEPluginHost; + if (hostFilename.containsIgnoreCase ("Maschine")) return Maschine; if (hostFilename.containsIgnoreCase ("Vienna Ensemble Pro")) return ViennaEnsemblePro; if (hostFilename.containsIgnoreCase ("auvaltool")) return AUVal; if (hostFilename.containsIgnoreCase ("com.apple.audio.infohelper")) return AppleInfoHelper; @@ -280,6 +282,7 @@ PluginHostType::HostType PluginHostType::getHostType() if (hostFilename.containsIgnoreCase ("Wavelab")) return SteinbergWavelabGeneric; if (hostFilename.containsIgnoreCase ("TestHost")) return SteinbergTestHost; if (hostFilename.containsIgnoreCase ("rm-host")) return MuseReceptorGeneric; + if (hostFilename.containsIgnoreCase ("Maschine")) return Maschine; if (hostFilename.startsWith ("FL")) return FruityLoops; if (hostFilename.contains ("ilbridge.")) return FruityLoops; if (hostPath.containsIgnoreCase ("Studio One")) return StudioOne; diff --git a/modules/juce_audio_processors/utilities/juce_PluginHostType.h b/modules/juce_audio_processors/utilities/juce_PluginHostType.h index cf5f0e405b44..b9366c0c79f0 100644 --- a/modules/juce_audio_processors/utilities/juce_PluginHostType.h +++ b/modules/juce_audio_processors/utilities/juce_PluginHostType.h @@ -78,6 +78,7 @@ class PluginHostType MagixSequoia, /**< Represents Magix Sequoia. */ MergingPyramix, /**< Represents Merging Pyramix. */ MuseReceptorGeneric, /**< Represents Muse Receptor. */ + Maschine, /**< Represents Native Instruments Maschine. */ pluginval, /**< Represents pluginval. */ Reaper, /**< Represents Cockos Reaper. */ Reason, /**< Represents Reason. */ @@ -203,6 +204,8 @@ class PluginHostType bool isWavelab() const noexcept { return isWavelabLegacy() || type == SteinbergWavelab7 || type == SteinbergWavelab8 || type == SteinbergWavelabGeneric; } /** Returns true if the host is Steinberg WaveLab 6 or below. */ bool isWavelabLegacy() const noexcept { return type == SteinbergWavelab5 || type == SteinbergWavelab6; } + /** Returns true if the host is Native Instruments Maschine. */ + bool isMaschine() const noexcept { return type == Maschine; } //============================================================================== /** Returns a human-readable description of the host. */ diff --git a/modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h b/modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h index c24c52b94dea..4707e8f53a05 100644 --- a/modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h +++ b/modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h @@ -36,6 +36,8 @@ namespace juce i.e. the identifiers AudioParameterFloatAttributes and RangedAudioParameterAttributes should not be interchangable because we might need to add float-specific attributes in the future. Users should not refer directly to RangedAudioParameterAttributes. + + @tags{Audio} */ template class RangedAudioParameterAttributes diff --git a/modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp b/modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp similarity index 62% rename from modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp rename to modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp index e8b42e9b0a8f..b7ea7f21082d 100644 --- a/modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.cpp +++ b/modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp @@ -26,14 +26,14 @@ namespace juce { -pointer_sized_int VSTCallbackHandler::handleVstPluginCanDo ([[maybe_unused]] int32 index, - [[maybe_unused]] pointer_sized_int value, - [[maybe_unused]] void* ptr, - [[maybe_unused]] float opt) +pointer_sized_int VST2ClientExtensions::handleVstPluginCanDo ([[maybe_unused]] int32 index, + [[maybe_unused]] pointer_sized_int value, + [[maybe_unused]] void* ptr, + [[maybe_unused]] float opt) { return 0; } -void VSTCallbackHandler::handleVstHostCallbackAvailable ([[maybe_unused]] std::function&& callback) {} +void VST2ClientExtensions::handleVstHostCallbackAvailable ([[maybe_unused]] std::function&& callback) {} } // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h b/modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h similarity index 68% rename from modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h rename to modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h index 9fe3a0ad82c3..b656ec4cefca 100644 --- a/modules/juce_audio_processors/utilities/juce_VSTCallbackHandler.h +++ b/modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h @@ -26,19 +26,19 @@ namespace juce { -/** An interface to allow an AudioProcessor to send and receive VST specific calls from - the host. +/** + An interface to allow an AudioProcessor to implement extended VST2-specific functionality. - To use this class, ensure that your AudioProcessor publicly inherits - from VSTCallbackHandler. + To use this class, create an object that inherits from it, implement the methods, then return + a pointer to the object in your AudioProcessor::getVST2ClientExtensions() method. - @see VST3ClientExtensions + @see AudioProcessor, AAXClientExtensions, VST3ClientExtensions @tags{Audio} */ -struct VSTCallbackHandler +struct VST2ClientExtensions { - virtual ~VSTCallbackHandler() = default; + virtual ~VST2ClientExtensions() = default; /** This is called by the VST plug-in wrapper when it receives unhandled plug-in "can do" calls from the host. @@ -56,13 +56,12 @@ struct VSTCallbackHandler void* ptr, float opt) = 0; - // Note: VS2013 prevents a "using" declaration here /** The host callback function type. */ - typedef pointer_sized_int (VstHostCallbackType) (int32 opcode, - int32 index, - pointer_sized_int value, - void* ptr, - float opt); + using VstHostCallbackType = pointer_sized_int (int32 opcode, + int32 index, + pointer_sized_int value, + void* ptr, + float opt); /** This is called once by the VST plug-in wrapper after its constructor. You can use the supplied function to query the VST host. @@ -70,4 +69,6 @@ struct VSTCallbackHandler virtual void handleVstHostCallbackAvailable (std::function&& callback); }; +using VSTCallbackHandler [[deprecated ("replace with VST2ClientExtensions")]] = VST2ClientExtensions; + } // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h index 9d70828f34b2..665f11f1f787 100644 --- a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h @@ -37,13 +37,13 @@ namespace Steinberg namespace juce { -/** An interface to allow an AudioProcessor to implement extended VST3-specific - functionality. +/** + An interface to allow an AudioProcessor to implement extended VST3-specific functionality. - To use this class, ensure that your AudioProcessor publicly inherits - from VST3ClientExtensions. + To use this class, create an object that inherits from it, implement the methods, then return + a pointer to the object in your AudioProcessor::getVST3ClientExtensions() method. - @see VSTCallbackHandler + @see AudioProcessor, AAXClientExtensions, VST2ClientExtensions @tags{Audio} */ @@ -94,6 +94,17 @@ struct VST3ClientExtensions All other input buses will always be designated kAux. */ virtual bool getPluginHasMainInput() const { return true; } + + /** This function should return the UIDs of any compatible VST2 plug-ins. + + Each item in the vector should be a 32-character string consisting only + of the characters 0-9 and A-F. + + This information will be used to implement the IPluginCompatibility + interface. Hosts can use this interface to determine whether this VST3 + is capable of replacing a given VST2. + */ + virtual std::vector getCompatibleClasses() const { return {}; } }; } // namespace juce diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index 809162f583fb..fcf922ee1555 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -401,9 +401,11 @@ class AudioDeviceSettingsPanel : public Component, } if (error.isNotEmpty()) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS("Error when trying to open audio device!"), - error); + messageBox = AlertWindow::showScopedAsync (MessageBoxOptions().withIconType (MessageBoxIconType::WarningIcon) + .withTitle (TRANS ("Error when trying to open audio device!")) + .withMessage (error) + .withButton (TRANS ("OK")), + nullptr); } bool showDeviceControlPanel() @@ -720,7 +722,7 @@ class AudioDeviceSettingsPanel : public Component, auto currentRate = currentDevice->getCurrentSampleRate(); - if (currentRate == 0) + if (exactlyEqual (currentRate, 0.0)) currentRate = 48000.0; for (auto bs : currentDevice->getAvailableBufferSizes()) @@ -966,6 +968,7 @@ class AudioDeviceSettingsPanel : public Component, private: std::unique_ptr inputChanList, outputChanList; + ScopedMessageBox messageBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSettingsPanel) }; diff --git a/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp b/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp index 377b70edcd64..31b13de0f957 100644 --- a/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp @@ -501,8 +501,8 @@ class AudioThumbnail::CachedWindow if (numSamples == numSamplesCached && numChannelsCached == numChans - && startTime == cachedStart - && timePerPixel == cachedTimePerPixel + && approximatelyEqual (startTime, cachedStart) + && approximatelyEqual (timePerPixel, cachedTimePerPixel) && ! cacheNeedsRefilling) { return ! cacheNeedsRefilling; diff --git a/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.cpp b/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.cpp index 64db4b6056e4..048a53b41c75 100644 --- a/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.cpp +++ b/modules/juce_audio_utils/gui/juce_KeyboardComponentBase.cpp @@ -79,7 +79,7 @@ void KeyboardComponentBase::setKeyWidth (float widthInPixels) { jassert (widthInPixels > 0); - if (keyWidth != widthInPixels) // Prevent infinite recursion if the width is being computed in a 'resized()' callback + if (! approximatelyEqual (keyWidth, widthInPixels)) // Prevent infinite recursion if the width is being computed in a 'resized()' callback { keyWidth = widthInPixels; resized(); @@ -130,7 +130,7 @@ void KeyboardComponentBase::setLowestVisibleKeyFloat (float noteNumber) { noteNumber = jlimit ((float) rangeStart, (float) rangeEnd, noteNumber); - if (noteNumber != firstKey) + if (! approximatelyEqual (noteNumber, firstKey)) { bool hasMoved = (((int) firstKey) != (int) noteNumber); firstKey = noteNumber; @@ -151,7 +151,7 @@ void KeyboardComponentBase::setBlackNoteLengthProportion (float ratio) noexcept { jassert (ratio >= 0.0f && ratio <= 1.0f); - if (blackNoteLengthRatio != ratio) + if (! approximatelyEqual (blackNoteLengthRatio, ratio)) { blackNoteLengthRatio = ratio; resized(); @@ -168,7 +168,7 @@ void KeyboardComponentBase::setBlackNoteWidthProportion (float ratio) noexcept { jassert (ratio >= 0.0f && ratio <= 1.0f); - if (blackNoteWidthRatio != ratio) + if (! approximatelyEqual (blackNoteWidthRatio, ratio)) { blackNoteWidthRatio = ratio; resized(); @@ -452,7 +452,7 @@ void KeyboardComponentBase::resized() //============================================================================== void KeyboardComponentBase::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) { - auto amount = (orientation == horizontalKeyboard && wheel.deltaX != 0) + auto amount = (orientation == horizontalKeyboard && ! approximatelyEqual (wheel.deltaX, 0.0f)) ? wheel.deltaX : (orientation == verticalKeyboardFacingLeft ? wheel.deltaY : -wheel.deltaY); diff --git a/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp b/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp index f6121c3ce9e7..76e022f4c56d 100644 --- a/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.cpp @@ -59,7 +59,7 @@ struct MPEKeyboardComponent::MPENoteComponent : public Component g.drawEllipse (bounds.withSizeKeepingCentre (pressSize, pressSize), 1.0f); } - //========================================================================== + //============================================================================== MPEKeyboardComponent& owner; float radiusScale = 0.0f, noteOnVelocity = 0.0f, pressure = 0.5f; @@ -145,7 +145,7 @@ void MPEKeyboardComponent::colourChanged() repaint(); } -//========================================================================== +//============================================================================== MPEValue MPEKeyboardComponent::mousePositionToPitchbend (int initialNote, Point mousePos) { auto constrainedMousePos = [&] diff --git a/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h b/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h index b149bd6bb11e..a53be6f01d8f 100644 --- a/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h +++ b/modules/juce_audio_utils/gui/juce_MPEKeyboardComponent.h @@ -100,7 +100,7 @@ class JUCE_API MPEKeyboardComponent : public KeyboardComponentBase, void colourChanged() override; private: - //========================================================================== + //============================================================================== struct MPENoteComponent; //============================================================================== diff --git a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp index fbd90eac384c..7029445979c5 100644 --- a/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp @@ -32,11 +32,11 @@ MidiKeyboardComponent::MidiKeyboardComponent (MidiKeyboardState& stateToUse, Ori { state.addListener (this); - // initialise with a default set of qwerty key-mappings.. - int note = 0; + // initialise with a default set of qwerty key-mappings. + const std::string_view keys { "awsedftgyhujkolp;" }; - for (char c : "awsedftgyhujkolp;") - setKeyPressForNote ({ c, 0, 0 }, note++); + for (const char& c : keys) + setKeyPressForNote ({c, 0, 0}, (int) std::distance (keys.data(), &c)); mouseOverNotes.insertMultiple (0, -1, 32); mouseDownNotes.insertMultiple (0, -1, 32); diff --git a/modules/juce_audio_utils/juce_audio_utils.cpp b/modules/juce_audio_utils/juce_audio_utils.cpp index 1afb4d11ce17..39afebc4d6a9 100644 --- a/modules/juce_audio_utils/juce_audio_utils.cpp +++ b/modules/juce_audio_utils/juce_audio_utils.cpp @@ -67,38 +67,38 @@ #include "audio_cd/juce_AudioCDReader.cpp" #if JUCE_MAC - #include "native/juce_mac_BluetoothMidiDevicePairingDialogue.mm" + #include "native/juce_BluetoothMidiDevicePairingDialogue_mac.mm" #if JUCE_USE_CDREADER - #include "native/juce_mac_AudioCDReader.mm" + #include "native/juce_AudioCDReader_mac.mm" #endif #if JUCE_USE_CDBURNER - #include "native/juce_mac_AudioCDBurner.mm" + #include "native/juce_AudioCDBurner_mac.mm" #endif #elif JUCE_IOS - #include "native/juce_ios_BluetoothMidiDevicePairingDialogue.mm" + #include "native/juce_BluetoothMidiDevicePairingDialogue_ios.mm" #elif JUCE_ANDROID - #include "native/juce_android_BluetoothMidiDevicePairingDialogue.cpp" + #include "native/juce_BluetoothMidiDevicePairingDialogue_android.cpp" #elif JUCE_LINUX || JUCE_BSD #if JUCE_USE_CDREADER - #include "native/juce_linux_AudioCDReader.cpp" + #include "native/juce_AudioCDReader_linux.cpp" #endif - #include "native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp" + #include "native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp" #elif JUCE_WINDOWS - #include "native/juce_win_BluetoothMidiDevicePairingDialogue.cpp" + #include "native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp" #if JUCE_USE_CDREADER - #include "native/juce_win32_AudioCDReader.cpp" + #include "native/juce_AudioCDReader_windows.cpp" #endif #if JUCE_USE_CDBURNER - #include "native/juce_win32_AudioCDBurner.cpp" + #include "native/juce_AudioCDBurner_windows.cpp" #endif #endif diff --git a/modules/juce_audio_utils/juce_audio_utils.h b/modules/juce_audio_utils/juce_audio_utils.h index c7170cdb1b00..929052c85ad5 100644 --- a/modules/juce_audio_utils/juce_audio_utils.h +++ b/modules/juce_audio_utils/juce_audio_utils.h @@ -35,7 +35,7 @@ ID: juce_audio_utils vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE extra audio utility classes description: Classes for audio-related GUI and miscellaneous tasks. website: http://www.juce.com/juce diff --git a/modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm b/modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm similarity index 100% rename from modules/juce_audio_utils/native/juce_mac_AudioCDBurner.mm rename to modules/juce_audio_utils/native/juce_AudioCDBurner_mac.mm diff --git a/modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp b/modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp similarity index 100% rename from modules/juce_audio_utils/native/juce_win32_AudioCDBurner.cpp rename to modules/juce_audio_utils/native/juce_AudioCDBurner_windows.cpp diff --git a/modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp b/modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp similarity index 100% rename from modules/juce_audio_utils/native/juce_linux_AudioCDReader.cpp rename to modules/juce_audio_utils/native/juce_AudioCDReader_linux.cpp diff --git a/modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm b/modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm similarity index 100% rename from modules/juce_audio_utils/native/juce_mac_AudioCDReader.mm rename to modules/juce_audio_utils/native/juce_AudioCDReader_mac.mm diff --git a/modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp b/modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp similarity index 100% rename from modules/juce_audio_utils/native/juce_win32_AudioCDReader.cpp rename to modules/juce_audio_utils/native/juce_AudioCDReader_windows.cpp diff --git a/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp similarity index 96% rename from modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp rename to modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp index 4cbea0a07e8c..6673568a3c4c 100644 --- a/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp +++ b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_android.cpp @@ -27,7 +27,7 @@ namespace juce { #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ - STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothManager;") + STATICMETHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "(Landroid/content/Context;)Lcom/rmsl/juce/JuceMidiSupport$BluetoothMidiManager;") DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidJuceMidiSupport, "com/rmsl/juce/JuceMidiSupport", 23) #undef JNI_CLASS_MEMBERS @@ -40,7 +40,7 @@ DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidJuceMidiSupport, "com/rmsl/juce/JuceMidiS METHOD (getBluetoothDeviceStatus, "getBluetoothDeviceStatus", "(Ljava/lang/String;)I") \ METHOD (startStopScan, "startStopScan", "(Z)V") -DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidBluetoothManager, "com/rmsl/juce/JuceMidiSupport$BluetoothManager", 23) +DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidBluetoothManager, "com/rmsl/juce/JuceMidiSupport$BluetoothMidiManager", 23) #undef JNI_CLASS_MEMBERS //============================================================================== diff --git a/modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm similarity index 100% rename from modules/juce_audio_utils/native/juce_ios_BluetoothMidiDevicePairingDialogue.mm rename to modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_ios.mm diff --git a/modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp similarity index 100% rename from modules/juce_audio_utils/native/juce_linux_BluetoothMidiDevicePairingDialogue.cpp rename to modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_linux.cpp diff --git a/modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm similarity index 100% rename from modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm rename to modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_mac.mm diff --git a/modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp b/modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp similarity index 100% rename from modules/juce_audio_utils/native/juce_win_BluetoothMidiDevicePairingDialogue.cpp rename to modules/juce_audio_utils/native/juce_BluetoothMidiDevicePairingDialogue_windows.cpp diff --git a/modules/juce_box2d/box2d/Common/b2Math.h b/modules/juce_box2d/box2d/Common/b2Math.h index e42428e6ef5c..f8415fe7591a 100644 --- a/modules/juce_box2d/box2d/Common/b2Math.h +++ b/modules/juce_box2d/box2d/Common/b2Math.h @@ -143,7 +143,7 @@ struct b2Vec2 return b2Vec2(-y, x); } - float32 x, y; + float32 x{}, y{}; }; /// A 2D column vector with 3 elements. diff --git a/modules/juce_box2d/juce_box2d.cpp b/modules/juce_box2d/juce_box2d.cpp index c73151e38a4d..bd5181a7567a 100644 --- a/modules/juce_box2d/juce_box2d.cpp +++ b/modules/juce_box2d/juce_box2d.cpp @@ -35,15 +35,16 @@ #include "juce_box2d.h" JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", - "-Wsign-conversion", +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", + "-Wconversion", "-Wfloat-conversion", - "-Wcast-align", - "-Wswitch-enum", + "-Wfloat-equal", + "-Wmaybe-uninitialized", + "-Wsign-conversion", "-Wswitch-default", + "-Wswitch-enum", "-Wunused-but-set-variable", - "-Wzero-as-null-pointer-constant", - "-Wmaybe-uninitialized") + "-Wzero-as-null-pointer-constant") #include diff --git a/modules/juce_box2d/juce_box2d.h b/modules/juce_box2d/juce_box2d.h index 64593859ae2b..c00f52d4b818 100644 --- a/modules/juce_box2d/juce_box2d.h +++ b/modules/juce_box2d/juce_box2d.h @@ -35,7 +35,7 @@ ID: juce_box2d vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE wrapper for the Box2D physics engine description: The Box2D physics engine and some utility classes. website: http://www.juce.com/juce @@ -56,11 +56,12 @@ #include JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion", + "-Wdeprecated", + "-Wfloat-equal", + "-Wmaybe-uninitialized", "-Wshadow-field", - "-Wzero-as-null-pointer-constant", "-Wsign-conversion", - "-Wdeprecated", - "-Wmaybe-uninitialized") + "-Wzero-as-null-pointer-constant") #include #include diff --git a/modules/juce_core/containers/juce_Array.h b/modules/juce_core/containers/juce_Array.h index 316e54526f9f..934357ba1d98 100644 --- a/modules/juce_core/containers/juce_Array.h +++ b/modules/juce_core/containers/juce_Array.h @@ -386,7 +386,7 @@ class Array auto endPtr = values.end(); for (; e != endPtr; ++e) - if (elementToLookFor == *e) + if (exactlyEqual (elementToLookFor, *e)) return static_cast (e - values.begin()); return -1; @@ -404,7 +404,7 @@ class Array auto endPtr = values.end(); for (; e != endPtr; ++e) - if (elementToLookFor == *e) + if (exactlyEqual (elementToLookFor, *e)) return true; return false; diff --git a/modules/juce_core/containers/juce_ArrayBase.h b/modules/juce_core/containers/juce_ArrayBase.h index 353fcfae50a5..d24d56216057 100644 --- a/modules/juce_core/containers/juce_ArrayBase.h +++ b/modules/juce_core/containers/juce_ArrayBase.h @@ -123,7 +123,7 @@ class ArrayBase : public TypeOfCriticalSectionToUse auto* e = begin(); for (auto& o : other) - if (! (*e++ == o)) + if (! exactlyEqual (*e++, o)) return false; return true; diff --git a/modules/juce_core/containers/juce_ListenerList.h b/modules/juce_core/containers/juce_ListenerList.h index 595e37793dde..5f657a0757de 100644 --- a/modules/juce_core/containers/juce_ListenerList.h +++ b/modules/juce_core/containers/juce_ListenerList.h @@ -325,7 +325,10 @@ class ListenerList WrappedIterator (const ListenerList& listToIterate, WrappedIterator*& listHeadIn) : it (listToIterate), listHead (listHeadIn), next (listHead) { + // GCC 12.2 with O1 and above gets confused here + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdangling-pointer") listHead = this; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE } ~WrappedIterator() diff --git a/modules/juce_core/containers/juce_Optional.h b/modules/juce_core/containers/juce_Optional.h index b7609278e3b8..bbcce347855a 100644 --- a/modules/juce_core/containers/juce_Optional.h +++ b/modules/juce_core/containers/juce_Optional.h @@ -30,7 +30,9 @@ constexpr auto nullopt = std::nullopt; // link time code generation. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702) +#ifndef DOXYGEN #define JUCE_OPTIONAL_OPERATORS X(==) X(!=) X(<) X(<=) X(>) X(>=) +#endif /** A simple optional type. @@ -161,6 +163,7 @@ Optional> makeOptional (Value&& v) return std::forward (v); } +#ifndef DOXYGEN #define X(op) \ template bool operator op (const Optional& lhs, const Optional& rhs) { return lhs.opt op rhs.opt; } \ template bool operator op (const Optional& lhs, Nullopt rhs) { return lhs.opt op rhs; } \ @@ -171,7 +174,7 @@ Optional> makeOptional (Value&& v) JUCE_OPTIONAL_OPERATORS #undef X - #undef JUCE_OPTIONAL_OPERATORS +#endif } // namespace juce diff --git a/modules/juce_core/containers/juce_Span.h b/modules/juce_core/containers/juce_Span.h new file mode 100644 index 000000000000..00712e6f381d --- /dev/null +++ b/modules/juce_core/containers/juce_Span.h @@ -0,0 +1,150 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +inline constexpr auto dynamicExtent = std::numeric_limits::max(); + +namespace detail +{ + //============================================================================== + template + constexpr auto hasToAddress = false; + + template + constexpr auto hasToAddress::to_address (std::declval()))>> = true; + + template + constexpr auto hasDataAndSize = false; + + template + constexpr auto hasDataAndSize())), + decltype (std::size (std::declval()))>> = true; + + template + struct NumBase + { + constexpr NumBase() = default; + + constexpr explicit NumBase (size_t) {} + + constexpr size_t size() const { return Extent; } + }; + + template <> + struct NumBase + { + constexpr NumBase() = default; + + constexpr explicit NumBase (size_t arg) + : num (arg) {} + + constexpr size_t size() const { return num; } + + size_t num{}; + }; + + template + constexpr T* toAddress (T* p) + { + return p; + } + + template + constexpr auto toAddress (const It& it) + { + if constexpr (detail::hasToAddress) + return std::pointer_traits::to_address (it); + else + return toAddress (it.operator->()); + } +} + +//============================================================================== +/** + A non-owning view over contiguous objects stored in an Array or vector + or other similar container. + + This is a bit like std::span from C++20, but with a more limited interface. + + @tags{Core} +*/ +template +class Span : private detail::NumBase // for empty-base optimisation +{ + using Base = detail::NumBase; + +public: + static constexpr auto extent = Extent; + + template = 0> + constexpr Span() {} + + template + constexpr Span (It it, size_t end) + : Base (end), ptr (detail::toAddress (it)) {} + + template , int> = 0> + constexpr Span (Range&& range) + : Base (std::size (range)), ptr (std::data (range)) {} + + constexpr Span (const Span&) = default; + + constexpr Span& operator= (const Span&) = default; + + using Base::size; + + constexpr Value* begin() const { return ptr; } + constexpr Value* end() const { return ptr + size(); } + + constexpr auto& front() const { return ptr[0]; } + constexpr auto& back() const { return ptr[size() - 1]; } + + constexpr auto& operator[] (size_t index) const { return ptr[index]; } + constexpr Value* data() const { return ptr; } + + constexpr bool empty() const { return size() == 0; } + +private: + Value* ptr = nullptr; +}; + +template +Span (T, End) -> Span()))>>; + +template +Span (T (&) [N]) -> Span; + +template +Span (std::array&) -> Span; + +template +Span (const std::array&) -> Span; + +template +Span (Range&& r) -> Span>; + + +} // namespace juce diff --git a/modules/juce_core/containers/juce_Variant.cpp b/modules/juce_core/containers/juce_Variant.cpp index e84baa02af19..12b1394f83ee 100644 --- a/modules/juce_core/containers/juce_Variant.cpp +++ b/modules/juce_core/containers/juce_Variant.cpp @@ -201,7 +201,7 @@ struct var::VariantType static int64 doubleToInt64 (const ValueUnion& data) noexcept { return (int64) data.doubleValue; } static double doubleToDouble (const ValueUnion& data) noexcept { return data.doubleValue; } static String doubleToString (const ValueUnion& data) { return serialiseDouble (data.doubleValue); } - static bool doubleToBool (const ValueUnion& data) noexcept { return data.doubleValue != 0.0; } + static bool doubleToBool (const ValueUnion& data) noexcept { return ! exactlyEqual (data.doubleValue, 0.0); } static bool doubleEquals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) noexcept { @@ -645,7 +645,7 @@ static int compare (const var& v1, const var& v2) return v1.toString().compare (v2.toString()); auto diff = static_cast (v1) - static_cast (v2); - return diff == 0 ? 0 : (diff < 0 ? -1 : 1); + return exactlyEqual (diff, 0.0) ? 0 : (diff < 0 ? -1 : 1); } bool operator== (const var& v1, const var& v2) { return v1.equals (v2); } diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index d19f14b86886..43e226e38ef4 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -970,7 +970,7 @@ bool File::createSymbolicLink (const File& linkFileToCreate, linkFileToCreate.deleteFile(); } - #if JUCE_MAC || JUCE_LINUX + #if JUCE_MAC || JUCE_LINUX || JUCE_BSD // one common reason for getting an error here is that the file already exists if (symlink (nativePathOfTarget.toRawUTF8(), linkFileToCreate.getFullPathName().toRawUTF8()) == -1) { diff --git a/modules/juce_core/files/juce_FileSearchPath.cpp b/modules/juce_core/files/juce_FileSearchPath.cpp index 6b4ad3981bfc..9b786ac05e8e 100644 --- a/modules/juce_core/files/juce_FileSearchPath.cpp +++ b/modules/juce_core/files/juce_FileSearchPath.cpp @@ -63,7 +63,12 @@ int FileSearchPath::getNumPaths() const File FileSearchPath::operator[] (int index) const { - return File (directories[index]); + return File (getRawString (index)); +} + +String FileSearchPath::getRawString (int index) const +{ + return directories[index]; } String FileSearchPath::toString() const @@ -110,21 +115,30 @@ void FileSearchPath::addPath (const FileSearchPath& other) void FileSearchPath::removeRedundantPaths() { - for (int i = directories.size(); --i >= 0;) + std::vector reduced; + + for (const auto& directory : directories) { - const File d1 (directories[i]); + const auto checkedIsChildOf = [&] (const auto& a, const auto& b) + { + return File::isAbsolutePath (a) && File::isAbsolutePath (b) && File (a).isAChildOf (b); + }; - for (int j = directories.size(); --j >= 0;) + const auto fContainsDirectory = [&] (const auto& f) { - const File d2 (directories[j]); + return f == directory || checkedIsChildOf (directory, f); + }; - if (i != j && (d1.isAChildOf (d2) || d1 == d2)) - { - directories.remove (i); - break; - } - } + if (std::find_if (reduced.begin(), reduced.end(), fContainsDirectory) != reduced.end()) + continue; + + const auto directoryContainsF = [&] (const auto& f) { return checkedIsChildOf (f, directory); }; + + reduced.erase (std::remove_if (reduced.begin(), reduced.end(), directoryContainsF), reduced.end()); + reduced.push_back (directory); } + + directories = StringArray (reduced.data(), (int) reduced.size()); } void FileSearchPath::removeNonExistentPaths() @@ -172,4 +186,54 @@ bool FileSearchPath::isFileInPath (const File& fileToCheck, return false; } +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +class FileSearchPathTests : public UnitTest +{ +public: + FileSearchPathTests() : UnitTest ("FileSearchPath", UnitTestCategories::files) {} + + void runTest() override + { + beginTest ("removeRedundantPaths"); + { + #if JUCE_WINDOWS + const String prefix = "C:"; + #else + const String prefix = ""; + #endif + + { + FileSearchPath fsp { prefix + "/a/b/c/d;" + prefix + "/a/b/c/e;" + prefix + "/a/b/c" }; + fsp.removeRedundantPaths(); + expectEquals (fsp.toString(), prefix + "/a/b/c"); + } + + { + FileSearchPath fsp { prefix + "/a/b/c;" + prefix + "/a/b/c/d;" + prefix + "/a/b/c/e" }; + fsp.removeRedundantPaths(); + expectEquals (fsp.toString(), prefix + "/a/b/c"); + } + + { + FileSearchPath fsp { prefix + "/a/b/c/d;" + prefix + "/a/b/c;" + prefix + "/a/b/c/e" }; + fsp.removeRedundantPaths(); + expectEquals (fsp.toString(), prefix + "/a/b/c"); + } + + { + FileSearchPath fsp { "%FOO%;" + prefix + "/a/b/c;%FOO%;" + prefix + "/a/b/c/d" }; + fsp.removeRedundantPaths(); + expectEquals (fsp.toString(), "%FOO%;" + prefix + "/a/b/c"); + } + } + } +}; + +static FileSearchPathTests fileSearchPathTests; + +#endif + } // namespace juce diff --git a/modules/juce_core/files/juce_FileSearchPath.h b/modules/juce_core/files/juce_FileSearchPath.h index 8b48162ba515..d789cf413312 100644 --- a/modules/juce_core/files/juce_FileSearchPath.h +++ b/modules/juce_core/files/juce_FileSearchPath.h @@ -71,10 +71,21 @@ class JUCE_API FileSearchPath /** Returns one of the folders in this search path. The file returned isn't guaranteed to actually be a valid directory. - @see getNumPaths + @see getNumPaths, getRawString */ File operator[] (int index) const; + /** Returns the unaltered text of the folder at the specified index. + + Unlike operator[], this function returns the exact text that was entered. It does not + attempt to convert the path into an absolute path. + + This may be useful if the directory string is expected to understand environment variables + or other placeholders that the File constructor doesn't necessarily understand. + @see operator[] + */ + String getRawString (int index) const; + /** Returns the search path as a semicolon-separated list of directories. */ String toString() const; diff --git a/modules/juce_core/files/juce_common_MimeTypes.cpp b/modules/juce_core/files/juce_common_MimeTypes.cpp index 42e150e93e28..fe08f71a8d93 100644 --- a/modules/juce_core/files/juce_common_MimeTypes.cpp +++ b/modules/juce_core/files/juce_common_MimeTypes.cpp @@ -206,6 +206,7 @@ class Table { "fdf", "application/vnd.fdf" }, { "fif", "application/fractals" }, { "fif", "image/fif" }, + { "flac", "audio/flac" }, { "fli", "video/fli" }, { "fli", "video/x-fli" }, { "flo", "image/florian" }, diff --git a/modules/juce_core/files/juce_common_MimeTypes.h b/modules/juce_core/files/juce_common_MimeTypes.h index d3b3e7be9c9c..4b6437a29b55 100644 --- a/modules/juce_core/files/juce_common_MimeTypes.h +++ b/modules/juce_core/files/juce_common_MimeTypes.h @@ -28,18 +28,17 @@ namespace juce { +/** @internal */ struct MimeTypeTable { - -/* @internal */ +/** @internal */ static void registerCustomMimeTypeForFileExtension (const String& mimeType, const String& fileExtension); -/* @internal */ +/** @internal */ static StringArray getMimeTypesForFileExtension (const String& fileExtension); -/* @internal */ +/** @internal */ static StringArray getFileExtensionsForMimeType (const String& mimeType); - }; } // namespace juce diff --git a/modules/juce_core/javascript/juce_Javascript.cpp b/modules/juce_core/javascript/juce_Javascript.cpp index 1582571c145d..3a1f9ba8b90f 100644 --- a/modules/juce_core/javascript/juce_Javascript.cpp +++ b/modules/juce_core/javascript/juce_Javascript.cpp @@ -520,7 +520,7 @@ struct JavascriptEngine::RootObject : public DynamicObject { EqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::equals) {} var getWithUndefinedArg() const override { return true; } - var getWithDoubles (double a, double b) const override { return a == b; } + var getWithDoubles (double a, double b) const override { return exactlyEqual (a, b); } var getWithInts (int64 a, int64 b) const override { return a == b; } var getWithStrings (const String& a, const String& b) const override { return a == b; } var getWithArrayOrObject (const var& a, const var& b) const override { return a == b; } @@ -530,7 +530,7 @@ struct JavascriptEngine::RootObject : public DynamicObject { NotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::notEquals) {} var getWithUndefinedArg() const override { return false; } - var getWithDoubles (double a, double b) const override { return a != b; } + var getWithDoubles (double a, double b) const override { return ! exactlyEqual (a, b); } var getWithInts (int64 a, int64 b) const override { return a != b; } var getWithStrings (const String& a, const String& b) const override { return a != b; } var getWithArrayOrObject (const var& a, const var& b) const override { return a != b; } @@ -593,14 +593,14 @@ struct JavascriptEngine::RootObject : public DynamicObject struct DivideOp : public BinaryOperator { DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {} - var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits::infinity(); } + var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits::infinity() : a / b; } var getWithInts (int64 a, int64 b) const override { return b != 0 ? var ((double) a / (double) b) : var (std::numeric_limits::infinity()); } }; struct ModuloOp : public BinaryOperator { ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {} - var getWithDoubles (double a, double b) const override { return b != 0 ? fmod (a, b) : std::numeric_limits::infinity(); } + var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits::infinity() : fmod (a, b); } var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits::infinity()); } }; @@ -1711,6 +1711,7 @@ struct JavascriptEngine::RootObject : public DynamicObject setMethod ("exp", Math_exp); setMethod ("pow", Math_pow); setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt); setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor); + setMethod ("hypot", Math_hypot); setProperty ("PI", MathConstants::pi); setProperty ("E", MathConstants::euler); @@ -1749,6 +1750,7 @@ struct JavascriptEngine::RootObject : public DynamicObject static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); } static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); } static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); } + static var Math_hypot (Args a) { return std::hypot (getDouble (a, 0), getDouble (a, 1)); } // We can't use the std namespace equivalents of these functions without breaking // compatibility with older versions of OS X. diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp index 99884b30bd2a..788c74b02778 100644 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -41,7 +41,7 @@ #include #include -#if ! JUCE_ANDROID +#if ! (JUCE_ANDROID || JUCE_BSD) #include #include #endif @@ -186,67 +186,83 @@ #include "zip/juce_ZipFile.cpp" #include "files/juce_FileFilter.cpp" #include "files/juce_WildcardFileFilter.cpp" -#include "native/juce_native_ThreadPriorities.h" +#include "native/juce_ThreadPriorities_native.h" +#include "native/juce_PlatformTimerListener.h" //============================================================================== #if ! JUCE_WINDOWS - #include "native/juce_posix_SharedCode.h" - #include "native/juce_posix_NamedPipe.cpp" + #include "native/juce_SharedCode_posix.h" + #include "native/juce_NamedPipe_posix.cpp" #if ! JUCE_ANDROID || __ANDROID_API__ >= 24 - #include "native/juce_posix_IPAddress.h" + #include "native/juce_IPAddress_posix.h" #endif #endif //============================================================================== #if JUCE_MAC || JUCE_IOS - #include "native/juce_mac_Files.mm" - #include "native/juce_mac_Network.mm" - #include "native/juce_mac_Strings.mm" - #include "native/juce_intel_SharedCode.h" - #include "native/juce_mac_SystemStats.mm" - #include "native/juce_mac_Threads.mm" + #include "native/juce_Files_mac.mm" + #include "native/juce_Network_mac.mm" + #include "native/juce_Strings_mac.mm" + #include "native/juce_SharedCode_intel.h" + #include "native/juce_SystemStats_mac.mm" + #include "native/juce_Threads_mac.mm" + #include "native/juce_PlatformTimer_generic.cpp" //============================================================================== #elif JUCE_WINDOWS - #include "native/juce_win32_Files.cpp" - #include "native/juce_win32_Network.cpp" - #include "native/juce_win32_Registry.cpp" - #include "native/juce_win32_SystemStats.cpp" - #include "native/juce_win32_Threads.cpp" + #include "native/juce_Files_windows.cpp" + #include "native/juce_Network_windows.cpp" + #include "native/juce_Registry_windows.cpp" + #include "native/juce_SystemStats_windows.cpp" + #include "native/juce_Threads_windows.cpp" + #include "native/juce_PlatformTimer_windows.cpp" //============================================================================== -#elif JUCE_LINUX || JUCE_BSD - #include "native/juce_linux_CommonFile.cpp" - #include "native/juce_linux_Files.cpp" - #include "native/juce_linux_Network.cpp" +#elif JUCE_LINUX + #include "native/juce_CommonFile_linux.cpp" + #include "native/juce_Files_linux.cpp" + #include "native/juce_Network_linux.cpp" #if JUCE_USE_CURL - #include "native/juce_curl_Network.cpp" + #include "native/juce_Network_curl.cpp" #endif - #if JUCE_BSD - #include "native/juce_intel_SharedCode.h" + #include "native/juce_SystemStats_linux.cpp" + #include "native/juce_Threads_linux.cpp" + #include "native/juce_PlatformTimer_generic.cpp" + +//============================================================================== +#elif JUCE_BSD + #include "native/juce_CommonFile_linux.cpp" + #include "native/juce_Files_linux.cpp" + #include "native/juce_Network_linux.cpp" + #if JUCE_USE_CURL + #include "native/juce_Network_curl.cpp" #endif - #include "native/juce_linux_SystemStats.cpp" - #include "native/juce_linux_Threads.cpp" + #include "native/juce_SharedCode_intel.h" + #include "native/juce_SystemStats_linux.cpp" + #include "native/juce_Threads_linux.cpp" + #include "native/juce_PlatformTimer_generic.cpp" //============================================================================== #elif JUCE_ANDROID - #include "native/juce_linux_CommonFile.cpp" - #include "native/juce_android_JNIHelpers.cpp" - #include "native/juce_android_Files.cpp" - #include "native/juce_android_Misc.cpp" - #include "native/juce_android_Network.cpp" - #include "native/juce_android_SystemStats.cpp" - #include "native/juce_android_Threads.cpp" - #include "native/juce_android_RuntimePermissions.cpp" + #include "native/juce_CommonFile_linux.cpp" + #include "native/juce_JNIHelpers_android.cpp" + #include "native/juce_Files_android.cpp" + #include "native/juce_Misc_android.cpp" + #include "native/juce_Network_android.cpp" + #include "native/juce_SystemStats_android.cpp" + #include "native/juce_Threads_android.cpp" + #include "native/juce_RuntimePermissions_android.cpp" + #include "native/juce_PlatformTimer_generic.cpp" +//============================================================================== #elif JUCE_WASM - #include "native/juce_wasm_SystemStats.cpp" - + #include "native/juce_SystemStats_wasm.cpp" + #include "native/juce_PlatformTimer_generic.cpp" #endif #include "files/juce_common_MimeTypes.h" #include "files/juce_common_MimeTypes.cpp" -#include "native/juce_android_AndroidDocument.cpp" +#include "native/juce_AndroidDocument_android.cpp" #include "threads/juce_HighResolutionTimer.cpp" #include "threads/juce_WaitableEvent.cpp" #include "network/juce_URL.cpp" @@ -260,8 +276,9 @@ //============================================================================== #if JUCE_UNIT_TESTS #include "containers/juce_HashMap_test.cpp" - #include "containers/juce_Optional_test.cpp" + #include "maths/juce_MathsFunctions_test.cpp" + #include "misc/juce_EnumHelpers_test.cpp" #endif //============================================================================== diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 4ce05eb81316..f23eaed660e8 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -32,7 +32,7 @@ ID: juce_core vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE core classes description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality. website: http://www.juce.com/juce @@ -40,7 +40,7 @@ minimumCppStandard: 17 dependencies: - OSXFrameworks: Cocoa Foundation IOKit + OSXFrameworks: Cocoa Foundation IOKit Security iOSFrameworks: Foundation linuxLibs: rt dl pthread mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm @@ -219,6 +219,7 @@ namespace juce extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noexcept; } +#include "misc/juce_EnumHelpers.h" #include "memory/juce_Memory.h" #include "maths/juce_MathsFunctions.h" #include "memory/juce_ByteOrder.h" @@ -276,6 +277,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "text/juce_LocalisedStrings.h" #include "text/juce_Base64.h" #include "misc/juce_Functional.h" +#include "containers/juce_Span.h" #include "misc/juce_Result.h" #include "misc/juce_Uuid.h" #include "misc/juce_ConsoleApplication.h" @@ -313,12 +315,12 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "misc/juce_WindowsRegistry.h" #include "threads/juce_ChildProcess.h" #include "threads/juce_DynamicLibrary.h" -#include "threads/juce_HighResolutionTimer.h" #include "threads/juce_InterProcessLock.h" #include "threads/juce_Process.h" #include "threads/juce_SpinLock.h" #include "threads/juce_WaitableEvent.h" #include "threads/juce_Thread.h" +#include "threads/juce_HighResolutionTimer.h" #include "threads/juce_ThreadLocalValue.h" #include "threads/juce_ThreadPool.h" #include "threads/juce_TimeSliceThread.h" @@ -347,16 +349,16 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "streams/juce_AndroidDocumentInputSource.h" #if JUCE_CORE_INCLUDE_OBJC_HELPERS && (JUCE_MAC || JUCE_IOS) - #include "native/juce_mac_ObjCHelpers.h" + #include "native/juce_ObjCHelpers_mac.h" #endif #if JUCE_CORE_INCLUDE_COM_SMART_PTR && JUCE_WINDOWS - #include "native/juce_win32_ComSmartPtr.h" + #include "native/juce_ComSmartPtr_windows.h" #endif #if JUCE_CORE_INCLUDE_JNI_HELPERS && JUCE_ANDROID #include - #include "native/juce_android_JNIHelpers.h" + #include "native/juce_JNIHelpers_android.h" #endif #if JUCE_UNIT_TESTS diff --git a/modules/juce_core/maths/juce_MathsFunctions.h b/modules/juce_core/maths/juce_MathsFunctions.h index cc61820ec728..30365240e17d 100644 --- a/modules/juce_core/maths/juce_MathsFunctions.h +++ b/modules/juce_core/maths/juce_MathsFunctions.h @@ -86,6 +86,250 @@ using uint32 = unsigned int; using ssize_t = pointer_sized_int; #endif +//============================================================================== +/** Handy function for avoiding unused variables warning. */ +template +void ignoreUnused (Types&&...) noexcept {} + +/** Handy function for getting the number of elements in a simple const C array. + E.g. + @code + static int myArray[] = { 1, 2, 3 }; + + int numElements = numElementsInArray (myArray) // returns 3 + @endcode +*/ +template +constexpr int numElementsInArray (Type (&)[N]) noexcept { return N; } + +//============================================================================== +// Some useful maths functions that aren't always present with all compilers and build settings. + +/** Using juce_hypot is easier than dealing with the different types of hypot function + that are provided by the various platforms and compilers. */ +template +Type juce_hypot (Type a, Type b) noexcept +{ + #if JUCE_MSVC + return static_cast (_hypot (a, b)); + #else + return static_cast (hypot (a, b)); + #endif +} + +#ifndef DOXYGEN +template <> +inline float juce_hypot (float a, float b) noexcept +{ + #if JUCE_MSVC + return _hypotf (a, b); + #else + return hypotf (a, b); + #endif +} +#endif + +//============================================================================== +/** Commonly used mathematical constants + + @tags{Core} +*/ +template +struct MathConstants +{ + /** A predefined value for Pi */ + static constexpr FloatType pi = static_cast (3.141592653589793238L); + + /** A predefined value for 2 * Pi */ + static constexpr FloatType twoPi = static_cast (2 * 3.141592653589793238L); + + /** A predefined value for Pi / 2 */ + static constexpr FloatType halfPi = static_cast (3.141592653589793238L / 2); + + /** A predefined value for Euler's number */ + static constexpr FloatType euler = static_cast (2.71828182845904523536L); + + /** A predefined value for sqrt(2) */ + static constexpr FloatType sqrt2 = static_cast (1.4142135623730950488L); +}; + +#ifndef DOXYGEN +/** A double-precision constant for pi. */ +[[deprecated ("This is deprecated in favour of MathConstants::pi.")]] +const constexpr double double_Pi = MathConstants::pi; + +/** A single-precision constant for pi. */ +[[deprecated ("This is deprecated in favour of MathConstants::pi.")]] +const constexpr float float_Pi = MathConstants::pi; +#endif + +/** Converts an angle in degrees to radians. */ +template +constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants::pi / FloatType (180)); } + +/** Converts an angle in radians to degrees. */ +template +constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants::pi); } + +//============================================================================== +/** The isfinite() method seems to vary between platforms, so this is a + platform-independent function for it. +*/ +template +bool juce_isfinite (NumericType value) noexcept +{ + if constexpr (std::numeric_limits::has_infinity + || std::numeric_limits::has_quiet_NaN + || std::numeric_limits::has_signaling_NaN) + { + return std::isfinite (value); + } + else + { + ignoreUnused (value); + return true; + } +} + +//============================================================================== +/** Equivalent to operator==, but suppresses float-equality warnings. + + This allows code to be explicit about float-equality checks that are known to have the correct + semantics. +*/ +template +constexpr bool exactlyEqual (Type a, Type b) +{ + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfloat-equal") + return a == b; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE +} + +/** A class encapsulating both relative and absolute tolerances for use in floating-point comparisons. + + @see approximatelyEqual, absoluteTolerance, relativeTolerance +*/ +template +class Tolerance +{ +public: + Tolerance() = default; + + /** Returns a copy of this Tolerance object with a new absolute tolerance. + + If you just need a Tolerance object with an absolute tolerance, it might be worth using the + absoluteTolerance() function. + + @see getAbsolute, absoluteTolerance + */ + [[nodiscard]] Tolerance withAbsolute (Type newAbsolute) + { + return withMember (*this, &Tolerance::absolute, std::abs (newAbsolute)); + } + + /** Returns a copy of this Tolerance object with a new relative tolerance. + + If you just need a Tolerance object with a relative tolerance, it might be worth using the + relativeTolerance() function. + + @see getRelative, relativeTolerance + */ + [[nodiscard]] Tolerance withRelative (Type newRelative) + { + return withMember (*this, &Tolerance::relative, std::abs (newRelative)); + } + + [[nodiscard]] Type getAbsolute() const { return absolute; } + [[nodiscard]] Type getRelative() const { return relative; } + +private: + Type absolute{}; + Type relative{}; +}; + +/** Returns a type deduced Tolerance object containing only an absolute tolerance. + + @see Tolerance::withAbsolute, approximatelyEqual + */ +template +static Tolerance absoluteTolerance (Type tolerance) +{ + return Tolerance{}.withAbsolute (tolerance); +} + +/** Returns a type deduced Tolerance object containing only a relative tolerance. + + @see Tolerance::withRelative, approximatelyEqual + */ +template +static Tolerance relativeTolerance (Type tolerance) +{ + return Tolerance{}.withRelative (tolerance); +} + + +/** Returns true if the two floating-point numbers are approximately equal. + + If either a or b are not finite, returns exactlyEqual (a, b). + + The default absolute tolerance is equal to the minimum normal value. This ensures + differences that are subnormal are always considered equal. It is highly recommend this + value is reviewed depending on the calculation being carried out. In general specifying an + absolute value is useful when considering values close to zero. For example you might + expect sin(pi) to return 0, but what it actually returns is close to the error of the value pi. + Therefore, in this example it might be better to set the absolute tolerance to sin(pi). + + The default relative tolerance is equal to the machine epsilon which is the difference between + 1.0 and the next floating-point value that can be represented by Type. In most cases this value + is probably reasonable. This value is multiplied by the largest absolute value of a and b so as + to scale relatively according to the input parameters. For example, specifying a relative value + of 0.05 will ensure values return equal if the difference between them is less than or equal to + 5% of the larger of the two absolute values. + + @param a The first number to compare. + @param b The second number to compare. + @param tolerance An object that represents both absolute and relative tolerances + when evaluating if a and b are equal. + + @see exactlyEqual +*/ +template , int> = 0> +constexpr bool approximatelyEqual (Type a, Type b, + Tolerance tolerance = Tolerance{} + .withAbsolute (std::numeric_limits::min()) + .withRelative (std::numeric_limits::epsilon())) +{ + if (! (juce_isfinite (a) && juce_isfinite (b))) + return exactlyEqual (a, b); + + const auto diff = std::abs (a - b); + + return diff <= tolerance.getAbsolute() + || diff <= tolerance.getRelative() * std::max (std::abs (a), std::abs (b)); +} + +/** Special case for non-floating-point types that returns true if both are exactly equal. */ +template , int> = 0> +constexpr bool approximatelyEqual (Type a, Type b) +{ + return a == b; +} + +//============================================================================== +/** Returns the next representable value by FloatType in the direction of the largest representable value. */ +template +FloatType nextFloatUp (FloatType value) noexcept +{ + return std::nextafter (value, std::numeric_limits::max()); +} + +/** Returns the next representable value by FloatType in the direction of the lowest representable value. */ +template +FloatType nextFloatDown (FloatType value) noexcept +{ + return std::nextafter (value, std::numeric_limits::lowest()); +} + //============================================================================== // Some indispensable min/max functions @@ -126,7 +370,7 @@ constexpr Type jmap (Type value0To1, Type targetRangeMin, Type targetRangeMax) template Type jmap (Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax) { - jassert (sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN! + jassert (! approximatelyEqual (sourceRangeMax, sourceRangeMin)); // mapping from a range of zero will produce NaN! return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin); } @@ -317,132 +561,6 @@ bool isWithin (Type a, Type b, Type tolerance) noexcept return std::abs (a - b) <= tolerance; } -/** Returns true if the two numbers are approximately equal. This is useful for floating-point - and double comparisons. -*/ -template -bool approximatelyEqual (Type a, Type b) noexcept -{ - return std::abs (a - b) <= (std::numeric_limits::epsilon() * std::max (a, b)) - || std::abs (a - b) < std::numeric_limits::min(); -} - -//============================================================================== -/** Handy function for avoiding unused variables warning. */ -template -void ignoreUnused (Types&&...) noexcept {} - -/** Handy function for getting the number of elements in a simple const C array. - E.g. - @code - static int myArray[] = { 1, 2, 3 }; - - int numElements = numElementsInArray (myArray) // returns 3 - @endcode -*/ -template -constexpr int numElementsInArray (Type (&)[N]) noexcept { return N; } - -//============================================================================== -// Some useful maths functions that aren't always present with all compilers and build settings. - -/** Using juce_hypot is easier than dealing with the different types of hypot function - that are provided by the various platforms and compilers. */ -template -Type juce_hypot (Type a, Type b) noexcept -{ - #if JUCE_MSVC - return static_cast (_hypot (a, b)); - #else - return static_cast (hypot (a, b)); - #endif -} - -#ifndef DOXYGEN -template <> -inline float juce_hypot (float a, float b) noexcept -{ - #if JUCE_MSVC - return _hypotf (a, b); - #else - return hypotf (a, b); - #endif -} -#endif - -//============================================================================== -/** Commonly used mathematical constants - - @tags{Core} -*/ -template -struct MathConstants -{ - /** A predefined value for Pi */ - static constexpr FloatType pi = static_cast (3.141592653589793238L); - - /** A predefined value for 2 * Pi */ - static constexpr FloatType twoPi = static_cast (2 * 3.141592653589793238L); - - /** A predefined value for Pi / 2 */ - static constexpr FloatType halfPi = static_cast (3.141592653589793238L / 2); - - /** A predefined value for Euler's number */ - static constexpr FloatType euler = static_cast (2.71828182845904523536L); - - /** A predefined value for sqrt(2) */ - static constexpr FloatType sqrt2 = static_cast (1.4142135623730950488L); -}; - -#ifndef DOXYGEN -/** A double-precision constant for pi. */ -[[deprecated ("This is deprecated in favour of MathConstants::pi.")]] -const constexpr double double_Pi = MathConstants::pi; - -/** A single-precision constant for pi. */ -[[deprecated ("This is deprecated in favour of MathConstants::pi.")]] -const constexpr float float_Pi = MathConstants::pi; -#endif - -/** Converts an angle in degrees to radians. */ -template -constexpr FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * (MathConstants::pi / FloatType (180)); } - -/** Converts an angle in radians to degrees. */ -template -constexpr FloatType radiansToDegrees (FloatType radians) noexcept { return radians * (FloatType (180) / MathConstants::pi); } - - -//============================================================================== -/** The isfinite() method seems to vary between platforms, so this is a - platform-independent function for it. -*/ -template -bool juce_isfinite (NumericType) noexcept -{ - return true; // Integer types are always finite -} - -template <> -inline bool juce_isfinite (float value) noexcept -{ - #if JUCE_WINDOWS && ! JUCE_MINGW - return _finite (value) != 0; - #else - return std::isfinite (value); - #endif -} - -template <> -inline bool juce_isfinite (double value) noexcept -{ - #if JUCE_WINDOWS && ! JUCE_MINGW - return _finite (value) != 0; - #else - return std::isfinite (value); - #endif -} - //============================================================================== #if JUCE_MSVC #pragma optimize ("t", off) diff --git a/modules/juce_core/maths/juce_MathsFunctions_test.cpp b/modules/juce_core/maths/juce_MathsFunctions_test.cpp new file mode 100644 index 000000000000..2dcf427b9c03 --- /dev/null +++ b/modules/juce_core/maths/juce_MathsFunctions_test.cpp @@ -0,0 +1,543 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +template +String getTemplatedMathsFunctionUnitTestName (const String& functionName) +{ + const auto getTypeName = []() -> String + { + if constexpr (std::is_same_v) + return "int"; + + if constexpr (std::is_same_v) + return "float"; + + if constexpr (std::is_same_v) + return "double"; + + if constexpr (std::is_same_v) + return "long double"; + }; + + return functionName + "<" + getTypeName() + ">"; +} + +template +class ApproximatelyEqualTests final : public UnitTest +{ +public: + ApproximatelyEqualTests() + : UnitTest { getTemplatedMathsFunctionUnitTestName ("approximatelyEqual"), UnitTestCategories::maths } + {} + + void runTest() final + { + using limits = std::numeric_limits; + + constexpr auto zero = T{}; + constexpr auto one = T (1); + constexpr auto min = limits::min(); + constexpr auto max = limits::max(); + constexpr auto epsilon = limits::epsilon(); + constexpr auto oneThird = one / (T) 3; + + beginTest ("Equal values are always equal"); + { + expect (approximatelyEqual (zero, zero)); + expect (approximatelyEqual (zero, -zero)); + expect (approximatelyEqual (-zero, -zero)); + + expect (approximatelyEqual (min, min)); + expect (approximatelyEqual (-min, -min)); + + expect (approximatelyEqual (one, one)); + expect (approximatelyEqual (-one, -one)); + + expect (approximatelyEqual (max, max)); + expect (approximatelyEqual (-max, -max)); + + const Tolerance zeroTolerance{}; + + expect (approximatelyEqual (zero, zero, zeroTolerance)); + expect (approximatelyEqual (zero, -zero, zeroTolerance)); + expect (approximatelyEqual (-zero, -zero, zeroTolerance)); + + expect (approximatelyEqual (min, min, zeroTolerance)); + expect (approximatelyEqual (-min, -min, zeroTolerance)); + + expect (approximatelyEqual (one, one, zeroTolerance)); + expect (approximatelyEqual (-one, -one, zeroTolerance)); + + expect (approximatelyEqual (max, max, zeroTolerance)); + expect (approximatelyEqual (-max, -max, zeroTolerance)); + } + + beginTest ("Comparing subnormal values to zero, returns true"); + { + expect (! exactlyEqual (zero, nextFloatUp (zero))); + expect (approximatelyEqual (zero, nextFloatUp (zero))); + + expect (! exactlyEqual (zero, nextFloatDown (zero))); + expect (approximatelyEqual (zero, nextFloatDown (zero))); + + expect (! exactlyEqual (zero, nextFloatDown (min))); + expect (approximatelyEqual (zero, nextFloatDown (min))); + + expect (! exactlyEqual (zero, nextFloatUp (-min))); + expect (approximatelyEqual (zero, nextFloatUp (-min))); + } + + beginTest ("Comparing the minimum normal value to zero, returns true"); + { + expect (approximatelyEqual (zero, min)); + expect (approximatelyEqual (zero, -min)); + } + + beginTest ("Comparing normal values greater than the minimum to zero, returns true"); + { + expect (! approximatelyEqual (zero, one)); + expect (! approximatelyEqual (zero, epsilon)); + expect (! approximatelyEqual (zero, nextFloatUp (min))); + expect (! approximatelyEqual (zero, nextFloatDown (-min))); + } + + beginTest ("Values with large ranges can be compared"); + { + expect (! approximatelyEqual (zero, max)); + expect ( approximatelyEqual (zero, max, absoluteTolerance (max))); + expect ( approximatelyEqual (zero, max, relativeTolerance (one))); + expect (! approximatelyEqual (-one, max)); + expect (! approximatelyEqual (-max, max)); + } + + beginTest ("Larger values have a boundary that is a factor of the epsilon"); + { + for (auto exponent = 0; exponent < 127; ++exponent) + { + const auto value = std::pow ((T) 2, (T) exponent); + const auto boundaryValue = value * (one + epsilon); + + expect (juce_isfinite (value)); + expect (juce_isfinite (boundaryValue)); + + expect ( approximatelyEqual (value, boundaryValue)); + expect (! approximatelyEqual (value, nextFloatUp (boundaryValue))); + + expect ( approximatelyEqual (-value, -boundaryValue)); + expect (! approximatelyEqual (-value, nextFloatDown (-boundaryValue))); + } + } + + beginTest ("Tolerances scale with the values being compared"); + { + + expect (approximatelyEqual ((T) 100'000'000'000'000.01, + (T) 100'000'000'000'000.011)); + + expect (! approximatelyEqual ((T) 100.01, + (T) 100.011)); + + expect (! approximatelyEqual ((T) 123'000, (T) 121'000, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123'000, (T) 122'000, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123'000, (T) 123'000, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123'000, (T) 124'000, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 123'000, (T) 125'000, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual ((T) 123, (T) 121, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123, (T) 122, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123, (T) 123, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 123, (T) 124, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 123, (T) 125, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual ((T) 12.3, (T) 12.1, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 12.3, (T) 12.2, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 12.3, (T) 12.3, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 12.3, (T) 12.4, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 12.3, (T) 12.5, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual ((T) 1.23, (T) 1.21, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 1.23, (T) 1.22, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 1.23, (T) 1.23, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 1.23, (T) 1.24, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 1.23, (T) 1.25, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual ((T) 0.123, (T) 0.121, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.123, (T) 0.122, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.123, (T) 0.123, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.123, (T) 0.124, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 0.123, (T) 0.125, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual ((T) 0.000123, (T) 0.000121, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.000123, (T) 0.000122, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.000123, (T) 0.000123, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual ((T) 0.000123, (T) 0.000124, relativeTolerance ((T) 1e-2))); + expect (! approximatelyEqual ((T) 0.000123, (T) 0.000125, relativeTolerance ((T) 1e-2))); + } + + beginTest ("The square of the square root of 2 is approximately 2"); + { + constexpr auto two = (T) 2; + const auto sqrtOfTwo = std::sqrt (two); + + expect (approximatelyEqual (sqrtOfTwo * sqrtOfTwo, two)); + expect (approximatelyEqual (-sqrtOfTwo * sqrtOfTwo, -two)); + expect (approximatelyEqual (two / sqrtOfTwo, sqrtOfTwo)); + } + + if constexpr (limits::has_quiet_NaN) + { + beginTest ("Values are never equal to NaN"); + { + const auto nan = limits::quiet_NaN(); + + expect (! approximatelyEqual (nan, nan)); + + const auto expectNotEqualTo = [&](auto value) + { + expect (! approximatelyEqual (value, nan)); + expect (! approximatelyEqual (nan, value)); + }; + + expectNotEqualTo (zero); + expectNotEqualTo (-zero); + expectNotEqualTo (min); + expectNotEqualTo (-min); + expectNotEqualTo (one); + expectNotEqualTo (-one); + expectNotEqualTo (max); + expectNotEqualTo (-max); + } + } + + if constexpr (limits::has_infinity) + { + beginTest ("Only infinity is equal to infinity"); + { + const auto inf = limits::infinity(); + expect (approximatelyEqual (inf, inf)); + expect (approximatelyEqual (-inf, -inf)); + expect (! approximatelyEqual (inf, -inf)); + expect (! approximatelyEqual (-inf, inf)); + + const auto expectNotEqualTo = [&](auto value) + { + expect (! approximatelyEqual (value, inf)); + expect (! approximatelyEqual (value, -inf)); + expect (! approximatelyEqual (inf, value)); + expect (! approximatelyEqual (-inf, value)); + }; + + expectNotEqualTo (zero); + expectNotEqualTo (-zero); + expectNotEqualTo (min); + expectNotEqualTo (-min); + expectNotEqualTo (one); + expectNotEqualTo (-one); + expectNotEqualTo (max); + expectNotEqualTo (-max); + } + } + + beginTest ("Can set an absolute tolerance"); + { + constexpr std::array negativePowersOfTwo + { + (T) 0.5 /* 2^-1 */, + (T) 0.25 /* 2^-2 */, + (T) 0.125 /* 2^-3 */, + (T) 0.0625 /* 2^-4 */, + (T) 0.03125 /* 2^-5 */, + (T) 0.015625 /* 2^-6 */, + (T) 0.0078125 /* 2^-7 */ + }; + + const auto testTolerance = [&](auto tolerance) + { + const auto t = Tolerance{}.withAbsolute ((T) tolerance); + + const auto testValue= [&](auto value) + { + const auto boundary = value + tolerance; + + expect (approximatelyEqual (value, boundary, t)); + expect (! approximatelyEqual (value, nextFloatUp (boundary), t)); + + expect (approximatelyEqual (-value, -boundary, t)); + expect (! approximatelyEqual (-value, nextFloatDown (-boundary), t)); + }; + + testValue (zero); + testValue (min); + testValue (epsilon); + testValue (one); + + for (const auto value : negativePowersOfTwo) + testValue (value); + }; + + for (const auto toleranceValue : negativePowersOfTwo) + testTolerance (toleranceValue); + } + + beginTest ("Can set a relative tolerance"); + { + expect (! approximatelyEqual (oneThird, (T) 0.34, relativeTolerance ((T) 1e-2))); + expect ( approximatelyEqual (oneThird, (T) 0.334, relativeTolerance ((T) 1e-2))); + + expect (! approximatelyEqual (oneThird, (T) 0.334, relativeTolerance ((T) 1e-3))); + expect ( approximatelyEqual (oneThird, (T) 0.3334, relativeTolerance ((T) 1e-3))); + + expect (! approximatelyEqual (oneThird, (T) 0.3334, relativeTolerance ((T) 1e-4))); + expect ( approximatelyEqual (oneThird, (T) 0.33334, relativeTolerance ((T) 1e-4))); + + expect (! approximatelyEqual (oneThird, (T) 0.33334, relativeTolerance ((T) 1e-5))); + expect ( approximatelyEqual (oneThird, (T) 0.333334, relativeTolerance ((T) 1e-5))); + + expect (! approximatelyEqual (oneThird, (T) 0.333334, relativeTolerance ((T) 1e-6))); + expect ( approximatelyEqual (oneThird, (T) 0.3333334, relativeTolerance ((T) 1e-6))); + + expect (! approximatelyEqual (oneThird, (T) 0.3333334, relativeTolerance ((T) 1e-7))); + expect ( approximatelyEqual (oneThird, (T) 0.33333334, relativeTolerance ((T) 1e-7))); + + expect ( approximatelyEqual ((T) 1e6, (T) 1e6 + (T) 1, relativeTolerance ((T) 1e-6))); + expect (! approximatelyEqual ((T) 1e6, (T) 1e6 + (T) 1, relativeTolerance ((T) 1e-7))); + + expect ( approximatelyEqual ((T) -1e-6, (T) -1.0000009e-6, relativeTolerance ((T) 1e-6))); + expect (! approximatelyEqual ((T) -1e-6, (T) -1.0000009e-6, relativeTolerance ((T) 1e-7))); + + const auto a = (T) 1.234567; + const auto b = (T) 1.234568; + + for (auto exponent = 0; exponent < 39; ++exponent) + { + const auto m = std::pow ((T) 10, (T) exponent); + expect ( approximatelyEqual (a * m, b * m, relativeTolerance ((T) 1e-6))); + expect (! approximatelyEqual (a * m, b * m, relativeTolerance ((T) 1e-7))); + } + } + + beginTest ("A relative tolerance is always scaled by the maximum value"); + { + expect ( approximatelyEqual ((T) 9, (T) 10, absoluteTolerance ((T) 10.0 * (T) 0.1))); + expect (! approximatelyEqual ((T) 9, (T) 10, absoluteTolerance ((T) 9.0 * (T) 0.1))); + + expect (approximatelyEqual ((T) 9, (T) 10, relativeTolerance ((T) 0.1))); + expect (approximatelyEqual ((T) 10, (T) 9, relativeTolerance ((T) 0.1))); + } + + beginTest ("Documentation examples"); + { + constexpr auto pi = MathConstants::pi; + + expect (! approximatelyEqual (zero, std::sin (pi))); + expect ( approximatelyEqual (zero, std::sin (pi), absoluteTolerance (std::sin (pi)))); + + expect ( approximatelyEqual ((T) 100, (T) 95, relativeTolerance ((T) 0.05))); + expect (! approximatelyEqual ((T) 100, (T) 94, relativeTolerance ((T) 0.05))); + } + } +}; + +template<> +class ApproximatelyEqualTests final : public UnitTest +{ +public: + ApproximatelyEqualTests() + : UnitTest { getTemplatedMathsFunctionUnitTestName ("approximatelyEqual"), UnitTestCategories::maths } + {} + + void runTest() final + { + beginTest ("Identical integers are always equal"); + { + expect (approximatelyEqual ( 0, 0)); + expect (approximatelyEqual (-0, -0)); + + expect (approximatelyEqual ( 1, 1)); + expect (approximatelyEqual (-1, -1)); + + using limits = std::numeric_limits; + constexpr auto min = limits::min(); + constexpr auto max = limits::max(); + + expect (approximatelyEqual (min, min)); + expect (approximatelyEqual (max, max)); + } + + beginTest ("Non-identical integers are never equal"); + { + expect (! approximatelyEqual ( 0, 1)); + expect (! approximatelyEqual ( 0, -1)); + + expect (! approximatelyEqual ( 1, 2)); + expect (! approximatelyEqual (-1, -2)); + + using limits = std::numeric_limits; + constexpr auto min = limits::min(); + constexpr auto max = limits::max(); + + expect (! approximatelyEqual (min, min + 1)); + expect (! approximatelyEqual (max, max - 1)); + } + + beginTest ("Zero is equal regardless of the sign"); + { + expect (approximatelyEqual ( 0, -0)); + expect (approximatelyEqual (-0, 0)); + } + } +}; + +template +class IsFiniteTests final : public UnitTest +{ +public: + IsFiniteTests() + : UnitTest { getTemplatedMathsFunctionUnitTestName ("juce_isfinite"), UnitTestCategories::maths } + {} + + void runTest() final + { + using limits = std::numeric_limits; + + constexpr auto zero = T{}; + constexpr auto one = (T) 1; + constexpr auto max = limits::max(); + constexpr auto inf = limits::infinity(); + constexpr auto nan = limits::quiet_NaN(); + + beginTest ("Zero is finite"); + { + expect (juce_isfinite (zero)); + expect (juce_isfinite (-zero)); + } + + beginTest ("Subnormals are finite"); + { + expect (juce_isfinite (nextFloatUp (zero))); + expect (juce_isfinite (nextFloatDown (zero))); + } + + beginTest ("One is finite"); + { + expect (juce_isfinite (one)); + expect (juce_isfinite (-one)); + } + + beginTest ("Max is finite"); + { + expect (juce_isfinite (max)); + expect (juce_isfinite (-max)); + } + + beginTest ("Infinity is not finite"); + { + expect (! juce_isfinite (inf)); + expect (! juce_isfinite (-inf)); + } + + beginTest ("NaN is not finite"); + { + expect (! juce_isfinite (nan)); + expect (! juce_isfinite (-nan)); + expect (! juce_isfinite (std::sqrt ((T) -1))); + expect (! juce_isfinite (inf * zero)); + } + } +}; + +template +class NextFloatTests final : public UnitTest +{ +public: + NextFloatTests() + : UnitTest { getTemplatedMathsFunctionUnitTestName ("nextFloat"), UnitTestCategories::maths } + {} + + void runTest() final + { + using limits = std::numeric_limits; + + constexpr auto zero = T{}; + constexpr auto one = T (1); + constexpr auto min = limits::min(); + constexpr auto epsilon = limits::epsilon(); + + beginTest ("nextFloat from zero is subnormal"); + { + expect (juce_isfinite (nextFloatUp (zero))); + expect (! exactlyEqual (zero, nextFloatUp (zero))); + expect (! std::isnormal (nextFloatUp (zero))); + + expect (juce_isfinite (nextFloatDown (zero))); + expect (! exactlyEqual (zero, nextFloatDown (zero))); + expect (! std::isnormal (nextFloatDown (zero))); + } + + beginTest ("nextFloat from min, towards zero, is subnormal"); + { + expect (std::isnormal (min)); + expect (std::isnormal (-min)); + expect (! std::isnormal (nextFloatDown (min))); + expect (! std::isnormal (nextFloatUp (-min))); + } + + beginTest ("nextFloat from one matches epsilon"); + { + expect (! exactlyEqual (one, nextFloatUp (one))); + expect ( exactlyEqual (one + epsilon, nextFloatUp (one))); + + expect (! exactlyEqual (-one, nextFloatDown (-one))); + expect ( exactlyEqual (-one - epsilon, nextFloatDown (-one))); + } + } +}; + +template +struct MathsFloatingPointFunctionsTests +{ + IsFiniteTests isFiniteTests; + NextFloatTests nextFloatTests; + ApproximatelyEqualTests approximatelyEqualTests; +}; + +template<> +struct MathsFloatingPointFunctionsTests +{ + ApproximatelyEqualTests approximatelyEqualTests; +}; + +struct MathsFunctionsTests +{ + MathsFloatingPointFunctionsTests intFunctionTests; + MathsFloatingPointFunctionsTests floatFunctionTests; + MathsFloatingPointFunctionsTests doubleFunctionTests; + MathsFloatingPointFunctionsTests longDoubleFunctionTests; +}; + +static MathsFunctionsTests mathsFunctionsTests; + +} // namespace juce diff --git a/modules/juce_core/maths/juce_NormalisableRange.h b/modules/juce_core/maths/juce_NormalisableRange.h index 2909a5dc5235..d2eafa0bbed3 100644 --- a/modules/juce_core/maths/juce_NormalisableRange.h +++ b/modules/juce_core/maths/juce_NormalisableRange.h @@ -128,7 +128,7 @@ class NormalisableRange auto proportion = clampTo0To1 ((v - start) / (end - start)); - if (skew == static_cast (1)) + if (exactlyEqual (skew, static_cast (1))) return proportion; if (! symmetricSkew) @@ -154,7 +154,7 @@ class NormalisableRange if (! symmetricSkew) { - if (skew != static_cast (1) && proportion > ValueType()) + if (! exactlyEqual (skew, static_cast (1)) && proportion > ValueType()) proportion = std::exp (std::log (proportion) / skew); return start + (end - start) * proportion; @@ -162,7 +162,7 @@ class NormalisableRange auto distanceFromMiddle = static_cast (2) * proportion - static_cast (1); - if (skew != static_cast (1) && distanceFromMiddle != static_cast (0)) + if (! exactlyEqual (skew, static_cast (1)) && ! exactlyEqual (distanceFromMiddle, static_cast (0))) distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew) * (distanceFromMiddle < ValueType() ? static_cast (-1) : static_cast (1)); @@ -250,7 +250,7 @@ class NormalisableRange // If you hit this assertion then either your normalisation function is not working // correctly or your input is out of the expected bounds. - jassert (clampedValue == value); + jassert (exactlyEqual (clampedValue, value)); return clampedValue; } diff --git a/modules/juce_core/maths/juce_Random.cpp b/modules/juce_core/maths/juce_Random.cpp index df9b266526c4..b98dc5e6f239 100644 --- a/modules/juce_core/maths/juce_Random.cpp +++ b/modules/juce_core/maths/juce_Random.cpp @@ -103,7 +103,7 @@ float Random::nextFloat() noexcept { auto result = static_cast (static_cast (nextInt())) / (static_cast (std::numeric_limits::max()) + 1.0f); - return result == 1.0f ? 1.0f - std::numeric_limits::epsilon() : result; + return jmin (result, 1.0f - std::numeric_limits::epsilon()); } double Random::nextDouble() noexcept diff --git a/modules/juce_core/maths/juce_Range.h b/modules/juce_core/maths/juce_Range.h index 9a71195999b2..f5eb53181585 100644 --- a/modules/juce_core/maths/juce_Range.h +++ b/modules/juce_core/maths/juce_Range.h @@ -86,7 +86,7 @@ class Range constexpr inline ValueType getEnd() const noexcept { return end; } /** Returns true if the range has a length of zero. */ - constexpr inline bool isEmpty() const noexcept { return start == end; } + constexpr inline bool isEmpty() const noexcept { return exactlyEqual (start, end); } //============================================================================== /** Changes the start position of the range, leaving the end position unchanged. @@ -198,8 +198,13 @@ class Range return Range (start - amountToSubtract, end - amountToSubtract); } - constexpr bool operator== (Range other) const noexcept { return start == other.start && end == other.end; } - constexpr bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; } + constexpr bool operator== (Range other) const noexcept + { + const auto tie = [] (const Range& r) { return std::tie (r.start, r.end); }; + return tie (*this) == tie (other); + } + + constexpr bool operator!= (Range other) const noexcept { return ! operator== (other); } //============================================================================== /** Returns true if the given position lies inside this range. diff --git a/modules/juce_core/memory/juce_Reservoir.h b/modules/juce_core/memory/juce_Reservoir.h index 3829f73e41b7..6d7fe94b5d37 100644 --- a/modules/juce_core/memory/juce_Reservoir.h +++ b/modules/juce_core/memory/juce_Reservoir.h @@ -25,6 +25,8 @@ namespace juce /** Helper functions for managing buffered readers. + + @tags{Audio} */ struct Reservoir { diff --git a/modules/juce_core/misc/juce_EnumHelpers.h b/modules/juce_core/misc/juce_EnumHelpers.h new file mode 100644 index 000000000000..ec648ab5e6bb --- /dev/null +++ b/modules/juce_core/misc/juce_EnumHelpers.h @@ -0,0 +1,103 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +//============================================================================== +/** + Macro to enable bitwise operations for scoped enums (enum struct/class). + + To use this, add the line JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (MyEnum) + after your enum declaration at file scope level. + + e.g. @code + + enum class MyEnum + { + one = 1 << 0, + two = 1 << 1, + three = 1 << 2 + }; + + JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (MyEnum) + + MyEnum e = MyEnum::one | MyEnum::two; + + bool hasTwo = (e & MyEnum::two) != MyEnum{}; // true + bool hasTwo = hasBitValueSet (e, MyEnum::two); // true + + e = withBitValueCleared (e, MyEnum::two); + + bool hasTwo = hasBitValueSet (e, MyEnum::two); // false + + @endcode +*/ +#define JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS(EnumType) \ + static_assert (std::is_enum_v, \ + "JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS " \ + "should only be used with enum types"); \ + constexpr auto operator& (EnumType a, EnumType b) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (base_type (a) & base_type (b)); \ + } \ + constexpr auto operator| (EnumType a, EnumType b) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (base_type (a) | base_type (b)); \ + } \ + constexpr auto operator~ (EnumType a) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (~base_type (a)); \ + } \ + constexpr auto& operator|= (EnumType& a, EnumType b) \ + { \ + a = (a | b); \ + return a; \ + } \ + constexpr auto& operator&= (EnumType& a, EnumType b) \ + { \ + a = (a & b); \ + return a; \ + } + + +namespace juce +{ + +template , int> = 0> +constexpr bool hasBitValueSet (EnumType enumValue, EnumType valueToLookFor) noexcept +{ + return (enumValue & valueToLookFor) != EnumType{}; +} + +template , int> = 0> +constexpr EnumType withBitValueSet (EnumType enumValue, EnumType valueToAdd) noexcept +{ + return enumValue | valueToAdd; +} + +template , int> = 0> +constexpr EnumType withBitValueCleared (EnumType enumValue, EnumType valueToRemove) noexcept +{ + return enumValue & ~valueToRemove; +} +} diff --git a/modules/juce_core/misc/juce_EnumHelpers_test.cpp b/modules/juce_core/misc/juce_EnumHelpers_test.cpp new file mode 100644 index 000000000000..0441e4c30226 --- /dev/null +++ b/modules/juce_core/misc/juce_EnumHelpers_test.cpp @@ -0,0 +1,94 @@ +/* +============================================================================== + +This file is part of the JUCE library. +Copyright (c) 2022 - Raw Material Software Limited + +JUCE is an open source library subject to commercial or open-source +licensing. + +The code included in this file is provided under the terms of the ISC license +http://www.isc.org/downloads/software-support-policy/isc-license. Permission +To use, copy, modify, and/or distribute this software for any purpose with or +without fee is hereby granted provided that the above copyright notice and +this permission notice appear in all copies. + +JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER +EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE +DISCLAIMED. + +============================================================================== +*/ + +namespace juce +{ + +namespace detail +{ +enum class TestEnum +{ + one = 1 << 0, + four = 1 << 1, + other = 1 << 2 +}; + +JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (TestEnum) +} + +class EnumHelperTest : public UnitTest +{ +public: + EnumHelperTest() : UnitTest ("EnumHelpers", UnitTestCategories::containers) {} + + void runTest() override + { + using detail::TestEnum; + + TestEnum e = {}; + + beginTest ("Default initialised enum is 'none'"); + { + expect (e == TestEnum{}); + expect (! hasBitValueSet (e, TestEnum{})); + } + + beginTest ("withBitValueSet sets correct bit on empty enum"); + { + e = withBitValueSet (e, TestEnum::other); + expect (e == TestEnum::other); + expect (hasBitValueSet (e, TestEnum::other)); + } + + beginTest ("withBitValueSet sets correct bit on non-empty enum"); + { + e = withBitValueSet (e, TestEnum::one); + expect (hasBitValueSet (e, TestEnum::one)); + } + + beginTest ("withBitValueCleared clears correct bit"); + { + e = withBitValueCleared (e, TestEnum::one); + expect (e != TestEnum::one); + expect (hasBitValueSet (e, TestEnum::other)); + expect (! hasBitValueSet (e, TestEnum::one)); + } + + beginTest ("operators work as expected"); + { + e = {}; + + e = TestEnum::one; + expect ((e & TestEnum::one) != TestEnum{}); + e |= TestEnum::other; + expect ((e & TestEnum::other) != TestEnum{}); + + e &= ~TestEnum::one; + expect ((e & TestEnum::one) == TestEnum{}); + expect ((e & TestEnum::other) != TestEnum{}); + } + } +}; + +static EnumHelperTest enumHelperTest; + +} // namespace juce diff --git a/modules/juce_core/misc/juce_Functional.h b/modules/juce_core/misc/juce_Functional.h index e2a8bbfd1fc3..040132f7f0e9 100644 --- a/modules/juce_core/misc/juce_Functional.h +++ b/modules/juce_core/misc/juce_Functional.h @@ -80,7 +80,7 @@ using DisableIfSameOrDerived = std::enable_if_t -Object withMember (Object copy, Member OtherObject::* member, Other&& value) +[[nodiscard]] Object withMember (Object copy, Member OtherObject::* member, Other&& value) { copy.*member = std::forward (value); return copy; @@ -109,6 +109,8 @@ Object withMember (Object copy, Member OtherObject::* member, Other&& value) doWorkHavingEstablishedPreconditions(); } // ...or here! @endcode + + @tags{Core} */ template struct ScopeGuard : Fn { ~ScopeGuard() { Fn::operator()(); } }; template ScopeGuard (Fn) -> ScopeGuard; diff --git a/modules/juce_core/native/juce_android_AndroidDocument.cpp b/modules/juce_core/native/juce_AndroidDocument_android.cpp similarity index 100% rename from modules/juce_core/native/juce_android_AndroidDocument.cpp rename to modules/juce_core/native/juce_AndroidDocument_android.cpp diff --git a/modules/juce_core/native/juce_BasicNativeHeaders.h b/modules/juce_core/native/juce_BasicNativeHeaders.h index f444f9c07fd4..5227ea4481cb 100644 --- a/modules/juce_core/native/juce_BasicNativeHeaders.h +++ b/modules/juce_core/native/juce_BasicNativeHeaders.h @@ -209,6 +209,8 @@ #include #include #include + #include + #include #include #include @@ -265,11 +267,13 @@ #include #include #include + #include + #include #include #include - // If you are getting include errors here, then you to re-build the Projucer - // and re-save your .jucer file. + // If you are getting include errors here, then you need to re-build + // the Projucer and re-save your .jucer file. #include #endif diff --git a/modules/juce_core/native/juce_mac_CFHelpers.h b/modules/juce_core/native/juce_CFHelpers_mac.h similarity index 100% rename from modules/juce_core/native/juce_mac_CFHelpers.h rename to modules/juce_core/native/juce_CFHelpers_mac.h diff --git a/modules/juce_core/native/juce_win32_ComSmartPtr.h b/modules/juce_core/native/juce_ComSmartPtr_windows.h similarity index 100% rename from modules/juce_core/native/juce_win32_ComSmartPtr.h rename to modules/juce_core/native/juce_ComSmartPtr_windows.h diff --git a/modules/juce_core/native/juce_linux_CommonFile.cpp b/modules/juce_core/native/juce_CommonFile_linux.cpp similarity index 100% rename from modules/juce_core/native/juce_linux_CommonFile.cpp rename to modules/juce_core/native/juce_CommonFile_linux.cpp diff --git a/modules/juce_core/native/juce_android_Files.cpp b/modules/juce_core/native/juce_Files_android.cpp similarity index 100% rename from modules/juce_core/native/juce_android_Files.cpp rename to modules/juce_core/native/juce_Files_android.cpp diff --git a/modules/juce_core/native/juce_linux_Files.cpp b/modules/juce_core/native/juce_Files_linux.cpp similarity index 95% rename from modules/juce_core/native/juce_linux_Files.cpp rename to modules/juce_core/native/juce_Files_linux.cpp index 38429ba69eed..03fa3eaabd22 100644 --- a/modules/juce_core/native/juce_linux_Files.cpp +++ b/modules/juce_core/native/juce_Files_linux.cpp @@ -20,10 +20,6 @@ ============================================================================== */ -#if JUCE_BSD -extern char** environ; -#endif - namespace juce { @@ -229,7 +225,7 @@ bool Process::openDocument (const String& fileName, const String& parameters) setsid(); // Child process - execve (argv[0], (char**) argv, environ); + execv (argv[0], (char**) argv); exit (0); } diff --git a/modules/juce_core/native/juce_mac_Files.mm b/modules/juce_core/native/juce_Files_mac.mm similarity index 100% rename from modules/juce_core/native/juce_mac_Files.mm rename to modules/juce_core/native/juce_Files_mac.mm diff --git a/modules/juce_core/native/juce_win32_Files.cpp b/modules/juce_core/native/juce_Files_windows.cpp similarity index 100% rename from modules/juce_core/native/juce_win32_Files.cpp rename to modules/juce_core/native/juce_Files_windows.cpp diff --git a/modules/juce_core/native/juce_posix_IPAddress.h b/modules/juce_core/native/juce_IPAddress_posix.h similarity index 100% rename from modules/juce_core/native/juce_posix_IPAddress.h rename to modules/juce_core/native/juce_IPAddress_posix.h diff --git a/modules/juce_core/native/juce_android_JNIHelpers.cpp b/modules/juce_core/native/juce_JNIHelpers_android.cpp similarity index 94% rename from modules/juce_core/native/juce_android_JNIHelpers.cpp rename to modules/juce_core/native/juce_JNIHelpers_android.cpp index 45eb542f433f..6f677c575cb2 100644 --- a/modules/juce_core/native/juce_android_JNIHelpers.cpp +++ b/modules/juce_core/native/juce_JNIHelpers_android.cpp @@ -94,8 +94,8 @@ struct SystemJavaClassComparator if ((! isSysClassA) && (! isSysClassB)) { - return DefaultElementComparator::compareElements (first != nullptr ? first->byteCode != nullptr : false, - second != nullptr ? second->byteCode != nullptr : false); + return DefaultElementComparator::compareElements (first != nullptr && first->byteCode != nullptr, + second != nullptr && second->byteCode != nullptr); } return DefaultElementComparator::compareElements (isSystemClass (first), @@ -631,43 +631,17 @@ jobject FragmentOverlay::getNativeHandle() } //============================================================================== -class ActivityLauncher : public FragmentOverlay +void startAndroidActivityForResult (const LocalRef& intent, + int requestCode, + std::function)>&& callback) { -public: - ActivityLauncher (const LocalRef& intentToUse, - int requestCodeToUse, - std::function)> && callbackToUse) - : intent (intentToUse), requestCode (requestCodeToUse), callback (std::move (callbackToUse)) - {} - - void onStart() override - { - if (! std::exchange (activityHasStarted, true)) - getEnv()->CallVoidMethod (getNativeHandle(), AndroidFragment.startActivityForResult, - intent.get(), requestCode); - } - - void onActivityResult (int activityRequestCode, int resultCode, LocalRef data) override + auto* launcher = new ActivityLauncher (intent, requestCode); + launcher->callback = [launcher, c = std::move (callback)] (auto&&... args) { - if (callback) - callback (activityRequestCode, resultCode, std::move (data)); - - getEnv()->CallVoidMethod (getNativeHandle(), JuceFragmentOverlay.close); - delete this; - } - -private: - GlobalRef intent; - int requestCode; - std::function)> callback; - bool activityHasStarted = false; -}; - -void startAndroidActivityForResult (const LocalRef& intent, int requestCode, - std::function)> && callback) -{ - auto* activityLauncher = new ActivityLauncher (intent, requestCode, std::move (callback)); - activityLauncher->open(); + NullCheckedInvocation::invoke (c, args...); + delete launcher; + }; + launcher->open(); } //============================================================================== diff --git a/modules/juce_core/native/juce_android_JNIHelpers.h b/modules/juce_core/native/juce_JNIHelpers_android.h similarity index 94% rename from modules/juce_core/native/juce_android_JNIHelpers.h rename to modules/juce_core/native/juce_JNIHelpers_android.h index aeb49f97b2f8..54cc785397b5 100644 --- a/modules/juce_core/native/juce_android_JNIHelpers.h +++ b/modules/juce_core/native/juce_JNIHelpers_android.h @@ -262,7 +262,8 @@ template constexpr auto numBytes (const T (&) [N]) { retu METHOD (getApplicationInfo, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;") \ METHOD (checkCallingOrSelfPermission, "checkCallingOrSelfPermission", "(Ljava/lang/String;)I") \ METHOD (checkCallingOrSelfUriPermission, "checkCallingOrSelfUriPermission", "(Landroid/net/Uri;I)I") \ - METHOD (getCacheDir, "getCacheDir", "()Ljava/io/File;") + METHOD (getCacheDir, "getCacheDir", "()Ljava/io/File;") \ + METHOD (registerReceiver, "registerReceiver", "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;") \ DECLARE_JNI_CLASS (AndroidContext, "android/content/Context") #undef JNI_CLASS_MEMBERS @@ -418,6 +419,7 @@ DECLARE_JNI_CLASS (AndroidHandlerThread, "android/os/HandlerThread") METHOD (putExtraStrings, "putExtra", "(Ljava/lang/String;[Ljava/lang/String;)Landroid/content/Intent;") \ METHOD (putExtraParcelable, "putExtra", "(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;") \ METHOD (putExtraBool, "putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;") \ + METHOD (putExtraInt, "putExtra", "(Ljava/lang/String;I)Landroid/content/Intent;") \ METHOD (putParcelableArrayListExtra, "putParcelableArrayListExtra", "(Ljava/lang/String;Ljava/util/ArrayList;)Landroid/content/Intent;") \ METHOD (setAction, "setAction", "(Ljava/lang/String;)Landroid/content/Intent;") \ METHOD (setFlags, "setFlags", "(I)Landroid/content/Intent;") \ @@ -427,6 +429,12 @@ DECLARE_JNI_CLASS (AndroidHandlerThread, "android/os/HandlerThread") DECLARE_JNI_CLASS (AndroidIntent, "android/content/Intent") #undef JNI_CLASS_MEMBERS +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + STATICMETHOD (createChooser, "createChooser", "(Landroid/content/Intent;Ljava/lang/CharSequence;Landroid/content/IntentSender;)Landroid/content/Intent;") \ + +DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidIntent22, "android/content/Intent", 22) +#undef JNI_CLASS_MEMBERS + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (constructor, "", "()V") \ METHOD (postRotate, "postRotate", "(FFF)Z") \ @@ -490,7 +498,8 @@ DECLARE_JNI_CLASS (AndroidPaint, "android/graphics/Paint") #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ STATICMETHOD (getActivity, "getActivity", "(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;") \ - METHOD (getIntentSender, "getIntentSender", "()Landroid/content/IntentSender;") + STATICMETHOD (getBroadcast, "getBroadcast", "(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;") \ + METHOD (getIntentSender, "getIntentSender", "()Landroid/content/IntentSender;") \ DECLARE_JNI_CLASS (AndroidPendingIntent, "android/app/PendingIntent") #undef JNI_CLASS_MEMBERS @@ -1026,10 +1035,37 @@ class FragmentOverlay //============================================================================== // Allows you to start an activity without requiring to have an activity -void startAndroidActivityForResult (const LocalRef& intent, int requestCode, - std::function)> && callback); +void startAndroidActivityForResult (const LocalRef& intent, + int requestCode, + std::function)>&& callback); -//============================================================================== +class ActivityLauncher : public FragmentOverlay +{ +public: + ActivityLauncher (const LocalRef& intentToUse, int requestCodeToUse) + : intent (intentToUse), requestCode (requestCodeToUse) + {} + + void onStart() override + { + if (! std::exchange (activityHasStarted, true)) + getEnv()->CallVoidMethod (getNativeHandle(), AndroidFragment.startActivityForResult, intent.get(), requestCode); + } + + void onActivityResult (int activityRequestCode, int resultCode, LocalRef data) override + { + NullCheckedInvocation::invoke (callback, activityRequestCode, resultCode, std::move (data)); + } + + std::function)> callback; + +private: + GlobalRef intent; + int requestCode; + bool activityHasStarted = false; +}; + + //============================================================================== bool androidHasSystemFeature (const String& property); String audioManagerGetProperty (const String& property); diff --git a/modules/juce_core/native/juce_android_Misc.cpp b/modules/juce_core/native/juce_Misc_android.cpp similarity index 100% rename from modules/juce_core/native/juce_android_Misc.cpp rename to modules/juce_core/native/juce_Misc_android.cpp diff --git a/modules/juce_core/native/juce_posix_NamedPipe.cpp b/modules/juce_core/native/juce_NamedPipe_posix.cpp similarity index 100% rename from modules/juce_core/native/juce_posix_NamedPipe.cpp rename to modules/juce_core/native/juce_NamedPipe_posix.cpp diff --git a/modules/juce_core/native/juce_android_Network.cpp b/modules/juce_core/native/juce_Network_android.cpp similarity index 100% rename from modules/juce_core/native/juce_android_Network.cpp rename to modules/juce_core/native/juce_Network_android.cpp diff --git a/modules/juce_core/native/juce_curl_Network.cpp b/modules/juce_core/native/juce_Network_curl.cpp similarity index 94% rename from modules/juce_core/native/juce_curl_Network.cpp rename to modules/juce_core/native/juce_Network_curl.cpp index 47d5e81a2582..1cf9ecf48236 100644 --- a/modules/juce_core/native/juce_curl_Network.cpp +++ b/modules/juce_core/native/juce_Network_curl.cpp @@ -89,7 +89,9 @@ struct CURLSymbols static DynamicLibrary libcurl; if (libcurl.getNativeHandle() == nullptr) - for (auto libName : { "libcurl.so", "libcurl.so.4", "libcurl.so.3" }) + for (auto libName : { "libcurl.so", + "libcurl.so.4", "libcurl.so.3", + "libcurl-gnutls.so.4", "libcurl-gnutls.so.3" }) if (libcurl.open (libName)) break; @@ -371,11 +373,18 @@ class WebInputStream::Pimpl if (symbols->curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode) == CURLE_OK) statusCode = static_cast (responseCode); - // get content length size + #if LIBCURL_VERSION_MAJOR < 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR < 55) double curlLength; if (symbols->curl_easy_getinfo (curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curlLength) == CURLE_OK) + { + #else + curl_off_t curlLength; + if (symbols->curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &curlLength) == CURLE_OK) + { + #endif contentLength = static_cast (curlLength); - } + } + } return true; } diff --git a/modules/juce_core/native/juce_linux_Network.cpp b/modules/juce_core/native/juce_Network_linux.cpp similarity index 96% rename from modules/juce_core/native/juce_linux_Network.cpp rename to modules/juce_core/native/juce_Network_linux.cpp index 6de7e2d26707..c71a13e237bd 100644 --- a/modules/juce_core/native/juce_linux_Network.cpp +++ b/modules/juce_core/native/juce_Network_linux.cpp @@ -34,7 +34,7 @@ void MACAddress::findAllAddresses (Array& result) { if (i->ifa_addr->sa_family == AF_LINK) { - struct sockaddr_dl* sdl = (struct sockaddr_dl*) i->ifa_addr; + auto sdl = unalignedPointerCast (i->ifa_addr); MACAddress ma ((const uint8*) (sdl->sdl_data + sdl->sdl_nlen)); if (! ma.isNull()) diff --git a/modules/juce_core/native/juce_mac_Network.mm b/modules/juce_core/native/juce_Network_mac.mm similarity index 96% rename from modules/juce_core/native/juce_mac_Network.mm rename to modules/juce_core/native/juce_Network_mac.mm index 56110874d2c5..901214b256ac 100644 --- a/modules/juce_core/native/juce_mac_Network.mm +++ b/modules/juce_core/native/juce_Network_mac.mm @@ -686,7 +686,12 @@ static void didCompleteWithError (id self, SEL, NSURLConnection*, NSURLSessionTa activeSessions.set (uniqueIdentifier, this); auto nsUrl = [NSURL URLWithString: juceStringToNS (urlToUse.toString (true))]; + + jassert (nsUrl != nullptr); + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullable-to-nonnull-conversion") NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL: nsUrl]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE if (options.usePost) [request setHTTPMethod: @"POST"]; diff --git a/modules/juce_core/native/juce_win32_Network.cpp b/modules/juce_core/native/juce_Network_windows.cpp similarity index 100% rename from modules/juce_core/native/juce_win32_Network.cpp rename to modules/juce_core/native/juce_Network_windows.cpp diff --git a/modules/juce_core/native/juce_mac_ObjCHelpers.h b/modules/juce_core/native/juce_ObjCHelpers_mac.h similarity index 89% rename from modules/juce_core/native/juce_mac_ObjCHelpers.h rename to modules/juce_core/native/juce_ObjCHelpers_mac.h index 7f17c07b9590..b7c2c143db75 100644 --- a/modules/juce_core/native/juce_mac_ObjCHelpers.h +++ b/modules/juce_core/native/juce_ObjCHelpers_mac.h @@ -20,7 +20,7 @@ ============================================================================== */ -#include "juce_mac_CFHelpers.h" +#include "juce_CFHelpers_mac.h" /* This file contains a few helper functions that are used internally but which need to be kept away from the public headers because they use obj-C symbols. @@ -504,29 +504,59 @@ auto createObjCBlockImpl (Class* object, Fn func, Signature) } } // namespace detail +/* Creates an Obj-C block automatically from a member function. */ template auto CreateObjCBlock (Class* object, MemberFunc fn) { return detail::createObjCBlockImpl (object, fn, detail::getSignature (fn)); } +/* Automatically copies and releases a block, a bit like a smart pointer for an Obj-C block. + + This is helpful to automatically manage the lifetime of blocks, e.g. if you need to keep a block + around to be used later. This is the case in the AudioUnit API, where the host may provide a + musicalContextBlock that can be called by the plugin during rendering. Copying blocks isn't + realtime-safe, so the plugin must cache the block before rendering. + + If you're just creating blocks to pass them directly to an Obj-C API, you probably won't need to + use this type. +*/ template class ObjCBlock { public: - ObjCBlock() { block = nullptr; } - template - ObjCBlock (C* _this, R (C::*fn)(P...)) : block (CreateObjCBlock (_this, fn)) {} - ObjCBlock (BlockType b) : block ([b copy]) {} - ObjCBlock& operator= (const BlockType& other) { if (block != nullptr) { [block release]; } block = [other copy]; return *this; } - bool operator== (const void* ptr) const { return ((const void*) block == ptr); } - bool operator!= (const void* ptr) const { return ((const void*) block != ptr); } - ~ObjCBlock() { if (block != nullptr) [block release]; } + ObjCBlock() = default; + + ObjCBlock (BlockType b) + : block ([b copy]) {} + + ObjCBlock (const ObjCBlock& other) + : block (other.block != nullptr ? [other.block copy] : nullptr) {} + + ObjCBlock& operator= (const BlockType& other) + { + ObjCBlock { other }.swap (*this); + return *this; + } + + ~ObjCBlock() noexcept + { + if (block != nullptr) + [block release]; + } + + bool operator== (BlockType ptr) const { return block == ptr; } + bool operator!= (BlockType ptr) const { return block != ptr; } operator BlockType() const { return block; } + void swap (ObjCBlock& other) noexcept + { + std::swap (other.block, block); + } + private: - BlockType block; + BlockType block = nullptr; }; //============================================================================== diff --git a/modules/juce_core/native/juce_PlatformTimerListener.h b/modules/juce_core/native/juce_PlatformTimerListener.h new file mode 100644 index 000000000000..fe04fa737386 --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimerListener.h @@ -0,0 +1,32 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +struct PlatformTimerListener +{ + virtual ~PlatformTimerListener() = default; + virtual void onTimerExpired() = 0; +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimer_generic.cpp b/modules/juce_core/native/juce_PlatformTimer_generic.cpp new file mode 100644 index 000000000000..321e5f7fb046 --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_generic.cpp @@ -0,0 +1,149 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final : private Thread +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : Thread { "HighResolutionTimerThread" }, + listener { ptl } + { + startThread (Priority::highest); + } + + ~PlatformTimer() + { + stopThread (-1); + } + + void startTimer (int newIntervalMs) + { + jassert (newIntervalMs > 0); + jassert (timer == nullptr); + + { + std::scoped_lock lock { runCopyMutex }; + timer = std::make_shared (listener, newIntervalMs); + } + + notify(); + } + + void cancelTimer() + { + jassert (timer != nullptr); + + timer->cancel(); + + // Note the only race condition we need to protect against + // here is the copy in run(). + // + // Calls to startTimer(), cancelTimer(), and getIntervalMs() + // are already guaranteed to be both thread safe and well + // synchronised. + + std::scoped_lock lock { runCopyMutex }; + timer = nullptr; + } + + int getIntervalMs() const + { + return isThreadRunning() && timer != nullptr ? timer->getIntervalMs() : 0; + } + +private: + void run() final + { + const auto copyTimer = [&] + { + std::scoped_lock lock { runCopyMutex }; + return timer; + }; + + while (! threadShouldExit()) + { + if (auto t = copyTimer()) + t->run(); + + wait (-1); + } + } + + class Timer + { + public: + Timer (PlatformTimerListener& l, int i) + : listener { l }, intervalMs { i } {} + + int getIntervalMs() const + { + return intervalMs; + } + + void cancel() + { + stop.signal(); + } + + void run() + { + #if JUCE_MAC || JUCE_IOS + tryToUpgradeCurrentThreadToRealtime (Thread::RealtimeOptions{}.withPeriodMs (intervalMs)); + #endif + + const auto millisecondsUntil = [] (auto time) + { + return jmax (0.0, time - Time::getMillisecondCounterHiRes()); + }; + + while (! stop.wait (millisecondsUntil (nextEventTime))) + { + if (Time::getMillisecondCounterHiRes() >= nextEventTime) + { + listener.onTimerExpired(); + nextEventTime += intervalMs; + } + } + } + + private: + PlatformTimerListener& listener; + const int intervalMs; + double nextEventTime = Time::getMillisecondCounterHiRes() + intervalMs; + WaitableEvent stop { true }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Timer) + JUCE_DECLARE_NON_MOVEABLE (Timer) + }; + + PlatformTimerListener& listener; + mutable std::mutex runCopyMutex; + std::shared_ptr timer; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimer_windows.cpp b/modules/juce_core/native/juce_PlatformTimer_windows.cpp new file mode 100644 index 000000000000..13d3ead177f1 --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_windows.cpp @@ -0,0 +1,68 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : listener { ptl } {} + + void startTimer (int newIntervalMs) + { + jassert (newIntervalMs > 0); + + const auto callback = [] (UINT, UINT, DWORD_PTR context, DWORD_PTR, DWORD_PTR) + { + reinterpret_cast (context)->onTimerExpired(); + }; + + timerId = timeSetEvent ((UINT) newIntervalMs, 1, callback, (DWORD_PTR) &listener, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + intervalMs = timerId != 0 ? newIntervalMs : 0; + } + + void cancelTimer() + { + jassert (timerId != 0); + + timeKillEvent (timerId); + timerId = 0; + intervalMs = 0; + } + + int getIntervalMs() const + { + return intervalMs; + } + +private: + PlatformTimerListener& listener; + UINT timerId { 0 }; + int intervalMs { 0 }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_win32_Registry.cpp b/modules/juce_core/native/juce_Registry_windows.cpp similarity index 100% rename from modules/juce_core/native/juce_win32_Registry.cpp rename to modules/juce_core/native/juce_Registry_windows.cpp diff --git a/modules/juce_core/native/juce_android_RuntimePermissions.cpp b/modules/juce_core/native/juce_RuntimePermissions_android.cpp similarity index 94% rename from modules/juce_core/native/juce_android_RuntimePermissions.cpp rename to modules/juce_core/native/juce_RuntimePermissions_android.cpp index 285b92c1e166..45a30233e775 100644 --- a/modules/juce_core/native/juce_android_RuntimePermissions.cpp +++ b/modules/juce_core/native/juce_RuntimePermissions_android.cpp @@ -43,7 +43,11 @@ static StringArray jucePermissionToAndroidPermissions (RuntimePermissions::Permi "android.permission.BLUETOOTH_CONNECT" }; } - case RuntimePermissions::writeExternalStorage: return { "android.permission.WRITE_EXTERNAL_STORAGE" }; + // WRITE_EXTERNAL_STORAGE has no effect on SDK 29+ + case RuntimePermissions::writeExternalStorage: + return getAndroidSDKVersion() < 29 ? StringArray { "android.permission.WRITE_EXTERNAL_STORAGE" } + : StringArray{}; + case RuntimePermissions::camera: return { "android.permission.CAMERA" }; case RuntimePermissions::readExternalStorage: diff --git a/modules/juce_core/native/juce_intel_SharedCode.h b/modules/juce_core/native/juce_SharedCode_intel.h similarity index 100% rename from modules/juce_core/native/juce_intel_SharedCode.h rename to modules/juce_core/native/juce_SharedCode_intel.h diff --git a/modules/juce_core/native/juce_posix_SharedCode.h b/modules/juce_core/native/juce_SharedCode_posix.h similarity index 94% rename from modules/juce_core/native/juce_posix_SharedCode.h rename to modules/juce_core/native/juce_SharedCode_posix.h index a2649055acb6..03313eaa270d 100644 --- a/modules/juce_core/native/juce_posix_SharedCode.h +++ b/modules/juce_core/native/juce_SharedCode_posix.h @@ -854,7 +854,7 @@ class PosixThreadAttribute public: explicit PosixThreadAttribute (size_t stackSize) { - if (valid) + if (valid && stackSize != 0) pthread_attr_setstacksize (&attr, stackSize); } @@ -894,7 +894,7 @@ class PosixSchedulerPriority const auto min = jmax (0, sched_get_priority_min (SCHED_RR)); const auto max = jmax (1, sched_get_priority_max (SCHED_RR)); - return jmap (rt->priority, 0, 10, min, max); + return jmap (rt->getPriority(), 0, 10, min, max); } // We only use this helper if we're on an old macos/ios platform that might @@ -924,9 +924,9 @@ class PosixSchedulerPriority return 0; }(); - #if JUCE_MAC || JUCE_IOS + #if JUCE_MAC || JUCE_IOS || JUCE_BSD const auto scheduler = SCHED_OTHER; - #elif JUCE_LINUX || JUCE_BSD + #elif JUCE_LINUX const auto backgroundSched = prio == Thread::Priority::background ? SCHED_IDLE : SCHED_OTHER; const auto scheduler = isRealtime ? SCHED_RR : backgroundSched; @@ -959,11 +959,13 @@ class PosixSchedulerPriority int priority; }; -static void* makeThreadHandle (PosixThreadAttribute& attr, Thread* userData, void* (*threadEntryProc) (void*)) +static void* makeThreadHandle (PosixThreadAttribute& attr, void* userData, void* (*threadEntryProc) (void*)) { pthread_t handle = {}; - if (pthread_create (&handle, attr.get(), threadEntryProc, userData) != 0) + const auto status = pthread_create (&handle, attr.get(), threadEntryProc, userData); + + if (status != 0) return nullptr; pthread_detach (handle); @@ -1020,8 +1022,16 @@ void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask ([[maybe_unused]] uint32 CPU_ZERO (&affinity); for (int i = 0; i < 32; ++i) + { if ((affinityMask & (uint32) (1 << i)) != 0) + { + // GCC 12 on FreeBSD complains about CPU_SET irrespective of + // the type of the first argument + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsign-conversion") CPU_SET ((size_t) i, &affinity); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } + } #if (! JUCE_ANDROID) && ((! (JUCE_LINUX || JUCE_BSD)) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004)) pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity); diff --git a/modules/juce_core/native/juce_mac_Strings.mm b/modules/juce_core/native/juce_Strings_mac.mm similarity index 100% rename from modules/juce_core/native/juce_mac_Strings.mm rename to modules/juce_core/native/juce_Strings_mac.mm diff --git a/modules/juce_core/native/juce_android_SystemStats.cpp b/modules/juce_core/native/juce_SystemStats_android.cpp similarity index 100% rename from modules/juce_core/native/juce_android_SystemStats.cpp rename to modules/juce_core/native/juce_SystemStats_android.cpp diff --git a/modules/juce_core/native/juce_linux_SystemStats.cpp b/modules/juce_core/native/juce_SystemStats_linux.cpp similarity index 95% rename from modules/juce_core/native/juce_linux_SystemStats.cpp rename to modules/juce_core/native/juce_SystemStats_linux.cpp index 5366995f121c..f733714ce35a 100644 --- a/modules/juce_core/native/juce_linux_SystemStats.cpp +++ b/modules/juce_core/native/juce_SystemStats_linux.cpp @@ -153,7 +153,7 @@ int SystemStats::getMemorySizeInMegabytes() int64 memory = 0; auto memorySize = sizeof (memory); auto result = sysctl (mib, numElementsInArray (mib), &memory, &memorySize, nullptr, 0); - return result == 0 ? (int) (memory / 1e6) : 0; + return result == 0 ? (int) (memory / (int64) 1e6) : 0; #else struct sysinfo sysi; @@ -204,7 +204,7 @@ String SystemStats::getUserLanguage() return {}; #else - return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); + return getLocaleValue (_NL_ADDRESS_LANG_AB); #endif } @@ -213,7 +213,7 @@ String SystemStats::getUserRegion() #if JUCE_BSD return {}; #else - return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); + return getLocaleValue (_NL_ADDRESS_COUNTRY_AB2); #endif } diff --git a/modules/juce_core/native/juce_mac_SystemStats.mm b/modules/juce_core/native/juce_SystemStats_mac.mm similarity index 77% rename from modules/juce_core/native/juce_mac_SystemStats.mm rename to modules/juce_core/native/juce_SystemStats_mac.mm index fe9da4bf929d..dc1e48f43737 100644 --- a/modules/juce_core/native/juce_mac_SystemStats.mm +++ b/modules/juce_core/native/juce_SystemStats_mac.mm @@ -209,7 +209,7 @@ static String getOSXVersion() return String (reinterpret_cast (vendor), 12); #else - return {}; + return "Apple"; #endif } @@ -226,17 +226,25 @@ static String getOSXVersion() int SystemStats::getCpuSpeedInMegahertz() { + #ifdef JUCE_INTEL uint64 speedHz = 0; - size_t speedSize = sizeof (speedHz); + size_t optSize = sizeof (speedHz); int mib[] = { CTL_HW, HW_CPU_FREQ }; - sysctl (mib, 2, &speedHz, &speedSize, nullptr, 0); - - #if JUCE_BIG_ENDIAN - if (speedSize == 4) - speedHz >>= 32; - #endif + sysctl (mib, 2, &speedHz, &optSize, nullptr, 0); return (int) (speedHz / 1000000); + #else + size_t hz = 0; + size_t optSize = sizeof (hz); + sysctlbyname ("hw.tbfrequency", &hz, &optSize, nullptr, 0); + + struct clockinfo ci{}; + optSize = sizeof (ci); + int mib[] = { CTL_KERN, KERN_CLOCKRATE }; + sysctl (mib, 2, &ci, &optSize, nullptr, 0); + + return (int) (double (hz * uint64_t (ci.hz)) / 1000000.0); + #endif } //============================================================================== @@ -343,32 +351,63 @@ uint32 millisecondsSinceStartup() const noexcept String SystemStats::getUniqueDeviceID() { - static const auto deviceId = [] + #if JUCE_MAC + constexpr mach_port_t port = 0; + + const auto dict = IOServiceMatching ("IOPlatformExpertDevice"); + + if (const auto service = IOServiceGetMatchingService (port, dict); service != IO_OBJECT_NULL) { - ChildProcess proc; + const ScopeGuard scope { [&] { IOObjectRelease (service); } }; - if (proc.start ("ioreg -rd1 -c IOPlatformExpertDevice", ChildProcess::wantStdOut)) - { - constexpr const char key[] = "\"IOPlatformUUID\""; - constexpr const auto keyLen = (int) sizeof (key); + if (const CFUniquePtr uuidTypeRef { IORegistryEntryCreateCFProperty (service, CFSTR ("IOPlatformUUID"), kCFAllocatorDefault, 0) }) + if (CFGetTypeID (uuidTypeRef.get()) == CFStringGetTypeID()) + return String::fromCFString ((CFStringRef) uuidTypeRef.get()).removeCharacters ("-"); + } + #elif JUCE_IOS + JUCE_AUTORELEASEPOOL + { + if (UIDevice* device = [UIDevice currentDevice]) + if (NSUUID* uuid = [device identifierForVendor]) + return nsStringToJuce ([uuid UUIDString]); + } + #endif - auto output = proc.readAllProcessOutput(); - auto index = output.indexOf (key); + return ""; +} - if (index >= 0) - { - auto start = output.indexOf (index + keyLen, "\""); - auto end = output.indexOf (start + 1, "\""); - return output.substring (start + 1, end).replace("-", ""); - } - } +#if JUCE_MAC +bool SystemStats::isAppSandboxEnabled() +{ + static const auto result = [&] + { + SecCodeRef ref = nullptr; + + if (const auto err = SecCodeCopySelf (kSecCSDefaultFlags, &ref); err != noErr) + return false; + + const CFUniquePtr managedRef (ref); + CFDictionaryRef infoDict = nullptr; - return String(); + if (const auto err = SecCodeCopySigningInformation (managedRef.get(), kSecCSDynamicInformation, &infoDict); err != noErr) + return false; + + const CFUniquePtr managedInfoDict (infoDict); + const void* entitlementsDict = nullptr; + + if (! CFDictionaryGetValueIfPresent (managedInfoDict.get(), kSecCodeInfoEntitlementsDict, &entitlementsDict)) + return false; + + const void* flag = nullptr; + + if (! CFDictionaryGetValueIfPresent (static_cast (entitlementsDict), @"com.apple.security.app-sandbox", &flag)) + return false; + + return static_cast (CFBooleanGetValue (static_cast (flag))); }(); - // Please tell someone at JUCE if this occurs - jassert (deviceId.isNotEmpty()); - return deviceId; + return result; } +#endif } // namespace juce diff --git a/modules/juce_core/native/juce_wasm_SystemStats.cpp b/modules/juce_core/native/juce_SystemStats_wasm.cpp similarity index 100% rename from modules/juce_core/native/juce_wasm_SystemStats.cpp rename to modules/juce_core/native/juce_SystemStats_wasm.cpp diff --git a/modules/juce_core/native/juce_win32_SystemStats.cpp b/modules/juce_core/native/juce_SystemStats_windows.cpp similarity index 71% rename from modules/juce_core/native/juce_win32_SystemStats.cpp rename to modules/juce_core/native/juce_SystemStats_windows.cpp index 63163d148b67..113b2c57341b 100644 --- a/modules/juce_core/native/juce_win32_SystemStats.cpp +++ b/modules/juce_core/native/juce_SystemStats_windows.cpp @@ -659,28 +659,221 @@ String SystemStats::getDisplayLanguage() return languagesBuffer.data(); } -String SystemStats::getUniqueDeviceID() +static constexpr DWORD generateProviderID (const char* string) { - #define PROVIDER(string) (DWORD) (string[0] << 24 | string[1] << 16 | string[2] << 8 | string[3]) + return (DWORD) string[0] << 0x18 + | (DWORD) string[1] << 0x10 + | (DWORD) string[2] << 0x08 + | (DWORD) string[3] << 0x00; +} - auto bufLen = GetSystemFirmwareTable (PROVIDER ("RSMB"), PROVIDER ("RSDT"), nullptr, 0); +static std::optional> readSMBIOSData() +{ + const auto sig = generateProviderID ("RSMB"); + const auto id = generateProviderID ("RSDT"); - if (bufLen > 0) + if (const auto bufLen = GetSystemFirmwareTable (sig, id, nullptr, 0); bufLen > 0) { - HeapBlock buffer { bufLen }; - GetSystemFirmwareTable (PROVIDER ("RSMB"), PROVIDER ("RSDT"), (void*) buffer.getData(), bufLen); + std::vector buffer; + + buffer.resize (bufLen); + + if (GetSystemFirmwareTable (sig, id, buffer.data(), bufLen) == buffer.size()) + return std::make_optional (std::move (buffer)); + } + + return {}; +} - return [&] +String getLegacyUniqueDeviceID() +{ + if (const auto dump = readSMBIOSData()) + { + uint64_t hash = 0; + const auto start = dump->data(); + const auto end = start + jmin (1024, (int) dump->size()); + + for (auto dataPtr = start; dataPtr != end; ++dataPtr) + hash = hash * (uint64_t) 101 + (uint8_t) *dataPtr; + + return String (hash); + } + + return {}; +} + +String SystemStats::getUniqueDeviceID() +{ + if (const auto smbiosBuffer = readSMBIOSData()) + { + #pragma pack (push, 1) + struct RawSMBIOSData + { + uint8_t unused[4]; + uint32_t length; + }; + + struct SMBIOSHeader + { + uint8_t id; + uint8_t length; + uint16_t handle; + }; + #pragma pack (pop) + + if (smbiosBuffer->size() < sizeof (RawSMBIOSData)) { - uint64_t hash = 0; - const auto start = buffer.getData(); - const auto end = start + jmin (1024, (int) bufLen); + // Malformed buffer; not enough room for RawSMBIOSData instance + jassertfalse; + return {}; + } + + String uuid; + const auto* asRawSMBIOSData = unalignedPointerCast (smbiosBuffer->data()); + + if (smbiosBuffer->size() < sizeof (RawSMBIOSData) + static_cast (asRawSMBIOSData->length)) + { + // Malformed buffer; declared length is longer than the buffer we were given + jassertfalse; + return {}; + } + + Span content (smbiosBuffer->data() + sizeof (RawSMBIOSData), asRawSMBIOSData->length); - for (auto dataPtr = start; dataPtr != end; ++dataPtr) - hash = hash * (uint64_t) 101 + *dataPtr; + while (! content.empty()) + { + if (content.size() < sizeof (SMBIOSHeader)) + { + // Malformed buffer; not enough room for header + jassertfalse; + break; + } + + const auto* header = unalignedPointerCast (content.data()); + + if (content.size() < header->length) + { + // Malformed buffer; declared length is longer than the buffer we were given + jassertfalse; + break; + } + + std::vector strings; + + // Each table comprises a struct and a varying number of null terminated + // strings. The string section is delimited by a pair of null terminators. + // Some fields in the header are indices into the string table. + + const auto endOfStringTable = [&header, &strings, &content] + { + const auto* dataTable = unalignedPointerCast (content.data()); + size_t stringOffset = header->length; + + while (stringOffset < content.size()) + { + const auto* str = dataTable + stringOffset; + const auto maxLength = content.size() - stringOffset; + const auto n = strnlen (str, maxLength); + + if (n == 0) + break; + + strings.emplace_back (str, n); + stringOffset += std::min (n + 1, maxLength); + } + + const auto lengthAfterHeader = jmax ((size_t) header->length + 2, stringOffset + 1); + return jmin (lengthAfterHeader, content.size()); + }(); + + const auto stringFromOffset = [&content, &strings] (size_t byteOffset) -> String + { + if (! isPositiveAndBelow (byteOffset, content.size())) + return std::string{}; + + const auto index = std::to_integer (content[byteOffset]); + + if (index <= 0 || strings.size() < index) + return std::string{}; + + const auto view = strings[index - 1]; + return std::string { view }; + }; + + enum + { + systemManufacturer = 0x04, + systemProductName = 0x05, + systemSerialNumber = 0x07, + systemUUID = 0x08, // 16byte UUID. Can be all 0xFF or all 0x00. Might be user changeable. + systemSKU = 0x19, + systemFamily = 0x1a, + + baseboardManufacturer = 0x04, + baseboardProduct = 0x05, + baseboardVersion = 0x06, + baseboardSerialNumber = 0x07, + baseboardAssetTag = 0x08, + + processorManufacturer = 0x07, + processorVersion = 0x10, + processorAssetTag = 0x21, + processorPartNumber = 0x22 + }; + + switch (header->id) + { + case 1: // System + { + uuid += stringFromOffset (systemManufacturer); + uuid += "\n"; + uuid += stringFromOffset (systemProductName); + uuid += "\n"; + + char hexBuf[(16 * 2) + 1]{}; + + if (systemUUID + 16 < content.size()) + { + const auto* src = content.data() + systemUUID; + + for (auto i = 0; i != 16; ++i) + snprintf (hexBuf + 2 * i, 3, "%02hhX", std::to_integer (src[i])); + } + + uuid += hexBuf; + uuid += "\n"; + break; + } + + case 2: // Baseboard + uuid += stringFromOffset (baseboardManufacturer); + uuid += "\n"; + uuid += stringFromOffset (baseboardProduct); + uuid += "\n"; + uuid += stringFromOffset (baseboardVersion); + uuid += "\n"; + uuid += stringFromOffset (baseboardSerialNumber); + uuid += "\n"; + uuid += stringFromOffset (baseboardAssetTag); + uuid += "\n"; + break; + + case 4: // Processor + uuid += stringFromOffset (processorManufacturer); + uuid += "\n"; + uuid += stringFromOffset (processorVersion); + uuid += "\n"; + uuid += stringFromOffset (processorAssetTag); + uuid += "\n"; + uuid += stringFromOffset (processorPartNumber); + uuid += "\n"; + break; + } + + content = Span (content.data() + endOfStringTable, content.size() - endOfStringTable); + } - return String (hash); - }(); + return String (uuid.hashCode64()); } // Please tell someone at JUCE if this occurs diff --git a/modules/juce_core/native/juce_native_ThreadPriorities.h b/modules/juce_core/native/juce_ThreadPriorities_native.h similarity index 100% rename from modules/juce_core/native/juce_native_ThreadPriorities.h rename to modules/juce_core/native/juce_ThreadPriorities_native.h diff --git a/modules/juce_core/native/juce_android_Threads.cpp b/modules/juce_core/native/juce_Threads_android.cpp similarity index 96% rename from modules/juce_core/native/juce_android_Threads.cpp rename to modules/juce_core/native/juce_Threads_android.cpp index fe6088553a98..68967499c182 100644 --- a/modules/juce_core/native/juce_android_Threads.cpp +++ b/modules/juce_core/native/juce_Threads_android.cpp @@ -448,6 +448,4 @@ JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {} JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {} - - } // namespace juce diff --git a/modules/juce_core/native/juce_linux_Threads.cpp b/modules/juce_core/native/juce_Threads_linux.cpp similarity index 100% rename from modules/juce_core/native/juce_linux_Threads.cpp rename to modules/juce_core/native/juce_Threads_linux.cpp diff --git a/modules/juce_core/native/juce_mac_Threads.mm b/modules/juce_core/native/juce_Threads_mac.mm similarity index 61% rename from modules/juce_core/native/juce_mac_Threads.mm rename to modules/juce_core/native/juce_Threads_mac.mm index 7c692be76871..77a7ab994085 100644 --- a/modules/juce_core/native/juce_mac_Threads.mm +++ b/modules/juce_core/native/juce_Threads_mac.mm @@ -64,28 +64,99 @@ static auto getJucePriority (qos_class_t qos) return Thread::Priority::normal; } +template +static std::optional firstOptionalWithValue (const std::initializer_list>& optionals) +{ + for (const auto& optional : optionals) + if (optional.has_value()) + return optional; + + return {}; +} + +static bool tryToUpgradeCurrentThreadToRealtime (const Thread::RealtimeOptions& options) +{ + const auto periodMs = options.getPeriodMs().value_or (0.0); + + const auto processingTimeMs = firstOptionalWithValue ( + { + options.getProcessingTimeMs(), + options.getMaximumProcessingTimeMs(), + options.getPeriodMs() + }).value_or (10.0); + + const auto maxProcessingTimeMs = options.getMaximumProcessingTimeMs() + .value_or (processingTimeMs); + + // The processing time can not exceed the maximum processing time! + jassert (maxProcessingTimeMs >= processingTimeMs); + + thread_time_constraint_policy_data_t policy; + policy.period = (uint32_t) Time::secondsToHighResolutionTicks (periodMs / 1'000.0); + policy.computation = (uint32_t) Time::secondsToHighResolutionTicks (processingTimeMs / 1'000.0); + policy.constraint = (uint32_t) Time::secondsToHighResolutionTicks (maxProcessingTimeMs / 1'000.0); + policy.preemptible = true; + + const auto result = thread_policy_set (pthread_mach_thread_np (pthread_self()), + THREAD_TIME_CONSTRAINT_POLICY, + (thread_policy_t) &policy, + THREAD_TIME_CONSTRAINT_POLICY_COUNT); + + if (result == KERN_SUCCESS) + return true; + + // testing has shown that passing a computation value > 50ms can + // lead to thread_policy_set returning an error indicating that an + // invalid argument was passed. If that happens this code tries to + // limit that value in the hope of resolving the issue. + + if (result == KERN_INVALID_ARGUMENT && options.getProcessingTimeMs() > 50.0) + return tryToUpgradeCurrentThreadToRealtime (options.withProcessingTimeMs (50.0)); + + return false; +} + bool Thread::createNativeThread (Priority priority) { - PosixThreadAttribute attr { threadStackSize }; + PosixThreadAttribute attribute { threadStackSize }; if (@available (macos 10.10, *)) - pthread_attr_set_qos_class_np (attr.get(), getNativeQOS (priority), 0); + pthread_attr_set_qos_class_np (attribute.get(), getNativeQOS (priority), 0); else - PosixSchedulerPriority::getNativeSchedulerAndPriority (realtimeOptions, priority).apply (attr); + PosixSchedulerPriority::getNativeSchedulerAndPriority (realtimeOptions, priority).apply (attribute); + + struct ThreadData + { + Thread& thread; + std::promise started{}; + }; + + ThreadData threadData { *this, {} }; - threadId = threadHandle = makeThreadHandle (attr, this, [] (void* userData) -> void* + threadId = threadHandle = makeThreadHandle (attribute, &threadData, [] (void* userData) -> void* { - auto* myself = static_cast (userData); + auto& data { *static_cast (userData) }; + auto& thread = data.thread; + + if (thread.isRealtime() + && ! tryToUpgradeCurrentThreadToRealtime (*thread.realtimeOptions)) + { + data.started.set_value (false); + return nullptr; + } + + data.started.set_value (true); JUCE_AUTORELEASEPOOL { - juce_threadEntryPoint (myself); + juce_threadEntryPoint (&thread); } return nullptr; }); - return threadId != nullptr; + return threadId != nullptr + && threadData.started.get_future().get(); } void Thread::killThread() @@ -122,30 +193,6 @@ static auto getJucePriority (qos_class_t qos) { jassert (Thread::getCurrentThreadId() == getThreadId()); - if (isRealtime()) - { - // macOS/iOS needs to know how much time you need! - jassert (realtimeOptions->workDurationMs > 0); - - mach_timebase_info_data_t timebase; - mach_timebase_info (&timebase); - - const auto periodMs = realtimeOptions->workDurationMs; - const auto ticksPerMs = ((double) timebase.denom * 1000000.0) / (double) timebase.numer; - const auto periodTicks = (uint32_t) jmin ((double) std::numeric_limits::max(), periodMs * ticksPerMs); - - thread_time_constraint_policy_data_t policy; - policy.period = periodTicks; - policy.computation = jmin ((uint32_t) 50000, policy.period); - policy.constraint = policy.period; - policy.preemptible = true; - - return thread_policy_set (pthread_mach_thread_np (pthread_self()), - THREAD_TIME_CONSTRAINT_POLICY, - (thread_policy_t) &policy, - THREAD_TIME_CONSTRAINT_POLICY_COUNT) == KERN_SUCCESS; - } - if (@available (macOS 10.10, *)) return pthread_set_qos_class_self_np (getNativeQOS (priority), 0) == 0; diff --git a/modules/juce_core/native/juce_win32_Threads.cpp b/modules/juce_core/native/juce_Threads_windows.cpp similarity index 100% rename from modules/juce_core/native/juce_win32_Threads.cpp rename to modules/juce_core/native/juce_Threads_windows.cpp diff --git a/modules/juce_core/network/juce_WebInputStream.cpp b/modules/juce_core/network/juce_WebInputStream.cpp index 1183c1bc728b..71b58311a5f2 100644 --- a/modules/juce_core/network/juce_WebInputStream.cpp +++ b/modules/juce_core/network/juce_WebInputStream.cpp @@ -61,11 +61,8 @@ StringPairArray WebInputStream::parseHttpHeaders (const String& headerData) StringPairArray headerPairs; auto headerLines = StringArray::fromLines (headerData); - // ignore the first line as this is the status line - for (int i = 1; i < headerLines.size(); ++i) + for (const auto& headersEntry : headerLines) { - const auto& headersEntry = headerLines[i]; - if (headersEntry.isNotEmpty()) { const auto key = headersEntry.upToFirstOccurrenceOf (": ", false, false); diff --git a/modules/juce_core/streams/juce_MemoryInputStream.cpp b/modules/juce_core/streams/juce_MemoryInputStream.cpp index 5e60dd612d8f..800646731e79 100644 --- a/modules/juce_core/streams/juce_MemoryInputStream.cpp +++ b/modules/juce_core/streams/juce_MemoryInputStream.cpp @@ -138,8 +138,8 @@ class MemoryStreamTests : public UnitTest expectEquals (mi.readString(), randomString); expect (mi.readInt64() == randomInt64); expect (mi.readInt64BigEndian() == randomInt64); - expect (mi.readDouble() == randomDouble); - expect (mi.readDoubleBigEndian() == randomDouble); + expectEquals (mi.readDouble(), randomDouble); + expectEquals (mi.readDoubleBigEndian(), randomDouble); const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26); MemoryInputStream stream (data, true); diff --git a/modules/juce_core/system/juce_CompilerWarnings.h b/modules/juce_core/system/juce_CompilerWarnings.h index 05845903f31f..e13af095d6c4 100644 --- a/modules/juce_core/system/juce_CompilerWarnings.h +++ b/modules/juce_core/system/juce_CompilerWarnings.h @@ -31,7 +31,8 @@ #define JUCE_NTH_ARG_(_00, _01, _02, _03, _04, _05, _06, _07, _08, _09, \ _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ - _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, N, ...)\ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \ + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, N, ...)\ N #define JUCE_EACH_00_(FN) @@ -74,10 +75,30 @@ #define JUCE_EACH_37_(FN, X, ...) FN(X) JUCE_EACH_36_(FN, __VA_ARGS__) #define JUCE_EACH_38_(FN, X, ...) FN(X) JUCE_EACH_37_(FN, __VA_ARGS__) #define JUCE_EACH_39_(FN, X, ...) FN(X) JUCE_EACH_38_(FN, __VA_ARGS__) +#define JUCE_EACH_40_(FN, X, ...) FN(X) JUCE_EACH_39_(FN, __VA_ARGS__) +#define JUCE_EACH_41_(FN, X, ...) FN(X) JUCE_EACH_40_(FN, __VA_ARGS__) +#define JUCE_EACH_42_(FN, X, ...) FN(X) JUCE_EACH_41_(FN, __VA_ARGS__) +#define JUCE_EACH_43_(FN, X, ...) FN(X) JUCE_EACH_42_(FN, __VA_ARGS__) +#define JUCE_EACH_44_(FN, X, ...) FN(X) JUCE_EACH_43_(FN, __VA_ARGS__) +#define JUCE_EACH_45_(FN, X, ...) FN(X) JUCE_EACH_44_(FN, __VA_ARGS__) +#define JUCE_EACH_46_(FN, X, ...) FN(X) JUCE_EACH_45_(FN, __VA_ARGS__) +#define JUCE_EACH_47_(FN, X, ...) FN(X) JUCE_EACH_46_(FN, __VA_ARGS__) +#define JUCE_EACH_48_(FN, X, ...) FN(X) JUCE_EACH_47_(FN, __VA_ARGS__) +#define JUCE_EACH_49_(FN, X, ...) FN(X) JUCE_EACH_48_(FN, __VA_ARGS__) /** Apply the macro FN to each of the other arguments. */ #define JUCE_EACH(FN, ...) \ JUCE_NTH_ARG_(, __VA_ARGS__, \ + JUCE_EACH_49_, \ + JUCE_EACH_48_, \ + JUCE_EACH_47_, \ + JUCE_EACH_46_, \ + JUCE_EACH_45_, \ + JUCE_EACH_44_, \ + JUCE_EACH_43_, \ + JUCE_EACH_42_, \ + JUCE_EACH_41_, \ + JUCE_EACH_40_, \ JUCE_EACH_39_, \ JUCE_EACH_38_, \ JUCE_EACH_37_, \ diff --git a/modules/juce_core/system/juce_StandardHeader.h b/modules/juce_core/system/juce_StandardHeader.h index 7a0714349caa..a7b2d350047d 100644 --- a/modules/juce_core/system/juce_StandardHeader.h +++ b/modules/juce_core/system/juce_StandardHeader.h @@ -29,7 +29,7 @@ */ #define JUCE_MAJOR_VERSION 7 #define JUCE_MINOR_VERSION 0 -#define JUCE_BUILDNUMBER 5 +#define JUCE_BUILDNUMBER 7 /** Current JUCE version number. @@ -72,6 +72,7 @@ #include #include #include +#include #include //============================================================================== diff --git a/modules/juce_core/system/juce_SystemStats.cpp b/modules/juce_core/system/juce_SystemStats.cpp index 8601bc084935..5f9b7526dca8 100644 --- a/modules/juce_core/system/juce_SystemStats.cpp +++ b/modules/juce_core/system/juce_SystemStats.cpp @@ -60,24 +60,64 @@ String SystemStats::getJUCEVersion() StringArray SystemStats::getDeviceIdentifiers() { - StringArray ids; + for (const auto flag : { MachineIdFlags::fileSystemId, MachineIdFlags::macAddresses }) + if (auto ids = getMachineIdentifiers (flag); ! ids.isEmpty()) + return ids; - #if JUCE_WINDOWS - File f (File::getSpecialLocation (File::windowsSystemDirectory)); - #else - File f ("~"); - #endif - if (auto num = f.getFileIdentifier()) + jassertfalse; // Failed to create any IDs! + return {}; +} + +String getLegacyUniqueDeviceID(); + +StringArray SystemStats::getMachineIdentifiers (MachineIdFlags flags) +{ + auto macAddressProvider = [] (StringArray& arr) { - ids.add (String::toHexString ((int64) num)); - } - else + for (const auto& mac : MACAddress::getAllAddresses()) + arr.add (mac.toString()); + }; + + auto fileSystemProvider = [] (StringArray& arr) { - for (auto& address : MACAddress::getAllAddresses()) - ids.add (address.toString()); + #if JUCE_WINDOWS + File f (File::getSpecialLocation (File::windowsSystemDirectory)); + #else + File f ("~"); + #endif + if (auto num = f.getFileIdentifier()) + arr.add (String::toHexString ((int64) num)); + }; + + auto legacyIdProvider = [] ([[maybe_unused]] StringArray& arr) + { + #if JUCE_WINDOWS + arr.add (getLegacyUniqueDeviceID()); + #endif + }; + + auto uniqueIdProvider = [] (StringArray& arr) + { + arr.add (getUniqueDeviceID()); + }; + + struct Provider { MachineIdFlags flag; void (*func) (StringArray&); }; + static const Provider providers[] = + { + { MachineIdFlags::macAddresses, macAddressProvider }, + { MachineIdFlags::fileSystemId, fileSystemProvider }, + { MachineIdFlags::legacyUniqueId, legacyIdProvider }, + { MachineIdFlags::uniqueId, uniqueIdProvider } + }; + + StringArray ids; + + for (const auto& provider : providers) + { + if (hasBitValueSet (flags, provider.flag)) + provider.func (ids); } - jassert (! ids.isEmpty()); // Failed to create any IDs! return ids; } @@ -177,7 +217,7 @@ String SystemStats::getStackBacktrace() auto frames = backtrace (stack, numElementsInArray (stack)); char** frameStrings = backtrace_symbols (stack, frames); - for (int i = 0; i < frames; ++i) + for (auto i = (decltype (frames)) 0; i < frames; ++i) result << frameStrings[i] << newLine; ::free (frameStrings); @@ -230,13 +270,8 @@ void SystemStats::setApplicationCrashHandler (CrashHandlerFunction handler) bool SystemStats::isRunningInAppExtensionSandbox() noexcept { #if JUCE_MAC || JUCE_IOS - static bool firstQuery = true; - static bool isRunningInAppSandbox = false; - - if (firstQuery) + static bool isRunningInAppSandbox = [&] { - firstQuery = false; - File bundle = File::getSpecialLocation (File::invokedExecutableFile).getParentDirectory(); #if JUCE_MAC @@ -244,8 +279,10 @@ bool SystemStats::isRunningInAppExtensionSandbox() noexcept #endif if (bundle.isDirectory()) - isRunningInAppSandbox = (bundle.getFileExtension() == ".appex"); - } + return bundle.getFileExtension() == ".appex"; + + return false; + }(); return isRunningInAppSandbox; #else diff --git a/modules/juce_core/system/juce_SystemStats.h b/modules/juce_core/system/juce_SystemStats.h index a80cc541de72..777ce65b7d8f 100644 --- a/modules/juce_core/system/juce_SystemStats.h +++ b/modules/juce_core/system/juce_SystemStats.h @@ -153,10 +153,41 @@ class JUCE_API SystemStats final changes. This ID will be invalidated by changes to the motherboard and CPU on non-mobile - platforms, or resetting an Android device. + platforms, or performing a system restore on an Android device. + + There are some extra caveats on iOS: The returned ID is unique to the vendor part of + your 'Bundle Identifier' and is stable for all associated apps. The key is invalidated + once all associated apps are uninstalled. This function can return an empty string + under certain conditions, for example, If the device has not been unlocked since a + restart. */ static String getUniqueDeviceID(); + /** Kinds of identifier that are passed to getMachineIdentifiers(). */ + enum class MachineIdFlags + { + macAddresses = 1 << 0, ///< All Mac addresses of the machine. + fileSystemId = 1 << 1, ///< The filesystem id of the user's home directory (or system directory on Windows). + legacyUniqueId = 1 << 2, ///< Only implemented on Windows. A hash of the full smbios table, may be unstable on certain machines. + uniqueId = 1 << 3, ///< The most stable kind of machine identifier. A good default to use. + }; + + /** Returns a list of strings that can be used to uniquely identify a machine. + + To get multiple kinds of identifier at once, you can combine flags using + bitwise-or, e.g. `uniqueId | legacyUniqueId`. + + If a particular kind of identifier isn't available, it will be omitted from + the StringArray of results, so passing `uniqueId | legacyUniqueId` + may return 0, 1, or 2 results, depending on the platform and whether any + errors are encountered. + + If you've previously generated a machine ID and just want to check it against + all possible identifiers, you can enable all of the flags and check whether + the stored identifier matches any of the results. + */ + static StringArray getMachineIdentifiers (MachineIdFlags flags); + //============================================================================== // CPU and memory information.. @@ -228,7 +259,7 @@ class JUCE_API SystemStats final /** A function type for use in setApplicationCrashHandler(). When called, its void* argument will contain platform-specific data about the crash. */ - using CrashHandlerFunction = void(*)(void*); + using CrashHandlerFunction = void (*) (void*); /** Sets up a global callback function that will be called if the application executes some kind of illegal instruction. @@ -243,6 +274,10 @@ class JUCE_API SystemStats final */ static bool isRunningInAppExtensionSandbox() noexcept; + #if JUCE_MAC + static bool isAppSandboxEnabled(); + #endif + //============================================================================== #ifndef DOXYGEN [[deprecated ("This method was spelt wrong! Please change your code to use getCpuSpeedInMegahertz instead.")]] @@ -254,4 +289,6 @@ class JUCE_API SystemStats final JUCE_DECLARE_NON_COPYABLE (SystemStats) }; +JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (SystemStats::MachineIdFlags) + } // namespace juce diff --git a/modules/juce_core/system/juce_TargetPlatform.h b/modules/juce_core/system/juce_TargetPlatform.h index a93c27967783..595027c41573 100644 --- a/modules/juce_core/system/juce_TargetPlatform.h +++ b/modules/juce_core/system/juce_TargetPlatform.h @@ -62,7 +62,7 @@ #elif defined (JUCE_ANDROID) #undef JUCE_ANDROID #define JUCE_ANDROID 1 -#elif defined (__FreeBSD__) || (__OpenBSD__) +#elif defined (__FreeBSD__) || defined (__OpenBSD__) #define JUCE_BSD 1 #elif defined (LINUX) || defined (__linux__) #define JUCE_LINUX 1 diff --git a/modules/juce_core/text/juce_CharacterFunctions.cpp b/modules/juce_core/text/juce_CharacterFunctions.cpp index f1b466ffbbc9..407e70a68811 100644 --- a/modules/juce_core/text/juce_CharacterFunctions.cpp +++ b/modules/juce_core/text/juce_CharacterFunctions.cpp @@ -134,7 +134,7 @@ double CharacterFunctions::mulexp10 (const double value, int exponent) noexcept if (exponent == 0) return value; - if (value == 0.0) + if (exactlyEqual (value, 0.0)) return 0; const bool negative = (exponent < 0); diff --git a/modules/juce_core/text/juce_String.cpp b/modules/juce_core/text/juce_String.cpp index 02c2c8f8a1e4..4675f1ec785c 100644 --- a/modules/juce_core/text/juce_String.cpp +++ b/modules/juce_core/text/juce_String.cpp @@ -2266,7 +2266,7 @@ static String serialiseDouble (double input) int intInput = (int) input; - if ((double) intInput == input) + if (exactlyEqual ((double) intInput, input)) return { input, 1 }; auto numberOfDecimalPlaces = [absInput] @@ -2567,16 +2567,16 @@ class StringTests : public UnitTest beginTest ("Numeric conversions"); expect (String().getIntValue() == 0); - expect (String().getDoubleValue() == 0.0); - expect (String().getFloatValue() == 0.0f); + expectEquals (String().getDoubleValue(), 0.0); + expectEquals (String().getFloatValue(), 0.0f); expect (s.getIntValue() == 12345678); expect (s.getLargeIntValue() == (int64) 12345678); - expect (s.getDoubleValue() == 12345678.0); - expect (s.getFloatValue() == 12345678.0f); + expectEquals (s.getDoubleValue(), 12345678.0); + expectEquals (s.getFloatValue(), 12345678.0f); expect (String (-1234).getIntValue() == -1234); expect (String ((int64) -1234).getLargeIntValue() == -1234); - expect (String (-1234.56).getDoubleValue() == -1234.56); - expect (String (-1234.56f).getFloatValue() == -1234.56f); + expectEquals (String (-1234.56).getDoubleValue(), -1234.56); + expectEquals (String (-1234.56f).getFloatValue(), -1234.56f); expect (String (std::numeric_limits::max()).getIntValue() == std::numeric_limits::max()); expect (String (std::numeric_limits::min()).getIntValue() == std::numeric_limits::min()); expect (String (std::numeric_limits::max()).getLargeIntValue() == std::numeric_limits::max()); diff --git a/modules/juce_core/text/juce_String.h b/modules/juce_core/text/juce_String.h index e24f79ba5f2c..f7f72906f0e8 100644 --- a/modules/juce_core/text/juce_String.h +++ b/modules/juce_core/text/juce_String.h @@ -1117,7 +1117,7 @@ class JUCE_API String final { jassert (numberOfSignificantFigures > 0); - if (number == 0) + if (exactlyEqual (number, DecimalType())) { if (numberOfSignificantFigures > 1) { diff --git a/modules/juce_core/threads/juce_HighResolutionTimer.cpp b/modules/juce_core/threads/juce_HighResolutionTimer.cpp index 28ca899d96d6..cec292233a35 100644 --- a/modules/juce_core/threads/juce_HighResolutionTimer.cpp +++ b/modules/juce_core/threads/juce_HighResolutionTimer.cpp @@ -23,98 +23,411 @@ namespace juce { -class HighResolutionTimer::Pimpl : public Thread +//============================================================================== +class HighResolutionTimer::Impl : private PlatformTimerListener { - using steady_clock = std::chrono::steady_clock; - using milliseconds = std::chrono::milliseconds; - public: - explicit Pimpl (HighResolutionTimer& ownerRef) - : Thread ("HighResolutionTimerThread"), - owner (ownerRef) - { - } - - using Thread::isThreadRunning; + explicit Impl (HighResolutionTimer& o) + : owner { o } {} - void start (int periodMs) + void startTimer (int newIntervalMs) { + shouldCancelCallbacks.store (true); + + const auto shouldWaitForPendingCallbacks = [&] { - const std::scoped_lock lk { mutex }; - periodMillis = periodMs; - nextTickTime = steady_clock::now() + milliseconds (periodMillis); - } + const std::scoped_lock lock { timerMutex }; - waitEvent.notify_one(); + if (timer.getIntervalMs() > 0) + timer.cancelTimer(); - if (! isThreadRunning()) - startThread (Thread::Priority::high); - } + jassert (timer.getIntervalMs() == 0); - void stop() - { - { - const std::scoped_lock lk { mutex }; - periodMillis = 0; - } + if (newIntervalMs > 0) + timer.startTimer (jmax (0, newIntervalMs)); - waitEvent.notify_one(); + return callbackThreadId != std::this_thread::get_id() + && timer.getIntervalMs() <= 0; + }(); + + if (shouldWaitForPendingCallbacks) + std::scoped_lock lock { callbackMutex }; + } - if (Thread::getCurrentThreadId() != getThreadId()) - stopThread (-1); + int getIntervalMs() const + { + const std::scoped_lock lock { timerMutex }; + return timer.getIntervalMs(); } - int getPeriod() const + bool isTimerRunning() const { - return periodMillis; + return getIntervalMs() > 0; } private: - void run() override + void onTimerExpired() final { - for (;;) - { - { - std::unique_lock lk { mutex }; + callbackThreadId.store (std::this_thread::get_id()); - if (waitEvent.wait_until (lk, nextTickTime, [this] { return periodMillis == 0; })) - break; + { + std::scoped_lock lock { callbackMutex }; - nextTickTime = steady_clock::now() + milliseconds (periodMillis); + if (isTimerRunning()) + { + try + { + owner.hiResTimerCallback(); + } + catch (...) + { + // Exceptions thrown in a timer callback won't be + // propagated to the main thread, it's best to find + // a way to avoid them if possible + jassertfalse; + } } - - owner.hiResTimerCallback(); } + + callbackThreadId.store ({}); } HighResolutionTimer& owner; - std::atomic periodMillis { 0 }; - steady_clock::time_point nextTickTime; - std::mutex mutex; - std::condition_variable waitEvent; + mutable std::mutex timerMutex; + std::mutex callbackMutex; + std::atomic callbackThreadId{}; + std::atomic shouldCancelCallbacks { false }; + PlatformTimer timer { *this }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Impl) + JUCE_DECLARE_NON_MOVEABLE (Impl) }; +//============================================================================== HighResolutionTimer::HighResolutionTimer() - : pimpl (new Pimpl (*this)) -{ -} + : impl (std::make_unique (*this)) {} HighResolutionTimer::~HighResolutionTimer() { + // You *must* call stopTimer from the derived class destructor to + // avoid data races on the timer's vtable + jassert (! isTimerRunning()); stopTimer(); } -void HighResolutionTimer::startTimer (int periodMs) +void HighResolutionTimer::startTimer (int newIntervalMs) { - pimpl->start (jmax (1, periodMs)); + impl->startTimer (newIntervalMs); } void HighResolutionTimer::stopTimer() { - pimpl->stop(); + impl->startTimer (0); } -bool HighResolutionTimer::isTimerRunning() const noexcept { return getTimerInterval() != 0; } -int HighResolutionTimer::getTimerInterval() const noexcept { return pimpl->getPeriod(); } +int HighResolutionTimer::getTimerInterval() const noexcept +{ + return impl->getIntervalMs(); +} + +bool HighResolutionTimer::isTimerRunning() const noexcept +{ + return impl->isTimerRunning(); +} + +//============================================================================== +#if JUCE_UNIT_TESTS + +class HighResolutionTimerTests : public UnitTest +{ +public: + HighResolutionTimerTests() + : UnitTest ("HighResolutionTimer", UnitTestCategories::threads) {} + + void runTest() override + { + constexpr int maximumTimeoutMs {30'000}; + + beginTest ("Start/stop a timer"); + { + WaitableEvent timerFiredOnce; + WaitableEvent timerFiredTwice; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: timerFiredOnce.signal(); return; + case 2: timerFiredTwice.signal(); return; + default: return; + } + }}; + + expect (! timer.isTimerRunning()); + expect (timer.getTimerInterval() == 0); + + timer.startTimer (1); + expect (timer.isTimerRunning()); + expect (timer.getTimerInterval() == 1); + expect (timerFiredOnce.wait (maximumTimeoutMs)); + expect (timerFiredTwice.wait (maximumTimeoutMs)); + + timer.stopTimer(); + expect (! timer.isTimerRunning()); + expect (timer.getTimerInterval() == 0); + } + + beginTest ("Stop a timer from the timer callback"); + { + WaitableEvent stoppedTimer; + + auto timerCallback = [&](Timer& timer) + { + expect (timer.isTimerRunning()); + timer.stopTimer(); + expect (! timer.isTimerRunning()); + stoppedTimer.signal(); + }; + + Timer timer {[&]{ timerCallback (timer); }}; + timer.startTimer (1); + expect (stoppedTimer.wait (maximumTimeoutMs)); + } + + beginTest ("Restart a timer from the timer callback"); + { + WaitableEvent restartTimer; + WaitableEvent timerRestarted; + WaitableEvent timerFiredAfterRestart; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + expect (restartTimer.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 1); + + timer.startTimer (2); + expect (timer.getTimerInterval() == 2); + timerRestarted.signal(); + return; + + case 2: + expect (timer.getTimerInterval() == 2); + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timer.getTimerInterval() == 1); + + restartTimer.signal(); + expect (timerRestarted.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 2); + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + + timer.stopTimer(); + } + + beginTest ("Calling stopTimer on a timer, waits for any timer callbacks to finish"); + { + WaitableEvent timerCallbackStarted; + WaitableEvent stoppingTimer; + std::atomic timerCallbackFinished { false }; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + timerCallbackStarted.signal(); + expect (stoppingTimer.wait (maximumTimeoutMs)); + Thread::sleep (10); + timerCallbackFinished = true; + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timerCallbackStarted.wait (maximumTimeoutMs)); + + stoppingTimer.signal(); + timer.stopTimer(); + expect (timerCallbackFinished); + } + + beginTest ("Calling stopTimer on a timer, waits for any timer callbacks to finish, even if the timer callback calls stopTimer first"); + { + WaitableEvent stoppedFromInsideTimerCallback; + WaitableEvent stoppingFromOutsideTimerCallback; + std::atomic timerCallbackFinished { false }; + + Timer timer {[&]() + { + timer.stopTimer(); + stoppedFromInsideTimerCallback.signal(); + expect (stoppingFromOutsideTimerCallback.wait (maximumTimeoutMs)); + Thread::sleep (10); + timerCallbackFinished = true; + + }}; + + timer.startTimer (1); + expect (stoppedFromInsideTimerCallback.wait (maximumTimeoutMs)); + + stoppingFromOutsideTimerCallback.signal(); + timer.stopTimer(); + expect (timerCallbackFinished); + } + + beginTest ("Adjusting a timer period from outside the timer callback doesn't cause data races"); + { + WaitableEvent timerCallbackStarted; + WaitableEvent timerRestarted; + WaitableEvent timerFiredAfterRestart; + std::atomic lastCallbackCount {0}; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + expect (timer.getTimerInterval() == 1); + timerCallbackStarted.signal(); + Thread::sleep (10); + lastCallbackCount = 1; + return; + + case 2: + expect (timerRestarted.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 2); + lastCallbackCount = 2; + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timerCallbackStarted.wait (maximumTimeoutMs)); + + timer.startTimer (2); + timerRestarted.signal(); + + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + expect (lastCallbackCount == 2); + + timer.stopTimer(); + expect (lastCallbackCount == 2); + } + + beginTest ("A timer can be restarted externally, after being stopped internally"); + { + WaitableEvent timerStopped; + WaitableEvent timerFiredAfterRestart; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + timer.stopTimer(); + timerStopped.signal(); + return; + + case 2: + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + expect (! timer.isTimerRunning()); + timer.startTimer (1); + expect (timer.isTimerRunning()); + + expect (timerStopped.wait (maximumTimeoutMs)); + expect (! timer.isTimerRunning()); + + timer.startTimer (1); + expect (timer.isTimerRunning()); + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + } + + beginTest ("Calls to `startTimer` and `getTimerInterval` succeed while a callback is blocked"); + { + WaitableEvent timerBlocked; + WaitableEvent unblockTimer; + + Timer timer {[&] + { + timerBlocked.signal(); + unblockTimer.wait(); + timer.stopTimer(); + }}; + + timer.startTimer (1); + timerBlocked.wait(); + + expect (timer.getTimerInterval() == 1); + timer.startTimer (2); + expect (timer.getTimerInterval() == 2); + + unblockTimer.signal(); + timer.stopTimer(); + } + + beginTest ("Stress test"); + { + constexpr auto maxNumTimers { 100 }; + + std::vector> timers; + timers.reserve (maxNumTimers); + + for (int i = 0; i < maxNumTimers; ++i) + { + auto timer = std::make_unique ([]{}); + timer->startTimer (1); + + if (! timer->isTimerRunning()) + break; + + timers.push_back (std::move (timer)); + } + + expect (timers.size() >= 16); + } + } + + class Timer : public HighResolutionTimer + { + public: + explicit Timer (std::function fn) + : callback (std::move (fn)) {} + + ~Timer() override { stopTimer(); } + + void hiResTimerCallback() override { callback(); } + + private: + std::function callback; + }; +}; + +static HighResolutionTimerTests highResolutionTimerTests; + +#endif } // namespace juce diff --git a/modules/juce_core/threads/juce_HighResolutionTimer.h b/modules/juce_core/threads/juce_HighResolutionTimer.h index 2ac6402a9341..37bd72d1c3d3 100644 --- a/modules/juce_core/threads/juce_HighResolutionTimer.h +++ b/modules/juce_core/threads/juce_HighResolutionTimer.h @@ -32,8 +32,8 @@ namespace juce You should only use this class in situations where you really need accuracy, because unlike the normal Timer class, which is very lightweight and cheap - to start/stop, the HighResolutionTimer will use far more resources, and - starting/stopping it may involve launching and killing threads. + the HighResolutionTimer will use far more resources and require thread + safety considerations. @see Timer @@ -57,20 +57,29 @@ class JUCE_API HighResolutionTimer This will be called on a dedicated timer thread, so make sure your implementation is thread-safe! + On some platforms the dedicated timer thread may be shared with + other HighResolutionTimer's so aim to complete any work in this + callback as fast as possible. + It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. + callback to change the subsequent intervals. However, if you call + stopTimer() in the callback it's still best practice to call stopTimer() + from the destructor in order to avoid data races. */ virtual void hiResTimerCallback() = 0; //============================================================================== /** Starts the timer and sets the length of interval required. - If the timer is already started, this will reset its counter, so the - time between calling this method and the next timer callback will not be - less than the interval length passed in. + If the timer has already started, this will reset the timer, so the + time between calling this method and the next timer callback + will not be less than the interval length passed in. + + In exceptional circumstances the dedicated timer thread may not start, + if this is a potential concern for your use case, you can call isTimerRunning() + to confirm if the timer actually started. - @param intervalInMilliseconds the interval to use (any values less than 1 will be - rounded up to 1) + @param intervalInMilliseconds the interval to use (a value of zero or less will stop the timer) */ void startTimer (int intervalInMilliseconds); @@ -79,6 +88,9 @@ class JUCE_API HighResolutionTimer This method may block while it waits for pending callbacks to complete. Once it returns, no more callbacks will be made. If it is called from the timer's own thread, it will cancel the timer after the current callback returns. + + To prevent data races it's normally best practice to call this in the derived classes + destructor, even if stopTimer() was called in the hiResTimerCallback(). */ void stopTimer(); @@ -93,8 +105,8 @@ class JUCE_API HighResolutionTimer int getTimerInterval() const noexcept; private: - class Pimpl; - std::unique_ptr pimpl; + class Impl; + std::unique_ptr impl; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HighResolutionTimer) }; diff --git a/modules/juce_core/threads/juce_Thread.cpp b/modules/juce_core/threads/juce_Thread.cpp index 5b870311c4d7..7136608803f2 100644 --- a/modules/juce_core/threads/juce_Thread.cpp +++ b/modules/juce_core/threads/juce_Thread.cpp @@ -166,7 +166,7 @@ bool Thread::startRealtimeThread (const RealtimeOptions& options) if (threadHandle == nullptr) { - realtimeOptions = makeOptional (options); + realtimeOptions = std::make_optional (options); if (startThreadInternal (Priority::normal)) return true; @@ -276,7 +276,7 @@ void Thread::removeListener (Listener* listener) bool Thread::isRealtime() const { - return realtimeOptions.hasValue(); + return realtimeOptions.has_value(); } void Thread::setAffinityMask (const uint32 newAffinityMask) @@ -285,7 +285,7 @@ void Thread::setAffinityMask (const uint32 newAffinityMask) } //============================================================================== -bool Thread::wait (const int timeOutMilliseconds) const +bool Thread::wait (double timeOutMilliseconds) const { return defaultEvent.wait (timeOutMilliseconds); } @@ -417,7 +417,7 @@ class AtomicTests : public UnitTest class AtomicTester { public: - AtomicTester() {} + AtomicTester() = default; static void testInteger (UnitTest& test) { @@ -460,17 +460,17 @@ class AtomicTests : public UnitTest /* These are some simple test cases to check the atomics - let me know if any of these assertions fail on your system! */ - test.expect (a.get() == (Type) 101); + test.expect (exactlyEqual (a.get(), (Type) 101)); test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200)); - test.expect (a.get() == (Type) 101); + test.expect (exactlyEqual (a.get(), (Type) 101)); test.expect (a.compareAndSetBool ((Type) 200, a.get())); - test.expect (a.get() == (Type) 200); + test.expect (exactlyEqual (a.get(), (Type) 200)); - test.expect (a.exchange ((Type) 300) == (Type) 200); - test.expect (a.get() == (Type) 300); + test.expect (exactlyEqual (a.exchange ((Type) 300), (Type) 200)); + test.expect (exactlyEqual (a.get(), (Type) 300)); b = a; - test.expect (b.get() == a.get()); + test.expect (exactlyEqual (b.get(), a.get())); } }; }; diff --git a/modules/juce_core/threads/juce_Thread.h b/modules/juce_core/threads/juce_Thread.h index 97b66ff6fbb8..94abaea6e941 100644 --- a/modules/juce_core/threads/juce_Thread.h +++ b/modules/juce_core/threads/juce_Thread.h @@ -42,6 +42,9 @@ namespace juce class JUCE_API Thread { public: + //============================================================================== + static constexpr size_t osDefaultStackSize { 0 }; + //============================================================================== /** The different runtime priorities of non-realtime threads. @@ -72,14 +75,114 @@ class JUCE_API Thread */ struct RealtimeOptions { - /** Linux only: A value with a range of 0-10, where 10 is the highest priority. */ - int priority = 5; + /** A value with a range of 0-10, where 10 is the highest priority. + + Currently only used by Posix platforms. + + @see getPriority + */ + [[nodiscard]] RealtimeOptions withPriority (int newPriority) const + { + jassert (isPositiveAndNotGreaterThan (newPriority, 10)); + return withMember (*this, &RealtimeOptions::priority, juce::jlimit (0, 10, newPriority)); + } + + /** Specify the expected amount of processing time required each time the thread wakes up. + + Only used by macOS/iOS. + + @see getProcessingTimeMs, withMaximumProcessingTimeMs, withPeriodMs, withPeriodHz + */ + [[nodiscard]] RealtimeOptions withProcessingTimeMs (double newProcessingTimeMs) const + { + jassert (newProcessingTimeMs > 0.0); + return withMember (*this, &RealtimeOptions::processingTimeMs, newProcessingTimeMs); + } + + /** Specify the maximum amount of processing time required each time the thread wakes up. + + Only used by macOS/iOS. + + @see getMaximumProcessingTimeMs, withProcessingTimeMs, withPeriodMs, withPeriodHz + */ + [[nodiscard]] RealtimeOptions withMaximumProcessingTimeMs (double newMaximumProcessingTimeMs) const + { + jassert (newMaximumProcessingTimeMs > 0.0); + return withMember (*this, &RealtimeOptions::maximumProcessingTimeMs, newMaximumProcessingTimeMs); + } + + /** Specify the approximate amount of time between each thread wake up. + + Alternatively call withPeriodHz(). + + Only used by macOS/iOS. + + @see getPeriodMs, withPeriodHz, withProcessingTimeMs, withMaximumProcessingTimeMs, + */ + [[nodiscard]] RealtimeOptions withPeriodMs (double newPeriodMs) const + { + jassert (newPeriodMs > 0.0); + return withMember (*this, &RealtimeOptions::periodMs, newPeriodMs); + } - /** iOS/macOS only: A millisecond value representing the estimated time between each - 'Thread::run' call. Your thread may be penalised if you frequently - overrun this. + /** Specify the approximate frequency at which the thread will be woken up. + + Alternatively call withPeriodMs(). + + Only used by macOS/iOS. + + @see getPeriodHz, withPeriodMs, withProcessingTimeMs, withMaximumProcessingTimeMs, + */ + [[nodiscard]] RealtimeOptions withPeriodHz (double newPeriodHz) const + { + jassert (newPeriodHz > 0.0); + return withPeriodMs (1'000.0 / newPeriodHz); + } + + /** Returns a value with a range of 0-10, where 10 is the highest priority. + + @see withPriority + */ + [[nodiscard]] int getPriority() const + { + return priority; + } + + /** Returns the expected amount of processing time required each time the thread + wakes up. + + @see withProcessingTimeMs, getMaximumProcessingTimeMs, getPeriodMs */ - uint32_t workDurationMs = 0; + [[nodiscard]] std::optional getProcessingTimeMs() const + { + return processingTimeMs; + } + + /** Returns the maximum amount of processing time required each time the thread + wakes up. + + @see withMaximumProcessingTimeMs, getProcessingTimeMs, getPeriodMs + */ + [[nodiscard]] std::optional getMaximumProcessingTimeMs() const + { + return maximumProcessingTimeMs; + } + + /** Returns the approximate amount of time between each thread wake up, or + nullopt if there is no inherent periodicity. + + @see withPeriodMs, withPeriodHz, getProcessingTimeMs, getMaximumProcessingTimeMs + */ + [[nodiscard]] std::optional getPeriodMs() const + { + return periodMs; + } + + private: + int priority { 5 }; + std::optional processingTimeMs; + std::optional maximumProcessingTimeMs; + std::optional periodMs{}; }; //============================================================================== @@ -95,7 +198,7 @@ class JUCE_API Thread is zero then the default stack size of the OS will be used. */ - explicit Thread (const String& threadName, size_t threadStackSize = 0); + explicit Thread (const String& threadName, size_t threadStackSize = osDefaultStackSize); /** Destructor. @@ -337,7 +440,7 @@ class JUCE_API Thread @returns true if the event has been signalled, false if the timeout expires. */ - bool wait (int timeOutMilliseconds) const; + bool wait (double timeOutMilliseconds) const; /** Wakes up the thread. @@ -461,7 +564,7 @@ class JUCE_API Thread const String threadName; std::atomic threadHandle { nullptr }; std::atomic threadId { nullptr }; - Optional realtimeOptions = {}; + std::optional realtimeOptions = {}; CriticalSection startStopLock; WaitableEvent startSuspensionEvent, defaultEvent; size_t threadStackSize; diff --git a/modules/juce_core/threads/juce_ThreadPool.cpp b/modules/juce_core/threads/juce_ThreadPool.cpp index 8639481de651..3d6a78913f21 100644 --- a/modules/juce_core/threads/juce_ThreadPool.cpp +++ b/modules/juce_core/threads/juce_ThreadPool.cpp @@ -25,8 +25,9 @@ namespace juce struct ThreadPool::ThreadPoolThread : public Thread { - ThreadPoolThread (ThreadPool& p, size_t stackSize) - : Thread ("Pool", stackSize), pool (p) + ThreadPoolThread (ThreadPool& p, const Options& options) + : Thread { options.threadName, options.threadStackSizeBytes }, + pool { p } { } @@ -93,18 +94,24 @@ ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob() } //============================================================================== -ThreadPool::ThreadPool (int numThreads, size_t threadStackSize, Thread::Priority priority) +ThreadPool::ThreadPool (const Options& options) { - jassert (numThreads > 0); // not much point having a pool without any threads! + // not much point having a pool without any threads! + jassert (options.numberOfThreads > 0); - for (int i = jmax (1, numThreads); --i >= 0;) - threads.add (new ThreadPoolThread (*this, threadStackSize)); + for (int i = jmax (1, options.numberOfThreads); --i >= 0;) + threads.add (new ThreadPoolThread (*this, options)); for (auto* t : threads) - t->startThread (priority); + t->startThread (options.desiredThreadPriority); } -ThreadPool::ThreadPool() : ThreadPool (SystemStats::getNumCpus(), 0, Thread::Priority::normal) +ThreadPool::ThreadPool (int numberOfThreads, + size_t threadStackSizeBytes, + Thread::Priority desiredThreadPriority) + : ThreadPool { Options{}.withNumberOfThreads (numberOfThreads) + .withThreadStackSizeBytes (threadStackSizeBytes) + .withDesiredThreadPriority (desiredThreadPriority) } { } @@ -162,13 +169,13 @@ void ThreadPool::addJob (std::function jobToRun) { struct LambdaJobWrapper : public ThreadPoolJob { - LambdaJobWrapper (std::function j) : ThreadPoolJob ("lambda"), job (j) {} + LambdaJobWrapper (std::function j) : ThreadPoolJob ("lambda"), job (std::move (j)) {} JobStatus runJob() override { job(); return ThreadPoolJob::jobHasFinished; } std::function job; }; - addJob (new LambdaJobWrapper (jobToRun), true); + addJob (new LambdaJobWrapper (std::move (jobToRun)), true); } int ThreadPool::getNumJobs() const noexcept diff --git a/modules/juce_core/threads/juce_ThreadPool.h b/modules/juce_core/threads/juce_ThreadPool.h index 779b1d02fe76..668c6423223b 100644 --- a/modules/juce_core/threads/juce_ThreadPool.h +++ b/modules/juce_core/threads/juce_ThreadPool.h @@ -140,6 +140,51 @@ class JUCE_API ThreadPoolJob JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob) }; +//============================================================================== +/** + A set of threads that will run a list of jobs. + + When a ThreadPoolJob object is added to the ThreadPool's list, its runJob() method + will be called by the next pooled thread that becomes free. + + @see ThreadPoolJob, Thread + + @tags{Core} +*/ +struct ThreadPoolOptions +{ + /** The name to give each thread in the pool. */ + [[nodiscard]] ThreadPoolOptions withThreadName (String newThreadName) const + { + return withMember (*this, &ThreadPoolOptions::threadName, newThreadName); + } + + /** The number of threads to run. + These will be started when a pool is created, and run until the pool is destroyed. + */ + [[nodiscard]] ThreadPoolOptions withNumberOfThreads (int newNumberOfThreads) const + { + return withMember (*this, &ThreadPoolOptions::numberOfThreads, newNumberOfThreads); + } + + /** The size of the stack of each thread in the pool. */ + [[nodiscard]] ThreadPoolOptions withThreadStackSizeBytes (size_t newThreadStackSizeBytes) const + { + return withMember (*this, &ThreadPoolOptions::threadStackSizeBytes, newThreadStackSizeBytes); + } + + /** The desired priority of each thread in the pool. */ + [[nodiscard]] ThreadPoolOptions withDesiredThreadPriority (Thread::Priority newDesiredThreadPriority) const + { + return withMember (*this, &ThreadPoolOptions::desiredThreadPriority, newDesiredThreadPriority); + } + + String threadName { "Pool" }; + int numberOfThreads { SystemStats::getNumCpus() }; + size_t threadStackSizeBytes { Thread::osDefaultStackSize }; + Thread::Priority desiredThreadPriority { Thread::Priority::normal }; +}; + //============================================================================== /** @@ -155,26 +200,38 @@ class JUCE_API ThreadPoolJob class JUCE_API ThreadPool { public: + using Options = ThreadPoolOptions; + //============================================================================== - /** Creates a thread pool. + /** Creates a thread pool based on the provided options. + Once you've created a pool, you can give it some jobs by calling addJob(). + + @see ThreadPool::ThreadPoolOptions + */ + explicit ThreadPool (const Options& options); + + /** Creates a thread pool based using the default arguments provided by + ThreadPoolOptions. + Once you've created a pool, you can give it some jobs by calling addJob(). - @param numberOfThreads the number of threads to run. These will be started - immediately, and will run until the pool is deleted. - @param threadStackSize the size of the stack of each thread. If this value - is zero then the default stack size of the OS will - be used. - @param priority the desired priority of each thread in the pool. + @see ThreadPoolOptions */ - ThreadPool (int numberOfThreads, size_t threadStackSize = 0, Thread::Priority priority = Thread::Priority::normal); + ThreadPool() : ThreadPool { Options{} } {} - /** Creates a thread pool with one thread per CPU core. + /** Creates a thread pool. Once you've created a pool, you can give it some jobs by calling addJob(). - If you want to specify the number of threads, use the other constructor; this - one creates a pool which has one thread for each CPU core. - @see SystemStats::getNumCpus() + + @param numberOfThreads the number of threads to run. These will be started + immediately, and will run until the pool is deleted. + @param threadStackSizeBytes the size of the stack of each thread. If this value + is zero then the default stack size of the OS will + be used. + @param desiredThreadPriority the desired priority of each thread in the pool. */ - ThreadPool(); + ThreadPool (int numberOfThreads, + size_t threadStackSizeBytes = Thread::osDefaultStackSize, + Thread::Priority desiredThreadPriority = Thread::Priority::normal); /** Destructor. diff --git a/modules/juce_core/threads/juce_WaitableEvent.cpp b/modules/juce_core/threads/juce_WaitableEvent.cpp index 14323707b2b1..f2b29ab0503b 100644 --- a/modules/juce_core/threads/juce_WaitableEvent.cpp +++ b/modules/juce_core/threads/juce_WaitableEvent.cpp @@ -28,19 +28,19 @@ WaitableEvent::WaitableEvent (bool manualReset) noexcept { } -bool WaitableEvent::wait (int timeOutMilliseconds) const +bool WaitableEvent::wait (double timeOutMilliseconds) const { std::unique_lock lock (mutex); if (! triggered) { - if (timeOutMilliseconds < 0) + if (timeOutMilliseconds < 0.0) { condition.wait (lock, [this] { return triggered == true; }); } else { - if (! condition.wait_for (lock, std::chrono::milliseconds (timeOutMilliseconds), + if (! condition.wait_for (lock, std::chrono::duration { timeOutMilliseconds }, [this] { return triggered == true; })) { return false; diff --git a/modules/juce_core/threads/juce_WaitableEvent.h b/modules/juce_core/threads/juce_WaitableEvent.h index 406ad74ccdbe..ca55f904b162 100644 --- a/modules/juce_core/threads/juce_WaitableEvent.h +++ b/modules/juce_core/threads/juce_WaitableEvent.h @@ -61,7 +61,7 @@ class JUCE_API WaitableEvent @returns true if the object has been signalled, false if the timeout expires first. @see signal, reset */ - bool wait (int timeOutMilliseconds = -1) const; + bool wait (double timeOutMilliseconds = -1.0) const; /** Wakes up any threads that are currently waiting on this object. diff --git a/modules/juce_core/time/juce_RelativeTime.cpp b/modules/juce_core/time/juce_RelativeTime.cpp index 60b1a1e9a578..bd8c233d8631 100644 --- a/modules/juce_core/time/juce_RelativeTime.cpp +++ b/modules/juce_core/time/juce_RelativeTime.cpp @@ -54,8 +54,16 @@ RelativeTime RelativeTime::operator-= (double secs) noexcept { numSeconds JUCE_API RelativeTime JUCE_CALLTYPE operator+ (RelativeTime t1, RelativeTime t2) noexcept { return t1 += t2; } JUCE_API RelativeTime JUCE_CALLTYPE operator- (RelativeTime t1, RelativeTime t2) noexcept { return t1 -= t2; } -JUCE_API bool JUCE_CALLTYPE operator== (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() == t2.inSeconds(); } -JUCE_API bool JUCE_CALLTYPE operator!= (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() != t2.inSeconds(); } +JUCE_API bool JUCE_CALLTYPE operator== (RelativeTime t1, RelativeTime t2) noexcept +{ + return exactlyEqual (t1.inSeconds(), t2.inSeconds()); +} + +JUCE_API bool JUCE_CALLTYPE operator!= (RelativeTime t1, RelativeTime t2) noexcept +{ + return ! (t1 == t2); +} + JUCE_API bool JUCE_CALLTYPE operator> (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() > t2.inSeconds(); } JUCE_API bool JUCE_CALLTYPE operator< (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() < t2.inSeconds(); } JUCE_API bool JUCE_CALLTYPE operator>= (RelativeTime t1, RelativeTime t2) noexcept { return t1.inSeconds() >= t2.inSeconds(); } diff --git a/modules/juce_core/unit_tests/juce_UnitTest.h b/modules/juce_core/unit_tests/juce_UnitTest.h index 1685f5bcf088..96c5fb884c3b 100644 --- a/modules/juce_core/unit_tests/juce_UnitTest.h +++ b/modules/juce_core/unit_tests/juce_UnitTest.h @@ -150,7 +150,7 @@ class JUCE_API UnitTest template void expectEquals (ValueType actual, ValueType expected, String failureMessage = String()) { - bool result = actual == expected; + bool result = exactlyEqual (actual, expected); expectResultAndPrint (actual, expected, result, "", failureMessage); } @@ -160,7 +160,7 @@ class JUCE_API UnitTest template void expectNotEquals (ValueType value, ValueType valueToCompareTo, String failureMessage = String()) { - bool result = value != valueToCompareTo; + bool result = ! exactlyEqual (value, valueToCompareTo); expectResultAndPrint (value, valueToCompareTo, result, "unequal to", failureMessage); } diff --git a/modules/juce_cryptography/juce_cryptography.h b/modules/juce_cryptography/juce_cryptography.h index 8373b1464d41..807d0c2d665c 100644 --- a/modules/juce_cryptography/juce_cryptography.h +++ b/modules/juce_cryptography/juce_cryptography.h @@ -35,7 +35,7 @@ ID: juce_cryptography vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE cryptography classes description: Classes for various basic cryptography functions, including RSA, Blowfish, MD5, SHA, etc. website: http://www.juce.com/juce diff --git a/modules/juce_data_structures/juce_data_structures.h b/modules/juce_data_structures/juce_data_structures.h index 4f9ebdf0245e..a39fb1ea49dc 100644 --- a/modules/juce_data_structures/juce_data_structures.h +++ b/modules/juce_data_structures/juce_data_structures.h @@ -35,7 +35,7 @@ ID: juce_data_structures vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE data model helper classes description: Classes for undo/redo management, and smart data structures. website: http://www.juce.com/juce diff --git a/modules/juce_data_structures/values/juce_CachedValue.h b/modules/juce_data_structures/values/juce_CachedValue.h index 0ce17a863be1..11f870b90548 100644 --- a/modules/juce_data_structures/values/juce_CachedValue.h +++ b/modules/juce_data_structures/values/juce_CachedValue.h @@ -116,13 +116,18 @@ class CachedValue : private ValueTree::Listener is equal to other. */ template - bool operator== (const OtherType& other) const { return cachedValue == other; } + bool operator== (const OtherType& other) const + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wfloat-equal") + return cachedValue == other; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } /** Returns true if the current value of the property (or the fallback value) is not equal to other. */ template - bool operator!= (const OtherType& other) const { return cachedValue != other; } + bool operator!= (const OtherType& other) const { return ! operator== (other); } //============================================================================== /** Returns the current property as a Value object. */ @@ -245,7 +250,7 @@ inline CachedValue& CachedValue::operator= (const Type& newValue) template inline void CachedValue::setValue (const Type& newValue, UndoManager* undoManagerToUse) { - if (cachedValue != newValue || isUsingDefault()) + if (! exactlyEqual (cachedValue, newValue) || isUsingDefault()) { cachedValue = newValue; targetTree.setProperty (targetProperty, VariantConverter::toVar (newValue), undoManagerToUse); diff --git a/modules/juce_dsp/containers/juce_AudioBlock_test.cpp b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp index 17ffad601f8c..bfd2f8aa486a 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock_test.cpp +++ b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp @@ -28,6 +28,9 @@ namespace juce namespace dsp { +template +String& operator<< (String& str, SIMDRegister) { return str; } + template class AudioBlockUnitTests : public UnitTest { @@ -79,25 +82,25 @@ class AudioBlockUnitTests : public UnitTest resetBlocks(); expect (block != otherBlock); - expect (block.getSample (0, 0) == SampleType (1.0)); - expect (block.getSample (0, 4) == SampleType (5.0)); - expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); - expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); + expectEquals (block.getSample (0, 0), SampleType (1.0)); + expectEquals (block.getSample (0, 4), SampleType (5.0)); + expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0)); + expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0)); block.swap (otherBlock); expect (block != otherBlock); - expect (otherBlock.getSample (0, 0) == SampleType (1.0)); - expect (otherBlock.getSample (0, 4) == SampleType (5.0)); - expect (block.getSample (0, 0) == SampleType (-1.0)); - expect (block.getSample (0, 3) == SampleType (-4.0)); + expectEquals (otherBlock.getSample (0, 0), SampleType (1.0)); + expectEquals (otherBlock.getSample (0, 4), SampleType (5.0)); + expectEquals (block.getSample (0, 0), SampleType (-1.0)); + expectEquals (block.getSample (0, 3), SampleType (-4.0)); block.swap (otherBlock); - expect (block.getSample (0, 0) == SampleType (1.0)); - expect (block.getSample (0, 4) == SampleType (5.0)); - expect (otherBlock.getSample (0, 0) == SampleType (-1.0)); - expect (otherBlock.getSample (0, 3) == SampleType (-4.0)); + expectEquals (block.getSample (0, 0), SampleType (1.0)); + expectEquals (block.getSample (0, 4), SampleType (5.0)); + expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0)); + expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0)); } beginTest ("Getters and setters"); @@ -107,49 +110,49 @@ class AudioBlockUnitTests : public UnitTest expectEquals ((int) block.getNumChannels(), (int) data.size()); expectEquals ((int) block.getNumSamples(), numSamples); - expect (block.getChannelPointer (0)[2] == SampleType (3.0)); + expectEquals (block.getChannelPointer (0)[2], SampleType (3.0)); block.getChannelPointer (0)[2] = SampleType (999.0); - expect (block.getChannelPointer (0)[2] == SampleType (999.0)); + expectEquals (block.getChannelPointer (0)[2], SampleType (999.0)); - expect (block.getSample (0, 4) == SampleType (5.0)); - expect (block.getSample (1, 4) == SampleType (11.0)); + expectEquals (block.getSample (0, 4), SampleType (5.0)); + expectEquals (block.getSample (1, 4), SampleType (11.0)); - expect (block.getSingleChannelBlock (1).getSample (0, 3) == block.getSample (1, 3)); + expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3)); - expect (block.getSubsetChannelBlock (0, 2).getSample (1, 3) == block.getSample (1, 3)); - expect (block.getSubsetChannelBlock (1, 1).getSample (0, 3) == block.getSample (1, 3)); + expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3)); + expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3)); block.setSample (1, 1, SampleType (777.0)); - expect (block.getSample (1, 1) == SampleType (777.0)); + expectEquals (block.getSample (1, 1), SampleType (777.0)); block.addSample (1, 1, SampleType (1.0)); - expect (block.getSample (1, 1) == SampleType (778.0)); + expectEquals (block.getSample (1, 1), SampleType (778.0)); } beginTest ("Basic copying"); { block.clear(); - expect (block.getSample (0, 2) == SampleType (0.0)); - expect (block.getSample (1, 4) == SampleType (0.0)); + expectEquals (block.getSample (0, 2), SampleType (0.0)); + expectEquals (block.getSample (1, 4), SampleType (0.0)); block.fill ((NumericType) 456.0); - expect (block.getSample (0, 2) == SampleType (456.0)); - expect (block.getSample (1, 4) == SampleType (456.0)); + expectEquals (block.getSample (0, 2), SampleType (456.0)); + expectEquals (block.getSample (1, 4), SampleType (456.0)); block.copyFrom (otherBlock); expect (block != otherBlock); - expect (block.getSample (0, 2) == otherBlock.getSample (0, 2)); - expect (block.getSample (1, 4) == otherBlock.getSample (1, 4)); + expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2)); + expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4)); resetBlocks(); SampleType testSample1 = block.getSample (0, 2); SampleType testSample2 = block.getSample (1, 3); - expect (testSample1 != block.getSample (0, 4)); - expect (testSample2 != block.getSample (1, 5)); + expectNotEquals (testSample1, block.getSample (0, 4)); + expectNotEquals (testSample2, block.getSample (1, 5)); block.move (0, 2); - expect (block.getSample (0, 4) == testSample1); - expect (block.getSample (1, 5) == testSample2); + expectEquals (block.getSample (0, 4), testSample1); + expectEquals (block.getSample (1, 5), testSample2); } beginTest ("Addition"); @@ -157,22 +160,22 @@ class AudioBlockUnitTests : public UnitTest resetBlocks(); block.add ((NumericType) 15.0); - expect (block.getSample (0, 4) == SampleType (20.0)); - expect (block.getSample (1, 4) == SampleType (26.0)); + expectEquals (block.getSample (0, 4), SampleType (20.0)); + expectEquals (block.getSample (1, 4), SampleType (26.0)); block.add (otherBlock); - expect (block.getSample (0, 4) == SampleType (15.0)); - expect (block.getSample (1, 4) == SampleType (15.0)); + expectEquals (block.getSample (0, 4), SampleType (15.0)); + expectEquals (block.getSample (1, 4), SampleType (15.0)); block.replaceWithSumOf (otherBlock, (NumericType) 9.0); - expect (block.getSample (0, 4) == SampleType (4.0)); - expect (block.getSample (1, 4) == SampleType (-2.0)); + expectEquals (block.getSample (0, 4), SampleType (4.0)); + expectEquals (block.getSample (1, 4), SampleType (-2.0)); resetBlocks(); block.replaceWithSumOf (block, otherBlock); - expect (block.getSample (0, 4) == SampleType (0.0)); - expect (block.getSample (1, 4) == SampleType (0.0)); + expectEquals (block.getSample (0, 4), SampleType (0.0)); + expectEquals (block.getSample (1, 4), SampleType (0.0)); } beginTest ("Subtraction"); @@ -180,22 +183,22 @@ class AudioBlockUnitTests : public UnitTest resetBlocks(); block.subtract ((NumericType) 15.0); - expect (block.getSample (0, 4) == SampleType (-10.0)); - expect (block.getSample (1, 4) == SampleType (-4.0)); + expectEquals (block.getSample (0, 4), SampleType (-10.0)); + expectEquals (block.getSample (1, 4), SampleType (-4.0)); block.subtract (otherBlock); - expect (block.getSample (0, 4) == SampleType (-5.0)); - expect (block.getSample (1, 4) == SampleType (7.0)); + expectEquals (block.getSample (0, 4), SampleType (-5.0)); + expectEquals (block.getSample (1, 4), SampleType (7.0)); block.replaceWithDifferenceOf (otherBlock, (NumericType) 9.0); - expect (block.getSample (0, 4) == SampleType (-14.0)); - expect (block.getSample (1, 4) == SampleType (-20.0)); + expectEquals (block.getSample (0, 4), SampleType (-14.0)); + expectEquals (block.getSample (1, 4), SampleType (-20.0)); resetBlocks(); block.replaceWithDifferenceOf (block, otherBlock); - expect (block.getSample (0, 4) == SampleType (10.0)); - expect (block.getSample (1, 4) == SampleType (22.0)); + expectEquals (block.getSample (0, 4), SampleType (10.0)); + expectEquals (block.getSample (1, 4), SampleType (22.0)); } beginTest ("Multiplication"); @@ -203,22 +206,22 @@ class AudioBlockUnitTests : public UnitTest resetBlocks(); block.multiplyBy ((NumericType) 10.0); - expect (block.getSample (0, 4) == SampleType (50.0)); - expect (block.getSample (1, 4) == SampleType (110.0)); + expectEquals (block.getSample (0, 4), SampleType (50.0)); + expectEquals (block.getSample (1, 4), SampleType (110.0)); block.multiplyBy (otherBlock); - expect (block.getSample (0, 4) == SampleType (-250.0)); - expect (block.getSample (1, 4) == SampleType (-1210.0)); + expectEquals (block.getSample (0, 4), SampleType (-250.0)); + expectEquals (block.getSample (1, 4), SampleType (-1210.0)); block.replaceWithProductOf (otherBlock, (NumericType) 3.0); - expect (block.getSample (0, 4) == SampleType (-15.0)); - expect (block.getSample (1, 4) == SampleType (-33.0)); + expectEquals (block.getSample (0, 4), SampleType (-15.0)); + expectEquals (block.getSample (1, 4), SampleType (-33.0)); resetBlocks(); block.replaceWithProductOf (block, otherBlock); - expect (block.getSample (0, 4) == SampleType (-25.0)); - expect (block.getSample (1, 4) == SampleType (-121.0)); + expectEquals (block.getSample (0, 4), SampleType (-25.0)); + expectEquals (block.getSample (1, 4), SampleType (-121.0)); } beginTest ("Multiply add"); @@ -226,12 +229,12 @@ class AudioBlockUnitTests : public UnitTest resetBlocks(); block.addProductOf (otherBlock, (NumericType) -1.0); - expect (block.getSample (0, 4) == SampleType (10.0)); - expect (block.getSample (1, 4) == SampleType (22.0)); + expectEquals (block.getSample (0, 4), SampleType (10.0)); + expectEquals (block.getSample (1, 4), SampleType (22.0)); block.addProductOf (otherBlock, otherBlock); - expect (block.getSample (0, 4) == SampleType (35.0)); - expect (block.getSample (1, 4) == SampleType (143.0)); + expectEquals (block.getSample (0, 4), SampleType (35.0)); + expectEquals (block.getSample (1, 4), SampleType (143.0)); } beginTest ("Negative abs min max"); @@ -240,68 +243,68 @@ class AudioBlockUnitTests : public UnitTest otherBlock.negate(); block.add (otherBlock); - expect (block.getSample (0, 4) == SampleType (10.0)); - expect (block.getSample (1, 4) == SampleType (22.0)); + expectEquals (block.getSample (0, 4), SampleType (10.0)); + expectEquals (block.getSample (1, 4), SampleType (22.0)); block.replaceWithNegativeOf (otherBlock); - expect (block.getSample (0, 4) == SampleType (-5.0)); - expect (block.getSample (1, 4) == SampleType (-11.0)); + expectEquals (block.getSample (0, 4), SampleType (-5.0)); + expectEquals (block.getSample (1, 4), SampleType (-11.0)); block.clear(); otherBlock.negate(); block.replaceWithAbsoluteValueOf (otherBlock); - expect (block.getSample (0, 4) == SampleType (5.0)); - expect (block.getSample (1, 4) == SampleType (11.0)); + expectEquals (block.getSample (0, 4), SampleType (5.0)); + expectEquals (block.getSample (1, 4), SampleType (11.0)); resetBlocks(); block.replaceWithMinOf (block, otherBlock); - expect (block.getSample (0, 4) == SampleType (-5.0)); - expect (block.getSample (1, 4) == SampleType (-11.0)); + expectEquals (block.getSample (0, 4), SampleType (-5.0)); + expectEquals (block.getSample (1, 4), SampleType (-11.0)); resetBlocks(); block.replaceWithMaxOf (block, otherBlock); - expect (block.getSample (0, 4) == SampleType (5.0)); - expect (block.getSample (1, 4) == SampleType (11.0)); + expectEquals (block.getSample (0, 4), SampleType (5.0)); + expectEquals (block.getSample (1, 4), SampleType (11.0)); resetBlocks(); auto range = block.findMinAndMax(); - expect (SampleType (range.getStart()) == SampleType (1.0)); - expect (SampleType (range.getEnd()) == SampleType (12.0)); + expectEquals (SampleType (range.getStart()), SampleType (1.0)); + expectEquals (SampleType (range.getEnd()), SampleType (12.0)); } beginTest ("Operators"); { resetBlocks(); block += (NumericType) 10.0; - expect (block.getSample (0, 4) == SampleType (15.0)); - expect (block.getSample (1, 4) == SampleType (21.0)); + expectEquals (block.getSample (0, 4), SampleType (15.0)); + expectEquals (block.getSample (1, 4), SampleType (21.0)); block += otherBlock; - expect (block.getSample (0, 4) == SampleType (10.0)); - expect (block.getSample (1, 4) == SampleType (10.0)); + expectEquals (block.getSample (0, 4), SampleType (10.0)); + expectEquals (block.getSample (1, 4), SampleType (10.0)); resetBlocks(); block -= (NumericType) 10.0; - expect (block.getSample (0, 4) == SampleType (-5.0)); - expect (block.getSample (1, 4) == SampleType (1.0)); + expectEquals (block.getSample (0, 4), SampleType (-5.0)); + expectEquals (block.getSample (1, 4), SampleType (1.0)); block -= otherBlock; - expect (block.getSample (0, 4) == SampleType (0.0)); - expect (block.getSample (1, 4) == SampleType (12.0)); + expectEquals (block.getSample (0, 4), SampleType (0.0)); + expectEquals (block.getSample (1, 4), SampleType (12.0)); resetBlocks(); block *= (NumericType) 10.0; - expect (block.getSample (0, 4) == SampleType (50.0)); - expect (block.getSample (1, 4) == SampleType (110.0)); + expectEquals (block.getSample (0, 4), SampleType (50.0)); + expectEquals (block.getSample (1, 4), SampleType (110.0)); block *= otherBlock; - expect (block.getSample (0, 4) == SampleType (-250.0)); - expect (block.getSample (1, 4) == SampleType (-1210.0)); + expectEquals (block.getSample (0, 4), SampleType (-250.0)); + expectEquals (block.getSample (1, 4), SampleType (-1210.0)); } beginTest ("Process"); { resetBlocks(); AudioBlock::process (block, otherBlock, [] (SampleType x) { return x + (NumericType) 1.0; }); - expect (otherBlock.getSample (0, 4) == SampleType (6.0)); - expect (otherBlock.getSample (1, 4) == SampleType (12.0)); + expectEquals (otherBlock.getSample (0, 4), SampleType (6.0)); + expectEquals (otherBlock.getSample (1, 4), SampleType (12.0)); } beginTest ("Copying"); diff --git a/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp b/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp index a8881fcb7740..7b2bcbc5061f 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp +++ b/modules/juce_dsp/containers/juce_SIMDRegister_test.cpp @@ -117,19 +117,12 @@ class SIMDRegisterUnitTests : public UnitTest template static bool allValuesEqualTo (const SIMDRegister& vec, const type scalar) { - #ifdef _MSC_VER - __declspec(align(sizeof (SIMDRegister))) type elements[SIMDRegister::SIMDNumElements]; - #else - type elements[SIMDRegister::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister)))); - #endif + alignas (sizeof (SIMDRegister)) type elements[SIMDRegister::SIMDNumElements]; vec.copyToRawArray (elements); // as we do not want to rely on the access operator we cast this to a primitive pointer - for (size_t i = 0; i < SIMDRegister::SIMDNumElements; ++i) - if (elements[i] != scalar) return false; - - return true; + return std::all_of (std::begin (elements), std::end (elements), [scalar] (const auto x) { return exactlyEqual (x, scalar); }); } template @@ -307,7 +300,7 @@ class SIMDRegisterUnitTests : public UnitTest const SIMDRegister& b = a; for (size_t i = 0; i < SIMDRegister::SIMDNumElements; ++i) - u.expect (b[i] == array[i]); + u.expect (exactlyEqual (b[i], array[i])); } }; @@ -539,8 +532,8 @@ class SIMDRegisterUnitTests : public UnitTest // do check for (size_t j = 0; j < SIMDRegister::SIMDNumElements; ++j) { - array_eq [j] = (array_a[j] == array_b[j]) ? static_cast (-1) : 0; - array_neq [j] = (array_a[j] != array_b[j]) ? static_cast (-1) : 0; + array_eq [j] = ( exactlyEqual (array_a[j], array_b[j])) ? static_cast (-1) : 0; + array_neq [j] = (! exactlyEqual (array_a[j], array_b[j])) ? static_cast (-1) : 0; array_lt [j] = (array_a[j] < array_b[j]) ? static_cast (-1) : 0; array_le [j] = (array_a[j] <= array_b[j]) ? static_cast (-1) : 0; array_gt [j] = (array_a[j] > array_b[j]) ? static_cast (-1) : 0; diff --git a/modules/juce_dsp/filter_design/juce_FilterDesign.cpp b/modules/juce_dsp/filter_design/juce_FilterDesign.cpp index efea14d27218..5bd99b798c70 100644 --- a/modules/juce_dsp/filter_design/juce_FilterDesign.cpp +++ b/modules/juce_dsp/filter_design/juce_FilterDesign.cpp @@ -145,6 +145,11 @@ typename FIR::Coefficients::Ptr auto* result = new typename FIR::Coefficients (static_cast (N)); auto* c = result->getRawCoefficients(); + auto sinc = [] (double x) + { + return approximatelyEqual (x, 0.0) ? 1 : std::sin (x * MathConstants::pi) / (MathConstants::pi * x); + }; + if (N % 2 == 1) { // Type I @@ -153,9 +158,6 @@ typename FIR::Coefficients::Ptr Matrix b (M + 1, 1), q (2 * M + 1, 1); - auto sinc = [] (double x) { return x == 0 ? 1 : std::sin (x * MathConstants::pi) - / (MathConstants::pi * x); }; - auto factorp = wp / MathConstants::pi; auto factors = ws / MathConstants::pi; @@ -191,9 +193,6 @@ typename FIR::Coefficients::Ptr Matrix qp (2 * M, 1); Matrix qs (2 * M, 1); - auto sinc = [] (double x) { return x == 0 ? 1 : std::sin (x * MathConstants::pi) - / (MathConstants::pi * x); }; - auto factorp = wp / MathConstants::pi; auto factors = ws / MathConstants::pi; diff --git a/modules/juce_dsp/frequency/juce_Convolution.cpp b/modules/juce_dsp/frequency/juce_Convolution.cpp index dbcaa64cc35b..ef44a2cec9ea 100644 --- a/modules/juce_dsp/frequency/juce_Convolution.cpp +++ b/modules/juce_dsp/frequency/juce_Convolution.cpp @@ -647,7 +647,7 @@ static AudioBuffer resampleImpulseResponse (const AudioBuffer& buf const double srcSampleRate, const double destSampleRate) { - if (srcSampleRate == destSampleRate) + if (approximatelyEqual (srcSampleRate, destSampleRate)) return buf; const auto factorReading = srcSampleRate / destSampleRate; diff --git a/modules/juce_dsp/frequency/juce_Convolution_test.cpp b/modules/juce_dsp/frequency/juce_Convolution_test.cpp index ab676f44bbe7..e705f9d15f19 100644 --- a/modules/juce_dsp/frequency/juce_Convolution_test.cpp +++ b/modules/juce_dsp/frequency/juce_Convolution_test.cpp @@ -97,7 +97,7 @@ class ConvolutionTest : public UnitTest expect (std::any_of (channel, channel + block.getNumSamples(), [] (float sample) { - return sample != 0.0f; + return ! approximatelyEqual (sample, 0.0f); })); } } @@ -193,7 +193,7 @@ class ConvolutionTest : public UnitTest processBlocksWithDiracImpulse(); // Check if the impulse response was loaded - if (block.getSample (0, 1) != 0.0f) + if (! approximatelyEqual (block.getSample (0, 1), 0.0f)) break; } } @@ -470,7 +470,7 @@ class ConvolutionTest : public UnitTest Convolution::Stereo::no, Convolution::Trim::yes, Convolution::Normalise::no, - AudioBlock (channels, numElementsInArray (channels), length)); + AudioBlock (channels, numElementsInArray (channels), (size_t) length)); } beginTest ("IRs with extra silence are trimmed appropriately"); diff --git a/modules/juce_dsp/juce_dsp.cpp b/modules/juce_dsp/juce_dsp.cpp index e939a6a86774..f53eccdb8266 100644 --- a/modules/juce_dsp/juce_dsp.cpp +++ b/modules/juce_dsp/juce_dsp.cpp @@ -81,12 +81,12 @@ #if JUCE_USE_SIMD #if JUCE_INTEL #ifdef __AVX2__ - #include "native/juce_avx_SIMDNativeOps.cpp" + #include "native/juce_SIMDNativeOps_avx.cpp" #else - #include "native/juce_sse_SIMDNativeOps.cpp" + #include "native/juce_SIMDNativeOps_sse.cpp" #endif #elif JUCE_ARM - #include "native/juce_neon_SIMDNativeOps.cpp" + #include "native/juce_SIMDNativeOps_neon.cpp" #else #error "SIMD register support not implemented for this platform" #endif diff --git a/modules/juce_dsp/juce_dsp.h b/modules/juce_dsp/juce_dsp.h index a64e65adb454..cc6e746e50d4 100644 --- a/modules/juce_dsp/juce_dsp.h +++ b/modules/juce_dsp/juce_dsp.h @@ -35,7 +35,7 @@ ID: juce_dsp vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE DSP classes description: Classes for audio buffer manipulation, digital audio processing, filtering, oversampling, fast math functions etc. website: http://www.juce.com/juce @@ -220,17 +220,17 @@ namespace juce //============================================================================== #if JUCE_USE_SIMD - #include "native/juce_fallback_SIMDNativeOps.h" + #include "native/juce_SIMDNativeOps_fallback.h" // include the correct native file for this build target CPU #if defined(__i386__) || defined(__amd64__) || defined(_M_X64) || defined(_X86_) || defined(_M_IX86) #ifdef __AVX2__ - #include "native/juce_avx_SIMDNativeOps.h" + #include "native/juce_SIMDNativeOps_avx.h" #else - #include "native/juce_sse_SIMDNativeOps.h" + #include "native/juce_SIMDNativeOps_sse.h" #endif #elif JUCE_ARM - #include "native/juce_neon_SIMDNativeOps.h" + #include "native/juce_SIMDNativeOps_neon.h" #else #error "SIMD register support not implemented for this platform" #endif diff --git a/modules/juce_dsp/maths/juce_LogRampedValue.h b/modules/juce_dsp/maths/juce_LogRampedValue.h index 998e2494138f..821e07e2ee79 100644 --- a/modules/juce_dsp/maths/juce_LogRampedValue.h +++ b/modules/juce_dsp/maths/juce_LogRampedValue.h @@ -108,7 +108,7 @@ class LogRampedValue : public SmoothedValueBase > */ void setTargetValue (FloatType newValue) noexcept { - if (newValue == this->target) + if (approximatelyEqual (newValue, this->target)) return; if (stepsToTarget <= 0) diff --git a/modules/juce_dsp/maths/juce_Matrix.cpp b/modules/juce_dsp/maths/juce_Matrix.cpp index 56c460cd3064..6d5c8acd6750 100644 --- a/modules/juce_dsp/maths/juce_Matrix.cpp +++ b/modules/juce_dsp/maths/juce_Matrix.cpp @@ -176,7 +176,7 @@ bool Matrix::solve (Matrix& b) const noexcept { auto denominator = A (0,0); - if (denominator == 0) + if (approximatelyEqual (denominator, (ElementType) 0)) return false; b (0, 0) /= denominator; @@ -187,7 +187,7 @@ bool Matrix::solve (Matrix& b) const noexcept { auto denominator = A (0, 0) * A (1, 1) - A (0, 1) * A (1, 0); - if (denominator == 0) + if (approximatelyEqual (denominator, (ElementType) 0)) return false; auto factor = (1 / denominator); @@ -204,7 +204,7 @@ bool Matrix::solve (Matrix& b) const noexcept + A (0, 1) * (A (1, 2) * A (2, 0) - A (1, 0) * A (2, 2)) + A (0, 2) * (A (1, 0) * A (2, 1) - A (1, 1) * A (2, 0)); - if (denominator == 0) + if (approximatelyEqual (denominator, (ElementType) 0)) return false; auto factor = 1 / denominator; @@ -231,10 +231,10 @@ bool Matrix::solve (Matrix& b) const noexcept for (size_t j = 0; j < n; ++j) { - if (M (j, j) == 0) + if (approximatelyEqual (M (j, j), (ElementType) 0)) { auto i = j; - while (i < n && M (i, j) == 0) + while (i < n && approximatelyEqual (M (i, j), (ElementType) 0)) ++i; if (i == n) diff --git a/modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp b/modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp similarity index 100% rename from modules/juce_dsp/native/juce_avx_SIMDNativeOps.cpp rename to modules/juce_dsp/native/juce_SIMDNativeOps_avx.cpp diff --git a/modules/juce_dsp/native/juce_avx_SIMDNativeOps.h b/modules/juce_dsp/native/juce_SIMDNativeOps_avx.h similarity index 100% rename from modules/juce_dsp/native/juce_avx_SIMDNativeOps.h rename to modules/juce_dsp/native/juce_SIMDNativeOps_avx.h diff --git a/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h b/modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h similarity index 95% rename from modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h rename to modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h index 595e02e049e9..22d1917a6211 100644 --- a/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h +++ b/modules/juce_dsp/native/juce_SIMDNativeOps_fallback.h @@ -147,7 +147,7 @@ struct SIMDFallbackOps UnionType a {av}, b {bv}; for (size_t i = 0; i < n; ++i) - if (a.s[i] != b.s[i]) + if (! exactlyEqual (a.s[i], b.s[i])) return false; return true; @@ -181,8 +181,8 @@ struct SIMDFallbackOps struct ScalarOr { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a | b; } }; struct ScalarXor { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return a ^ b; } }; struct ScalarNot { static forcedinline MaskType op (MaskType a, MaskType b) noexcept { return (~a) & b; } }; - struct ScalarEq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a == b); } }; - struct ScalarNeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a != b); } }; + struct ScalarEq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return exactlyEqual (a, b); } }; + struct ScalarNeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return ! exactlyEqual (a, b); } }; struct ScalarGt { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a > b); } }; struct ScalarGeq { static forcedinline bool op (ScalarType a, ScalarType b) noexcept { return (a >= b); } }; diff --git a/modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp b/modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp similarity index 100% rename from modules/juce_dsp/native/juce_neon_SIMDNativeOps.cpp rename to modules/juce_dsp/native/juce_SIMDNativeOps_neon.cpp diff --git a/modules/juce_dsp/native/juce_neon_SIMDNativeOps.h b/modules/juce_dsp/native/juce_SIMDNativeOps_neon.h similarity index 100% rename from modules/juce_dsp/native/juce_neon_SIMDNativeOps.h rename to modules/juce_dsp/native/juce_SIMDNativeOps_neon.h diff --git a/modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp b/modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp similarity index 100% rename from modules/juce_dsp/native/juce_sse_SIMDNativeOps.cpp rename to modules/juce_dsp/native/juce_SIMDNativeOps_sse.cpp diff --git a/modules/juce_dsp/native/juce_sse_SIMDNativeOps.h b/modules/juce_dsp/native/juce_SIMDNativeOps_sse.h similarity index 100% rename from modules/juce_dsp/native/juce_sse_SIMDNativeOps.h rename to modules/juce_dsp/native/juce_SIMDNativeOps_sse.h diff --git a/modules/juce_dsp/processors/juce_DelayLine.cpp b/modules/juce_dsp/processors/juce_DelayLine.cpp index 3ea3edbc4d9e..a3f020ae7578 100644 --- a/modules/juce_dsp/processors/juce_DelayLine.cpp +++ b/modules/juce_dsp/processors/juce_DelayLine.cpp @@ -86,7 +86,7 @@ template void DelayLine::setMaximumDelayInSamples (int maxDelayInSamples) { jassert (maxDelayInSamples >= 0); - totalSize = jmax (4, maxDelayInSamples + 1); + totalSize = jmax (4, maxDelayInSamples + 2); bufferData.setSize ((int) bufferData.getNumChannels(), totalSize, false, false, true); reset(); } diff --git a/modules/juce_dsp/processors/juce_DelayLine.h b/modules/juce_dsp/processors/juce_DelayLine.h index 0d9223760607..29c53d28e880 100644 --- a/modules/juce_dsp/processors/juce_DelayLine.h +++ b/modules/juce_dsp/processors/juce_DelayLine.h @@ -125,7 +125,7 @@ class DelayLine For very short delay times, the result of getMaximumDelayInSamples() may differ from the last value passed to setMaximumDelayInSamples(). */ - int getMaximumDelayInSamples() const noexcept { return totalSize - 1; } + int getMaximumDelayInSamples() const noexcept { return totalSize - 2; } /** Resets the internal state variables of the processor. */ void reset(); @@ -271,7 +271,7 @@ class DelayLine auto value1 = bufferData.getSample (channel, index1); auto value2 = bufferData.getSample (channel, index2); - auto output = delayFrac == 0 ? value1 : value2 + alpha * (value1 - v[(size_t) channel]); + auto output = approximatelyEqual (delayFrac, (SampleType) 0) ? value1 : value2 + alpha * (value1 - v[(size_t) channel]); v[(size_t) channel] = output; return output; @@ -283,7 +283,7 @@ class DelayLine { if constexpr (std::is_same_v) { - if (delayInt >= 1) + if (delayFrac < (SampleType) 2.0 && delayInt >= 1) { delayFrac++; delayInt--; diff --git a/modules/juce_dsp/processors/juce_IIRFilter.cpp b/modules/juce_dsp/processors/juce_IIRFilter.cpp index 69f99417fc8e..37bed1e8fbd9 100644 --- a/modules/juce_dsp/processors/juce_IIRFilter.cpp +++ b/modules/juce_dsp/processors/juce_IIRFilter.cpp @@ -30,6 +30,8 @@ namespace dsp namespace IIR { +constexpr auto minimumDecibels = -300.0; + template std::array ArrayCoefficients::makeFirstOrderLowPass (double sampleRate, NumericType frequency) @@ -37,7 +39,7 @@ std::array ArrayCoefficients::makeFirstOrderLowPass jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { n, n, n + 1, n - 1 } }; } @@ -49,7 +51,7 @@ std::array ArrayCoefficients::makeFirstOrderHighPas jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { 1, -1, n + 1, n - 1 } }; } @@ -61,7 +63,7 @@ std::array ArrayCoefficients::makeFirstOrderAllPass jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { n - 1, n + 1, n + 1, n - 1 } }; } @@ -82,10 +84,10 @@ std::array ArrayCoefficients::makeLowPass (double s jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1, c1 * 2, c1, 1, c1 * 2 * (1 - nSquared), @@ -108,10 +110,10 @@ std::array ArrayCoefficients::makeHighPass (double jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1, c1 * -2, c1, 1, c1 * 2 * (nSquared - 1), @@ -134,10 +136,10 @@ std::array ArrayCoefficients::makeBandPass (double jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1 * n * invQ, 0, -c1 * n * invQ, 1, @@ -161,12 +163,12 @@ std::array ArrayCoefficients::makeNotch (double sam jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + n * invQ + nSquared); - auto b0 = c1 * (1 + nSquared); - auto b1 = 2 * c1 * (1 - nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + n * invQ + nSquared); + const auto b0 = c1 * (1 + nSquared); + const auto b1 = 2 * c1 * (1 - nSquared); return { { b0, b1, b0, 1, b1, c1 * (1 - n * invQ + nSquared) } }; } @@ -187,12 +189,12 @@ std::array ArrayCoefficients::makeAllPass (double s jassert (frequency > 0 && frequency <= sampleRate * 0.5); jassert (Q > 0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); - auto b0 = c1 * (1 - n * invQ + nSquared); - auto b1 = c1 * 2 * (1 - nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); + const auto b0 = c1 * (1 - n * invQ + nSquared); + const auto b1 = c1 * 2 * (1 - nSquared); return { { b0, b1, 1, 1, b1, b0 } }; } @@ -207,13 +209,13 @@ std::array ArrayCoefficients::makeLowShelf (double jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto aminus1 = A - 1; - auto aplus1 = A + 1; - auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); - auto coso = std::cos (omega); - auto beta = std::sin (omega) * std::sqrt (A) / Q; - auto aminus1TimesCoso = aminus1 * coso; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, (NumericType) minimumDecibels)); + const auto aminus1 = A - 1; + const auto aplus1 = A + 1; + const auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return { { A * (aplus1 - aminus1TimesCoso + beta), A * 2 * (aminus1 - aplus1 * coso), @@ -233,13 +235,13 @@ std::array ArrayCoefficients::makeHighShelf (double jassert (cutOffFrequency > 0 && cutOffFrequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto aminus1 = A - 1; - auto aplus1 = A + 1; - auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); - auto coso = std::cos (omega); - auto beta = std::sin (omega) * std::sqrt (A) / Q; - auto aminus1TimesCoso = aminus1 * coso; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, (NumericType) minimumDecibels)); + const auto aminus1 = A - 1; + const auto aplus1 = A + 1; + const auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return { { A * (aplus1 + aminus1TimesCoso + beta), A * -2 * (aminus1 + aplus1 * coso), @@ -260,12 +262,12 @@ std::array ArrayCoefficients::makePeakFilter (doubl jassert (Q > 0); jassert (gainFactor > 0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto omega = (2 * MathConstants::pi * jmax (frequency, static_cast (2.0))) / static_cast (sampleRate); - auto alpha = std::sin (omega) / (Q * 2); - auto c2 = -2 * std::cos (omega); - auto alphaTimesA = alpha * A; - auto alphaOverA = alpha / A; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, (NumericType) minimumDecibels)); + const auto omega = (2 * MathConstants::pi * jmax (frequency, static_cast (2.0))) / static_cast (sampleRate); + const auto alpha = std::sin (omega) / (Q * 2); + const auto c2 = -2 * std::cos (omega); + const auto alphaTimesA = alpha * A; + const auto alphaOverA = alpha / A; return { { 1 + alphaTimesA, c2, 1 - alphaTimesA, 1 + alphaOverA, c2, 1 - alphaOverA } }; } diff --git a/modules/juce_dsp/processors/juce_IIRFilter_Impl.h b/modules/juce_dsp/processors/juce_IIRFilter_Impl.h index 150ab429e946..b30caf7cd742 100644 --- a/modules/juce_dsp/processors/juce_IIRFilter_Impl.h +++ b/modules/juce_dsp/processors/juce_IIRFilter_Impl.h @@ -39,8 +39,9 @@ Coefficients& Coefficients::assignImpl (const NumericT static_assert (Num % 2 == 0, "Must supply an even number of coefficients"); const auto a0Index = Num / 2; const auto a0 = values[a0Index]; - const auto a0Inv = a0 != NumericType() ? static_cast (1) / values[a0Index] - : NumericType(); + const auto a0Inv = ! approximatelyEqual (a0, NumericType()) + ? static_cast (1) / values[a0Index] + : NumericType(); coefficients.clearQuick(); coefficients.ensureStorageAllocated ((int) jmax ((size_t) 8, Num)); diff --git a/modules/juce_dsp/processors/juce_Oversampling.cpp b/modules/juce_dsp/processors/juce_Oversampling.cpp index f79c432851e4..8600b18e5248 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.cpp +++ b/modules/juce_dsp/processors/juce_Oversampling.cpp @@ -755,7 +755,7 @@ void Oversampling::updateDelayLine() auto latency = getUncompensatedLatency(); fractionalDelay = static_cast (1.0) - (latency - std::floor (latency)); - if (fractionalDelay == static_cast (1.0)) + if (approximatelyEqual (fractionalDelay, static_cast (1.0))) fractionalDelay = static_cast (0.0); else if (fractionalDelay < static_cast (0.618)) fractionalDelay += static_cast (1.0); diff --git a/modules/juce_dsp/processors/juce_Oversampling.h b/modules/juce_dsp/processors/juce_Oversampling.h index 95ffd987563b..9d5990ae0bbb 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.h +++ b/modules/juce_dsp/processors/juce_Oversampling.h @@ -28,7 +28,7 @@ namespace juce namespace dsp { -//=============================================================================== +//============================================================================== /** A processor that performs multi-channel oversampling. @@ -63,7 +63,7 @@ class JUCE_API Oversampling numFilterTypes }; - //=============================================================================== + //============================================================================== /** The default constructor. Note: This creates a "dummy" oversampling stage, which needs to be removed @@ -97,7 +97,7 @@ class JUCE_API Oversampling /** Destructor. */ ~Oversampling(); - //=============================================================================== + //============================================================================== /* Sets if this processor should add some fractional delay at the end of the signal path to ensure that the overall latency of the oversampling is an integer. */ @@ -118,7 +118,7 @@ class JUCE_API Oversampling /** Returns the current oversampling factor. */ size_t getOversamplingFactor() const noexcept; - //=============================================================================== + //============================================================================== /** Must be called before any processing, to set the buffer sizes of the internal buffers of the oversampling processing. */ @@ -143,7 +143,7 @@ class JUCE_API Oversampling */ void processSamplesDown (AudioBlock& outputBlock) noexcept; - //=============================================================================== + //============================================================================== /** Adds a new oversampling stage to the Oversampling class, multiplying the current oversampling factor by two. This is used with the default constructor to create custom oversampling chains, requiring a call to the @@ -187,7 +187,7 @@ class JUCE_API Oversampling */ void clearOversamplingStages(); - //=============================================================================== + //============================================================================== size_t factorOversampling = 1; size_t numChannels = 1; @@ -196,17 +196,17 @@ class JUCE_API Oversampling #endif private: - //=============================================================================== + //============================================================================== void updateDelayLine(); SampleType getUncompensatedLatency() const noexcept; - //=============================================================================== + //============================================================================== OwnedArray stages; bool isReady = false, shouldUseIntegerLatency = false; DelayLine delay { 8 }; SampleType fractionalDelay = 0; - //=============================================================================== + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling) }; diff --git a/modules/juce_dsp/processors/juce_ProcessContext.h b/modules/juce_dsp/processors/juce_ProcessContext.h index 983dd5363477..6da17bb766ba 100644 --- a/modules/juce_dsp/processors/juce_ProcessContext.h +++ b/modules/juce_dsp/processors/juce_ProcessContext.h @@ -48,9 +48,12 @@ struct ProcessSpec constexpr bool operator== (const ProcessSpec& a, const ProcessSpec& b) { - return a.sampleRate == b.sampleRate - && a.maximumBlockSize == b.maximumBlockSize - && a.numChannels == b.numChannels; + const auto tie = [] (const ProcessSpec& p) + { + return std::tie (p.sampleRate, p.maximumBlockSize, p.numChannels); + }; + + return tie (a) == tie (b); } constexpr bool operator!= (const ProcessSpec& a, const ProcessSpec& b) { return ! (a == b); } diff --git a/modules/juce_dsp/processors/juce_ProcessorChain_test.cpp b/modules/juce_dsp/processors/juce_ProcessorChain_test.cpp index c820581005b2..80ff01fee4cb 100644 --- a/modules/juce_dsp/processors/juce_ProcessorChain_test.cpp +++ b/modules/juce_dsp/processors/juce_ProcessorChain_test.cpp @@ -39,7 +39,7 @@ class ProcessorChainTest : public UnitTest template void process (const Context& context) noexcept { - bufferWasClear = context.getInputBlock().getSample (0, 0) == 0; + bufferWasClear = approximatelyEqual (context.getInputBlock().getSample (0, 0), 0.0f); if (! context.isBypassed) context.getOutputBlock().add (AddValue); diff --git a/modules/juce_dsp/widgets/juce_Bias.h b/modules/juce_dsp/widgets/juce_Bias.h index cc255dad8516..cbd68b86fc47 100644 --- a/modules/juce_dsp/widgets/juce_Bias.h +++ b/modules/juce_dsp/widgets/juce_Bias.h @@ -64,7 +64,7 @@ class Bias /** Sets the length of the ramp used for smoothing gain changes. */ void setRampDurationSeconds (double newDurationSeconds) noexcept { - if (rampDurationSeconds != newDurationSeconds) + if (! approximatelyEqual (rampDurationSeconds, newDurationSeconds)) { rampDurationSeconds = newDurationSeconds; updateRamp(); diff --git a/modules/juce_dsp/widgets/juce_Gain.h b/modules/juce_dsp/widgets/juce_Gain.h index c43c240fdc5b..1e98dc692285 100644 --- a/modules/juce_dsp/widgets/juce_Gain.h +++ b/modules/juce_dsp/widgets/juce_Gain.h @@ -55,7 +55,7 @@ class Gain /** Sets the length of the ramp used for smoothing gain changes. */ void setRampDurationSeconds (double newDurationSeconds) noexcept { - if (rampDurationSeconds != newDurationSeconds) + if (! approximatelyEqual (rampDurationSeconds, newDurationSeconds)) { rampDurationSeconds = newDurationSeconds; reset(); diff --git a/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp b/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp new file mode 100644 index 000000000000..c87db1a595a6 --- /dev/null +++ b/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.cpp @@ -0,0 +1,133 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class LockingAsyncUpdater::Impl : public CallbackMessage +{ +public: + explicit Impl (std::function cb) + : callback (std::move (cb)) {} + + void clear() + { + const ScopedLock lock (mutex); + deliver = false; + callback = nullptr; + } + + void trigger() + { + { + const ScopedLock lock (mutex); + + if (deliver) + return; + + deliver = true; + } + + if (! post()) + cancel(); + } + + void cancel() + { + const ScopedLock lock (mutex); + deliver = false; + } + + bool isPending() + { + const ScopedLock lock (mutex); + return deliver; + } + + void messageCallback() override + { + const ScopedLock lock (mutex); + + if (std::exchange (deliver, false)) + NullCheckedInvocation::invoke (callback); + } + +private: + CriticalSection mutex; + std::function callback; + bool deliver = false; +}; + +//============================================================================== +LockingAsyncUpdater::LockingAsyncUpdater (std::function callbackToUse) + : impl (new Impl (std::move (callbackToUse))) {} + +LockingAsyncUpdater::LockingAsyncUpdater (LockingAsyncUpdater&& other) noexcept + : impl (std::exchange (other.impl, nullptr)) {} + +LockingAsyncUpdater& LockingAsyncUpdater::operator= (LockingAsyncUpdater&& other) noexcept +{ + LockingAsyncUpdater temp { std::move (other) }; + std::swap (temp.impl, impl); + return *this; +} + +LockingAsyncUpdater::~LockingAsyncUpdater() +{ + if (impl != nullptr) + impl->clear(); +} + +void LockingAsyncUpdater::triggerAsyncUpdate() +{ + if (impl != nullptr) + impl->trigger(); + else + jassertfalse; // moved-from! +} + +void LockingAsyncUpdater::cancelPendingUpdate() noexcept +{ + if (impl != nullptr) + impl->cancel(); + else + jassertfalse; // moved-from! +} + +void LockingAsyncUpdater::handleUpdateNowIfNeeded() +{ + if (impl != nullptr) + impl->messageCallback(); + else + jassertfalse; // moved-from! +} + +bool LockingAsyncUpdater::isUpdatePending() const noexcept +{ + if (impl != nullptr) + return impl->isPending(); + + jassertfalse; // moved-from! + return false; +} + +} // namespace juce diff --git a/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h b/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h new file mode 100644 index 000000000000..6a9e449d8bc2 --- /dev/null +++ b/modules/juce_events/broadcasters/juce_LockingAsyncUpdater.h @@ -0,0 +1,113 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + A bit like an AsyncUpdater, but guarantees that after cancelPendingUpdate() returns, + the async function will never be called until triggerAsyncUpdate() is called again. + This is an important guarantee for writing classes with async behaviour that can + still be destroyed safely from a background thread. + + Note that all of the member functions of this type have a chance of blocking, so + this class is unsuitable for broadcasting changes from a realtime thread. + + @tags{Events} +*/ +class JUCE_API LockingAsyncUpdater final +{ +public: + //============================================================================== + /** Creates a LockingAsyncUpdater object that will call the provided callback + on the main thread when triggered. + + Note that the LockingAsyncUpdater takes an internal mutex before calling + the provided callback. Therefore, in order to avoid deadlocks, you should + (ideally) ensure that no locks are taken inside the callbackToUse. If you + do need to take a lock inside the callback, make sure that you do not + hold the same lock while calling any of the LockingAsyncUpdater member + functions. + */ + explicit LockingAsyncUpdater (std::function callbackToUse); + + /** Move constructor. */ + LockingAsyncUpdater (LockingAsyncUpdater&& other) noexcept; + + /** Move assignment operator. */ + LockingAsyncUpdater& operator= (LockingAsyncUpdater&& other) noexcept; + + /** Destructor. + If there are any pending callbacks when the object is deleted, these are lost. + The async callback is guaranteed not to be called again once the destructor has + completed. + */ + ~LockingAsyncUpdater(); + + //============================================================================== + /** Causes the callback to be triggered at a later time. + + This method returns quickly, after which a callback to the + handleAsyncUpdate() method will be made by the impl thread as + soon as possible. + + If an update callback is already pending but hasn't started yet, calling + this method will have no effect. + + It's thread-safe to call this method from any thread, BUT beware of calling + it from a real-time (e.g. audio) thread, because it unconditionally locks + a mutex. This may block, e.g. if this is called from a background thread + while the async callback is in progress on the main thread. + */ + void triggerAsyncUpdate(); + + /** This will stop any pending updates from happening. + + If a callback is already in progress on another thread, this will block until + the callback has finished before returning. + */ + void cancelPendingUpdate() noexcept; + + /** If an update has been triggered and is pending, this will invoke it + synchronously. + + Use this as a kind of "flush" operation - if an update is pending, the + handleAsyncUpdate() method will be called immediately; if no update is + pending, then nothing will be done. + + Because this may invoke the callback, this method must only be called on + the main event thread. + */ + void handleUpdateNowIfNeeded(); + + /** Returns true if there's an update callback in the pipeline. */ + bool isUpdatePending() const noexcept; + +private: + class Impl; + ReferenceCountedObjectPtr impl; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LockingAsyncUpdater) +}; + +} // namespace juce diff --git a/modules/juce_events/juce_events.cpp b/modules/juce_events/juce_events.cpp index c6678d5d28a7..67d555a9420b 100644 --- a/modules/juce_events/juce_events.cpp +++ b/modules/juce_events/juce_events.cpp @@ -60,6 +60,7 @@ #include "messages/juce_MessageManager.cpp" #include "broadcasters/juce_ActionBroadcaster.cpp" #include "broadcasters/juce_AsyncUpdater.cpp" +#include "broadcasters/juce_LockingAsyncUpdater.cpp" #include "broadcasters/juce_ChangeBroadcaster.cpp" #include "timers/juce_MultiTimer.cpp" #include "timers/juce_Timer.cpp" @@ -72,25 +73,26 @@ //============================================================================== #if JUCE_MAC || JUCE_IOS - #include "native/juce_osx_MessageQueue.h" + #include "native/juce_MessageQueue_mac.h" #if JUCE_MAC - #include "native/juce_mac_MessageManager.mm" + #include "native/juce_MessageManager_mac.mm" #else - #include "native/juce_ios_MessageManager.mm" + #include "native/juce_MessageManager_ios.mm" #endif #elif JUCE_WINDOWS - #include "native/juce_win32_Messaging.cpp" + #include "native/juce_RunningInUnity.h" + #include "native/juce_Messaging_windows.cpp" #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER - #include "native/juce_win32_WinRTWrapper.cpp" + #include "native/juce_WinRTWrapper_windows.cpp" #endif #elif JUCE_LINUX || JUCE_BSD - #include "native/juce_linux_EventLoopInternal.h" - #include "native/juce_linux_Messaging.cpp" + #include "native/juce_EventLoopInternal_linux.h" + #include "native/juce_Messaging_linux.cpp" #elif JUCE_ANDROID - #include "native/juce_android_Messaging.cpp" + #include "native/juce_Messaging_android.cpp" #endif diff --git a/modules/juce_events/juce_events.h b/modules/juce_events/juce_events.h index b3d60e3848ce..e11f371b45f3 100644 --- a/modules/juce_events/juce_events.h +++ b/modules/juce_events/juce_events.h @@ -32,7 +32,7 @@ ID: juce_events vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE message and event handling classes description: Classes for running an application's main event loop and sending/receiving messages, timers, etc. website: http://www.juce.com/juce @@ -82,6 +82,7 @@ #include "broadcasters/juce_ActionBroadcaster.h" #include "broadcasters/juce_ActionListener.h" #include "broadcasters/juce_AsyncUpdater.h" +#include "broadcasters/juce_LockingAsyncUpdater.h" #include "broadcasters/juce_ChangeListener.h" #include "broadcasters/juce_ChangeBroadcaster.h" #include "timers/juce_Timer.h" @@ -93,14 +94,14 @@ #include "native/juce_ScopedLowPowerModeDisabler.h" #if JUCE_LINUX || JUCE_BSD - #include "native/juce_linux_EventLoop.h" + #include "native/juce_EventLoop_linux.h" #endif #if JUCE_WINDOWS #if JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW - #include "native/juce_win32_HiddenMessageWindow.h" + #include "native/juce_HiddenMessageWindow_windows.h" #endif #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER - #include "native/juce_win32_WinRTWrapper.h" + #include "native/juce_WinRTWrapper_windows.h" #endif #endif diff --git a/modules/juce_events/messages/juce_ApplicationBase.cpp b/modules/juce_events/messages/juce_ApplicationBase.cpp index 04f534bef6e2..7b0eb8725258 100644 --- a/modules/juce_events/messages/juce_ApplicationBase.cpp +++ b/modules/juce_events/messages/juce_ApplicationBase.cpp @@ -184,7 +184,7 @@ StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray() #endif #if (JUCE_LINUX || JUCE_BSD) && JUCE_MODULE_AVAILABLE_juce_gui_extra && (! defined(JUCE_WEB_BROWSER) || JUCE_WEB_BROWSER) - extern int juce_gtkWebkitMain (int argc, const char* argv[]); + extern "C" int juce_gtkWebkitMain (int argc, const char* const* argv); #endif #if JUCE_WINDOWS @@ -231,7 +231,7 @@ int JUCEApplicationBase::main (int argc, const char* argv[]) initialiseNSApplication(); #endif - #if (JUCE_LINUX || JUCE_BSD) && JUCE_MODULE_AVAILABLE_juce_gui_extra && (! defined(JUCE_WEB_BROWSER) || JUCE_WEB_BROWSER) + #if (JUCE_LINUX || JUCE_BSD) && JUCE_MODULE_AVAILABLE_juce_gui_extra && (! defined (JUCE_WEB_BROWSER) || JUCE_WEB_BROWSER) if (argc >= 2 && String (argv[1]) == "--juce-gtkwebkitfork-child") return juce_gtkWebkitMain (argc, argv); #endif diff --git a/modules/juce_events/messages/juce_MessageManager.cpp b/modules/juce_events/messages/juce_MessageManager.cpp index cca2d4925a21..da949d2e933a 100644 --- a/modules/juce_events/messages/juce_MessageManager.cpp +++ b/modules/juce_events/messages/juce_MessageManager.cpp @@ -81,8 +81,11 @@ bool MessageManager::MessageBase::post() //============================================================================== #if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID) -// implemented in platform-specific code (juce_linux_Messaging.cpp and juce_win32_Messaging.cpp) +// implemented in platform-specific code (juce_Messaging_linux.cpp and juce_Messaging_windows.cpp) +namespace detail +{ bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages); +} // namespace detail class MessageManager::QuitMessage : public MessageManager::MessageBase { @@ -106,7 +109,7 @@ void MessageManager::runDispatchLoop() { JUCE_TRY { - if (! dispatchNextMessageOnSystemQueue (false)) + if (! detail::dispatchNextMessageOnSystemQueue (false)) Thread::sleep (1); } JUCE_CATCH_EXCEPTION @@ -130,7 +133,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) { JUCE_TRY { - if (! dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0)) + if (! detail::dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0)) Thread::sleep (1); } JUCE_CATCH_EXCEPTION @@ -281,25 +284,41 @@ bool MessageManager::existsAndIsCurrentThread() noexcept */ struct MessageManager::Lock::BlockingMessage : public MessageManager::MessageBase { - BlockingMessage (const MessageManager::Lock* parent) noexcept - : owner (parent) - {} + explicit BlockingMessage (const MessageManager::Lock* parent) noexcept + : owner (parent) {} void messageCallback() override { - { - ScopedLock lock (ownerCriticalSection); + std::unique_lock lock { mutex }; - if (auto* o = owner.get()) - o->messageCallback(); + if (owner != nullptr) + { + owner->abort(); + acquired = true; } - releaseEvent.wait(); + condvar.wait (lock, [&] { return owner == nullptr; }); } - CriticalSection ownerCriticalSection; - Atomic owner; - WaitableEvent releaseEvent; + void stopWaiting() + { + const ScopeGuard scope { [&] { condvar.notify_one(); } }; + const std::scoped_lock lock { mutex }; + owner = nullptr; + } + + bool wasAcquired() + { + const std::scoped_lock lock { mutex }; + return acquired; + } + +private: + std::mutex mutex; + std::condition_variable condvar; + + const MessageManager::Lock* owner = nullptr; + bool acquired = false; JUCE_DECLARE_NON_COPYABLE (BlockingMessage) }; @@ -320,9 +339,12 @@ bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept return false; } - if (! lockIsMandatory && (abortWait.get() != 0)) + if (! lockIsMandatory && [&] + { + const std::scoped_lock lock { mutex }; + return std::exchange (abortWait, false); + }()) { - abortWait.set (0); return false; } @@ -347,65 +369,54 @@ bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept return false; } - do + for (;;) { - while (abortWait.get() == 0) - lockedEvent.wait (-1); - - abortWait.set (0); + { + std::unique_lock lock { mutex }; + condvar.wait (lock, [&] { return std::exchange (abortWait, false); }); + } - if (lockGained.get() != 0) + if (blockingMessage->wasAcquired()) { mm->threadWithLock = Thread::getCurrentThreadId(); return true; } - } while (lockIsMandatory); + if (! lockIsMandatory) + break; + } // we didn't get the lock - blockingMessage->releaseEvent.signal(); - - { - ScopedLock lock (blockingMessage->ownerCriticalSection); - - lockGained.set (0); - blockingMessage->owner.set (nullptr); - } + blockingMessage->stopWaiting(); blockingMessage = nullptr; return false; } void MessageManager::Lock::exit() const noexcept { - if (lockGained.compareAndSetBool (false, true)) - { - auto* mm = MessageManager::instance; + if (blockingMessage == nullptr) + return; - jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager()); - lockGained.set (0); + const ScopeGuard scope { [&] { blockingMessage = nullptr; } }; - if (mm != nullptr) - mm->threadWithLock = {}; + blockingMessage->stopWaiting(); - if (blockingMessage != nullptr) - { - blockingMessage->releaseEvent.signal(); - blockingMessage = nullptr; - } - } -} + if (! blockingMessage->wasAcquired()) + return; -void MessageManager::Lock::messageCallback() const -{ - lockGained.set (1); - abort(); + if (auto* mm = MessageManager::instance) + { + jassert (mm->currentThreadHasLockedMessageManager()); + mm->threadWithLock = {}; + } } void MessageManager::Lock::abort() const noexcept { - abortWait.set (1); - lockedEvent.signal(); + const ScopeGuard scope { [&] { condvar.notify_one(); } }; + const std::scoped_lock lock { mutex }; + abortWait = true; } //============================================================================== diff --git a/modules/juce_events/messages/juce_MessageManager.h b/modules/juce_events/messages/juce_MessageManager.h index 8687a057cf48..01daff8e00d3 100644 --- a/modules/juce_events/messages/juce_MessageManager.h +++ b/modules/juce_events/messages/juce_MessageManager.h @@ -298,12 +298,12 @@ class JUCE_API MessageManager final friend class ReferenceCountedObjectPtr; bool tryAcquire (bool) const noexcept; - void messageCallback() const; //============================================================================== mutable ReferenceCountedObjectPtr blockingMessage; - WaitableEvent lockedEvent; - mutable Atomic abortWait, lockGained; + mutable std::mutex mutex; + mutable std::condition_variable condvar; + mutable bool abortWait = false, acquired = false; }; //============================================================================== diff --git a/modules/juce_events/native/juce_linux_EventLoopInternal.h b/modules/juce_events/native/juce_EventLoopInternal_linux.h similarity index 100% rename from modules/juce_events/native/juce_linux_EventLoopInternal.h rename to modules/juce_events/native/juce_EventLoopInternal_linux.h diff --git a/modules/juce_events/native/juce_linux_EventLoop.h b/modules/juce_events/native/juce_EventLoop_linux.h similarity index 100% rename from modules/juce_events/native/juce_linux_EventLoop.h rename to modules/juce_events/native/juce_EventLoop_linux.h diff --git a/modules/juce_events/native/juce_win32_HiddenMessageWindow.h b/modules/juce_events/native/juce_HiddenMessageWindow_windows.h similarity index 92% rename from modules/juce_events/native/juce_win32_HiddenMessageWindow.h rename to modules/juce_events/native/juce_HiddenMessageWindow_windows.h index e199569c27a0..e64271d16832 100644 --- a/modules/juce_events/native/juce_win32_HiddenMessageWindow.h +++ b/modules/juce_events/native/juce_HiddenMessageWindow_windows.h @@ -91,14 +91,13 @@ class JuceWindowIdentifier class DeviceChangeDetector : private Timer { public: - DeviceChangeDetector (const wchar_t* const name) - : messageWindow (name, (WNDPROC) deviceChangeEventCallback) + DeviceChangeDetector (const wchar_t* const name, std::function onChangeIn) + : messageWindow (name, (WNDPROC) deviceChangeEventCallback), + onChange (std::move (onChangeIn)) { SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this); } - virtual void systemDeviceChanged() = 0; - void triggerAsyncDeviceChangeCallback() { // We'll pause before sending a message, because on device removal, the OS hasn't always updated @@ -108,6 +107,7 @@ class DeviceChangeDetector : private Timer private: HiddenMessageWindow messageWindow; + std::function onChange; static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam) @@ -127,7 +127,7 @@ class DeviceChangeDetector : private Timer void timerCallback() override { stopTimer(); - systemDeviceChanged(); + NullCheckedInvocation::invoke (onChange); } }; diff --git a/modules/juce_events/native/juce_ios_MessageManager.mm b/modules/juce_events/native/juce_MessageManager_ios.mm similarity index 100% rename from modules/juce_events/native/juce_ios_MessageManager.mm rename to modules/juce_events/native/juce_MessageManager_ios.mm diff --git a/modules/juce_events/native/juce_mac_MessageManager.mm b/modules/juce_events/native/juce_MessageManager_mac.mm similarity index 56% rename from modules/juce_events/native/juce_mac_MessageManager.mm rename to modules/juce_events/native/juce_MessageManager_mac.mm index e254a96760ef..b0696430cbd8 100644 --- a/modules/juce_events/native/juce_mac_MessageManager.mm +++ b/modules/juce_events/native/juce_MessageManager_mac.mm @@ -35,151 +35,188 @@ //============================================================================== struct AppDelegateClass : public ObjCClass { - AppDelegateClass() : ObjCClass ("JUCEAppDelegate_") + AppDelegateClass() : ObjCClass ("JUCEAppDelegate_") { - addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching); - addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate); - addMethod (@selector (applicationWillTerminate:), applicationWillTerminate); - addMethod (@selector (application:openFile:), application_openFile); - addMethod (@selector (application:openFiles:), application_openFiles); - addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive); - addMethod (@selector (applicationDidResignActive:), applicationDidResignActive); - addMethod (@selector (applicationWillUnhide:), applicationWillUnhide); + addMethod (@selector (applicationWillFinishLaunching:), [] (id self, SEL, NSNotification*) + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") + [[NSAppleEventManager sharedAppleEventManager] setEventHandler: self + andSelector: @selector (getUrl:withReplyEvent:) + forEventClass: kInternetEventClass + andEventID: kAEGetURL]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + }); - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent); - addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback); - addMethod (@selector (mainMenuTrackingBegan:), mainMenuTrackingBegan); - addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded); - addMethod (@selector (dummyMethod), dummyMethod); - JUCE_END_IGNORE_WARNINGS_GCC_LIKE + addMethod (@selector (applicationShouldTerminate:), [] (id /*self*/, SEL, NSApplication*) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + app->systemRequestedQuit(); - #if JUCE_PUSH_NOTIFICATIONS - //============================================================================== - addIvar*> ("pushNotificationsDelegate"); + if (! MessageManager::getInstance()->hasStopMessageBeenSent()) + return NSTerminateCancel; + } - addMethod (@selector (applicationDidFinishLaunching:), applicationDidFinishLaunching); + return NSTerminateNow; + }); - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (setPushNotificationsDelegate:), setPushNotificationsDelegate); - JUCE_END_IGNORE_WARNINGS_GCC_LIKE + addMethod (@selector (applicationWillTerminate:), [] (id /*self*/, SEL, NSNotification*) + { + JUCEApplicationBase::appWillTerminateByForce(); + }); - addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications); - addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications); - addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification); - #endif + addMethod (@selector (application:openFile:), [] (id /*self*/, SEL, NSApplication*, NSString* filename) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + app->anotherInstanceStarted (quotedIfContainsSpaces (filename)); + return YES; + } - registerClass(); - } + return NO; + }); + + addMethod (@selector (application:openFiles:), [] (id /*self*/, SEL, NSApplication*, NSArray* filenames) + { + if (auto* app = JUCEApplicationBase::getInstance()) + { + StringArray files; + + for (NSString* f in filenames) + files.add (quotedIfContainsSpaces (f)); + + if (files.size() > 0) + app->anotherInstanceStarted (files.joinIntoString (" ")); + } + }); + + addMethod (@selector (applicationDidBecomeActive:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); + addMethod (@selector (applicationDidResignActive:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); + addMethod (@selector (applicationWillUnhide:), [] (id /*self*/, SEL, NSNotification*) { focusChanged(); }); -private: - static void applicationWillFinishLaunching (id self, SEL, NSNotification*) - { JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - [[NSAppleEventManager sharedAppleEventManager] setEventHandler: self - andSelector: @selector (getUrl:withReplyEvent:) - forEventClass: kInternetEventClass - andEventID: kAEGetURL]; - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - } + addMethod (@selector (getUrl:withReplyEvent:), [] (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*) + { + if (auto* app = JUCEApplicationBase::getInstance()) + app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue])); + }); - #if JUCE_PUSH_NOTIFICATIONS - static void applicationDidFinishLaunching (id self, SEL, NSNotification* notification) - { - if (notification.userInfo != nil) + addMethod (@selector (broadcastMessageCallback:), [] (id /*self*/, SEL, NSNotification* n) { - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") - // NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a - // replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type - NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey]; - JUCE_END_IGNORE_WARNINGS_GCC_LIKE + NSDictionary* dict = (NSDictionary*) [n userInfo]; + auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]); + MessageManager::getInstance()->deliverBroadcastMessage (messageString); + }); - if (userNotification != nil && userNotification.userInfo != nil) - didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo); - } - } - #endif + addMethod (@selector (mainMenuTrackingBegan:), [] (id /*self*/, SEL, NSNotification*) + { + if (menuTrackingChangedCallback != nullptr) + menuTrackingChangedCallback (true); + }); - static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*) - { - if (auto* app = JUCEApplicationBase::getInstance()) + addMethod (@selector (mainMenuTrackingEnded:), [] (id /*self*/, SEL, NSNotification*) { - app->systemRequestedQuit(); + if (menuTrackingChangedCallback != nullptr) + menuTrackingChangedCallback (false); + }); - if (! MessageManager::getInstance()->hasStopMessageBeenSent()) - return NSTerminateCancel; - } + // (used as a way of running a dummy thread) + addMethod (@selector (dummyMethod), [] (id /*self*/, SEL) {}); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE - return NSTerminateNow; - } + #if JUCE_PUSH_NOTIFICATIONS + //============================================================================== + addIvar*> ("pushNotificationsDelegate"); - static void applicationWillTerminate (id /*self*/, SEL, NSNotification*) - { - JUCEApplicationBase::appWillTerminateByForce(); - } + addMethod (@selector (applicationDidFinishLaunching:), [] (id self, SEL, NSNotification* notification) + { + if (notification.userInfo != nil) + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + // NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a + // replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type + NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullable-to-nonnull-conversion") + if (userNotification != nil && userNotification.userInfo != nil) + [self application: [NSApplication sharedApplication] didReceiveRemoteNotification: userNotification.userInfo]; + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + } + }); - static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename) - { - if (auto* app = JUCEApplicationBase::getInstance()) + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") + addMethod (@selector (setPushNotificationsDelegate:), [] (id self, SEL, NSObject* delegate) { - app->anotherInstanceStarted (quotedIfContainsSpaces (filename)); - return YES; - } + object_setInstanceVariable (self, "pushNotificationsDelegate", delegate); + }); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE - return NO; - } + addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), [] (id self, SEL, NSApplication* application, NSData* deviceToken) + { + auto* delegate = getPushNotificationsDelegate (self); - static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames) - { - if (auto* app = JUCEApplicationBase::getInstance()) + SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:); + + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &deviceToken atIndex:3]; + + [invocation invoke]; + } + }); + + addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), [] (id self, SEL, NSApplication* application, NSError* error) { - StringArray files; + auto* delegate = getPushNotificationsDelegate (self); - for (NSString* f in filenames) - files.add (quotedIfContainsSpaces (f)); + SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:); - if (files.size() > 0) - app->anotherInstanceStarted (files.joinIntoString (" ")); - } - } + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &error atIndex:3]; - static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); } - static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); } + [invocation invoke]; + } + }); - static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n) - { - NSDictionary* dict = (NSDictionary*) [n userInfo]; - auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]); - MessageManager::getInstance()->deliverBroadcastMessage (messageString); - } + addMethod (@selector (application:didReceiveRemoteNotification:), [] (id self, SEL, NSApplication* application, NSDictionary* userInfo) + { + auto* delegate = getPushNotificationsDelegate (self); - static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - menuTrackingChangedCallback (true); - } + SEL selector = @selector (application:didReceiveRemoteNotification:); - static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*) - { - if (menuTrackingChangedCallback != nullptr) - menuTrackingChangedCallback (false); - } + if (delegate != nil && [delegate respondsToSelector: selector]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; + [invocation setSelector: selector]; + [invocation setTarget: delegate]; + [invocation setArgument: &application atIndex:2]; + [invocation setArgument: &userInfo atIndex:3]; - static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread) + [invocation invoke]; + } + }); + #endif + registerClass(); + } + +private: static void focusChanged() { if (appFocusChangeCallback != nullptr) (*appFocusChangeCallback)(); } - static void getUrl_withReplyEvent (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*) - { - if (auto* app = JUCEApplicationBase::getInstance()) - app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue])); - } - static String quotedIfContainsSpaces (NSString* file) { String s (nsStringToJuce (file)); @@ -191,71 +228,12 @@ static String quotedIfContainsSpaces (NSString* file) return s; } - #if JUCE_PUSH_NOTIFICATIONS //============================================================================== - static void setPushNotificationsDelegate (id self, SEL, NSObject* delegate) - { - object_setInstanceVariable (self, "pushNotificationsDelegate", delegate); - } - + #if JUCE_PUSH_NOTIFICATIONS static NSObject* getPushNotificationsDelegate (id self) { return getIvar*> (self, "pushNotificationsDelegate"); } - - static void registeredForRemoteNotifications (id self, SEL, NSApplication* application, NSData* deviceToken) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &deviceToken atIndex:3]; - - [invocation invoke]; - } - } - - static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication* application, NSError* error) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &error atIndex:3]; - - [invocation invoke]; - } - } - - static void didReceiveRemoteNotification (id self, SEL, NSApplication* application, NSDictionary* userInfo) - { - auto* delegate = getPushNotificationsDelegate (self); - - SEL selector = @selector (application:didReceiveRemoteNotification:); - - if (delegate != nil && [delegate respondsToSelector: selector]) - { - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]]; - [invocation setSelector: selector]; - [invocation setTarget: delegate]; - [invocation setArgument: &application atIndex:2]; - [invocation setArgument: &userInfo atIndex:3]; - - [invocation invoke]; - } - } #endif }; @@ -459,27 +437,6 @@ void initialiseNSApplication() userInfo: info]; } -// Special function used by some plugin classes to re-post carbon events -void repostCurrentNSEvent(); -void repostCurrentNSEvent() -{ - struct EventReposter : public CallbackMessage - { - EventReposter() : e ([[NSApp currentEvent] retain]) {} - ~EventReposter() override { [e release]; } - - void messageCallback() override - { - [NSApp postEvent: e atStart: YES]; - } - - NSEvent* e; - }; - - (new EventReposter())->post(); -} - - //============================================================================== #if JUCE_MAC struct MountedVolumeListChangeDetector::Pimpl diff --git a/modules/juce_events/native/juce_osx_MessageQueue.h b/modules/juce_events/native/juce_MessageQueue_mac.h similarity index 100% rename from modules/juce_events/native/juce_osx_MessageQueue.h rename to modules/juce_events/native/juce_MessageQueue_mac.h diff --git a/modules/juce_events/native/juce_android_Messaging.cpp b/modules/juce_events/native/juce_Messaging_android.cpp similarity index 100% rename from modules/juce_events/native/juce_android_Messaging.cpp rename to modules/juce_events/native/juce_Messaging_android.cpp diff --git a/modules/juce_events/native/juce_linux_Messaging.cpp b/modules/juce_events/native/juce_Messaging_linux.cpp similarity index 96% rename from modules/juce_events/native/juce_linux_Messaging.cpp rename to modules/juce_events/native/juce_Messaging_linux.cpp index 69fa23943fa3..1564d4b5202f 100644 --- a/modules/juce_events/native/juce_linux_Messaging.cpp +++ b/modules/juce_events/native/juce_Messaging_linux.cpp @@ -327,6 +327,8 @@ void MessageManager::broadcastMessage (const String&) // TODO } +namespace detail +{ // this function expects that it will NEVER be called simultaneously for two concurrent threads bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) { @@ -349,6 +351,7 @@ bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) return true; } +} // namespace detail //============================================================================== void LinuxEventLoop::registerFdCallback (int fd, std::function readCallback, short eventMask) diff --git a/modules/juce_events/native/juce_win32_Messaging.cpp b/modules/juce_events/native/juce_Messaging_windows.cpp similarity index 91% rename from modules/juce_events/native/juce_win32_Messaging.cpp rename to modules/juce_events/native/juce_Messaging_windows.cpp index 0e91c2159628..e011373b959c 100644 --- a/modules/juce_events/native/juce_win32_Messaging.cpp +++ b/modules/juce_events/native/juce_Messaging_windows.cpp @@ -25,10 +25,6 @@ namespace juce extern HWND juce_messageWindowHandle; -#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - bool juce_isRunningInUnity(); -#endif - #if JUCE_MODULE_AVAILABLE_juce_gui_extra LRESULT juce_offerEventToActiveXControl (::MSG&); #endif @@ -94,13 +90,11 @@ class InternalMessageQueue if (! shouldTriggerMessageQueueDispatch) return; - #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity - if (juce_isRunningInUnity()) + if (detail::RunningInUnity::state) { SendNotifyMessage (juce_messageWindowHandle, customMessageID, 0, 0); return; } - #endif PostMessage (juce_messageWindowHandle, customMessageID, 0, 0); } @@ -260,6 +254,9 @@ JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue) const TCHAR InternalMessageQueue::messageWindowName[] = _T("JUCEWindow"); //============================================================================== +namespace detail +{ + bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) { if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) @@ -268,6 +265,8 @@ bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages) return false; } +} // namespace detail + bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message) { if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating()) @@ -299,25 +298,24 @@ void MessageManager::doPlatformSpecificShutdown() } //============================================================================== -struct MountedVolumeListChangeDetector::Pimpl : private DeviceChangeDetector +struct MountedVolumeListChangeDetector::Pimpl { - Pimpl (MountedVolumeListChangeDetector& d) : DeviceChangeDetector (L"MountedVolumeList"), owner (d) + explicit Pimpl (MountedVolumeListChangeDetector& d) + : owner (d) { File::findFileSystemRoots (lastVolumeList); } - void systemDeviceChanged() override + void systemDeviceChanged() { Array newList; File::findFileSystemRoots (newList); - if (lastVolumeList != newList) - { - lastVolumeList = newList; + if (std::exchange (lastVolumeList, newList) != newList) owner.mountedVolumeListChanged(); - } } + DeviceChangeDetector detector { L"MountedVolumeList", [this] { systemDeviceChanged(); } }; MountedVolumeListChangeDetector& owner; Array lastVolumeList; }; diff --git a/modules/juce_events/native/juce_RunningInUnity.h b/modules/juce_events/native/juce_RunningInUnity.h new file mode 100644 index 000000000000..6a96cf8a3613 --- /dev/null +++ b/modules/juce_events/native/juce_RunningInUnity.h @@ -0,0 +1,35 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#pragma once + +namespace juce::detail +{ + +class RunningInUnity +{ +public: + /* @internal */ + static inline bool state = false; +}; + +} // namespace juce::detail diff --git a/modules/juce_events/native/juce_win32_WinRTWrapper.cpp b/modules/juce_events/native/juce_WinRTWrapper_windows.cpp similarity index 100% rename from modules/juce_events/native/juce_win32_WinRTWrapper.cpp rename to modules/juce_events/native/juce_WinRTWrapper_windows.cpp diff --git a/modules/juce_events/native/juce_win32_WinRTWrapper.h b/modules/juce_events/native/juce_WinRTWrapper_windows.h similarity index 100% rename from modules/juce_events/native/juce_win32_WinRTWrapper.h rename to modules/juce_events/native/juce_WinRTWrapper_windows.h diff --git a/modules/juce_graphics/colour/juce_Colour.cpp b/modules/juce_graphics/colour/juce_Colour.cpp index 38d2d8b04f1c..47c343ec3c88 100644 --- a/modules/juce_graphics/colour/juce_Colour.cpp +++ b/modules/juce_graphics/colour/juce_Colour.cpp @@ -44,7 +44,7 @@ namespace ColourHelpers float hue = 0.0f; - if (hi > 0 && ! approximatelyEqual (hi, lo)) + if (hi > 0 && ! exactlyEqual (hi, lo)) { auto invDiff = 1.0f / (float) (hi - lo); @@ -291,13 +291,18 @@ Colour::Colour (PixelAlpha alpha) noexcept } //============================================================================== -const PixelARGB Colour::getPixelARGB() const noexcept +PixelARGB Colour::getPixelARGB() const noexcept { PixelARGB p (argb); p.premultiply(); return p; } +PixelARGB Colour::getNonPremultipliedPixelARGB() const noexcept +{ + return argb; +} + uint32 Colour::getARGB() const noexcept { return argb.getInARGBMaskOrder(); diff --git a/modules/juce_graphics/colour/juce_Colour.h b/modules/juce_graphics/colour/juce_Colour.h index 3077addde61e..2e1e4ee3d00b 100644 --- a/modules/juce_graphics/colour/juce_Colour.h +++ b/modules/juce_graphics/colour/juce_Colour.h @@ -194,7 +194,11 @@ class JUCE_API Colour final /** Returns a premultiplied ARGB pixel object that represents this colour. */ - const PixelARGB getPixelARGB() const noexcept; + PixelARGB getPixelARGB() const noexcept; + + /** Returns an ARGB pixel object that represents this colour. + */ + PixelARGB getNonPremultipliedPixelARGB() const noexcept; /** Returns a 32-bit integer that represents this colour. diff --git a/modules/juce_graphics/colour/juce_ColourGradient.cpp b/modules/juce_graphics/colour/juce_ColourGradient.cpp index a9dc3af6810e..c5bf13426365 100644 --- a/modules/juce_graphics/colour/juce_ColourGradient.cpp +++ b/modules/juce_graphics/colour/juce_ColourGradient.cpp @@ -30,7 +30,7 @@ ColourGradient::ColourGradient() noexcept : isRadial (false) { #if JUCE_DEBUG point1.setX (987654.0f); - #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED jassert (point1.x != 987654.0f); + #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED jassert (! exactlyEqual (point1.x, 987654.0f)); #else #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED #endif @@ -174,7 +174,7 @@ void ColourGradient::setColour (int index, Colour newColour) noexcept Colour ColourGradient::getColourAtPosition (double position) const noexcept { - jassert (colours.getReference(0).position == 0.0); // the first colour specified has to go at position 0 + jassert (approximatelyEqual (colours.getReference (0).position, 0.0)); // the first colour specified has to go at position 0 if (position <= 0 || colours.size() <= 1) return colours.getReference(0).colour; @@ -199,31 +199,30 @@ void ColourGradient::createLookupTable (PixelARGB* const lookupTable, const int JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED // Trying to use this object without setting its coordinates? jassert (colours.size() >= 2); jassert (numEntries > 0); - jassert (colours.getReference(0).position == 0.0); // The first colour specified has to go at position 0 + jassert (approximatelyEqual (colours.getReference(0).position, 0.0)); // The first colour specified has to go at position 0 - auto pix1 = colours.getReference (0).colour.getPixelARGB(); int index = 0; - for (int j = 1; j < colours.size(); ++j) + for (int j = 0; j < colours.size() - 1; ++j) { - auto& p = colours.getReference (j); - auto numToDo = roundToInt (p.position * (numEntries - 1)) - index; - auto pix2 = p.colour.getPixelARGB(); + const auto& o = colours.getReference (j + 0); + const auto& p = colours.getReference (j + 1); + const auto numToDo = roundToInt (p.position * (numEntries - 1)) - index; + const auto pix1 = o.colour.getNonPremultipliedPixelARGB(); + const auto pix2 = p.colour.getNonPremultipliedPixelARGB(); - for (int i = 0; i < numToDo; ++i) + for (auto i = 0; i < numToDo; ++i) { - jassert (index >= 0 && index < numEntries); + auto blended = pix1; + blended.tween (pix2, (uint32) ((i << 8) / numToDo)); + blended.premultiply(); - lookupTable[index] = pix1; - lookupTable[index].tween (pix2, (uint32) ((i << 8) / numToDo)); - ++index; + jassert (0 <= index && index < numEntries); + lookupTable[index++] = blended; } - - pix1 = pix2; } - while (index < numEntries) - lookupTable [index++] = pix1; + std::fill (lookupTable + index, lookupTable + numEntries, colours.getLast().colour.getPixelARGB()); } int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock& lookupTable) const @@ -259,12 +258,13 @@ bool ColourGradient::isInvisible() const noexcept bool ColourGradient::ColourPoint::operator== (ColourPoint other) const noexcept { - return position == other.position && colour == other.colour; + const auto tie = [] (const ColourPoint& p) { return std::tie (p.position, p.colour); }; + return tie (*this) == tie (other); } bool ColourGradient::ColourPoint::operator!= (ColourPoint other) const noexcept { - return position != other.position || colour != other.colour; + return ! operator== (other); } } // namespace juce diff --git a/modules/juce_graphics/colour/juce_ColourGradient.h b/modules/juce_graphics/colour/juce_ColourGradient.h index c38f5251f7ee..6a15d95f1766 100644 --- a/modules/juce_graphics/colour/juce_ColourGradient.h +++ b/modules/juce_graphics/colour/juce_ColourGradient.h @@ -185,6 +185,17 @@ class JUCE_API ColourGradient final */ void createLookupTable (PixelARGB* resultLookupTable, int numEntries) const noexcept; + /** Creates a set of interpolated premultiplied ARGB values. + This will fill an array of a user-specified size with the gradient, interpolating to fit. + When calling this, the ColourGradient must have at least 2 colour stops specified. + */ + template + void createLookupTable (PixelARGB (&resultLookupTable)[NumEntries]) const noexcept + { + static_assert (NumEntries != 0); + createLookupTable (resultLookupTable, NumEntries); + } + /** Returns true if all colours are opaque. */ bool isOpaque() const noexcept; diff --git a/modules/juce_graphics/contexts/juce_GraphicsContext.cpp b/modules/juce_graphics/contexts/juce_GraphicsContext.cpp index 640ac3b599b0..225145fdfe8d 100644 --- a/modules/juce_graphics/contexts/juce_GraphicsContext.cpp +++ b/modules/juce_graphics/contexts/juce_GraphicsContext.cpp @@ -627,7 +627,7 @@ void Graphics::drawEllipse (Rectangle area, float lineThickness) const { Path p; - if (area.getWidth() == area.getHeight()) + if (approximatelyEqual (area.getWidth(), area.getHeight())) { // For a circle, we can avoid having to generate a stroke p.addEllipse (area.expanded (lineThickness * 0.5f)); @@ -781,7 +781,7 @@ void Graphics::drawDashedLine (Line line, const float* dashLengths, const Line segment (line.getStart() + (delta * lastAlpha).toFloat(), line.getStart() + (delta * jmin (1.0, alpha)).toFloat()); - if (lineThickness != 1.0f) + if (! approximatelyEqual (lineThickness, 1.0f)) drawLine (segment, lineThickness); else context.drawLine (segment); diff --git a/modules/juce_graphics/fonts/juce_CustomTypeface.cpp b/modules/juce_graphics/fonts/juce_CustomTypeface.cpp index 11d37b084be3..8e5ff75739db 100644 --- a/modules/juce_graphics/fonts/juce_CustomTypeface.cpp +++ b/modules/juce_graphics/fonts/juce_CustomTypeface.cpp @@ -189,7 +189,7 @@ void CustomTypeface::addGlyph (juce_wchar character, const Path& path, float wid void CustomTypeface::addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) noexcept { - if (extraAmount != 0.0f) + if (! approximatelyEqual (extraAmount, 0.0f)) { if (auto* g = findGlyph (char1, true)) g->addKerningPair (char2, extraAmount); diff --git a/modules/juce_graphics/fonts/juce_Font.cpp b/modules/juce_graphics/fonts/juce_Font.cpp index b6a6ec00a8bf..8eb2c9d37251 100644 --- a/modules/juce_graphics/fonts/juce_Font.cpp +++ b/modules/juce_graphics/fonts/juce_Font.cpp @@ -291,7 +291,7 @@ class Font::SharedFontInternal : public ReferenceCountedObject { const ScopedLock lock (mutex); - if (ascent == 0.0f) + if (approximatelyEqual (ascent, 0.0f)) ascent = getTypefacePtr (f)->getAscent(); return height * ascent; @@ -569,7 +569,7 @@ void Font::setHeight (float newHeight) { newHeight = FontValues::limitFontHeight (newHeight); - if (font->getHeight() != newHeight) + if (! approximatelyEqual (font->getHeight(), newHeight)) { dupeInternalIfShared(); font->setHeight (newHeight); @@ -581,7 +581,7 @@ void Font::setHeightWithoutChangingWidth (float newHeight) { newHeight = FontValues::limitFontHeight (newHeight); - if (font->getHeight() != newHeight) + if (! approximatelyEqual (font->getHeight(), newHeight)) { dupeInternalIfShared(); font->setHorizontalScale (font->getHorizontalScale() * (font->getHeight() / newHeight)); @@ -626,9 +626,9 @@ void Font::setSizeAndStyle (float newHeight, { newHeight = FontValues::limitFontHeight (newHeight); - if (font->getHeight() != newHeight - || font->getHorizontalScale() != newHorizontalScale - || font->getKerning() != newKerningAmount) + if (! approximatelyEqual (font->getHeight(), newHeight) + || ! approximatelyEqual (font->getHorizontalScale(), newHorizontalScale) + || ! approximatelyEqual (font->getKerning(), newKerningAmount)) { dupeInternalIfShared(); font->setHeight (newHeight); @@ -647,9 +647,9 @@ void Font::setSizeAndStyle (float newHeight, { newHeight = FontValues::limitFontHeight (newHeight); - if (font->getHeight() != newHeight - || font->getHorizontalScale() != newHorizontalScale - || font->getKerning() != newKerningAmount) + if (! approximatelyEqual (font->getHeight(), newHeight) + || ! approximatelyEqual (font->getHorizontalScale(), newHorizontalScale) + || ! approximatelyEqual (font->getKerning(), newKerningAmount)) { dupeInternalIfShared(); font->setHeight (newHeight); @@ -748,7 +748,7 @@ float Font::getStringWidthFloat (const String& text) const { auto w = getTypefacePtr()->getStringWidth (text); - if (font->getKerning() != 0.0f) + if (! approximatelyEqual (font->getKerning(), 0.0f)) w += font->getKerning() * (float) text.length(); return w * font->getHeight() * font->getHorizontalScale(); @@ -763,7 +763,7 @@ void Font::getGlyphPositions (const String& text, Array& glyphs, ArraygetHeight() * font->getHorizontalScale(); auto* x = xOffsets.getRawDataPointer(); - if (font->getKerning() != 0.0f) + if (! approximatelyEqual (font->getKerning(), 0.0f)) { for (int i = 0; i < num; ++i) x[i] = (x[i] + (float) i * font->getKerning()) * scale; diff --git a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp index 648acfcc2591..93571e1d41b0 100644 --- a/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp +++ b/modules/juce_graphics/fonts/juce_GlyphArrangement.cpp @@ -312,7 +312,7 @@ void GlyphArrangement::addFittedText (const Font& f, const String& text, Justification layout, int maximumLines, float minimumHorizontalScale) { - if (minimumHorizontalScale == 0.0f) + if (approximatelyEqual (minimumHorizontalScale, 0.0f)) minimumHorizontalScale = Font::getDefaultMinimumHorizontalScaleFactor(); // doesn't make much sense if this is outside a sensible range of 0.5 to 1.0 @@ -363,7 +363,7 @@ void GlyphArrangement::moveRangeOfGlyphs (int startIndex, int num, const float d { jassert (startIndex >= 0); - if (dx != 0.0f || dy != 0.0f) + if (! approximatelyEqual (dx, 0.0f) || ! approximatelyEqual (dy, 0.0f)) { if (num < 0 || startIndex + num > glyphs.size()) num = glyphs.size() - startIndex; @@ -491,7 +491,7 @@ void GlyphArrangement::justifyGlyphs (int startIndex, int num, { auto glyphY = glyphs.getReference (startIndex + i).getBaselineY(); - if (glyphY != baseY) + if (! approximatelyEqual (glyphY, baseY)) { spreadOutLine (startIndex + lineStart, i - lineStart, width); @@ -695,7 +695,7 @@ void GlyphArrangement::drawGlyphUnderline (const Graphics& g, const PositionedGl auto lineThickness = (pg.font.getDescent()) * 0.3f; auto nextX = pg.x + pg.w; - if (i < glyphs.size() - 1 && glyphs.getReference (i + 1).y == pg.y) + if (i < glyphs.size() - 1 && approximatelyEqual (glyphs.getReference (i + 1).y, pg.y)) nextX = glyphs.getReference (i + 1).x; Path p; diff --git a/modules/juce_graphics/fonts/juce_TextLayout.cpp b/modules/juce_graphics/fonts/juce_TextLayout.cpp index 817d5ec32c07..da09e575d77f 100644 --- a/modules/juce_graphics/fonts/juce_TextLayout.cpp +++ b/modules/juce_graphics/fonts/juce_TextLayout.cpp @@ -294,7 +294,7 @@ void TextLayout::createLayoutWithBalancedLineLengths (const AttributedString& te maxWidth -= 10.0f; } - if (bestWidth != maxWidth) + if (! approximatelyEqual (bestWidth, maxWidth)) createLayout (text, bestWidth, maxHeight); } diff --git a/modules/juce_graphics/fonts/juce_Typeface.cpp b/modules/juce_graphics/fonts/juce_Typeface.cpp index cc1fef47027e..5c14043778fb 100644 --- a/modules/juce_graphics/fonts/juce_Typeface.cpp +++ b/modules/juce_graphics/fonts/juce_Typeface.cpp @@ -148,7 +148,7 @@ struct Typeface::HintingParams void applyVerticalHintingTransform (float fontSize, Path& path) { - if (cachedSize != fontSize) + if (! approximatelyEqual (cachedSize, fontSize)) { cachedSize = fontSize; cachedScale = Scaling (top, middle, bottom, fontSize); diff --git a/modules/juce_graphics/geometry/juce_AffineTransform.cpp b/modules/juce_graphics/geometry/juce_AffineTransform.cpp index d2aa599b338d..ddc55c291eb3 100644 --- a/modules/juce_graphics/geometry/juce_AffineTransform.cpp +++ b/modules/juce_graphics/geometry/juce_AffineTransform.cpp @@ -35,12 +35,12 @@ AffineTransform::AffineTransform (float m00, float m01, float m02, bool AffineTransform::operator== (const AffineTransform& other) const noexcept { - return mat00 == other.mat00 - && mat01 == other.mat01 - && mat02 == other.mat02 - && mat10 == other.mat10 - && mat11 == other.mat11 - && mat12 == other.mat12; + const auto tie = [] (const AffineTransform& a) + { + return std::tie (a.mat00, a.mat01, a.mat02, a.mat10, a.mat11, a.mat12); + }; + + return tie (*this) == tie (other); } bool AffineTransform::operator!= (const AffineTransform& other) const noexcept @@ -51,12 +51,7 @@ bool AffineTransform::operator!= (const AffineTransform& other) const noexcept //============================================================================== bool AffineTransform::isIdentity() const noexcept { - return mat01 == 0.0f - && mat02 == 0.0f - && mat10 == 0.0f - && mat12 == 0.0f - && mat00 == 1.0f - && mat11 == 1.0f; + return operator== (AffineTransform()); } const AffineTransform AffineTransform::identity (1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); @@ -207,7 +202,7 @@ AffineTransform AffineTransform::inverted() const noexcept bool AffineTransform::isSingularity() const noexcept { - return (mat00 * mat11 - mat10 * mat01) == 0.0f; + return exactlyEqual (mat00 * mat11 - mat10 * mat01, 0.0f); } AffineTransform AffineTransform::fromTargetPoints (float x00, float y00, @@ -229,10 +224,10 @@ AffineTransform AffineTransform::fromTargetPoints (float sx1, float sy1, float t bool AffineTransform::isOnlyTranslation() const noexcept { - return mat01 == 0.0f - && mat10 == 0.0f - && mat00 == 1.0f - && mat11 == 1.0f; + return exactlyEqual (mat01, 0.0f) + && exactlyEqual (mat10, 0.0f) + && exactlyEqual (mat00, 1.0f) + && exactlyEqual (mat11, 1.0f); } float AffineTransform::getDeterminant() const noexcept diff --git a/modules/juce_graphics/geometry/juce_EdgeTable.cpp b/modules/juce_graphics/geometry/juce_EdgeTable.cpp index 7b66053804e9..c1d9d6208bc5 100644 --- a/modules/juce_graphics/geometry/juce_EdgeTable.cpp +++ b/modules/juce_graphics/geometry/juce_EdgeTable.cpp @@ -46,17 +46,22 @@ EdgeTable::EdgeTable (Rectangle area, const Path& path, const AffineTransfo t += lineStrideElements; } - auto leftLimit = scale * bounds.getX(); - auto topLimit = scale * bounds.getY(); - auto rightLimit = scale * bounds.getRight(); - auto heightLimit = scale * bounds.getHeight(); + auto leftLimit = scale * static_cast (bounds.getX()); + auto topLimit = scale * static_cast (bounds.getY()); + auto rightLimit = scale * static_cast (bounds.getRight()); + auto heightLimit = scale * static_cast (bounds.getHeight()); PathFlatteningIterator iter (path, transform); while (iter.next()) { - auto y1 = roundToInt (iter.y1 * 256.0f); - auto y2 = roundToInt (iter.y2 * 256.0f); + const auto scaleIterY = [] (auto y) + { + return static_cast (y * 256.0f + (y >= 0 ? 0.5f : -0.5f)); + }; + + auto y1 = scaleIterY (iter.y1); + auto y2 = scaleIterY (iter.y2); if (y1 != y2) { @@ -82,19 +87,15 @@ EdgeTable::EdgeTable (Rectangle area, const Path& path, const AffineTransfo { const double startX = 256.0f * iter.x1; const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1); - auto stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier))); + auto stepSize = static_cast (jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier)))); do { auto step = jmin (stepSize, y2 - y1, 256 - (y1 & 255)); - auto x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY)); - - if (x < leftLimit) - x = leftLimit; - else if (x >= rightLimit) - x = rightLimit - 1; + auto x = static_cast (startX + multiplier * static_cast ((y1 + (step >> 1)) - startY)); + auto clampedX = static_cast (jlimit (leftLimit, rightLimit - 1, x)); - addEdgePoint (x, y1 / scale, direction * step); + addEdgePoint (clampedX, static_cast (y1 / scale), static_cast (direction * step)); y1 += step; } while (y1 < y2); diff --git a/modules/juce_graphics/geometry/juce_Line.h b/modules/juce_graphics/geometry/juce_Line.h index 940b095599de..3aac59d48721 100644 --- a/modules/juce_graphics/geometry/juce_Line.h +++ b/modules/juce_graphics/geometry/juce_Line.h @@ -204,7 +204,7 @@ class Line Point getPointAlongLine (ValueType distanceFromStart) const noexcept { const auto length = getLength(); - return length == 0 ? start : start + (end - start) * (distanceFromStart / length); + return approximatelyEqual (length, (ValueType) 0) ? start : start + (end - start) * (distanceFromStart / length); } /** Returns a point which is a certain distance along and to the side of this line. @@ -391,32 +391,34 @@ class Line auto d2 = p4 - p3; auto divisor = d1.x * d2.y - d2.x * d1.y; - if (divisor == 0) + const auto zero = ValueType{}; + + if (approximatelyEqual (divisor, zero)) { if (! (d1.isOrigin() || d2.isOrigin())) { - if (d1.y == 0 && d2.y != 0) + if (approximatelyEqual (d1.y, zero) && ! approximatelyEqual (d2.y, zero)) { auto along = (p1.y - p3.y) / d2.y; intersection = p1.withX (p3.x + along * d2.x); return isZeroToOne (along); } - if (d2.y == 0 && d1.y != 0) + if (approximatelyEqual (d2.y, zero) && ! approximatelyEqual (d1.y, zero)) { auto along = (p3.y - p1.y) / d1.y; intersection = p3.withX (p1.x + along * d1.x); return isZeroToOne (along); } - if (d1.x == 0 && d2.x != 0) + if (approximatelyEqual (d1.x, zero) && ! approximatelyEqual (d2.x, zero)) { auto along = (p1.x - p3.x) / d2.x; intersection = p1.withY (p3.y + along * d2.y); return isZeroToOne (along); } - if (d2.x == 0 && d1.x != 0) + if (approximatelyEqual (d2.x, zero) && ! approximatelyEqual (d1.x, zero)) { auto along = (p3.x - p1.x) / d1.x; intersection = p3.withY (p1.y + along * d1.y); diff --git a/modules/juce_graphics/geometry/juce_Path.cpp b/modules/juce_graphics/geometry/juce_Path.cpp index 5026a75d0090..a0ab1b317119 100644 --- a/modules/juce_graphics/geometry/juce_Path.cpp +++ b/modules/juce_graphics/geometry/juce_Path.cpp @@ -28,7 +28,7 @@ namespace juce // tests that some coordinates aren't NaNs #define JUCE_CHECK_COORDS_ARE_VALID(x, y) \ - jassert (x == x && y == y); + jassert (! std::isnan (x) && ! std::isnan (y)); //============================================================================== namespace PathHelpers @@ -58,18 +58,13 @@ namespace PathHelpers } //============================================================================== -const float Path::lineMarker = 100001.0f; -const float Path::moveMarker = 100002.0f; -const float Path::quadMarker = 100003.0f; -const float Path::cubicMarker = 100004.0f; -const float Path::closeSubPathMarker = 100005.0f; const float Path::defaultToleranceForTesting = 1.0f; const float Path::defaultToleranceForMeasurement = 0.6f; static bool isMarker (float value, float marker) noexcept { - return value == marker; + return exactlyEqual (value, marker); } //============================================================================== @@ -726,10 +721,11 @@ void Path::addBubble (Rectangle bodyArea, void Path::addPath (const Path& other) { const auto* d = other.data.begin(); + const auto size = other.data.size(); - for (int i = 0; i < other.data.size();) + for (int i = 0; i < size;) { - auto type = d[i++]; + const auto type = d[i++]; if (isMarker (type, moveMarker)) { @@ -767,10 +763,11 @@ void Path::addPath (const Path& other, const AffineTransform& transformToApply) { const auto* d = other.data.begin(); + const auto size = other.data.size(); - for (int i = 0; i < other.data.size();) + for (int i = 0; i < size;) { - auto type = d[i++]; + const auto type = d[i++]; if (isMarker (type, closeSubPathMarker)) { diff --git a/modules/juce_graphics/geometry/juce_Path.h b/modules/juce_graphics/geometry/juce_Path.h index 62dd72a18be5..849dad2c265c 100644 --- a/modules/juce_graphics/geometry/juce_Path.h +++ b/modules/juce_graphics/geometry/juce_Path.h @@ -827,11 +827,11 @@ class JUCE_API Path final PathBounds bounds; bool useNonZeroWinding = true; - static const float lineMarker; - static const float moveMarker; - static const float quadMarker; - static const float cubicMarker; - static const float closeSubPathMarker; + static constexpr float lineMarker = 100001.0f; + static constexpr float moveMarker = 100002.0f; + static constexpr float quadMarker = 100003.0f; + static constexpr float cubicMarker = 100004.0f; + static constexpr float closeSubPathMarker = 100005.0f; JUCE_LEAK_DETECTOR (Path) }; diff --git a/modules/juce_graphics/geometry/juce_PathIterator.cpp b/modules/juce_graphics/geometry/juce_PathIterator.cpp index 1239de232b8e..e883914216d2 100644 --- a/modules/juce_graphics/geometry/juce_PathIterator.cpp +++ b/modules/juce_graphics/geometry/juce_PathIterator.cpp @@ -138,9 +138,9 @@ bool PathFlatteningIterator::next() closesSubPath = stackPos == stackBase.get() && source != path.data.end() - && *source == Path::closeSubPathMarker - && x2 == subPathCloseX - && y2 == subPathCloseY; + && isMarker (*source, Path::closeSubPathMarker) + && approximatelyEqual (x2, subPathCloseX) + && approximatelyEqual (y2, subPathCloseY); return true; } @@ -167,8 +167,8 @@ bool PathFlatteningIterator::next() auto errorY = m3y - y2; auto outsideTolerance = errorX * errorX + errorY * errorY > toleranceSquared; - auto canBeSubdivided = (m3x != m1x && m3x != m2x) - || (m3y != m1y && m3y != m2y); + auto canBeSubdivided = (! approximatelyEqual (m3x, m1x) && ! approximatelyEqual (m3x, m2x)) + || (! approximatelyEqual (m3y, m1y) && ! approximatelyEqual (m3y, m2y)); if (outsideTolerance && canBeSubdivided) { @@ -226,10 +226,10 @@ bool PathFlatteningIterator::next() auto outsideTolerance = error1X * error1X + error1Y * error1Y > toleranceSquared || error2X * error2X + error2Y * error2Y > toleranceSquared; - auto canBeSubdivided = (m4x != m1x && m4x != m2x) - || (m4y != m1y && m4y != m2y) - || (m5x != m3x && m5x != m2x) - || (m5y != m3y && m5y != m2y); + auto canBeSubdivided = (! approximatelyEqual (m4x, m1x) && ! approximatelyEqual (m4x, m2x)) + || (! approximatelyEqual (m4y, m1y) && ! approximatelyEqual (m4y, m2y)) + || (! approximatelyEqual (m5x, m3x) && ! approximatelyEqual (m5x, m2x)) + || (! approximatelyEqual (m5y, m3y) && ! approximatelyEqual (m5y, m2y)); if (outsideTolerance && canBeSubdivided) { @@ -266,7 +266,7 @@ bool PathFlatteningIterator::next() } else if (isMarker (type, Path::closeSubPathMarker)) { - if (x2 != subPathCloseX || y2 != subPathCloseY) + if (! approximatelyEqual (x2, subPathCloseX) || ! approximatelyEqual (y2, subPathCloseY)) { x1 = x2; y1 = y2; diff --git a/modules/juce_graphics/geometry/juce_PathStrokeType.cpp b/modules/juce_graphics/geometry/juce_PathStrokeType.cpp index fae0391abc52..8bfcf9de5082 100644 --- a/modules/juce_graphics/geometry/juce_PathStrokeType.cpp +++ b/modules/juce_graphics/geometry/juce_PathStrokeType.cpp @@ -57,9 +57,8 @@ PathStrokeType::~PathStrokeType() noexcept bool PathStrokeType::operator== (const PathStrokeType& other) const noexcept { - return thickness == other.thickness - && jointStyle == other.jointStyle - && endStyle == other.endStyle; + const auto tie = [] (const PathStrokeType& p) { return std::tie (p.thickness, p.jointStyle, p.endStyle); }; + return tie (*this) == tie (other); } bool PathStrokeType::operator!= (const PathStrokeType& other) const noexcept @@ -70,122 +69,128 @@ bool PathStrokeType::operator!= (const PathStrokeType& other) const noexcept //============================================================================== namespace PathStrokeHelpers { - static bool lineIntersection (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - const float x4, const float y4, - float& intersectionX, - float& intersectionY, - float& distanceBeyondLine1EndSquared) noexcept + struct LineIntersection { - if (x2 != x3 || y2 != y3) + Point point; + float distanceBeyondLine1EndSquared; + bool intersects; + }; + + static LineIntersection lineIntersection (const float x1, const float y1, + const float x2, const float y2, + const float x3, const float y3, + const float x4, const float y4) + { + if (! approximatelyEqual (x2, x3) || ! approximatelyEqual (y2, y3)) { - auto dx1 = x2 - x1; - auto dy1 = y2 - y1; - auto dx2 = x4 - x3; - auto dy2 = y4 - y3; - auto divisor = dx1 * dy2 - dx2 * dy1; + const auto dx1 = x2 - x1; + const auto dy1 = y2 - y1; + const auto dx2 = x4 - x3; + const auto dy2 = y4 - y3; + const auto divisor = dx1 * dy2 - dx2 * dy1; - if (divisor == 0.0f) + if (approximatelyEqual (divisor, 0.0f)) { - if (! ((dx1 == 0.0f && dy1 == 0.0f) || (dx2 == 0.0f && dy2 == 0.0f))) + if (! ((approximatelyEqual (dx1, 0.0f) && approximatelyEqual (dy1, 0.0f)) + || (approximatelyEqual (dx2, 0.0f) && approximatelyEqual (dy2, 0.0f)))) { - if (dy1 == 0.0f && dy2 != 0.0f) + if (approximatelyEqual (dy1, 0.0f) && ! approximatelyEqual (dy2, 0.0f)) { - auto along = (y1 - y3) / dy2; - intersectionX = x3 + along * dx2; - intersectionY = y1; - - distanceBeyondLine1EndSquared = intersectionX - x2; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if ((x2 > x1) == (intersectionX < x2)) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; + const auto along = (y1 - y3) / dy2; + const auto intersectionX = x3 + along * dx2; + const auto intersectionY = y1; + + const auto distance = square (intersectionX - x2); + const auto distanceBeyondLine1EndSquared = (x2 > x1) == (intersectionX < x2) + ? -distance + : distance; + + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + along >= 0 && along <= 1.0f }; } - if (dy2 == 0.0f && dy1 != 0.0f) + if (approximatelyEqual (dy2, 0.0f) && ! approximatelyEqual (dy1, 0.0f)) { - auto along = (y3 - y1) / dy1; - intersectionX = x1 + along * dx1; - intersectionY = y3; + const auto along = (y3 - y1) / dy1; + const auto intersectionX = x1 + along * dx1; + const auto intersectionY = y3; - distanceBeyondLine1EndSquared = (along - 1.0f) * dx1; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if (along < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; + const auto distance = square ((along - 1.0f) * dx1); + const auto distanceBeyondLine1EndSquared = along < 1.0f ? -distance : distance; - return along >= 0 && along <= 1.0f; + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + along >= 0 && along <= 1.0f }; } - if (dx1 == 0.0f && dx2 != 0.0f) + if (approximatelyEqual (dx1, 0.0f) && ! approximatelyEqual (dx2, 0.0f)) { - auto along = (x1 - x3) / dx2; - intersectionX = x1; - intersectionY = y3 + along * dy2; - - distanceBeyondLine1EndSquared = intersectionY - y2; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - - if ((y2 > y1) == (intersectionY < y2)) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return along >= 0 && along <= 1.0f; + const auto along = (x1 - x3) / dx2; + const auto intersectionX = x1; + const auto intersectionY = y3 + along * dy2; + + const auto distance = square (intersectionY - y2); + const auto distanceBeyondLine1EndSquared = (y2 > y1) == (intersectionY < y2) + ? -distance + : distance; + + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + along >= 0 && along <= 1.0f }; } - if (dx2 == 0.0f && dx1 != 0.0f) + if (approximatelyEqual (dx2, 0.0f) && ! approximatelyEqual (dx1, 0.0f)) { - auto along = (x3 - x1) / dx1; - intersectionX = x3; - intersectionY = y1 + along * dy1; + const auto along = (x3 - x1) / dx1; + const auto intersectionX = x3; + const auto intersectionY = y1 + along * dy1; - distanceBeyondLine1EndSquared = (along - 1.0f) * dy1; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - if (along < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; + const auto distance = square ((along - 1.0f) * dy1); + const auto distanceBeyondLine1EndSquared = along < 1.0f ? -distance : distance; - return along >= 0 && along <= 1.0f; + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + along >= 0 && along <= 1.0f }; } } - intersectionX = 0.5f * (x2 + x3); - intersectionY = 0.5f * (y2 + y3); + const auto intersectionX = 0.5f * (x2 + x3); + const auto intersectionY = 0.5f * (y2 + y3); + + const auto distanceBeyondLine1EndSquared = 0.0f; - distanceBeyondLine1EndSquared = 0.0f; - return false; + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + false }; } - auto along1 = ((y1 - y3) * dx2 - (x1 - x3) * dy2) / divisor; + const auto along = ((y1 - y3) * dx2 - (x1 - x3) * dy2) / divisor; - intersectionX = x1 + along1 * dx1; - intersectionY = y1 + along1 * dy1; + const auto intersectionX = x1 + along * dx1; + const auto intersectionY = y1 + along * dy1; - if (along1 >= 0 && along1 <= 1.0f) + if (along >= 0 && along <= 1.0f) { - auto along2 = ((y1 - y3) * dx1 - (x1 - x3) * dy1) / divisor; + const auto along2 = ((y1 - y3) * dx1 - (x1 - x3) * dy1) / divisor; if (along2 >= 0 && along2 <= 1.0f) { - distanceBeyondLine1EndSquared = 0.0f; - return true; + return { { intersectionX, intersectionY }, + 0.0f, + true }; } } - distanceBeyondLine1EndSquared = along1 - 1.0f; - distanceBeyondLine1EndSquared *= distanceBeyondLine1EndSquared; - distanceBeyondLine1EndSquared *= (dx1 * dx1 + dy1 * dy1); + const auto distance = square (along - 1.0f) * (dx1 * dx1 + dy1 * dy1); + const auto distanceBeyondLine1EndSquared = along < 1.0f ? -distance : distance; - if (along1 < 1.0f) - distanceBeyondLine1EndSquared = -distanceBeyondLine1EndSquared; - - return false; + return { { intersectionX, intersectionY }, + distanceBeyondLine1EndSquared, + false }; } - intersectionX = x2; - intersectionY = y2; - - distanceBeyondLine1EndSquared = 0.0f; - return true; + return { Point { x2, y2 }, 0.0f, true }; } static void addEdgeAndJoint (Path& destPath, @@ -198,31 +203,29 @@ namespace PathStrokeHelpers const float midX, const float midY) { if (style == PathStrokeType::beveled - || (x3 == x4 && y3 == y4) - || (x1 == x2 && y1 == y2)) + || (approximatelyEqual (x3, x4) && approximatelyEqual (y3, y4)) + || (approximatelyEqual (x1, x2) && approximatelyEqual (y1, y2))) { destPath.lineTo (x2, y2); destPath.lineTo (x3, y3); } else { - float jx, jy, distanceBeyondLine1EndSquared; + const auto intersection = lineIntersection (x1, y1, x2, y2, x3, y3, x4, y4); // if they intersect, use this point.. - if (lineIntersection (x1, y1, x2, y2, - x3, y3, x4, y4, - jx, jy, distanceBeyondLine1EndSquared)) + if (intersection.intersects) { - destPath.lineTo (jx, jy); + destPath.lineTo (intersection.point); } else { if (style == PathStrokeType::mitered) { - if (distanceBeyondLine1EndSquared < maxMiterExtensionSquared - && distanceBeyondLine1EndSquared > 0.0f) + if (0.0f < intersection.distanceBeyondLine1EndSquared + && intersection.distanceBeyondLine1EndSquared < maxMiterExtensionSquared) { - destPath.lineTo (jx, jy); + destPath.lineTo (intersection.point); } else { @@ -301,7 +304,7 @@ namespace PathStrokeHelpers auto dy = y2 - y1; auto len = juce_hypot (dx, dy); - if (len == 0.0f) + if (approximatelyEqual (len, 0.0f)) { offx1 = offx2 = x1; offy1 = offy2 = y1; @@ -610,7 +613,7 @@ namespace PathStrokeHelpers { auto len = std::sqrt (hypotSquared); - if (len == 0.0f) + if (approximatelyEqual (len, 0.0f)) { l.rx1 = l.rx2 = l.lx1 = l.lx2 = l.x1; l.ry1 = l.ry2 = l.ly1 = l.ly2 = l.y1; diff --git a/modules/juce_graphics/geometry/juce_Point.h b/modules/juce_graphics/geometry/juce_Point.h index 5525328855c1..9e6117f0664d 100644 --- a/modules/juce_graphics/geometry/juce_Point.h +++ b/modules/juce_graphics/geometry/juce_Point.h @@ -54,14 +54,19 @@ class Point /** Copies this point from another one. */ Point& operator= (const Point&) = default; - constexpr inline bool operator== (Point other) const noexcept { return x == other.x && y == other.y; } - constexpr inline bool operator!= (Point other) const noexcept { return x != other.x || y != other.y; } + constexpr inline bool operator== (Point other) const noexcept + { + const auto tie = [] (const Point& p) { return std::tie (p.x, p.y); }; + return tie (*this) == tie (other); + } + + constexpr inline bool operator!= (Point other) const noexcept { return ! operator== (other); } /** Returns true if the point is (0, 0). */ - constexpr bool isOrigin() const noexcept { return x == ValueType() && y == ValueType(); } + constexpr bool isOrigin() const noexcept { return operator== (Point()); } /** Returns true if the coordinates are finite values. */ - constexpr inline bool isFinite() const noexcept { return juce_isfinite(x) && juce_isfinite(y); } + constexpr inline bool isFinite() const noexcept { return juce_isfinite (x) && juce_isfinite (y); } /** Returns the point's x coordinate. */ constexpr inline ValueType getX() const noexcept { return x; } diff --git a/modules/juce_graphics/geometry/juce_Rectangle.h b/modules/juce_graphics/geometry/juce_Rectangle.h index 9789f7ee275d..2e7bf03f2f36 100644 --- a/modules/juce_graphics/geometry/juce_Rectangle.h +++ b/modules/juce_graphics/geometry/juce_Rectangle.h @@ -613,10 +613,14 @@ class Rectangle //============================================================================== /** Returns true if the two rectangles are identical. */ - bool operator== (const Rectangle& other) const noexcept { return pos == other.pos && w == other.w && h == other.h; } + bool operator== (const Rectangle& other) const noexcept + { + const auto tie = [] (const Rectangle& r) { return std::tie (r.pos, r.w, r.h); }; + return tie (*this) == tie (other); + } /** Returns true if the two rectangles are not identical. */ - bool operator!= (const Rectangle& other) const noexcept { return pos != other.pos || w != other.w || h != other.h; } + bool operator!= (const Rectangle& other) const noexcept { return ! operator== (other); } /** Returns true if this coordinate is inside the rectangle. */ bool contains (ValueType xCoord, ValueType yCoord) const noexcept diff --git a/modules/juce_graphics/image_formats/juce_GIFLoader.cpp b/modules/juce_graphics/image_formats/juce_GIFLoader.cpp index f2cd0d86b1d0..6b3fb0f25b57 100644 --- a/modules/juce_graphics/image_formats/juce_GIFLoader.cpp +++ b/modules/juce_graphics/image_formats/juce_GIFLoader.cpp @@ -324,8 +324,8 @@ class GIFLoader if (finished) return -1; - buffer[0] = buffer [lastByteIndex - 2]; - buffer[1] = buffer [lastByteIndex - 1]; + buffer[0] = buffer [jmax (0, lastByteIndex - 2)]; + buffer[1] = buffer [jmax (0, lastByteIndex - 1)]; const int n = readDataBlock (buffer + 2); diff --git a/modules/juce_graphics/image_formats/juce_PNGLoader.cpp b/modules/juce_graphics/image_formats/juce_PNGLoader.cpp index 137e47ce45f2..fe40b145322c 100644 --- a/modules/juce_graphics/image_formats/juce_PNGLoader.cpp +++ b/modules/juce_graphics/image_formats/juce_PNGLoader.cpp @@ -58,13 +58,14 @@ namespace pnglibNamespace using std::free; #endif - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsign-conversion", + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcomma", + "-Wfloat-equal", "-Wimplicit-fallthrough", - "-Wtautological-constant-out-of-range-compare", - "-Wzero-as-null-pointer-constant", - "-Wcomma", "-Wmaybe-uninitialized", - "-Wnull-pointer-subtraction") + "-Wnull-pointer-subtraction", + "-Wsign-conversion", + "-Wtautological-constant-out-of-range-compare", + "-Wzero-as-null-pointer-constant") #undef check using std::abs; diff --git a/modules/juce_graphics/images/juce_ImageCache.cpp b/modules/juce_graphics/images/juce_ImageCache.cpp index b1731eb5774a..cdf6cc327bcc 100644 --- a/modules/juce_graphics/images/juce_ImageCache.cpp +++ b/modules/juce_graphics/images/juce_ImageCache.cpp @@ -30,7 +30,12 @@ struct ImageCache::Pimpl : private Timer, private DeletedAtShutdown { Pimpl() = default; - ~Pimpl() override { clearSingletonInstance(); } + + ~Pimpl() override + { + stopTimer(); + clearSingletonInstance(); + } JUCE_DECLARE_SINGLETON (ImageCache::Pimpl, false) diff --git a/modules/juce_graphics/images/juce_ScaledImage.h b/modules/juce_graphics/images/juce_ScaledImage.h index fac214536008..9dfd7c037615 100644 --- a/modules/juce_graphics/images/juce_ScaledImage.h +++ b/modules/juce_graphics/images/juce_ScaledImage.h @@ -40,6 +40,8 @@ namespace juce The ScaledImage class is designed to store an image alongside a scale factor that informs a renderer how to convert between the image's pixels and points. + + @tags{GUI} */ class JUCE_API ScaledImage { diff --git a/modules/juce_graphics/juce_graphics.cpp b/modules/juce_graphics/juce_graphics.cpp index d852554be1b4..bb8e6d86bb1f 100644 --- a/modules/juce_graphics/juce_graphics.cpp +++ b/modules/juce_graphics/juce_graphics.cpp @@ -139,32 +139,32 @@ #endif #if JUCE_USE_FREETYPE - #include "native/juce_freetype_Fonts.cpp" + #include "native/juce_Fonts_freetype.cpp" #endif //============================================================================== #if JUCE_MAC || JUCE_IOS - #include "native/juce_mac_Fonts.mm" - #include "native/juce_mac_CoreGraphicsContext.mm" - #include "native/juce_mac_IconHelpers.cpp" + #include "native/juce_Fonts_mac.mm" + #include "native/juce_CoreGraphicsContext_mac.mm" + #include "native/juce_IconHelpers_mac.cpp" #elif JUCE_WINDOWS - #include "native/juce_win32_DirectWriteTypeface.cpp" - #include "native/juce_win32_DirectWriteTypeLayout.cpp" - #include "native/juce_win32_Fonts.cpp" - #include "native/juce_win32_IconHelpers.cpp" + #include "native/juce_DirectWriteTypeface_windows.cpp" + #include "native/juce_DirectWriteTypeLayout_windows.cpp" + #include "native/juce_Fonts_windows.cpp" + #include "native/juce_IconHelpers_windows.cpp" #if JUCE_DIRECT2D - #include "native/juce_win32_Direct2DGraphicsContext.cpp" + #include "native/juce_Direct2DGraphicsContext_windows.cpp" #endif #elif JUCE_LINUX || JUCE_BSD - #include "native/juce_linux_Fonts.cpp" - #include "native/juce_linux_IconHelpers.cpp" + #include "native/juce_Fonts_linux.cpp" + #include "native/juce_IconHelpers_linux.cpp" #elif JUCE_ANDROID - #include "native/juce_android_GraphicsContext.cpp" - #include "native/juce_android_Fonts.cpp" - #include "native/juce_android_IconHelpers.cpp" + #include "native/juce_GraphicsContext_android.cpp" + #include "native/juce_Fonts_android.cpp" + #include "native/juce_IconHelpers_android.cpp" #endif diff --git a/modules/juce_graphics/juce_graphics.h b/modules/juce_graphics/juce_graphics.h index cb86476d61e8..7f35fc74d9e5 100644 --- a/modules/juce_graphics/juce_graphics.h +++ b/modules/juce_graphics/juce_graphics.h @@ -35,7 +35,7 @@ ID: juce_graphics vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE graphics classes description: Classes for 2D vector graphics, image loading/saving, font handling, etc. website: http://www.juce.com/juce @@ -150,10 +150,10 @@ namespace juce #include "effects/juce_GlowEffect.h" #if JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS && (JUCE_MAC || JUCE_IOS) - #include "native/juce_mac_CoreGraphicsHelpers.h" - #include "native/juce_mac_CoreGraphicsContext.h" + #include "native/juce_CoreGraphicsHelpers_mac.h" + #include "native/juce_CoreGraphicsContext_mac.h" #endif #if JUCE_DIRECT2D && JUCE_WINDOWS -#include "native/juce_win32_Direct2DGraphicsContext.h" +#include "native/juce_Direct2DGraphicsContext_windows.h" #endif diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h b/modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h similarity index 95% rename from modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h rename to modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h index 6230c99c1cc8..07ee759aca64 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h +++ b/modules/juce_graphics/native/juce_CoreGraphicsContext_mac.h @@ -120,8 +120,7 @@ class CoreGraphicsContext : public LowLevelGraphicsContext detail::ContextPtr context; const CGFloat flipHeight; detail::ColorSpacePtr rgbColourSpace, greyColourSpace; - mutable Rectangle lastClipRect; - mutable bool lastClipRectIsValid = false; + mutable std::optional> lastClipRect; struct SavedState { @@ -142,8 +141,8 @@ class CoreGraphicsContext : public LowLevelGraphicsContext std::unique_ptr state; OwnedArray stateStack; + void setContextClipToPath (const Path&, const AffineTransform&); void drawGradient(); - void createPath (const Path&) const; void createPath (const Path&, const AffineTransform&) const; void flip() const; void applyTransform (const AffineTransform&) const; diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm similarity index 87% rename from modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm rename to modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm index 77987afd52db..c80b8eb208ed 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/modules/juce_graphics/native/juce_CoreGraphicsContext_mac.mm @@ -221,8 +221,8 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) { CGContextTranslateCTM (context.get(), o.x, -o.y); - if (lastClipRectIsValid) - lastClipRect.translate (-o.x, -o.y); + if (lastClipRect.has_value()) + lastClipRect->translate (-o.x, -o.y); } void CoreGraphicsContext::addTransform (const AffineTransform& transform) @@ -231,7 +231,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) .followedBy (transform) .translated (0, (float) -flipHeight) .scaled (1.0f, -1.0f)); - lastClipRectIsValid = false; + lastClipRect.reset(); jassert (getPhysicalPixelScaleFactor() > 0.0f); } @@ -249,14 +249,14 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CGContextClipToRect (context.get(), CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); - if (lastClipRectIsValid) + if (lastClipRect.has_value()) { // This is actually incorrect, because the actual clip region may be complex, and // clipping its bounds to a rect may not be right... But, removing this shortcut // doesn't actually fix anything because CoreGraphics also ignores complex regions // when calculating the resultant clip bounds, and makes the same mistake! - lastClipRect = lastClipRect.getIntersection (r); - return ! lastClipRect.isEmpty(); + lastClipRect = lastClipRect->getIntersection (r); + return ! lastClipRect->isEmpty(); } return ! isClipEmpty(); @@ -267,7 +267,6 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) if (clipRegion.isEmpty()) { CGContextClipToRect (context.get(), CGRectZero); - lastClipRectIsValid = true; lastClipRect = Rectangle(); return false; } @@ -280,7 +279,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) rects[i++] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()); CGContextClipToRects (context.get(), rects, numRects); - lastClipRectIsValid = false; + lastClipRect.reset(); return true; } @@ -296,7 +295,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) clipToRectangleListWithoutTest (remaining); } -void CoreGraphicsContext::clipToPath (const Path& path, const AffineTransform& transform) +void CoreGraphicsContext::setContextClipToPath (const Path& path, const AffineTransform& transform) { createPath (path, transform); @@ -304,8 +303,12 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CGContextClip (context.get()); else CGContextEOClip (context.get()); +} - lastClipRectIsValid = false; +void CoreGraphicsContext::clipToPath (const Path& path, const AffineTransform& transform) +{ + setContextClipToPath (path, transform); + lastClipRect.reset(); } void CoreGraphicsContext::clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) @@ -329,7 +332,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) applyTransform (t.inverted()); flip(); - lastClipRectIsValid = false; + lastClipRect.reset(); } } @@ -340,18 +343,17 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) Rectangle CoreGraphicsContext::getClipBounds() const { - if (! lastClipRectIsValid) + if (! lastClipRect.has_value()) { auto bounds = CGRectIntegral (CGContextGetClipBoundingBox (context.get())); - lastClipRectIsValid = true; - lastClipRect.setBounds (roundToInt (bounds.origin.x), - roundToInt (flipHeight - (bounds.origin.y + bounds.size.height)), - roundToInt (bounds.size.width), - roundToInt (bounds.size.height)); + lastClipRect = Rectangle (roundToInt (bounds.origin.x), + roundToInt (flipHeight - (bounds.origin.y + bounds.size.height)), + roundToInt (bounds.size.width), + roundToInt (bounds.size.height)); } - return lastClipRect; + return *lastClipRect; } bool CoreGraphicsContext::isClipEmpty() const @@ -376,7 +378,7 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CGContextSetTextMatrix (context.get(), state->textMatrix); stateStack.removeLast (1, false); - lastClipRectIsValid = false; + lastClipRect.reset(); } else { @@ -470,56 +472,45 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CGContextSetBlendMode (context.get(), kCGBlendModeCopy); fillCGRect (cgRect, false); CGContextSetBlendMode (context.get(), kCGBlendModeNormal); + return; } - else + + if (state->fillType.isColour()) { - if (state->fillType.isColour()) - { - CGContextFillRect (context.get(), cgRect); - } - else - { - ScopedCGContextState scopedState (context.get()); + CGContextFillRect (context.get(), cgRect); + return; + } - CGContextClipToRect (context.get(), cgRect); + ScopedCGContextState scopedState (context.get()); + CGContextClipToRect (context.get(), cgRect); - if (state->fillType.isGradient()) - drawGradient(); - else - drawImage (state->fillType.image, state->fillType.transform, true); - } - } + if (state->fillType.isGradient()) + drawGradient(); + else + drawImage (state->fillType.image, state->fillType.transform, true); } void CoreGraphicsContext::fillPath (const Path& path, const AffineTransform& transform) { - ScopedCGContextState scopedState (context.get()); - if (state->fillType.isColour()) { - flip(); - applyTransform (transform); - createPath (path); + createPath (path, transform); if (path.isUsingNonZeroWinding()) CGContextFillPath (context.get()); else CGContextEOFillPath (context.get()); + + return; } - else - { - createPath (path, transform); - if (path.isUsingNonZeroWinding()) - CGContextClip (context.get()); - else - CGContextEOClip (context.get()); + ScopedCGContextState scopedState (context.get()); + setContextClipToPath (path, transform); - if (state->fillType.isGradient()) - drawGradient(); - else - drawImage (state->fillType.image, state->fillType.transform, true); - } + if (state->fillType.isGradient()) + drawGradient(); + else + drawImage (state->fillType.image, state->fillType.transform, true); } void CoreGraphicsContext::drawImage (const Image& sourceImage, const AffineTransform& transform) @@ -549,15 +540,20 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CGContextDrawTiledImage (context.get(), imageRect, image.get()); #else // There's a bug in CGContextDrawTiledImage that makes it incredibly slow - // if it's doing a transformation - it's quicker to just draw lots of images manually - if (&CGContextDrawTiledImage != nullptr && transform.isOnlyTranslation()) + // if it's doing a transformation - it's quicker to just draw lots of images manually, + // but we might not be able to draw the images ourselves if the clipping region is not + // finite + const auto doCustomTiling = [&] { - CGContextDrawTiledImage (context.get(), imageRect, image.get()); - } - else - { - // Fallback to manually doing a tiled fill - auto clip = CGRectIntegral (CGContextGetClipBoundingBox (context.get())); + if (transform.isOnlyTranslation()) + return false; + + const auto bound = CGContextGetClipBoundingBox (context.get()); + + if (CGRectIsNull (bound)) + return false; + + const auto clip = CGRectIntegral (bound); int x = 0, y = 0; while (x > clip.origin.x) x -= iw; @@ -573,7 +569,12 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) y += ih; } - } + + return true; + }; + + if (! doCustomTiling()) + CGContextDrawTiledImage (context.get(), imageRect, image.get()); #endif } else @@ -592,28 +593,25 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) void CoreGraphicsContext::fillRectList (const RectangleList& list) { - HeapBlock rects (list.getNumRectangles()); - - size_t num = 0; + std::vector rects; + rects.reserve ((size_t) list.getNumRectangles()); for (auto& r : list) - rects[num++] = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()); + rects.push_back (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); if (state->fillType.isColour()) { - CGContextFillRects (context.get(), rects, num); + CGContextFillRects (context.get(), rects.data(), rects.size()); + return; } - else - { - ScopedCGContextState scopedState (context.get()); - CGContextClipToRects (context.get(), rects, num); + ScopedCGContextState scopedState (context.get()); + CGContextClipToRects (context.get(), rects.data(), rects.size()); - if (state->fillType.isGradient()) - drawGradient(); - else - drawImage (state->fillType.image, state->fillType.transform, true); - } + if (state->fillType.isGradient()) + drawGradient(); + else + drawImage (state->fillType.image, state->fillType.transform, true); } void CoreGraphicsContext::setFont (const Font& newFont) @@ -702,10 +700,8 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) CoreGraphicsContext::SavedState::SavedState (const SavedState& other) : fillType (other.fillType), font (other.font), fontRef (other.fontRef), textMatrix (other.textMatrix), inverseTextMatrix (other.inverseTextMatrix), - gradient (other.gradient.get()) + gradient (other.gradient.get() != nullptr ? CGGradientRetain (other.gradient.get()) : nullptr) { - if (gradient != nullptr) - CGGradientRetain (gradient.get()); } CoreGraphicsContext::SavedState::~SavedState() = default; @@ -719,9 +715,9 @@ static CGBitmapInfo getCGImageFlags (const Image::PixelFormat& format) static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef colourSpace) { auto numColours = g.getNumColours(); - auto data = (CGFloat*) alloca ((size_t) numColours * 5 * sizeof (CGFloat)); - auto locations = data; - auto components = data + numColours; + std::vector data ((size_t) numColours * 5); + auto locations = data.data(); + auto components = locations + numColours; auto comps = components; for (int i = 0; i < numColours; ++i) @@ -734,8 +730,8 @@ static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef co locations[i] = (CGFloat) g.getColourPosition (i); // There's a bug (?) in the way the CG renderer works where it seems - // to go wrong if you have two colour stops both at position 0.. - jassert (i == 0 || locations[i] != 0); + // to go wrong if you have two colour stops both at position 0. + jassert (i == 0 || ! approximatelyEqual (locations[i], (CGFloat) 0.0)); } return CGGradientCreateWithColorComponents (colourSpace, components, locations, (size_t) numColours); @@ -763,24 +759,6 @@ static CGGradientRef createGradient (const ColourGradient& g, CGColorSpaceRef co kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); } -void CoreGraphicsContext::createPath (const Path& path) const -{ - CGContextBeginPath (context.get()); - - for (Path::Iterator i (path); i.next();) - { - switch (i.elementType) - { - case Path::Iterator::startNewSubPath: CGContextMoveToPoint (context.get(), i.x1, i.y1); break; - case Path::Iterator::lineTo: CGContextAddLineToPoint (context.get(), i.x1, i.y1); break; - case Path::Iterator::quadraticTo: CGContextAddQuadCurveToPoint (context.get(), i.x1, i.y1, i.x2, i.y2); break; - case Path::Iterator::cubicTo: CGContextAddCurveToPoint (context.get(), i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; - case Path::Iterator::closePath: CGContextClosePath (context.get()); break; - default: jassertfalse; break; - } - } -} - void CoreGraphicsContext::createPath (const Path& path, const AffineTransform& transform) const { CGContextBeginPath (context.get()); diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h b/modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h similarity index 100% rename from modules/juce_graphics/native/juce_mac_CoreGraphicsHelpers.h rename to modules/juce_graphics/native/juce_CoreGraphicsHelpers_mac.h diff --git a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp similarity index 100% rename from modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.cpp rename to modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp diff --git a/modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h similarity index 100% rename from modules/juce_graphics/native/juce_win32_Direct2DGraphicsContext.h rename to modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.h diff --git a/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp b/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp similarity index 97% rename from modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp rename to modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp index f565a58321f4..18f6a91ca00b 100644 --- a/modules/juce_graphics/native/juce_win32_DirectWriteTypeLayout.cpp +++ b/modules/juce_graphics/native/juce_DirectWriteTypeLayout_windows.cpp @@ -108,7 +108,7 @@ namespace DirectWriteTypeLayout if (! (baselineOriginY >= -1.0e10f && baselineOriginY <= 1.0e10f)) baselineOriginY = 0; // DirectWrite sometimes sends NaNs in this parameter - if (baselineOriginY != lastOriginY) + if (! approximatelyEqual (baselineOriginY, lastOriginY)) { lastOriginY = baselineOriginY; ++currentLine; diff --git a/modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp b/modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp similarity index 100% rename from modules/juce_graphics/native/juce_win32_DirectWriteTypeface.cpp rename to modules/juce_graphics/native/juce_DirectWriteTypeface_windows.cpp diff --git a/modules/juce_graphics/native/juce_android_Fonts.cpp b/modules/juce_graphics/native/juce_Fonts_android.cpp similarity index 100% rename from modules/juce_graphics/native/juce_android_Fonts.cpp rename to modules/juce_graphics/native/juce_Fonts_android.cpp diff --git a/modules/juce_graphics/native/juce_freetype_Fonts.cpp b/modules/juce_graphics/native/juce_Fonts_freetype.cpp similarity index 100% rename from modules/juce_graphics/native/juce_freetype_Fonts.cpp rename to modules/juce_graphics/native/juce_Fonts_freetype.cpp diff --git a/modules/juce_graphics/native/juce_linux_Fonts.cpp b/modules/juce_graphics/native/juce_Fonts_linux.cpp similarity index 100% rename from modules/juce_graphics/native/juce_linux_Fonts.cpp rename to modules/juce_graphics/native/juce_Fonts_linux.cpp diff --git a/modules/juce_graphics/native/juce_mac_Fonts.mm b/modules/juce_graphics/native/juce_Fonts_mac.mm similarity index 97% rename from modules/juce_graphics/native/juce_mac_Fonts.mm rename to modules/juce_graphics/native/juce_Fonts_mac.mm index ed96d2a80dc9..5fa2f0e965ec 100644 --- a/modules/juce_graphics/native/juce_mac_Fonts.mm +++ b/modules/juce_graphics/native/juce_Fonts_mac.mm @@ -295,7 +295,7 @@ static AttributedStringAndFontMap createCFAttributedString (const AttributedStri auto extraKerning = attr.font.getExtraKerningFactor(); - if (extraKerning != 0) + if (! approximatelyEqual (extraKerning, 0.0f)) { extraKerning *= attr.font.getHeight(); diff --git a/modules/juce_graphics/native/juce_win32_Fonts.cpp b/modules/juce_graphics/native/juce_Fonts_windows.cpp similarity index 100% rename from modules/juce_graphics/native/juce_win32_Fonts.cpp rename to modules/juce_graphics/native/juce_Fonts_windows.cpp diff --git a/modules/juce_graphics/native/juce_android_GraphicsContext.cpp b/modules/juce_graphics/native/juce_GraphicsContext_android.cpp similarity index 100% rename from modules/juce_graphics/native/juce_android_GraphicsContext.cpp rename to modules/juce_graphics/native/juce_GraphicsContext_android.cpp diff --git a/modules/juce_graphics/native/juce_android_IconHelpers.cpp b/modules/juce_graphics/native/juce_IconHelpers_android.cpp similarity index 100% rename from modules/juce_graphics/native/juce_android_IconHelpers.cpp rename to modules/juce_graphics/native/juce_IconHelpers_android.cpp diff --git a/modules/juce_graphics/native/juce_linux_IconHelpers.cpp b/modules/juce_graphics/native/juce_IconHelpers_linux.cpp similarity index 100% rename from modules/juce_graphics/native/juce_linux_IconHelpers.cpp rename to modules/juce_graphics/native/juce_IconHelpers_linux.cpp diff --git a/modules/juce_graphics/native/juce_mac_IconHelpers.cpp b/modules/juce_graphics/native/juce_IconHelpers_mac.cpp similarity index 100% rename from modules/juce_graphics/native/juce_mac_IconHelpers.cpp rename to modules/juce_graphics/native/juce_IconHelpers_mac.cpp diff --git a/modules/juce_graphics/native/juce_win32_IconHelpers.cpp b/modules/juce_graphics/native/juce_IconHelpers_windows.cpp similarity index 100% rename from modules/juce_graphics/native/juce_win32_IconHelpers.cpp rename to modules/juce_graphics/native/juce_IconHelpers_windows.cpp diff --git a/modules/juce_graphics/native/juce_RenderingHelpers.h b/modules/juce_graphics/native/juce_RenderingHelpers.h index 716236a7f67d..d9fd8c9965ac 100644 --- a/modules/juce_graphics/native/juce_RenderingHelpers.h +++ b/modules/juce_graphics/native/juce_RenderingHelpers.h @@ -86,8 +86,10 @@ class TranslationOrTransform complexTransform = getTransformWith (t); isOnlyTranslated = false; - isRotated = (complexTransform.mat01 != 0.0f || complexTransform.mat10 != 0.0f - || complexTransform.mat00 < 0 || complexTransform.mat11 < 0); + isRotated = (! approximatelyEqual (complexTransform.mat01, 0.0f) + || ! approximatelyEqual (complexTransform.mat10, 0.0f) + || complexTransform.mat00 < 0 + || complexTransform.mat11 < 0); } float getPhysicalPixelScaleFactor() const noexcept diff --git a/modules/juce_graphics/placement/juce_RectanglePlacement.cpp b/modules/juce_graphics/placement/juce_RectanglePlacement.cpp index 9459bfbcaddf..6a1319ef01e6 100644 --- a/modules/juce_graphics/placement/juce_RectanglePlacement.cpp +++ b/modules/juce_graphics/placement/juce_RectanglePlacement.cpp @@ -39,7 +39,7 @@ bool RectanglePlacement::operator!= (const RectanglePlacement& other) const noex void RectanglePlacement::applyTo (double& x, double& y, double& w, double& h, const double dx, const double dy, const double dw, const double dh) const noexcept { - if (w == 0.0 || h == 0.0) + if (approximatelyEqual (w, 0.0) || approximatelyEqual (h, 0.0)) return; if ((flags & stretchToFit) != 0) diff --git a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityEvent.h b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityEvent.h index 159f11e0b43c..5da54b64edfb 100644 --- a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityEvent.h +++ b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityEvent.h @@ -78,4 +78,4 @@ enum class AccessibilityEvent rowSelectionChanged }; -} +} // namespace juce diff --git a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h index d80c5a1e9123..76a068ad49c0 100644 --- a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h +++ b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h @@ -68,4 +68,4 @@ enum class AccessibilityRole unspecified }; -} +} // namespace juce diff --git a/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTableInterface.h b/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTableInterface.h index a50227ed2868..2d08cf6a9211 100644 --- a/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTableInterface.h +++ b/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTableInterface.h @@ -65,6 +65,7 @@ class JUCE_API AccessibilityTableInterface */ virtual const AccessibilityHandler* getHeaderHandler() const = 0; + /** A simple span of elements. */ struct Span { int begin, num; }; /** Given the handler of one of the cells in the table, returns the rows covered diff --git a/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp b/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp index 2ec625207e47..54a17bc3e722 100644 --- a/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp +++ b/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.cpp @@ -28,29 +28,62 @@ namespace juce AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr; -enum class InternalAccessibilityEvent -{ - elementCreated, - elementDestroyed, - elementMovedOrResized, - focusChanged, - windowOpened, - windowClosed -}; +class NativeChildHandler +{ +public: + static NativeChildHandler& getInstance() + { + static NativeChildHandler instance; + return instance; + } -void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent); + void* getNativeChild (Component& component) const + { + if (auto it = nativeChildForComponent.find (&component); + it != nativeChildForComponent.end()) + { + return it->second; + } -inline String getAccessibleApplicationOrPluginName() -{ - #if defined (JucePlugin_Name) - return JucePlugin_Name; - #else - if (auto* app = JUCEApplicationBase::getInstance()) - return app->getApplicationName(); + return nullptr; + } - return "JUCE Application"; - #endif -} + Component* getComponent (void* nativeChild) const + { + if (auto it = componentForNativeChild.find (nativeChild); + it != componentForNativeChild.end()) + { + return it->second; + } + + return nullptr; + } + + void setNativeChild (Component& component, void* nativeChild) + { + clearComponent (component); + + if (nativeChild != nullptr) + { + nativeChildForComponent[&component] = nativeChild; + componentForNativeChild[nativeChild] = &component; + } + } + +private: + NativeChildHandler() = default; + + void clearComponent (Component& component) + { + if (auto* nativeChild = getNativeChild (component)) + componentForNativeChild.erase (nativeChild); + + nativeChildForComponent.erase (&component); + } + + std::map componentForNativeChild; + std::map nativeChildForComponent; +}; AccessibilityHandler::AccessibilityHandler (Component& comp, AccessibilityRole accessibilityRole, @@ -68,7 +101,7 @@ AccessibilityHandler::AccessibilityHandler (Component& comp, AccessibilityHandler::~AccessibilityHandler() { giveAwayFocus(); - notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementDestroyed); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*this, detail::AccessibilityHelpers::Event::elementDestroyed); } //============================================================================== @@ -320,13 +353,13 @@ void AccessibilityHandler::grabFocusInternal (bool canTryParent) void AccessibilityHandler::giveAwayFocusInternal() const { currentlyFocusedHandler = nullptr; - notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*this, detail::AccessibilityHelpers::Event::focusChanged); } void AccessibilityHandler::takeFocus() { currentlyFocusedHandler = this; - notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*this, detail::AccessibilityHelpers::Event::focusChanged); if ((component.isShowing() || component.isOnDesktop()) && component.getWantsKeyboardFocus() @@ -336,4 +369,35 @@ void AccessibilityHandler::takeFocus() } } +std::unique_ptr AccessibilityHandler::createNativeImpl (AccessibilityHandler& handler) +{ + #if JUCE_NATIVE_ACCESSIBILITY_INCLUDED + return std::make_unique (handler); + #else + ignoreUnused (handler); + return nullptr; + #endif +} + +void* AccessibilityHandler::getNativeChildForComponent (Component& component) +{ + return NativeChildHandler::getInstance().getNativeChild (component); +} + +Component* AccessibilityHandler::getComponentForNativeChild (void* nativeChild) +{ + return NativeChildHandler::getInstance().getComponent (nativeChild); +} + +void AccessibilityHandler::setNativeChildForComponent (Component& component, void* nativeChild) +{ + NativeChildHandler::getInstance().setNativeChild (component, nativeChild); +} + +#if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED + void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {} + void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {} + AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; } +#endif + } // namespace juce diff --git a/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.h b/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.h index 5cab7a705e2d..a0a9d41a445b 100644 --- a/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.h +++ b/modules/juce_gui_basics/accessibility/juce_AccessibilityHandler.h @@ -291,6 +291,26 @@ class JUCE_API AccessibilityHandler AccessibilityNativeHandle* getNativeImplementation() const; /** @internal */ std::type_index getTypeIndex() const { return typeIndex; } + /** @internal */ + static void clearCurrentlyFocusedHandler() { currentlyFocusedHandler = nullptr; } + + /** @internal + + The following functions provide the means to associate JUCE Components with OS specific + types that provide their own accessibility mechanisms. This way accessibility navigation + can move from a JUCE Component to a native, embedded window and back. + + These functions assume that the concrete types behind the void* are + - Windows: HWND + - MacOS: NSView* + - iOS: UIView* + - Android: GlobalRef that points to an android.view.View + */ + static void* getNativeChildForComponent (Component& component); + /** @internal */ + static void setNativeChildForComponent (Component& component, void* nativeChild); + /** @internal */ + static Component* getComponentForNativeChild (void* nativeChild); private: //============================================================================== diff --git a/modules/juce_gui_basics/application/juce_Application.cpp b/modules/juce_gui_basics/application/juce_Application.cpp index 5e0844ba5c83..bd342bdf85b4 100644 --- a/modules/juce_gui_basics/application/juce_Application.cpp +++ b/modules/juce_gui_basics/application/juce_Application.cpp @@ -83,16 +83,12 @@ bool JUCEApplication::perform (const InvocationInfo& info) } //============================================================================== -#if JUCE_MAC - extern void juce_initialiseMacMainMenu(); -#endif - bool JUCEApplication::initialiseApp() { if (JUCEApplicationBase::initialiseApp()) { #if JUCE_MAC - juce_initialiseMacMainMenu(); // (needs to get the app's name) + initialiseMacMainMenu(); // (needs to get the app's name) #endif return true; diff --git a/modules/juce_gui_basics/buttons/juce_Button.cpp b/modules/juce_gui_basics/buttons/juce_Button.cpp index b66b88c2a28c..0dd5ce9f80da 100644 --- a/modules/juce_gui_basics/buttons/juce_Button.cpp +++ b/modules/juce_gui_basics/buttons/juce_Button.cpp @@ -715,100 +715,9 @@ void Button::repeatTimerCallback() } } -//============================================================================== -class ButtonAccessibilityHandler : public AccessibilityHandler -{ -public: - explicit ButtonAccessibilityHandler (Button& buttonToWrap, AccessibilityRole roleIn) - : AccessibilityHandler (buttonToWrap, - isRadioButton (buttonToWrap) ? AccessibilityRole::radioButton : roleIn, - getAccessibilityActions (buttonToWrap), - getAccessibilityInterfaces (buttonToWrap)), - button (buttonToWrap) - { - } - - AccessibleState getCurrentState() const override - { - auto state = AccessibilityHandler::getCurrentState(); - - if (button.isToggleable()) - { - state = state.withCheckable(); - - if (button.getToggleState()) - state = state.withChecked(); - } - - return state; - } - - String getTitle() const override - { - auto title = AccessibilityHandler::getTitle(); - - if (title.isEmpty()) - return button.getButtonText(); - - return title; - } - - String getHelp() const override { return button.getTooltip(); } - -private: - class ButtonValueInterface : public AccessibilityTextValueInterface - { - public: - explicit ButtonValueInterface (Button& buttonToWrap) - : button (buttonToWrap) - { - } - - bool isReadOnly() const override { return true; } - String getCurrentValueAsString() const override { return button.getToggleState() ? "On" : "Off"; } - void setValueAsString (const String&) override {} - - private: - Button& button; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonValueInterface) - }; - - static bool isRadioButton (const Button& button) noexcept - { - return button.getRadioGroupId() != 0; - } - - static AccessibilityActions getAccessibilityActions (Button& button) - { - auto actions = AccessibilityActions().addAction (AccessibilityActionType::press, - [&button] { button.triggerClick(); }); - - if (button.isToggleable()) - actions = actions.addAction (AccessibilityActionType::toggle, - [&button] { button.setToggleState (! button.getToggleState(), sendNotification); }); - - return actions; - } - - static Interfaces getAccessibilityInterfaces (Button& button) - { - if (button.isToggleable()) - return { std::make_unique (button) }; - - return {}; - } - - Button& button; - - //============================================================================== - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAccessibilityHandler) -}; - std::unique_ptr Button::createAccessibilityHandler() { - return std::make_unique (*this, AccessibilityRole::button); + return std::make_unique (*this, AccessibilityRole::button); } } // namespace juce diff --git a/modules/juce_gui_basics/buttons/juce_Button.h b/modules/juce_gui_basics/buttons/juce_Button.h index ce849023b972..e9878fb09f0f 100644 --- a/modules/juce_gui_basics/buttons/juce_Button.h +++ b/modules/juce_gui_basics/buttons/juce_Button.h @@ -495,6 +495,8 @@ class JUCE_API Button : public Component, void focusLost (FocusChangeType) override; /** @internal */ void enablementChanged() override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: //============================================================================== @@ -522,7 +524,6 @@ class JUCE_API Button : public Component, bool triggerOnMouseDown = false; bool generateTooltip = false; - std::unique_ptr createAccessibilityHandler() override; void checkToggleableState (bool wasToggleable); void repeatTimerCallback(); diff --git a/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp b/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp index a5f5440f47dd..962e6949799d 100644 --- a/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp +++ b/modules/juce_gui_basics/buttons/juce_HyperlinkButton.cpp @@ -123,7 +123,7 @@ void HyperlinkButton::paintButton (Graphics& g, std::unique_ptr HyperlinkButton::createAccessibilityHandler() { - return std::make_unique (*this, AccessibilityRole::hyperlink); + return std::make_unique (*this, AccessibilityRole::hyperlink); } } // namespace juce diff --git a/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h b/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h index 553464fa7a4f..de346033b9a4 100644 --- a/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h +++ b/modules/juce_gui_basics/buttons/juce_HyperlinkButton.h @@ -101,6 +101,9 @@ class JUCE_API HyperlinkButton : public Button /** Returns the type of justification, as set in setJustificationType(). */ Justification getJustificationType() const noexcept { return justification; } + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; + protected: //============================================================================== /** @internal */ @@ -111,8 +114,6 @@ class JUCE_API HyperlinkButton : public Button void paintButton (Graphics&, bool, bool) override; private: - std::unique_ptr createAccessibilityHandler() override; - //============================================================================== using Button::clicked; Font getFontToUse() const; diff --git a/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp b/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp index 0461ea12ddcd..74fe6d34fd69 100644 --- a/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp +++ b/modules/juce_gui_basics/buttons/juce_ToggleButton.cpp @@ -59,7 +59,7 @@ void ToggleButton::colourChanged() std::unique_ptr ToggleButton::createAccessibilityHandler() { - return std::make_unique (*this, AccessibilityRole::toggleButton); + return std::make_unique (*this, AccessibilityRole::toggleButton); } } // namespace juce diff --git a/modules/juce_gui_basics/buttons/juce_ToggleButton.h b/modules/juce_gui_basics/buttons/juce_ToggleButton.h index d01488c7ce7c..df5ffcc3a1a4 100644 --- a/modules/juce_gui_basics/buttons/juce_ToggleButton.h +++ b/modules/juce_gui_basics/buttons/juce_ToggleButton.h @@ -76,6 +76,9 @@ class JUCE_API ToggleButton : public Button tickDisabledColourId = 0x1006503 /**< The colour to use for the disabled tick mark and/or outline. */ }; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; + protected: //============================================================================== /** @internal */ @@ -84,8 +87,6 @@ class JUCE_API ToggleButton : public Button void colourChanged() override; private: - std::unique_ptr createAccessibilityHandler() override; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToggleButton) }; diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp index bfa089b381e5..db6f1bbbcc9e 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp @@ -270,7 +270,7 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget( // getting a bit desperate now: try all desktop comps.. for (int i = desktop.getNumComponents(); --i >= 0;) if (auto* component = desktop.getComponent (i)) - if (isForegroundOrEmbeddedProcess (component)) + if (detail::WindowingHelpers::isForegroundOrEmbeddedProcess (component)) if (auto* peer = component->getPeer()) if (auto* target = findTargetForComponent (peer->getLastFocusedSubcomponent())) return target; diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 9f8d9d7426b0..9f720c794bb7 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -23,6 +23,11 @@ ============================================================================== */ +#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \ + jassert ((MessageManager::getInstanceWithoutCreating() != nullptr \ + && MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()) \ + || getPeer() == nullptr); + namespace juce { @@ -158,343 +163,6 @@ class Component::MouseListenerList JUCE_DECLARE_NON_COPYABLE (MouseListenerList) }; -//============================================================================== -struct FocusRestorer -{ - FocusRestorer() : lastFocus (Component::getCurrentlyFocusedComponent()) {} - - ~FocusRestorer() - { - if (lastFocus != nullptr - && lastFocus->isShowing() - && ! lastFocus->isCurrentlyBlockedByAnotherModalComponent()) - lastFocus->grabKeyboardFocus(); - } - - WeakReference lastFocus; - - JUCE_DECLARE_NON_COPYABLE (FocusRestorer) -}; - -//============================================================================== -struct ScalingHelpers -{ - template - static PointOrRect unscaledScreenPosToScaled (float scale, PointOrRect pos) noexcept - { - return scale != 1.0f ? pos / scale : pos; - } - - template - static PointOrRect scaledScreenPosToUnscaled (float scale, PointOrRect pos) noexcept - { - return scale != 1.0f ? pos * scale : pos; - } - - // For these, we need to avoid getSmallestIntegerContainer being used, which causes - // judder when moving windows - static Rectangle unscaledScreenPosToScaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (roundToInt ((float) pos.getX() / scale), - roundToInt ((float) pos.getY() / scale), - roundToInt ((float) pos.getWidth() / scale), - roundToInt ((float) pos.getHeight() / scale)) : pos; - } - - static Rectangle scaledScreenPosToUnscaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (roundToInt ((float) pos.getX() * scale), - roundToInt ((float) pos.getY() * scale), - roundToInt ((float) pos.getWidth() * scale), - roundToInt ((float) pos.getHeight() * scale)) : pos; - } - - static Rectangle unscaledScreenPosToScaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (pos.getX() / scale, - pos.getY() / scale, - pos.getWidth() / scale, - pos.getHeight() / scale) : pos; - } - - static Rectangle scaledScreenPosToUnscaled (float scale, Rectangle pos) noexcept - { - return scale != 1.0f ? Rectangle (pos.getX() * scale, - pos.getY() * scale, - pos.getWidth() * scale, - pos.getHeight() * scale) : pos; - } - - template - static PointOrRect unscaledScreenPosToScaled (PointOrRect pos) noexcept - { - return unscaledScreenPosToScaled (Desktop::getInstance().getGlobalScaleFactor(), pos); - } - - template - static PointOrRect scaledScreenPosToUnscaled (PointOrRect pos) noexcept - { - return scaledScreenPosToUnscaled (Desktop::getInstance().getGlobalScaleFactor(), pos); - } - - template - static PointOrRect unscaledScreenPosToScaled (const Component& comp, PointOrRect pos) noexcept - { - return unscaledScreenPosToScaled (comp.getDesktopScaleFactor(), pos); - } - - template - static PointOrRect scaledScreenPosToUnscaled (const Component& comp, PointOrRect pos) noexcept - { - return scaledScreenPosToUnscaled (comp.getDesktopScaleFactor(), pos); - } - - static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition(); } - static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition(); } - static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } - static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } - static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition(); } - static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition(); } - static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } - static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } - - static Point screenPosToLocalPos (Component& comp, Point pos) - { - if (auto* peer = comp.getPeer()) - { - pos = peer->globalToLocal (pos); - auto& peerComp = peer->getComponent(); - return comp.getLocalPoint (&peerComp, unscaledScreenPosToScaled (peerComp, pos)); - } - - return comp.getLocalPoint (nullptr, unscaledScreenPosToScaled (comp, pos)); - } -}; - -static const char colourPropertyPrefix[] = "jcclr_"; - -//============================================================================== -struct Component::ComponentHelpers -{ - #if JUCE_MODAL_LOOPS_PERMITTED - static void* runModalLoopCallback (void* userData) - { - return (void*) (pointer_sized_int) static_cast (userData)->runModalLoop(); - } - #endif - - static Identifier getColourPropertyID (int colourID) - { - char buffer[32]; - auto* end = buffer + numElementsInArray (buffer) - 1; - auto* t = end; - *t = 0; - - for (auto v = (uint32) colourID;;) - { - *--t = "0123456789abcdef" [v & 15]; - v >>= 4; - - if (v == 0) - break; - } - - for (int i = (int) sizeof (colourPropertyPrefix) - 1; --i >= 0;) - *--t = colourPropertyPrefix[i]; - - return t; - } - - //============================================================================== - static bool hitTest (Component& comp, Point localPoint) - { - const auto intPoint = localPoint.roundToInt(); - return Rectangle { comp.getWidth(), comp.getHeight() }.contains (intPoint) - && comp.hitTest (intPoint.x, intPoint.y); - } - - // converts an unscaled position within a peer to the local position within that peer's component - template - static PointOrRect rawPeerPositionToLocal (const Component& comp, PointOrRect pos) noexcept - { - if (comp.isTransformed()) - pos = pos.transformedBy (comp.getTransform().inverted()); - - return ScalingHelpers::unscaledScreenPosToScaled (comp, pos); - } - - // converts a position within a peer's component to the unscaled position within the peer - template - static PointOrRect localPositionToRawPeerPos (const Component& comp, PointOrRect pos) noexcept - { - if (comp.isTransformed()) - pos = pos.transformedBy (comp.getTransform()); - - return ScalingHelpers::scaledScreenPosToUnscaled (comp, pos); - } - - template - static PointOrRect convertFromParentSpace (const Component& comp, const PointOrRect pointInParentSpace) - { - const auto transformed = comp.affineTransform != nullptr ? pointInParentSpace.transformedBy (comp.affineTransform->inverted()) - : pointInParentSpace; - - if (comp.isOnDesktop()) - { - if (auto* peer = comp.getPeer()) - return ScalingHelpers::unscaledScreenPosToScaled (comp, peer->globalToLocal (ScalingHelpers::scaledScreenPosToUnscaled (transformed))); - - jassertfalse; - return transformed; - } - - if (comp.getParentComponent() == nullptr) - return ScalingHelpers::subtractPosition (ScalingHelpers::unscaledScreenPosToScaled (comp, ScalingHelpers::scaledScreenPosToUnscaled (transformed)), comp); - - return ScalingHelpers::subtractPosition (transformed, comp); - } - - template - static PointOrRect convertToParentSpace (const Component& comp, const PointOrRect pointInLocalSpace) - { - const auto preTransform = [&] - { - if (comp.isOnDesktop()) - { - if (auto* peer = comp.getPeer()) - return ScalingHelpers::unscaledScreenPosToScaled (peer->localToGlobal (ScalingHelpers::scaledScreenPosToUnscaled (comp, pointInLocalSpace))); - - jassertfalse; - return pointInLocalSpace; - } - - if (comp.getParentComponent() == nullptr) - return ScalingHelpers::unscaledScreenPosToScaled (ScalingHelpers::scaledScreenPosToUnscaled (comp, ScalingHelpers::addPosition (pointInLocalSpace, comp))); - - return ScalingHelpers::addPosition (pointInLocalSpace, comp); - }(); - - return comp.affineTransform != nullptr ? preTransform.transformedBy (*comp.affineTransform) - : preTransform; - } - - template - static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, PointOrRect coordInParent) - { - auto* directParent = target.getParentComponent(); - jassert (directParent != nullptr); - - if (directParent == parent) - return convertFromParentSpace (target, coordInParent); - - JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) - return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); - JUCE_END_IGNORE_WARNINGS_MSVC - } - - template - static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) - { - while (source != nullptr) - { - if (source == target) - return p; - - JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) - - if (source->isParentOf (target)) - return convertFromDistantParentSpace (source, *target, p); - - JUCE_END_IGNORE_WARNINGS_MSVC - - p = convertToParentSpace (*source, p); - source = source->getParentComponent(); - } - - jassert (source == nullptr); - if (target == nullptr) - return p; - - auto* topLevelComp = target->getTopLevelComponent(); - - p = convertFromParentSpace (*topLevelComp, p); - - if (topLevelComp == target) - return p; - - return convertFromDistantParentSpace (topLevelComp, *target, p); - } - - static bool clipObscuredRegions (const Component& comp, Graphics& g, - const Rectangle clipRect, Point delta) - { - bool wasClipped = false; - - for (int i = comp.childComponentList.size(); --i >= 0;) - { - auto& child = *comp.childComponentList.getUnchecked(i); - - if (child.isVisible() && ! child.isTransformed()) - { - auto newClip = clipRect.getIntersection (child.boundsRelativeToParent); - - if (! newClip.isEmpty()) - { - if (child.isOpaque() && child.componentTransparency == 0) - { - g.excludeClipRegion (newClip + delta); - wasClipped = true; - } - else - { - auto childPos = child.getPosition(); - - if (clipObscuredRegions (child, g, newClip - childPos, childPos + delta)) - wasClipped = true; - } - } - } - } - - return wasClipped; - } - - static Rectangle getParentOrMainMonitorBounds (const Component& comp) - { - if (auto* p = comp.getParentComponent()) - return p->getLocalBounds(); - - return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea; - } - - static void releaseAllCachedImageResources (Component& c) - { - if (auto* cached = c.getCachedComponentImage()) - cached->releaseResources(); - - for (auto* child : c.childComponentList) - releaseAllCachedImageResources (*child); - } - - //============================================================================== - static bool modalWouldBlockComponent (const Component& maybeBlocked, Component* modal) - { - return modal != nullptr - && modal != &maybeBlocked - && ! modal->isParentOf (&maybeBlocked) - && ! modal->canModalEventBeSentToComponent (&maybeBlocked); - } - - template - static void sendMouseEventToComponentsThatAreBlockedByModal (Component& modal, Function&& function) - { - for (auto& ms : Desktop::getInstance().getMouseSources()) - if (auto* c = ms.getComponentUnderMouse()) - if (modalWouldBlockComponent (*c, &modal)) - (c->*function) (ms, ScalingHelpers::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime()); - } -}; - //============================================================================== Component::Component() noexcept : componentFlags (0) @@ -574,7 +242,7 @@ void Component::setVisible (bool shouldBeVisible) if (! shouldBeVisible) { - ComponentHelpers::releaseAllCachedImageResources (*this); + detail::ComponentHelpers::releaseAllCachedImageResources (*this); if (hasKeyboardFocus (true)) { @@ -664,8 +332,8 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) jmax (1, getHeight())); #endif - const auto unscaledPosition = ScalingHelpers::scaledScreenPosToUnscaled (getScreenPosition()); - const auto topLeft = ScalingHelpers::unscaledScreenPosToScaled (*this, unscaledPosition); + const auto unscaledPosition = detail::ScalingHelpers::scaledScreenPosToUnscaled (getScreenPosition()); + const auto topLeft = detail::ScalingHelpers::unscaledScreenPosToScaled (*this, unscaledPosition); bool wasFullscreen = false; bool wasMinimised = false; @@ -747,7 +415,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) internalHierarchyChanged(); if (auto* handler = getAccessibilityHandler()) - notifyAccessibilityEventInternal (*handler, InternalAccessibilityEvent::windowOpened); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::windowOpened); } } } @@ -761,9 +429,9 @@ void Component::removeFromDesktop() if (flags.hasHeavyweightPeerFlag) { if (auto* handler = getAccessibilityHandler()) - notifyAccessibilityEventInternal (*handler, InternalAccessibilityEvent::windowClosed); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::windowClosed); - ComponentHelpers::releaseAllCachedImageResources (*this); + detail::ComponentHelpers::releaseAllCachedImageResources (*this); auto* peer = ComponentPeer::getPeerFor (this); jassert (peer != nullptr); @@ -1115,15 +783,15 @@ int Component::getScreenY() const { return getScreenPositi Point Component::getScreenPosition() const { return localPointToGlobal (Point()); } Rectangle Component::getScreenBounds() const { return localAreaToGlobal (getLocalBounds()); } -Point Component::getLocalPoint (const Component* source, Point point) const { return ComponentHelpers::convertCoordinate (this, source, point); } -Point Component::getLocalPoint (const Component* source, Point point) const { return ComponentHelpers::convertCoordinate (this, source, point); } -Rectangle Component::getLocalArea (const Component* source, Rectangle area) const { return ComponentHelpers::convertCoordinate (this, source, area); } -Rectangle Component::getLocalArea (const Component* source, Rectangle area) const { return ComponentHelpers::convertCoordinate (this, source, area); } +Point Component::getLocalPoint (const Component* source, Point point) const { return detail::ComponentHelpers::convertCoordinate (this, source, point); } +Point Component::getLocalPoint (const Component* source, Point point) const { return detail::ComponentHelpers::convertCoordinate (this, source, point); } +Rectangle Component::getLocalArea (const Component* source, Rectangle area) const { return detail::ComponentHelpers::convertCoordinate (this, source, area); } +Rectangle Component::getLocalArea (const Component* source, Rectangle area) const { return detail::ComponentHelpers::convertCoordinate (this, source, area); } -Point Component::localPointToGlobal (Point point) const { return ComponentHelpers::convertCoordinate (nullptr, this, point); } -Point Component::localPointToGlobal (Point point) const { return ComponentHelpers::convertCoordinate (nullptr, this, point); } -Rectangle Component::localAreaToGlobal (Rectangle area) const { return ComponentHelpers::convertCoordinate (nullptr, this, area); } -Rectangle Component::localAreaToGlobal (Rectangle area) const { return ComponentHelpers::convertCoordinate (nullptr, this, area); } +Point Component::localPointToGlobal (Point point) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, point); } +Point Component::localPointToGlobal (Point point) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, point); } +Rectangle Component::localAreaToGlobal (Rectangle area) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, area); } +Rectangle Component::localAreaToGlobal (Rectangle area) const { return detail::ComponentHelpers::convertCoordinate (nullptr, this, area); } //============================================================================== void Component::setBounds (int x, int y, int w, int h) @@ -1238,7 +906,7 @@ void Component::sendMovedResizedMessages (bool wasMoved, bool wasResized) if ((wasMoved || wasResized) && ! checker.shouldBailOut()) if (auto* handler = getAccessibilityHandler()) - notifyAccessibilityEventInternal (*handler, InternalAccessibilityEvent::elementMovedOrResized); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*handler, detail::AccessibilityHelpers::Event::elementMovedOrResized); } void Component::setSize (int w, int h) { setBounds (getX(), getY(), w, h); } @@ -1271,7 +939,7 @@ void Component::setBoundsRelative (float x, float y, float w, float h) void Component::centreWithSize (int width, int height) { - auto parentArea = ComponentHelpers::getParentOrMainMonitorBounds (*this) + auto parentArea = detail::ComponentHelpers::getParentOrMainMonitorBounds (*this) .transformedBy (getTransform().inverted()); setBounds (parentArea.getCentreX() - width / 2, @@ -1281,7 +949,7 @@ void Component::centreWithSize (int width, int height) void Component::setBoundsInset (BorderSize borders) { - setBounds (borders.subtractedFrom (ComponentHelpers::getParentOrMainMonitorBounds (*this))); + setBounds (borders.subtractedFrom (detail::ComponentHelpers::getParentOrMainMonitorBounds (*this))); } void Component::setBoundsToFit (Rectangle targetArea, Justification justification, bool onlyReduceInSize) @@ -1391,7 +1059,7 @@ bool Component::hitTest (int x, int y) auto& child = *childComponentList.getUnchecked (i); if (child.isVisible() - && ComponentHelpers::hitTest (child, ComponentHelpers::convertFromParentSpace (child, Point (x, y).toFloat()))) + && detail::ComponentHelpers::hitTest (child, detail::ComponentHelpers::convertFromParentSpace (child, Point (x, y).toFloat()))) return true; } } @@ -1420,14 +1088,14 @@ bool Component::contains (Point point) bool Component::contains (Point point) { - if (ComponentHelpers::hitTest (*this, point)) + if (detail::ComponentHelpers::hitTest (*this, point)) { if (parentComponent != nullptr) - return parentComponent->contains (ComponentHelpers::convertToParentSpace (*this, point)); + return parentComponent->contains (detail::ComponentHelpers::convertToParentSpace (*this, point)); if (flags.hasHeavyweightPeerFlag) if (auto* peer = getPeer()) - return peer->contains (ComponentHelpers::localPositionToRawPeerPos (*this, point).roundToInt(), true); + return peer->contains (detail::ComponentHelpers::localPositionToRawPeerPos (*this, point).roundToInt(), true); } return false; @@ -1456,13 +1124,13 @@ Component* Component::getComponentAt (Point position) Component* Component::getComponentAt (Point position) { - if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position)) + if (flags.visibleFlag && detail::ComponentHelpers::hitTest (*this, position)) { for (int i = childComponentList.size(); --i >= 0;) { auto* child = childComponentList.getUnchecked (i); - child = child->getComponentAt (ComponentHelpers::convertFromParentSpace (*child, position)); + child = child->getComponentAt (detail::ComponentHelpers::convertFromParentSpace (*child, position)); if (child != nullptr) return child; @@ -1579,7 +1247,7 @@ Component* Component::removeChildComponent (int index, bool sendParentEvents, bo childComponentList.remove (index); child->parentComponent = nullptr; - ComponentHelpers::releaseAllCachedImageResources (*child); + detail::ComponentHelpers::releaseAllCachedImageResources (*child); // (NB: there are obscure situations where child->isShowing() = false, but it still has the focus) if (child->hasKeyboardFocus (true)) @@ -1732,7 +1400,7 @@ int Component::runModalLoop() { // use a callback so this can be called from non-gui threads return (int) (pointer_sized_int) MessageManager::getInstance() - ->callFunctionOnMessageThread (&ComponentHelpers::runModalLoopCallback, this); + ->callFunctionOnMessageThread (&detail::ComponentHelpers::runModalLoopCallback, this); } if (! isCurrentlyModal (false)) @@ -1758,7 +1426,7 @@ void Component::enterModalState (bool shouldTakeKeyboardFocus, // While this component is in modal state it may block other components from receiving // mouseExit events. To keep mouseEnter and mouseExit calls balanced on these components, // we must manually force the mouse to "leave" blocked components. - ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*this, &Component::internalMouseExit); + detail::ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*this, &Component::internalMouseExit); if (safeReference == nullptr) { @@ -1799,7 +1467,7 @@ void Component::exitModalState (int returnValue) // mouseEnter events. To keep mouseEnter and mouseExit calls balanced on these components, // we must manually force the mouse to "enter" blocked components. if (deletionChecker != nullptr) - ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*deletionChecker, &Component::internalMouseEnter); + detail::ComponentHelpers::sendMouseEventToComponentsThatAreBlockedByModal (*deletionChecker, &Component::internalMouseEnter); } else { @@ -1822,7 +1490,7 @@ bool Component::isCurrentlyModal (bool onlyConsiderForemostModalComponent) const bool Component::isCurrentlyBlockedByAnotherModalComponent() const { - return ComponentHelpers::modalWouldBlockComponent (*this, getCurrentlyModalComponent()); + return detail::ComponentHelpers::modalWouldBlockComponent (*this, getCurrentlyModalComponent()); } int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() noexcept @@ -1923,7 +1591,7 @@ void Component::repaint (Rectangle area) void Component::repaintParent() { if (parentComponent != nullptr) - parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, getLocalBounds())); + parentComponent->internalRepaint (detail::ComponentHelpers::convertToParentSpace (*this, getLocalBounds())); } void Component::internalRepaint (Rectangle area) @@ -1965,7 +1633,7 @@ void Component::internalRepaintUnchecked (Rectangle area, bool isEntireComp else { if (parentComponent != nullptr) - parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, area)); + parentComponent->internalRepaint (detail::ComponentHelpers::convertToParentSpace (*this, area)); } } } @@ -2006,7 +1674,7 @@ void Component::paintComponentAndChildren (Graphics& g) { Graphics::ScopedSaveState ss (g); - if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty())) + if (! (detail::ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty())) paint (g); } @@ -2209,7 +1877,7 @@ void Component::sendLookAndFeelChange() Colour Component::findColour (int colourID, bool inheritFromParent) const { - if (auto* v = properties.getVarPointer (ComponentHelpers::getColourPropertyID (colourID))) + if (auto* v = properties.getVarPointer (detail::ComponentHelpers::getColourPropertyID (colourID))) return Colour ((uint32) static_cast (*v)); if (inheritFromParent && parentComponent != nullptr @@ -2221,18 +1889,18 @@ Colour Component::findColour (int colourID, bool inheritFromParent) const bool Component::isColourSpecified (int colourID) const { - return properties.contains (ComponentHelpers::getColourPropertyID (colourID)); + return properties.contains (detail::ComponentHelpers::getColourPropertyID (colourID)); } void Component::removeColour (int colourID) { - if (properties.remove (ComponentHelpers::getColourPropertyID (colourID))) + if (properties.remove (detail::ComponentHelpers::getColourPropertyID (colourID))) colourChanged(); } void Component::setColour (int colourID, Colour colour) { - if (properties.set (ComponentHelpers::getColourPropertyID (colourID), (int) colour.getARGB())) + if (properties.set (detail::ComponentHelpers::getColourPropertyID (colourID), (int) colour.getARGB())) colourChanged(); } @@ -2244,7 +1912,7 @@ void Component::copyAllExplicitColoursTo (Component& target) const { auto name = properties.getName(i); - if (name.toString().startsWith (colourPropertyPrefix)) + if (name.toString().startsWith (detail::colourPropertyPrefix)) if (target.properties.set (name, properties [name])) changed = true; } @@ -2405,7 +2073,7 @@ void Component::internalMouseEnter (MouseInputSource source, Point relati repaint(); const auto me = makeMouseEvent (source, - PointerState().withPosition (relativePos), + detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), this, this, @@ -2442,7 +2110,7 @@ void Component::internalMouseExit (MouseInputSource source, Point relativ flags.cachedMouseInsideComponent = false; const auto me = makeMouseEvent (source, - PointerState().withPosition (relativePos), + detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), this, this, @@ -2462,7 +2130,9 @@ void Component::internalMouseExit (MouseInputSource source, Point relativ MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseExit); } -void Component::internalMouseDown (MouseInputSource source, const PointerState& relativePointerState, Time time) +void Component::internalMouseDown (MouseInputSource source, + const detail::PointerState& relativePointerState, + Time time) { auto& desktop = Desktop::getInstance(); @@ -2512,7 +2182,7 @@ void Component::internalMouseDown (MouseInputSource source, const PointerState& if (! flags.dontFocusOnMouseClickFlag) { - grabKeyboardFocusInternal (focusChangedByMouseClick, true); + grabKeyboardFocusInternal (focusChangedByMouseClick, true, FocusChangeDirection::unknown); if (checker.shouldBailOut()) return; @@ -2531,7 +2201,10 @@ void Component::internalMouseDown (MouseInputSource source, const PointerState& MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDown); } -void Component::internalMouseUp (MouseInputSource source, const PointerState& relativePointerState, Time time, const ModifierKeys oldModifiers) +void Component::internalMouseUp (MouseInputSource source, + const detail::PointerState& relativePointerState, + Time time, + const ModifierKeys oldModifiers) { if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent()) return; @@ -2579,7 +2252,7 @@ void Component::internalMouseUp (MouseInputSource source, const PointerState& re } } -void Component::internalMouseDrag (MouseInputSource source, const PointerState& relativePointerState, Time time) +void Component::internalMouseDrag (MouseInputSource source, const detail::PointerState& relativePointerState, Time time) { if (! isCurrentlyBlockedByAnotherModalComponent()) { @@ -2618,7 +2291,7 @@ void Component::internalMouseMove (MouseInputSource source, Point relativ else { const auto me = makeMouseEvent (source, - PointerState().withPosition (relativePos), + detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), this, this, @@ -2646,7 +2319,7 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati auto& desktop = Desktop::getInstance(); const auto me = makeMouseEvent (source, - PointerState().withPosition (relativePos), + detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), this, this, @@ -2683,7 +2356,7 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point re auto& desktop = Desktop::getInstance(); const auto me = makeMouseEvent (source, - PointerState().withPosition (relativePos), + detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), this, this, @@ -2762,17 +2435,20 @@ void Component::internalBroughtToFront() //============================================================================== void Component::focusGained (FocusChangeType) {} +void Component::focusGainedWithDirection (FocusChangeType, FocusChangeDirection) {} void Component::focusLost (FocusChangeType) {} void Component::focusOfChildComponentChanged (FocusChangeType) {} void Component::internalKeyboardFocusGain (FocusChangeType cause) { - internalKeyboardFocusGain (cause, WeakReference (this)); + internalKeyboardFocusGain (cause, WeakReference (this), FocusChangeDirection::unknown); } void Component::internalKeyboardFocusGain (FocusChangeType cause, - const WeakReference& safePointer) + const WeakReference& safePointer, + FocusChangeDirection direction) { + focusGainedWithDirection (cause, direction); focusGained (cause); if (safePointer == nullptr) @@ -2884,16 +2560,16 @@ Component* Component::findKeyboardFocusContainer() const return findContainer (this, &Component::isKeyboardFocusContainer); } -static const Identifier juce_explicitFocusOrderId ("_jexfo"); +static const Identifier explicitFocusOrderId ("_jexfo"); int Component::getExplicitFocusOrder() const { - return properties [juce_explicitFocusOrderId]; + return properties [explicitFocusOrderId]; } void Component::setExplicitFocusOrder (int newFocusOrderIndex) { - properties.set (juce_explicitFocusOrderId, newFocusOrderIndex); + properties.set (explicitFocusOrderId, newFocusOrderIndex); } std::unique_ptr Component::createFocusTraverser() @@ -2912,7 +2588,7 @@ std::unique_ptr Component::createKeyboardFocusTraverser() return parentComponent->createKeyboardFocusTraverser(); } -void Component::takeKeyboardFocus (FocusChangeType cause) +void Component::takeKeyboardFocus (FocusChangeType cause, FocusChangeDirection direction) { if (currentlyFocusedComponent == this) return; @@ -2941,11 +2617,11 @@ void Component::takeKeyboardFocus (FocusChangeType cause) componentLosingFocus->internalKeyboardFocusLoss (cause); if (currentlyFocusedComponent == this) - internalKeyboardFocusGain (cause, safePointer); + internalKeyboardFocusGain (cause, safePointer, direction); } } -void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent) +void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent, FocusChangeDirection direction) { if (! isShowing()) return; @@ -2953,7 +2629,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar if (flags.wantsKeyboardFocusFlag && (isEnabled() || parentComponent == nullptr)) { - takeKeyboardFocus (cause); + takeKeyboardFocus (cause, direction); return; } @@ -2964,7 +2640,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar { if (auto* defaultComp = traverser->getDefaultComponent (this)) { - defaultComp->grabKeyboardFocusInternal (cause, false); + defaultComp->grabKeyboardFocusInternal (cause, false, direction); return; } } @@ -2972,7 +2648,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar // if no children want it and we're allowed to try our parent comp, // then pass up to parent, which will try our siblings. if (canTryParent && parentComponent != nullptr) - parentComponent->grabKeyboardFocusInternal (cause, true); + parentComponent->grabKeyboardFocusInternal (cause, true, direction); } void Component::grabKeyboardFocus() @@ -2981,7 +2657,7 @@ void Component::grabKeyboardFocus() // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED - grabKeyboardFocusInternal (focusChangedDirectly, true); + grabKeyboardFocusInternal (focusChangedDirectly, true, FocusChangeDirection::unknown); // A component can only be focused when it's actually on the screen! // If this fails then you're probably trying to grab the focus before you've @@ -3057,7 +2733,10 @@ void Component::moveKeyboardFocusToSibling (bool moveToNext) return; } - nextComp->grabKeyboardFocusInternal (focusChangedByTabKey, true); + nextComp->grabKeyboardFocusInternal (focusChangedByTabKey, + true, + moveToNext ? FocusChangeDirection::forward + : FocusChangeDirection::backward); return; } } @@ -3300,7 +2979,7 @@ AccessibilityHandler* Component::getAccessibilityHandler() // created, the if() predicate above should evaluate to false on recursive calls, // terminating the recursion. if (accessibilityHandler != nullptr) - notifyAccessibilityEventInternal (*accessibilityHandler, InternalAccessibilityEvent::elementCreated); + detail::AccessibilityHelpers::notifyAccessibilityEvent (*accessibilityHandler, detail::AccessibilityHelpers::Event::elementCreated); else jassertfalse; // createAccessibilityHandler must return non-null } diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 9f7304969532..e5ca03d91743 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -1168,14 +1168,14 @@ class JUCE_API Component : public MouseListener Calling this method will also invoke the sendLookAndFeelChange() method. - @see getLookAndFeel, lookAndFeelChanged + @see getLookAndFeel, lookAndFeelChanged, sendLookAndFeelChange */ void setLookAndFeel (LookAndFeel* newLookAndFeel); /** Called to let the component react to a change in the look-and-feel setting. - When the look-and-feel is changed for a component, this will be called in - all its child components, recursively. + When the look-and-feel is changed for a component, this method, repaint(), and + colourChanged() are called on the original component and all its children recursively. It can also be triggered manually by the sendLookAndFeelChange() method, in case an application uses a LookAndFeel class that might have changed internally. @@ -1184,10 +1184,8 @@ class JUCE_API Component : public MouseListener */ virtual void lookAndFeelChanged(); - /** Calls the lookAndFeelChanged() method in this component and all its children. - - This will recurse through the children and their children, calling lookAndFeelChanged() - on them all. + /** Calls the methods repaint(), lookAndFeelChanged(), and colourChanged() in this + component and all its children recursively. @see lookAndFeelChanged */ @@ -1893,11 +1891,28 @@ class JUCE_API Component : public MouseListener focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */ }; + /** Enumeration used by the focusGainedWithDirection() method. */ + enum class FocusChangeDirection + { + unknown, + forward, + backward + }; + /** Called to indicate that this component has just acquired the keyboard focus. @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ virtual void focusGained (FocusChangeType cause); + /** Called to indicate that this component has just acquired the keyboard focus. + + This function is called every time focusGained() is called but it has an additional change + direction parameter. + + @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + */ + virtual void focusGainedWithDirection (FocusChangeType cause, FocusChangeDirection direction); + /** Called to indicate that this component has just lost the keyboard focus. @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ @@ -2113,13 +2128,14 @@ class JUCE_API Component : public MouseListener The callback is an optional object which will receive a callback when the modal component loses its modal status, either by being hidden or when exitModalState() is called. If you pass an object in here, the system will take care of deleting it - later, after making the callback + later, after making the callback. If deleteWhenDismissed is true, then when it is dismissed, the component will be deleted and then the callback will be called. (This will safely handle the situation where the component is deleted before its exitModalState() method is called). - @see exitModalState, runModalLoop, ModalComponentManager::attachCallback + @see exitModalState, runModalLoop, ModalComponentManager::attachCallback, + ModalCallbackFunction */ void enterModalState (bool takeKeyboardFocus = true, ModalComponentManager::Callback* callback = nullptr, @@ -2236,6 +2252,8 @@ class JUCE_API Component : public MouseListener method, which your component can override if it needs to do something when colours are altered. + Note repaint() is not automatically called when a colour is changed. + For more details about colour IDs, see the comments for findColour(). @see findColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour @@ -2257,8 +2275,11 @@ class JUCE_API Component : public MouseListener */ void copyAllExplicitColoursTo (Component& target) const; - /** This method is called when a colour is changed by the setColour() method. - @see setColour, findColour + /** This method is called when a colour is changed by the setColour() method, + or when the look-and-feel is changed by the setLookAndFeel() or + sendLookAndFeelChanged() methods. + + @see setColour, findColour, setLookAndFeel, sendLookAndFeelChanged */ virtual void colourChanged(); @@ -2479,6 +2500,9 @@ class JUCE_API Component : public MouseListener /** Returns the accessibility handler for this component, or nullptr if this component is not accessible. + To customise the accessibility handler for a component, override + createAccessibilityHandler(). + @see setAccessible */ AccessibilityHandler* getAccessibilityHandler(); @@ -2492,20 +2516,6 @@ class JUCE_API Component : public MouseListener void invalidateAccessibilityHandler(); //============================================================================== - #ifndef DOXYGEN - [[deprecated ("Use the setFocusContainerType that takes a more descriptive enum.")]] - void setFocusContainer (bool shouldBeFocusContainer) noexcept - { - setFocusContainerType (shouldBeFocusContainer ? FocusContainerType::keyboardFocusContainer - : FocusContainerType::none); - } - - [[deprecated ("Use the contains that takes a Point.")]] - void contains (int, int) = delete; - #endif - -private: - //============================================================================== /** Override this method to return a custom AccessibilityHandler for this component. The default implementation creates and returns a AccessibilityHandler object with an @@ -2519,13 +2529,34 @@ class JUCE_API Component : public MouseListener its Component, so it's safe to store and use a reference back to the Component inside the AccessibilityHandler if necessary. + This function should rarely be called directly. If you need to query a component's + accessibility handler, it's normally better to call getAccessibilityHandler(). + The exception to this rule is derived implementations of createAccessibilityHandler(), + which may find it useful to call the base class implementation, and then wrap or + modify the result. + @see getAccessibilityHandler */ virtual std::unique_ptr createAccessibilityHandler(); + //============================================================================== + #ifndef DOXYGEN + [[deprecated ("Use the setFocusContainerType that takes a more descriptive enum.")]] + void setFocusContainer (bool shouldBeFocusContainer) noexcept + { + setFocusContainerType (shouldBeFocusContainer ? FocusContainerType::keyboardFocusContainer + : FocusContainerType::none); + } + + [[deprecated ("Use the contains that takes a Point.")]] + void contains (int, int) = delete; + #endif + +private: + //============================================================================== friend class ComponentPeer; - friend class MouseInputSourceInternal; + friend class detail::MouseInputSourceImpl; #ifndef DOXYGEN static Component* currentlyFocusedComponent; @@ -2594,14 +2625,14 @@ class JUCE_API Component : public MouseListener //============================================================================== void internalMouseEnter (MouseInputSource, Point, Time); void internalMouseExit (MouseInputSource, Point, Time); - void internalMouseDown (MouseInputSource, const PointerState&, Time); - void internalMouseUp (MouseInputSource, const PointerState&, Time, const ModifierKeys oldModifiers); - void internalMouseDrag (MouseInputSource, const PointerState&, Time); + void internalMouseDown (MouseInputSource, const detail::PointerState&, Time); + void internalMouseUp (MouseInputSource, const detail::PointerState&, Time, const ModifierKeys oldModifiers); + void internalMouseDrag (MouseInputSource, const detail::PointerState&, Time); void internalMouseMove (MouseInputSource, Point, Time); void internalMouseWheel (MouseInputSource, Point, Time, const MouseWheelDetails&); void internalMagnifyGesture (MouseInputSource, Point, Time, float); void internalBroughtToFront(); - void internalKeyboardFocusGain (FocusChangeType, const WeakReference&); + void internalKeyboardFocusGain (FocusChangeType, const WeakReference&, FocusChangeDirection); void internalKeyboardFocusGain (FocusChangeType); void internalKeyboardFocusLoss (FocusChangeType); void internalChildKeyboardFocusChange (FocusChangeType, const WeakReference&); @@ -2619,14 +2650,13 @@ class JUCE_API Component : public MouseListener void sendMovedResizedMessagesIfPending(); void repaintParent(); void sendFakeMouseMove() const; - void takeKeyboardFocus (FocusChangeType); - void grabKeyboardFocusInternal (FocusChangeType, bool canTryParent); + void takeKeyboardFocus (FocusChangeType, FocusChangeDirection); + void grabKeyboardFocusInternal (FocusChangeType, bool canTryParent, FocusChangeDirection); void giveAwayKeyboardFocusInternal (bool sendFocusLossEvent); void sendEnablementChangeMessage(); void sendVisibilityChangeMessage(); - struct ComponentHelpers; - friend struct ComponentHelpers; + friend struct detail::ComponentHelpers; /* Components aren't allowed to have copy constructors, as this would mess up parent hierarchies. You might need to give your subclasses a private dummy constructor to avoid compiler warnings. diff --git a/modules/juce_gui_basics/components/juce_FocusTraverser.cpp b/modules/juce_gui_basics/components/juce_FocusTraverser.cpp index 188c33d6e8bb..34e5093687a0 100644 --- a/modules/juce_gui_basics/components/juce_FocusTraverser.cpp +++ b/modules/juce_gui_basics/components/juce_FocusTraverser.cpp @@ -26,111 +26,25 @@ namespace juce { -namespace FocusHelpers -{ - static int getOrder (const Component* c) - { - auto order = c->getExplicitFocusOrder(); - return order > 0 ? order : std::numeric_limits::max(); - } - - template - static void findAllComponents (Component* parent, - std::vector& components, - FocusContainerFn isFocusContainer) - { - if (parent == nullptr || parent->getNumChildComponents() == 0) - return; - - std::vector localComponents; - - for (auto* c : parent->getChildren()) - if (c->isVisible() && c->isEnabled()) - localComponents.push_back (c); - - const auto compareComponents = [&] (const Component* a, const Component* b) - { - const auto getComponentOrderAttributes = [] (const Component* c) - { - return std::make_tuple (getOrder (c), - c->isAlwaysOnTop() ? 0 : 1, - c->getY(), - c->getX()); - }; - - return getComponentOrderAttributes (a) < getComponentOrderAttributes (b); - }; - - // This will sort so that they are ordered in terms of explicit focus, - // always on top, left-to-right, and then top-to-bottom. - std::stable_sort (localComponents.begin(), localComponents.end(), compareComponents); - - for (auto* c : localComponents) - { - components.push_back (c); - - if (! (c->*isFocusContainer)()) - findAllComponents (c, components, isFocusContainer); - } - } - - enum class NavigationDirection { forwards, backwards }; - - template - static Component* navigateFocus (Component* current, - Component* focusContainer, - NavigationDirection direction, - FocusContainerFn isFocusContainer) - { - if (focusContainer != nullptr) - { - std::vector components; - findAllComponents (focusContainer, components, isFocusContainer); - - const auto iter = std::find (components.cbegin(), components.cend(), current); - - if (iter == components.cend()) - return nullptr; - - switch (direction) - { - case NavigationDirection::forwards: - if (iter != std::prev (components.cend())) - return *std::next (iter); - - break; - - case NavigationDirection::backwards: - if (iter != components.cbegin()) - return *std::prev (iter); - - break; - } - } - - return nullptr; - } -} - //============================================================================== Component* FocusTraverser::getNextComponent (Component* current) { jassert (current != nullptr); - return FocusHelpers::navigateFocus (current, - current->findFocusContainer(), - FocusHelpers::NavigationDirection::forwards, - &Component::isFocusContainer); + return detail::FocusHelpers::navigateFocus (current, + current->findFocusContainer(), + detail::FocusHelpers::NavigationDirection::forwards, + &Component::isFocusContainer); } Component* FocusTraverser::getPreviousComponent (Component* current) { jassert (current != nullptr); - return FocusHelpers::navigateFocus (current, - current->findFocusContainer(), - FocusHelpers::NavigationDirection::backwards, - &Component::isFocusContainer); + return detail::FocusHelpers::navigateFocus (current, + current->findFocusContainer(), + detail::FocusHelpers::NavigationDirection::backwards, + &Component::isFocusContainer); } Component* FocusTraverser::getDefaultComponent (Component* parentComponent) @@ -138,9 +52,9 @@ Component* FocusTraverser::getDefaultComponent (Component* parentComponent) if (parentComponent != nullptr) { std::vector components; - FocusHelpers::findAllComponents (parentComponent, - components, - &Component::isFocusContainer); + detail::FocusHelpers::findAllComponents (parentComponent, + components, + &Component::isFocusContainer); if (! components.empty()) return components.front(); @@ -152,9 +66,9 @@ Component* FocusTraverser::getDefaultComponent (Component* parentComponent) std::vector FocusTraverser::getAllComponents (Component* parentComponent) { std::vector components; - FocusHelpers::findAllComponents (parentComponent, - components, - &Component::isFocusContainer); + detail::FocusHelpers::findAllComponents (parentComponent, + components, + &Component::isFocusContainer); return components; } diff --git a/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp b/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp index 5d1287a7c11b..c08556860056 100644 --- a/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp +++ b/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp @@ -269,7 +269,7 @@ int ModalComponentManager::runEventLoopForCurrentComponent() if (auto* currentlyModal = getModalComponent (0)) { - FocusRestorer focusRestorer; + detail::FocusRestorer focusRestorer; bool finished = false; attachCallback (currentlyModal, ModalCallbackFunction::create ([&] (int r) { returnValue = r; finished = true; })); diff --git a/modules/juce_gui_basics/desktop/juce_Desktop.cpp b/modules/juce_gui_basics/desktop/juce_Desktop.cpp index 6382c52bb7e3..9c4e7517c5b9 100644 --- a/modules/juce_gui_basics/desktop/juce_Desktop.cpp +++ b/modules/juce_gui_basics/desktop/juce_Desktop.cpp @@ -27,7 +27,7 @@ namespace juce { Desktop::Desktop() - : mouseSources (new MouseInputSource::SourceList()), + : mouseSources (new detail::MouseInputSourceList()), masterScaleFactor ((float) getDefaultMasterScale()), nativeDarkModeChangeDetectorImpl (createNativeDarkModeChangeDetectorImpl()) { @@ -353,7 +353,7 @@ void Desktop::setGlobalScaleFactor (float newScaleFactor) noexcept { JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED - if (masterScaleFactor != newScaleFactor) + if (! approximatelyEqual (masterScaleFactor, newScaleFactor)) { masterScaleFactor = newScaleFactor; displays->refresh(); diff --git a/modules/juce_gui_basics/desktop/juce_Desktop.h b/modules/juce_gui_basics/desktop/juce_Desktop.h index 45388b32a33b..91df79e992fd 100644 --- a/modules/juce_gui_basics/desktop/juce_Desktop.h +++ b/modules/juce_gui_basics/desktop/juce_Desktop.h @@ -410,12 +410,12 @@ class JUCE_API Desktop : private DeletedAtShutdown, friend class Component; friend class ComponentPeer; - friend class MouseInputSourceInternal; + friend class detail::MouseInputSourceImpl; friend class DeletedAtShutdown; - friend class TopLevelWindowManager; + friend class detail::TopLevelWindowManager; friend class Displays; - std::unique_ptr mouseSources; + std::unique_ptr mouseSources; ListenerList mouseListeners; ListenerList focusListeners; diff --git a/modules/juce_gui_basics/desktop/juce_Displays.cpp b/modules/juce_gui_basics/desktop/juce_Displays.cpp index a20114344905..5b7189f63202 100644 --- a/modules/juce_gui_basics/desktop/juce_Displays.cpp +++ b/modules/juce_gui_basics/desktop/juce_Displays.cpp @@ -26,15 +26,6 @@ namespace juce { -template -auto* getPrimaryDisplayImpl (This& t) -{ - JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED - - const auto iter = std::find_if (t.displays.begin(), t.displays.end(), [] (auto& d) { return d.isMain; }); - return iter != t.displays.end() ? std::addressof (*iter) : nullptr; -} - Displays::Displays (Desktop& desktop) { init (desktop); @@ -171,7 +162,10 @@ Point Displays::logicalToPhysical (Point point, const Disp const Displays::Display* Displays::getPrimaryDisplay() const noexcept { - return getPrimaryDisplayImpl (*this); + JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED + + const auto iter = std::find_if (displays.begin(), displays.end(), [] (auto& d) { return d.isMain; }); + return iter != displays.end() ? iter : nullptr; } RectangleList Displays::getRectangleList (bool userAreasOnly) const @@ -266,10 +260,10 @@ static void processDisplay (DisplayNode* currentNode, Array& allNod Rectangle logicalArea (0.0, 0.0, logicalWidth, logicalHeight); - if (physicalArea.getRight() == physicalParentArea.getX()) logicalArea.setPosition ({ logicalParentArea.getX() - logicalWidth, physicalArea.getY() / parentScale }); // on left - else if (physicalArea.getX() == physicalParentArea.getRight()) logicalArea.setPosition ({ logicalParentArea.getRight(), physicalArea.getY() / parentScale }); // on right - else if (physicalArea.getBottom() == physicalParentArea.getY()) logicalArea.setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getY() - logicalHeight }); // on top - else if (physicalArea.getY() == physicalParentArea.getBottom()) logicalArea.setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getBottom() }); // on bottom + if (approximatelyEqual (physicalArea.getRight(), physicalParentArea.getX())) logicalArea.setPosition ({ logicalParentArea.getX() - logicalWidth, physicalArea.getY() / parentScale }); // on left + else if (approximatelyEqual (physicalArea.getX(), physicalParentArea.getRight())) logicalArea.setPosition ({ logicalParentArea.getRight(), physicalArea.getY() / parentScale }); // on right + else if (approximatelyEqual (physicalArea.getBottom(), physicalParentArea.getY())) logicalArea.setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getY() - logicalHeight }); // on top + else if (approximatelyEqual (physicalArea.getY(), physicalParentArea.getBottom())) logicalArea.setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getBottom() }); // on bottom else jassertfalse; currentNode->logicalArea = logicalArea; @@ -292,8 +286,8 @@ static void processDisplay (DisplayNode* currentNode, Array& allNod const auto otherPhysicalArea = node.display->totalArea.toDouble(); // If the displays are touching on any side - if (otherPhysicalArea.getX() == physicalArea.getRight() || otherPhysicalArea.getRight() == physicalArea.getX() - || otherPhysicalArea.getY() == physicalArea.getBottom() || otherPhysicalArea.getBottom() == physicalArea.getY()) + if (approximatelyEqual (otherPhysicalArea.getX(), physicalArea.getRight()) || approximatelyEqual (otherPhysicalArea.getRight(), physicalArea.getX()) + || approximatelyEqual (otherPhysicalArea.getY(), physicalArea.getBottom()) || approximatelyEqual (otherPhysicalArea.getBottom(), physicalArea.getY())) { node.parent = currentNode; children.add (&node); diff --git a/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp b/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp new file mode 100644 index 000000000000..b912bf6b1be0 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.cpp @@ -0,0 +1,33 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +#if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED + void AccessibilityHelpers::notifyAccessibilityEvent (const AccessibilityHandler&, Event) {} +#endif + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h b/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h new file mode 100644 index 000000000000..5cbe1d43cff8 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_AccessibilityHelpers.h @@ -0,0 +1,70 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct AccessibilityHelpers +{ + AccessibilityHelpers() = delete; + + enum class Event + { + elementCreated, + elementDestroyed, + elementMovedOrResized, + focusChanged, + windowOpened, + windowClosed + }; + + static void notifyAccessibilityEvent (const AccessibilityHandler&, Event); + + static String getApplicationOrPluginName() + { + #if defined (JucePlugin_Name) + return JucePlugin_Name; + #else + if (auto* app = JUCEApplicationBase::getInstance()) + return app->getApplicationName(); + + return "JUCE Application"; + #endif + } + + template + static const AccessibilityHandler* getEnclosingHandlerWithInterface (const AccessibilityHandler* handler, MemberFn fn) + { + if (handler == nullptr) + return nullptr; + + if ((handler->*fn)() != nullptr) + return handler; + + return getEnclosingHandlerWithInterface (handler->getParent(), fn); + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h b/modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h new file mode 100644 index 000000000000..298a983fd668 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_AlertWindowHelpers.h @@ -0,0 +1,115 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct AlertWindowHelpers +{ + AlertWindowHelpers() = delete; + + static std::unique_ptr create (const MessageBoxOptions& opts) + { + class AlertWindowImpl : public detail::ScopedMessageBoxInterface + { + public: + explicit AlertWindowImpl (const MessageBoxOptions& opts) : options (opts) {} + + void runAsync (std::function recipient) override + { + if (auto* comp = setUpAlert()) + comp->enterModalState (true, ModalCallbackFunction::create (std::move (recipient)), true); + else + NullCheckedInvocation::invoke (recipient, 0); + } + + int runSync() override + { + #if JUCE_MODAL_LOOPS_PERMITTED + if (auto comp = rawToUniquePtr (setUpAlert())) + return comp->runModalLoop(); + #endif + + jassertfalse; + return 0; + } + + void close() override + { + if (alert != nullptr) + if (alert->isCurrentlyModal()) + alert->exitModalState(); + + alert = nullptr; + } + + private: + Component* setUpAlert() + { + auto* component = options.getAssociatedComponent(); + + auto& lf = component != nullptr ? component->getLookAndFeel() + : LookAndFeel::getDefaultLookAndFeel(); + + alert = lf.createAlertWindow (options.getTitle(), + options.getMessage(), + options.getButtonText (0), + options.getButtonText (1), + options.getButtonText (2), + options.getIconType(), + options.getNumButtons(), + component); + + if (alert == nullptr) + { + // You have to return an alert box! + jassertfalse; + return nullptr; + } + + if (auto* parent = options.getParentComponent()) + { + parent->addAndMakeVisible (alert); + + if (options.getAssociatedComponent() == nullptr) + alert->setCentrePosition (parent->getLocalBounds().getCentre()); + } + + alert->setAlwaysOnTop (WindowUtils::areThereAnyAlwaysOnTopWindows()); + + return alert; + } + + const MessageBoxOptions options; + Component::SafePointer alert; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindowImpl) + }; + + return std::make_unique (opts); + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h b/modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h new file mode 100644 index 000000000000..82dabc700391 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ButtonAccessibilityHandler.h @@ -0,0 +1,125 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +//============================================================================== +class ButtonAccessibilityHandler : public AccessibilityHandler +{ +public: + ButtonAccessibilityHandler (Button& buttonToWrap, AccessibilityRole roleIn) + : AccessibilityHandler (buttonToWrap, + isRadioButton (buttonToWrap) ? AccessibilityRole::radioButton : roleIn, + getAccessibilityActions (buttonToWrap), + getAccessibilityInterfaces (buttonToWrap)), + button (buttonToWrap) + {} + + + AccessibleState getCurrentState() const override + { + auto state = AccessibilityHandler::getCurrentState(); + + if (button.isToggleable()) + { + state = state.withCheckable(); + + if (button.getToggleState()) + state = state.withChecked(); + } + + return state; + } + + + String getTitle() const override + { + auto title = AccessibilityHandler::getTitle(); + + if (title.isEmpty()) + return button.getButtonText(); + + return title; + } + + String getHelp() const override + { + return button.getTooltip(); + } + + +private: + class ButtonValueInterface : public AccessibilityTextValueInterface + { + public: + explicit ButtonValueInterface (Button& buttonToWrap) + : button (buttonToWrap) + { + } + + bool isReadOnly() const override { return true; } + String getCurrentValueAsString() const override { return button.getToggleState() ? "On" : "Off"; } + void setValueAsString (const String&) override {} + + private: + Button& button; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonValueInterface) + }; + + static bool isRadioButton (const Button& button) noexcept + { + return button.getRadioGroupId() != 0; + } + + static AccessibilityActions getAccessibilityActions (Button& button) + { + auto actions = AccessibilityActions().addAction (AccessibilityActionType::press, + [&button] { button.triggerClick(); }); + + if (button.isToggleable()) + actions = actions.addAction (AccessibilityActionType::toggle, + [&button] { button.setToggleState (! button.getToggleState(), sendNotification); }); + + return actions; + } + + static Interfaces getAccessibilityInterfaces (Button& button) + { + if (button.isToggleable()) + return { std::make_unique (button) }; + + return {}; + } + + Button& button; + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAccessibilityHandler) +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ComponentHelpers.h b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h new file mode 100644 index 000000000000..adb50b7455e4 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h @@ -0,0 +1,255 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +constexpr char colourPropertyPrefix[] = "jcclr_"; + +//============================================================================== +struct ComponentHelpers +{ + using SH = ScalingHelpers; + + #if JUCE_MODAL_LOOPS_PERMITTED + static void* runModalLoopCallback (void* userData) + { + return (void*) (pointer_sized_int) static_cast (userData)->runModalLoop(); + } + #endif + + static Identifier getColourPropertyID (int colourID) + { + char buffer[32]; + auto* end = buffer + numElementsInArray (buffer) - 1; + auto* t = end; + *t = 0; + + for (auto v = (uint32) colourID;;) + { + *--t = "0123456789abcdef" [v & 15]; + v >>= 4; + + if (v == 0) + break; + } + + for (int i = (int) sizeof (colourPropertyPrefix) - 1; --i >= 0;) + *--t = colourPropertyPrefix[i]; + + return t; + } + + //============================================================================== + static bool hitTest (Component& comp, Point localPoint) + { + const auto intPoint = localPoint.roundToInt(); + return Rectangle { comp.getWidth(), comp.getHeight() }.contains (intPoint) + && comp.hitTest (intPoint.x, intPoint.y); + } + + // converts an unscaled position within a peer to the local position within that peer's component + template + static PointOrRect rawPeerPositionToLocal (const Component& comp, PointOrRect pos) noexcept + { + if (comp.isTransformed()) + pos = pos.transformedBy (comp.getTransform().inverted()); + + return SH::unscaledScreenPosToScaled (comp, pos); + } + + // converts a position within a peer's component to the unscaled position within the peer + template + static PointOrRect localPositionToRawPeerPos (const Component& comp, PointOrRect pos) noexcept + { + if (comp.isTransformed()) + pos = pos.transformedBy (comp.getTransform()); + + return SH::scaledScreenPosToUnscaled (comp, pos); + } + + template + static PointOrRect convertFromParentSpace (const Component& comp, const PointOrRect pointInParentSpace) + { + const auto transformed = comp.affineTransform != nullptr ? pointInParentSpace.transformedBy (comp.affineTransform->inverted()) + : pointInParentSpace; + + if (comp.isOnDesktop()) + { + if (auto* peer = comp.getPeer()) + return SH::unscaledScreenPosToScaled (comp, peer->globalToLocal (SH::scaledScreenPosToUnscaled (transformed))); + + jassertfalse; + return transformed; + } + + if (comp.getParentComponent() == nullptr) + return SH::subtractPosition (SH::unscaledScreenPosToScaled (comp, SH::scaledScreenPosToUnscaled (transformed)), comp); + + return SH::subtractPosition (transformed, comp); + } + + template + static PointOrRect convertToParentSpace (const Component& comp, const PointOrRect pointInLocalSpace) + { + const auto preTransform = [&] + { + if (comp.isOnDesktop()) + { + if (auto* peer = comp.getPeer()) + return SH::unscaledScreenPosToScaled (peer->localToGlobal (SH::scaledScreenPosToUnscaled (comp, pointInLocalSpace))); + + jassertfalse; + return pointInLocalSpace; + } + + if (comp.getParentComponent() == nullptr) + return SH::unscaledScreenPosToScaled (SH::scaledScreenPosToUnscaled (comp, SH::addPosition (pointInLocalSpace, comp))); + + return SH::addPosition (pointInLocalSpace, comp); + }(); + + return comp.affineTransform != nullptr ? preTransform.transformedBy (*comp.affineTransform) + : preTransform; + } + + template + static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, PointOrRect coordInParent) + { + auto* directParent = target.getParentComponent(); + jassert (directParent != nullptr); + + if (directParent == parent) + return convertFromParentSpace (target, coordInParent); + + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) + return convertFromParentSpace (target, convertFromDistantParentSpace (parent, *directParent, coordInParent)); + JUCE_END_IGNORE_WARNINGS_MSVC + } + + template + static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) + { + while (source != nullptr) + { + if (source == target) + return p; + + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011) + + if (source->isParentOf (target)) + return convertFromDistantParentSpace (source, *target, p); + + JUCE_END_IGNORE_WARNINGS_MSVC + + p = convertToParentSpace (*source, p); + source = source->getParentComponent(); + } + + jassert (source == nullptr); + if (target == nullptr) + return p; + + auto* topLevelComp = target->getTopLevelComponent(); + + p = convertFromParentSpace (*topLevelComp, p); + + if (topLevelComp == target) + return p; + + return convertFromDistantParentSpace (topLevelComp, *target, p); + } + + static bool clipObscuredRegions (const Component& comp, Graphics& g, + const Rectangle clipRect, Point delta) + { + bool wasClipped = false; + + for (int i = comp.childComponentList.size(); --i >= 0;) + { + auto& child = *comp.childComponentList.getUnchecked(i); + + if (child.isVisible() && ! child.isTransformed()) + { + auto newClip = clipRect.getIntersection (child.boundsRelativeToParent); + + if (! newClip.isEmpty()) + { + if (child.isOpaque() && child.componentTransparency == 0) + { + g.excludeClipRegion (newClip + delta); + wasClipped = true; + } + else + { + auto childPos = child.getPosition(); + + if (clipObscuredRegions (child, g, newClip - childPos, childPos + delta)) + wasClipped = true; + } + } + } + } + + return wasClipped; + } + + static Rectangle getParentOrMainMonitorBounds (const Component& comp) + { + if (auto* p = comp.getParentComponent()) + return p->getLocalBounds(); + + return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea; + } + + static void releaseAllCachedImageResources (Component& c) + { + if (auto* cached = c.getCachedComponentImage()) + cached->releaseResources(); + + for (auto* child : c.childComponentList) + releaseAllCachedImageResources (*child); + } + + //============================================================================== + static bool modalWouldBlockComponent (const Component& maybeBlocked, Component* modal) + { + return modal != nullptr + && modal != &maybeBlocked + && ! modal->isParentOf (&maybeBlocked) + && ! modal->canModalEventBeSentToComponent (&maybeBlocked); + } + + template + static void sendMouseEventToComponentsThatAreBlockedByModal (Component& modal, Function&& function) + { + for (auto& ms : Desktop::getInstance().getMouseSources()) + if (auto* c = ms.getComponentUnderMouse()) + if (modalWouldBlockComponent (*c, &modal)) + (c->*function) (ms, SH::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime()); + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h b/modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h new file mode 100644 index 000000000000..573307f0e8e1 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_CustomMouseCursorInfo.h @@ -0,0 +1,35 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct CustomMouseCursorInfo +{ + ScaledImage image; + Point hotspot; +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_FocusHelpers.h b/modules/juce_gui_basics/detail/juce_FocusHelpers.h new file mode 100644 index 000000000000..7b7489630a5b --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_FocusHelpers.h @@ -0,0 +1,117 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct FocusHelpers +{ + FocusHelpers() = delete; + + static int getOrder (const Component* c) + { + auto order = c->getExplicitFocusOrder(); + return order > 0 ? order : std::numeric_limits::max(); + } + + template + static void findAllComponents (Component* parent, + std::vector& components, + FocusContainerFn isFocusContainer) + { + if (parent == nullptr || parent->getNumChildComponents() == 0) + return; + + std::vector localComponents; + + for (auto* c : parent->getChildren()) + if (c->isVisible() && c->isEnabled()) + localComponents.push_back (c); + + const auto compareComponents = [&] (const Component* a, const Component* b) + { + const auto getComponentOrderAttributes = [] (const Component* c) + { + return std::make_tuple (getOrder (c), + c->isAlwaysOnTop() ? 0 : 1, + c->getY(), + c->getX()); + }; + + return getComponentOrderAttributes (a) < getComponentOrderAttributes (b); + }; + + // This will sort so that they are ordered in terms of explicit focus, + // always on top, left-to-right, and then top-to-bottom. + std::stable_sort (localComponents.begin(), localComponents.end(), compareComponents); + + for (auto* c : localComponents) + { + components.push_back (c); + + if (! (c->*isFocusContainer)()) + findAllComponents (c, components, isFocusContainer); + } + } + + enum class NavigationDirection { forwards, backwards }; + + template + static Component* navigateFocus (Component* current, + Component* focusContainer, + NavigationDirection direction, + FocusContainerFn isFocusContainer) + { + if (focusContainer != nullptr) + { + std::vector components; + findAllComponents (focusContainer, components, isFocusContainer); + + const auto iter = std::find (components.cbegin(), components.cend(), current); + + if (iter == components.cend()) + return nullptr; + + switch (direction) + { + case NavigationDirection::forwards: + if (iter != std::prev (components.cend())) + return *std::next (iter); + + break; + + case NavigationDirection::backwards: + if (iter != components.cbegin()) + return *std::prev (iter); + + break; + } + } + + return nullptr; + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_FocusRestorer.h b/modules/juce_gui_basics/detail/juce_FocusRestorer.h new file mode 100644 index 000000000000..ff1367714c60 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_FocusRestorer.h @@ -0,0 +1,46 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct FocusRestorer +{ + FocusRestorer() : lastFocus (Component::getCurrentlyFocusedComponent()) {} + + ~FocusRestorer() + { + if (lastFocus != nullptr + && lastFocus->isShowing() + && ! lastFocus->isCurrentlyBlockedByAnotherModalComponent()) + lastFocus->grabKeyboardFocus(); + } + + WeakReference lastFocus; + + JUCE_DECLARE_NON_COPYABLE (FocusRestorer) +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h b/modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h new file mode 100644 index 000000000000..1f90fadd290d --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_LookAndFeelHelpers.h @@ -0,0 +1,62 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct LookAndFeelHelpers +{ + LookAndFeelHelpers() = delete; + + static Colour createBaseColour (Colour buttonColour, + bool hasKeyboardFocus, + bool shouldDrawButtonAsHighlighted, + bool shouldDrawButtonAsDown) noexcept + { + const float sat = hasKeyboardFocus ? 1.3f : 0.9f; + const Colour baseColour (buttonColour.withMultipliedSaturation (sat)); + + if (shouldDrawButtonAsDown) return baseColour.contrasting (0.2f); + if (shouldDrawButtonAsHighlighted) return baseColour.contrasting (0.1f); + + return baseColour; + } + + static TextLayout layoutTooltipText (const String& text, Colour colour) noexcept + { + const float tooltipFontSize = 13.0f; + const int maxToolTipWidth = 400; + + AttributedString s; + s.setJustification (Justification::centred); + s.append (text, Font (tooltipFontSize, Font::bold), colour); + + TextLayout tl; + tl.createLayoutWithBalancedLineLengths (s, (float) maxToolTipWidth); + return tl; + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h b/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h new file mode 100644 index 000000000000..26ac916f1909 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h @@ -0,0 +1,588 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +class MouseInputSourceImpl : private AsyncUpdater +{ +public: + using SH = ScalingHelpers; + + MouseInputSourceImpl (int i, MouseInputSource::InputSourceType type) + : index (i), + inputType (type) + {} + + //============================================================================== + bool isDragging() const noexcept + { + return buttonState.isAnyMouseButtonDown(); + } + + Component* getComponentUnderMouse() const noexcept + { + return componentUnderMouse.get(); + } + + ModifierKeys getCurrentModifiers() const noexcept + { + return ModifierKeys::currentModifiers + .withoutMouseButtons() + .withFlags (buttonState.getRawFlags()); + } + + ComponentPeer* getPeer() noexcept + { + if (! ComponentPeer::isValidPeer (lastPeer)) + lastPeer = nullptr; + + return lastPeer; + } + + static Component* findComponentAt (Point screenPos, ComponentPeer* peer) + { + if (! ComponentPeer::isValidPeer (peer)) + return nullptr; + + auto relativePos = SH::unscaledScreenPosToScaled (peer->getComponent(), + peer->globalToLocal (screenPos)); + auto& comp = peer->getComponent(); + + // (the contains() call is needed to test for overlapping desktop windows) + if (comp.contains (relativePos)) + return comp.getComponentAt (relativePos); + + return nullptr; + } + + Point getScreenPosition() const noexcept + { + // This needs to return the live position if possible, but it mustn't update the lastScreenPos + // value, because that can cause continuity problems. + return SH::unscaledScreenPosToScaled (getRawScreenPosition()); + } + + Point getRawScreenPosition() const noexcept + { + return unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition() + : lastPointerState.position); + } + + void setScreenPosition (Point p) + { + MouseInputSource::setRawMousePosition (SH::scaledScreenPosToUnscaled (p)); + } + + //============================================================================== + #if JUCE_DUMP_MOUSE_EVENTS + #define JUCE_MOUSE_EVENT_DBG(desc, screenPos) DBG ("Mouse " << desc << " #" << index \ + << ": " << SH::screenPosToLocalPos (comp, screenPos).toString() \ + << " - Comp: " << String::toHexString ((pointer_sized_int) &comp)); + #else + #define JUCE_MOUSE_EVENT_DBG(desc, screenPos) + #endif + + void sendMouseEnter (Component& comp, const detail::PointerState& pointerState, Time time) + { + JUCE_MOUSE_EVENT_DBG ("enter", pointerState.position) + comp.internalMouseEnter (MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); + } + + void sendMouseExit (Component& comp, const detail::PointerState& pointerState, Time time) + { + JUCE_MOUSE_EVENT_DBG ("exit", pointerState.position) + comp.internalMouseExit (MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); + } + + void sendMouseMove (Component& comp, const detail::PointerState& pointerState, Time time) + { + JUCE_MOUSE_EVENT_DBG ("move", pointerState.position) + comp.internalMouseMove (MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); + } + + void sendMouseDown (Component& comp, const detail::PointerState& pointerState, Time time) + { + JUCE_MOUSE_EVENT_DBG ("down", pointerState.position) + comp.internalMouseDown (MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time); + } + + void sendMouseDrag (Component& comp, const detail::PointerState& pointerState, Time time) + { + JUCE_MOUSE_EVENT_DBG ("drag", pointerState.position) + comp.internalMouseDrag (MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time); + } + + void sendMouseUp (Component& comp, const detail::PointerState& pointerState, Time time, ModifierKeys oldMods) + { + JUCE_MOUSE_EVENT_DBG ("up", pointerState.position) + comp.internalMouseUp (MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time, + oldMods); + } + + void sendMouseWheel (Component& comp, Point screenPos, Time time, const MouseWheelDetails& wheel) + { + JUCE_MOUSE_EVENT_DBG ("wheel", screenPos) + comp.internalMouseWheel (MouseInputSource (this), + SH::screenPosToLocalPos (comp, screenPos), + time, + wheel); + } + + void sendMagnifyGesture (Component& comp, Point screenPos, Time time, float amount) + { + JUCE_MOUSE_EVENT_DBG ("magnify", screenPos) + comp.internalMagnifyGesture (MouseInputSource (this), + SH::screenPosToLocalPos (comp, screenPos), + time, + amount); + } + + #undef JUCE_MOUSE_EVENT_DBG + + //============================================================================== + // (returns true if the button change caused a modal event loop) + bool setButtons (const detail::PointerState& pointerState, Time time, ModifierKeys newButtonState) + { + if (buttonState == newButtonState) + return false; + + // (avoid sending a spurious mouse-drag when we receive a mouse-up) + if (! (isDragging() && ! newButtonState.isAnyMouseButtonDown())) + setPointerState (pointerState, time, false); + + // (ignore secondary clicks when there's already a button down) + if (buttonState.isAnyMouseButtonDown() == newButtonState.isAnyMouseButtonDown()) + { + buttonState = newButtonState; + return false; + } + + auto lastCounter = mouseEventCounter; + + if (buttonState.isAnyMouseButtonDown()) + { + if (auto* current = getComponentUnderMouse()) + { + auto oldMods = getCurrentModifiers(); + buttonState = newButtonState; // must change this before calling sendMouseUp, in case it runs a modal loop + + sendMouseUp (*current, pointerState.withPositionOffset (unboundedMouseOffset), time, oldMods); + + if (lastCounter != mouseEventCounter) + return true; // if a modal loop happened, then newButtonState is no longer valid. + } + + enableUnboundedMouseMovement (false, false); + } + + buttonState = newButtonState; + + if (buttonState.isAnyMouseButtonDown()) + { + Desktop::getInstance().incrementMouseClickCounter(); + + if (auto* current = getComponentUnderMouse()) + { + registerMouseDown (pointerState.position, time, *current, buttonState, + inputType == MouseInputSource::InputSourceType::touch); + sendMouseDown (*current, pointerState, time); + } + } + + return lastCounter != mouseEventCounter; + } + + void setComponentUnderMouse (Component* newComponent, const detail::PointerState& pointerState, Time time) + { + auto* current = getComponentUnderMouse(); + + if (newComponent != current) + { + WeakReference safeNewComp (newComponent); + auto originalButtonState = buttonState; + + if (current != nullptr) + { + WeakReference safeOldComp (current); + setButtons (pointerState, time, ModifierKeys()); + + if (auto oldComp = safeOldComp.get()) + { + componentUnderMouse = safeNewComp; + sendMouseExit (*oldComp, pointerState, time); + } + + buttonState = originalButtonState; + } + + componentUnderMouse = safeNewComp.get(); + current = safeNewComp.get(); + + if (current != nullptr) + sendMouseEnter (*current, pointerState, time); + + revealCursor (false); + setButtons (pointerState, time, originalButtonState); + } + } + + void setPeer (ComponentPeer& newPeer, const detail::PointerState& pointerState, Time time) + { + if (&newPeer != lastPeer && ( findComponentAt (pointerState.position, &newPeer) != nullptr + || findComponentAt (pointerState.position, lastPeer) == nullptr)) + { + setComponentUnderMouse (nullptr, pointerState, time); + lastPeer = &newPeer; + setComponentUnderMouse (findComponentAt (pointerState.position, getPeer()), pointerState, time); + } + } + + void setPointerState (const detail::PointerState& newPointerState, Time time, bool forceUpdate) + { + const auto& newScreenPos = newPointerState.position; + + if (! isDragging()) + setComponentUnderMouse (findComponentAt (newScreenPos, getPeer()), newPointerState, time); + + if ((newPointerState != lastPointerState) || forceUpdate) + { + cancelPendingUpdate(); + + lastPointerState = newPointerState; + + if (auto* current = getComponentUnderMouse()) + { + if (isDragging()) + { + registerMouseDrag (newScreenPos); + sendMouseDrag (*current, newPointerState.withPositionOffset (unboundedMouseOffset), time); + + if (isUnboundedMouseModeOn) + handleUnboundedDrag (*current); + } + else + { + sendMouseMove (*current, newPointerState, time); + } + } + + revealCursor (false); + } + } + + //============================================================================== + void handleEvent (ComponentPeer& newPeer, Point positionWithinPeer, Time time, + const ModifierKeys newMods, float newPressure, float newOrientation, PenDetails pen) + { + lastTime = time; + ++mouseEventCounter; + const auto pointerState = detail::PointerState().withPosition (newPeer.localToGlobal (positionWithinPeer)) + .withPressure (newPressure) + .withOrientation (newOrientation) + .withRotation (MouseInputSource::defaultRotation) + .withTiltX (pen.tiltX) + .withTiltY (pen.tiltY); + + if (isDragging() && newMods.isAnyMouseButtonDown()) + { + setPointerState (pointerState, time, false); + } + else + { + setPeer (newPeer, pointerState, time); + + if (auto* peer = getPeer()) + { + if (setButtons (pointerState, time, newMods)) + return; // some modal events have been dispatched, so the current event is now out-of-date + + peer = getPeer(); + + if (peer != nullptr) + setPointerState (pointerState, time, false); + } + } + } + + Component* getTargetForGesture (ComponentPeer& peer, Point positionWithinPeer, + Time time, Point& screenPos) + { + lastTime = time; + ++mouseEventCounter; + + screenPos = peer.localToGlobal (positionWithinPeer); + const auto pointerState = lastPointerState.withPosition (screenPos); + setPeer (peer, pointerState, time); + setPointerState (pointerState, time, false); + triggerFakeMove(); + + return getComponentUnderMouse(); + } + + void handleWheel (ComponentPeer& peer, Point positionWithinPeer, + Time time, const MouseWheelDetails& wheel) + { + Desktop::getInstance().incrementMouseWheelCounter(); + Point screenPos; + + // This will make sure that when the wheel spins in its inertial phase, any events + // continue to be sent to the last component that the mouse was over when it was being + // actively controlled by the user. This avoids confusion when scrolling through nested + // scrollable components. + if (lastNonInertialWheelTarget == nullptr || ! wheel.isInertial) + lastNonInertialWheelTarget = getTargetForGesture (peer, positionWithinPeer, time, screenPos); + else + screenPos = peer.localToGlobal (positionWithinPeer); + + if (auto target = lastNonInertialWheelTarget.get()) + sendMouseWheel (*target, screenPos, time, wheel); + } + + void handleMagnifyGesture (ComponentPeer& peer, Point positionWithinPeer, + Time time, const float scaleFactor) + { + Point screenPos; + + if (auto* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos)) + sendMagnifyGesture (*current, screenPos, time, scaleFactor); + } + + //============================================================================== + Time getLastMouseDownTime() const noexcept + { + return mouseDowns[0].time; + } + + Point getLastMouseDownPosition() const noexcept + { + return SH::unscaledScreenPosToScaled (mouseDowns[0].position); + } + + int getNumberOfMultipleClicks() const noexcept + { + int numClicks = 1; + + if (! isLongPressOrDrag()) + { + for (int i = 1; i < numElementsInArray (mouseDowns); ++i) + { + if (mouseDowns[0].canBePartOfMultipleClickWith (mouseDowns[i], MouseEvent::getDoubleClickTimeout() * jmin (i, 2))) + ++numClicks; + else + break; + } + } + + return numClicks; + } + + bool isLongPressOrDrag() const noexcept + { + return movedSignificantly || + lastTime > (mouseDowns[0].time + RelativeTime::milliseconds (300)); + } + + bool hasMovedSignificantlySincePressed() const noexcept + { + return movedSignificantly; + } + + // Deprecated method + bool hasMouseMovedSignificantlySincePressed() const noexcept + { + return isLongPressOrDrag(); + } + + //============================================================================== + void triggerFakeMove() + { + triggerAsyncUpdate(); + } + + void handleAsyncUpdate() override + { + setPointerState (lastPointerState, + jmax (lastTime, Time::getCurrentTime()), true); + } + + //============================================================================== + void enableUnboundedMouseMovement (bool enable, bool keepCursorVisibleUntilOffscreen) + { + enable = enable && isDragging(); + isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen; + + if (enable != isUnboundedMouseModeOn) + { + if ((! enable) && ((! isCursorVisibleUntilOffscreen) || ! unboundedMouseOffset.isOrigin())) + { + // when released, return the mouse to within the component's bounds + if (auto* current = getComponentUnderMouse()) + setScreenPosition (current->getScreenBounds().toFloat() + .getConstrainedPoint (SH::unscaledScreenPosToScaled (lastPointerState.position))); + } + + isUnboundedMouseModeOn = enable; + unboundedMouseOffset = {}; + + revealCursor (true); + } + } + + void handleUnboundedDrag (Component& current) + { + auto componentScreenBounds = SH::scaledScreenPosToUnscaled (current.getParentMonitorArea() + .reduced (2, 2) + .toFloat()); + + if (! componentScreenBounds.contains (lastPointerState.position)) + { + auto componentCentre = current.getScreenBounds().toFloat().getCentre(); + unboundedMouseOffset += (lastPointerState.position - SH::scaledScreenPosToUnscaled (componentCentre)); + setScreenPosition (componentCentre); + } + else if (isCursorVisibleUntilOffscreen + && (! unboundedMouseOffset.isOrigin()) + && componentScreenBounds.contains (lastPointerState.position + unboundedMouseOffset)) + { + MouseInputSource::setRawMousePosition (lastPointerState.position + unboundedMouseOffset); + unboundedMouseOffset = {}; + } + } + + //============================================================================== + void showMouseCursor (MouseCursor cursor, bool forcedUpdate) + { + if (isUnboundedMouseModeOn && ((! unboundedMouseOffset.isOrigin()) || ! isCursorVisibleUntilOffscreen)) + { + cursor = MouseCursor::NoCursor; + forcedUpdate = true; + } + + if (forcedUpdate || cursor.getHandle() != currentCursorHandle) + { + currentCursorHandle = cursor.getHandle(); + cursor.showInWindow (getPeer()); + } + } + + void hideCursor() + { + showMouseCursor (MouseCursor::NoCursor, true); + } + + void revealCursor (bool forcedUpdate) + { + MouseCursor mc (MouseCursor::NormalCursor); + + if (auto* current = getComponentUnderMouse()) + mc = current->getLookAndFeel().getMouseCursorFor (*current); + + showMouseCursor (mc, forcedUpdate); + } + + //============================================================================== + const int index; + const MouseInputSource::InputSourceType inputType; + Point unboundedMouseOffset; // NB: these are unscaled coords + detail::PointerState lastPointerState; + ModifierKeys buttonState; + + bool isUnboundedMouseModeOn = false, isCursorVisibleUntilOffscreen = false; + +private: + WeakReference componentUnderMouse, lastNonInertialWheelTarget; + ComponentPeer* lastPeer = nullptr; + + void* currentCursorHandle = nullptr; + int mouseEventCounter = 0; + + struct RecentMouseDown + { + RecentMouseDown() = default; + + Point position; + Time time; + ModifierKeys buttons; + uint32 peerID = 0; + bool isTouch = false; + + bool canBePartOfMultipleClickWith (const RecentMouseDown& other, int maxTimeBetweenMs) const noexcept + { + return time - other.time < RelativeTime::milliseconds (maxTimeBetweenMs) + && std::abs (position.x - other.position.x) < (float) getPositionToleranceForInputType() + && std::abs (position.y - other.position.y) < (float) getPositionToleranceForInputType() + && buttons == other.buttons + && peerID == other.peerID; + } + + int getPositionToleranceForInputType() const noexcept { return isTouch ? 25 : 8; } + }; + + RecentMouseDown mouseDowns[4]; + Time lastTime; + bool movedSignificantly = false; + + void registerMouseDown (Point screenPos, Time time, Component& component, + const ModifierKeys modifiers, bool isTouchSource) noexcept + { + for (int i = numElementsInArray (mouseDowns); --i > 0;) + mouseDowns[i] = mouseDowns[i - 1]; + + mouseDowns[0].position = screenPos; + mouseDowns[0].time = time; + mouseDowns[0].buttons = modifiers.withOnlyMouseButtons(); + mouseDowns[0].isTouch = isTouchSource; + + if (auto* peer = component.getPeer()) + mouseDowns[0].peerID = peer->getUniqueID(); + else + mouseDowns[0].peerID = 0; + + movedSignificantly = false; + lastNonInertialWheelTarget = nullptr; + } + + void registerMouseDrag (Point screenPos) noexcept + { + movedSignificantly = movedSignificantly || mouseDowns[0].position.getDistanceFrom (screenPos) >= 4; + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseInputSourceImpl) +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_MouseInputSourceList.h b/modules/juce_gui_basics/detail/juce_MouseInputSourceList.h new file mode 100644 index 000000000000..f47a7bb95e90 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_MouseInputSourceList.h @@ -0,0 +1,154 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +class MouseInputSourceList : public Timer +{ +public: + MouseInputSourceList() + { + #if JUCE_ANDROID || JUCE_IOS + auto mainMouseInputType = MouseInputSource::InputSourceType::touch; + #else + auto mainMouseInputType = MouseInputSource::InputSourceType::mouse; + #endif + + addSource (0, mainMouseInputType); + } + + MouseInputSource* addSource (int index, MouseInputSource::InputSourceType type) + { + auto* s = new MouseInputSourceImpl (index, type); + sources.add (s); + sourceArray.add (MouseInputSource (s)); + + return &sourceArray.getReference (sourceArray.size() - 1); + } + + MouseInputSource* getMouseSource (int index) noexcept + { + return isPositiveAndBelow (index, sourceArray.size()) ? &sourceArray.getReference (index) + : nullptr; + } + + MouseInputSource* getOrCreateMouseInputSource (MouseInputSource::InputSourceType type, int touchIndex = 0) + { + if (type == MouseInputSource::InputSourceType::mouse + || type == MouseInputSource::InputSourceType::pen) + { + for (auto& m : sourceArray) + if (type == m.getType()) + return &m; + + addSource (0, type); + } + else if (type == MouseInputSource::InputSourceType::touch) + { + jassert (0 <= touchIndex && touchIndex < 100); // sanity-check on number of fingers + + for (auto& m : sourceArray) + if (type == m.getType() && touchIndex == m.getIndex()) + return &m; + + if (canUseTouch()) + return addSource (touchIndex, type); + } + + return nullptr; + } + + int getNumDraggingMouseSources() const noexcept + { + int num = 0; + + for (auto* s : sources) + if (s->isDragging()) + ++num; + + return num; + } + + MouseInputSource* getDraggingMouseSource (int index) noexcept + { + int num = 0; + + for (auto& s : sourceArray) + { + if (s.isDragging()) + { + if (index == num) + return &s; + + ++num; + } + } + + return nullptr; + } + + void beginDragAutoRepeat (int interval) + { + if (interval > 0) + { + if (getTimerInterval() != interval) + startTimer (interval); + } + else + { + stopTimer(); + } + } + + void timerCallback() override + { + bool anyDragging = false; + + for (auto* s : sources) + { + // NB: when doing auto-repeat, we need to force an update of the current position and button state, + // because on some OSes the queue can get overloaded with messages so that mouse-events don't get through.. + if (s->isDragging() && ComponentPeer::getCurrentModifiersRealtime().isAnyMouseButtonDown()) + { + s->lastPointerState.position = s->getRawScreenPosition(); + s->triggerFakeMove(); + anyDragging = true; + } + } + + if (! anyDragging) + stopTimer(); + } + + OwnedArray sources; + Array sourceArray; + +private: + bool addSource(); + bool canUseTouch() const; +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/mouse/juce_PointerState.h b/modules/juce_gui_basics/detail/juce_PointerState.h similarity index 96% rename from modules/juce_gui_basics/mouse/juce_PointerState.h rename to modules/juce_gui_basics/detail/juce_PointerState.h index 97fd53bc02a8..30bce9c0ee79 100644 --- a/modules/juce_gui_basics/mouse/juce_PointerState.h +++ b/modules/juce_gui_basics/detail/juce_PointerState.h @@ -23,11 +23,9 @@ ============================================================================== */ -namespace juce +namespace juce::detail { -#ifndef DOXYGEN - class PointerState { auto tie() const noexcept @@ -103,7 +101,4 @@ inline auto makeMouseEvent (MouseInputSource source, mouseWasDragged); } - -#endif - -} // namespace juce +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ScalingHelpers.h b/modules/juce_gui_basics/detail/juce_ScalingHelpers.h new file mode 100644 index 000000000000..81b25af292b0 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ScalingHelpers.h @@ -0,0 +1,123 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct ScalingHelpers +{ + template + static PointOrRect unscaledScreenPosToScaled (float scale, PointOrRect pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? pos / scale : pos; + } + + template + static PointOrRect scaledScreenPosToUnscaled (float scale, PointOrRect pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? pos * scale : pos; + } + + // For these, we need to avoid getSmallestIntegerContainer being used, which causes + // judder when moving windows + static Rectangle unscaledScreenPosToScaled (float scale, Rectangle pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? Rectangle (roundToInt ((float) pos.getX() / scale), + roundToInt ((float) pos.getY() / scale), + roundToInt ((float) pos.getWidth() / scale), + roundToInt ((float) pos.getHeight() / scale)) : pos; + } + + static Rectangle scaledScreenPosToUnscaled (float scale, Rectangle pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? Rectangle (roundToInt ((float) pos.getX() * scale), + roundToInt ((float) pos.getY() * scale), + roundToInt ((float) pos.getWidth() * scale), + roundToInt ((float) pos.getHeight() * scale)) : pos; + } + + static Rectangle unscaledScreenPosToScaled (float scale, Rectangle pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? Rectangle (pos.getX() / scale, + pos.getY() / scale, + pos.getWidth() / scale, + pos.getHeight() / scale) : pos; + } + + static Rectangle scaledScreenPosToUnscaled (float scale, Rectangle pos) noexcept + { + return ! approximatelyEqual (scale, 1.0f) ? Rectangle (pos.getX() * scale, + pos.getY() * scale, + pos.getWidth() * scale, + pos.getHeight() * scale) : pos; + } + + template + static PointOrRect unscaledScreenPosToScaled (PointOrRect pos) noexcept + { + return unscaledScreenPosToScaled (Desktop::getInstance().getGlobalScaleFactor(), pos); + } + + template + static PointOrRect scaledScreenPosToUnscaled (PointOrRect pos) noexcept + { + return scaledScreenPosToUnscaled (Desktop::getInstance().getGlobalScaleFactor(), pos); + } + + template + static PointOrRect unscaledScreenPosToScaled (const Component& comp, PointOrRect pos) noexcept + { + return unscaledScreenPosToScaled (comp.getDesktopScaleFactor(), pos); + } + + template + static PointOrRect scaledScreenPosToUnscaled (const Component& comp, PointOrRect pos) noexcept + { + return scaledScreenPosToUnscaled (comp.getDesktopScaleFactor(), pos); + } + + static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition(); } + static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition(); } + static Point addPosition (Point p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } + static Rectangle addPosition (Rectangle p, const Component& c) noexcept { return p + c.getPosition().toFloat(); } + static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition(); } + static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition(); } + static Point subtractPosition (Point p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } + static Rectangle subtractPosition (Rectangle p, const Component& c) noexcept { return p - c.getPosition().toFloat(); } + + static Point screenPosToLocalPos (Component& comp, Point pos) + { + if (auto* peer = comp.getPeer()) + { + pos = peer->globalToLocal (pos); + auto& peerComp = peer->getComponent(); + return comp.getLocalPoint (&peerComp, unscaledScreenPosToScaled (peerComp, pos)); + } + + return comp.getLocalPoint (nullptr, unscaledScreenPosToScaled (comp, pos)); + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h b/modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h new file mode 100644 index 000000000000..c4cc158e5bbb --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ScopedContentSharerImpl.h @@ -0,0 +1,98 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +class ConcreteScopedContentSharerImpl : public ScopedMessageBoxImpl, + private AsyncUpdater +{ +public: + static ScopedMessageBox show (std::unique_ptr&& native, + ContentSharer::Callback callback) + { + return ScopedMessageBox (runAsync (std::move (native), std::move (callback))); + } + + ~ConcreteScopedContentSharerImpl() override + { + cancelPendingUpdate(); + } + + void close() override + { + cancelPendingUpdate(); + nativeImplementation->close(); + self.reset(); + } + +private: + static std::shared_ptr runAsync (std::unique_ptr&& p, + ContentSharer::Callback&& c) + { + std::shared_ptr result (new ConcreteScopedContentSharerImpl (std::move (p), std::move (c))); + result->self = result; + result->triggerAsyncUpdate(); + return result; + } + + ConcreteScopedContentSharerImpl (std::unique_ptr&& p, + ContentSharer::Callback&& c) + : callback (std::move (c)), nativeImplementation (std::move (p)) {} + + void handleAsyncUpdate() override + { + nativeImplementation->runAsync ([weakRecipient = std::weak_ptr (self)] (bool result, const String& error) + { + const auto notifyRecipient = [result, error, weakRecipient] + { + if (const auto locked = weakRecipient.lock()) + { + NullCheckedInvocation::invoke (locked->callback, result, error); + locked->self.reset(); + } + }; + + if (MessageManager::getInstance()->isThisTheMessageThread()) + notifyRecipient(); + else + MessageManager::callAsync (notifyRecipient); + }); + } + + ContentSharer::Callback callback; + std::unique_ptr nativeImplementation; + + /* The 'old' native message box API doesn't have a concept of content sharer owners. + Instead, content sharers have to clean up after themselves, once they're done displaying. + To allow this mode of usage, the implementation keeps an owning reference to itself, + which is cleared once the content sharer is closed or asked to quit. To display a content + sharer box without a scoped lifetime, just create a Pimpl instance without using + the ScopedContentSharer wrapper, and the Pimpl will destroy itself after it is dismissed. + */ + std::shared_ptr self; +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h b/modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h new file mode 100644 index 000000000000..5e847ee4fdc2 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ScopedContentSharerInterface.h @@ -0,0 +1,211 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +/* + Instances of this type can show and dismiss a content sharer. + + This is an interface rather than a concrete type so that platforms can pick an implementation at + runtime if necessary. +*/ +struct ScopedContentSharerInterface +{ + virtual ~ScopedContentSharerInterface() = default; + + /* Shows the content sharer. + + When the content sharer exits normally, it should send the result to the passed-in function. + The passed-in function is safe to call from any thread at any time. + */ + virtual void runAsync (ContentSharer::Callback callback) + { + jassertfalse; + NullCheckedInvocation::invoke (callback, false, "Content sharing not available on this platform!"); + } + + /* Forcefully closes the content sharer. + + This will be called when the content sharer handle has fallen out of scope. + If the content sharer has already been closed by the user, this shouldn't do anything. + */ + virtual void close() {} + + /* Implemented differently for each platform. */ + static std::unique_ptr shareFiles (const Array&, Component*); + static std::unique_ptr shareText (const String&, Component*); + + /* Implemented below. */ + static std::unique_ptr shareImages (const Array&, std::unique_ptr, Component*); + static std::unique_ptr shareData (MemoryBlock, Component*); +}; + +class TemporaryFilesDecorator : public ScopedContentSharerInterface, + private AsyncUpdater +{ +public: + explicit TemporaryFilesDecorator (Component* parentIn) + : parent (parentIn) {} + + void runAsync (ContentSharer::Callback cb) override + { + callback = std::move (cb); + + task = std::async (std::launch::async, [this] + { + std::tie (temporaryFiles, error) = prepareTemporaryFiles(); + triggerAsyncUpdate(); + }); + } + + void close() override + { + if (inner != nullptr) + inner->close(); + } + +private: + virtual std::tuple, String> prepareTemporaryFiles() const = 0; + + void handleAsyncUpdate() override + { + if (error.isNotEmpty()) + { + NullCheckedInvocation::invoke (callback, false, error); + return; + } + + inner = shareFiles (temporaryFiles, parent); + + if (inner == nullptr) + { + NullCheckedInvocation::invoke (callback, false, TRANS ("Failed to create file sharer")); + return; + } + + inner->runAsync (callback); + } + + Array temporaryFiles; + String error; + std::unique_ptr inner; + ContentSharer::Callback callback; + std::future task; + Component* parent = nullptr; +}; + +std::unique_ptr ScopedContentSharerInterface::shareImages (const Array& images, + std::unique_ptr format, + Component* parent) +{ + class Decorator : public TemporaryFilesDecorator + { + public: + Decorator (Array imagesIn, std::unique_ptr formatIn, Component* parentIn) + : TemporaryFilesDecorator (parentIn), images (std::move (imagesIn)), format (std::move (formatIn)) {} + + private: + std::tuple, String> prepareTemporaryFiles() const override + { + const auto extension = format->getFormatName().toLowerCase(); + + Array result; + + for (const auto& image : images) + { + File tempFile = File::createTempFile (extension); + + if (! tempFile.create().wasOk()) + return { Array{}, TRANS ("Failed to create temporary file") }; + + std::unique_ptr outputStream (tempFile.createOutputStream()); + + if (outputStream == nullptr) + return { Array{}, TRANS ("Failed to open temporary file for writing") }; + + if (format->writeImageToStream (image, *outputStream)) + result.add (URL (tempFile)); + } + + for (const auto& url : result) + jassertquiet (url.isLocalFile() && url.getLocalFile().existsAsFile()); + + return { std::move (result), String{} }; + } + + Array images; + std::unique_ptr format; + }; + + return std::make_unique (images, + format == nullptr ? std::make_unique() : std::move (format), + parent); +} + +std::unique_ptr ScopedContentSharerInterface::shareData (MemoryBlock mb, Component* parent) +{ + class Decorator : public TemporaryFilesDecorator + { + public: + Decorator (MemoryBlock mbIn, Component* parentIn) + : TemporaryFilesDecorator (parentIn), mb (std::move (mbIn)) {} + + private: + std::tuple, String> prepareTemporaryFiles() const override + { + File tempFile = File::createTempFile ("data"); + + if (! tempFile.create().wasOk()) + return { Array{}, TRANS ("Failed to create temporary file") }; + + std::unique_ptr outputStream (tempFile.createOutputStream()); + + if (outputStream == nullptr) + return { Array{}, TRANS ("Failed to open temporary file for writing") }; + + size_t pos = 0; + size_t totalSize = mb.getSize(); + + while (pos < totalSize) + { + size_t numToWrite = std::min ((size_t) 8192, totalSize - pos); + + if (! outputStream->write (mb.begin() + pos, numToWrite)) + return { Array{}, TRANS ("Failed to write to temporary file") }; + + pos += numToWrite; + } + + return { Array { URL (tempFile) }, String{} }; + } + + MemoryBlock mb; + }; + + return std::make_unique (std::move (mb), parent); +} + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h b/modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h new file mode 100644 index 000000000000..8396ca829ff2 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ScopedMessageBoxImpl.h @@ -0,0 +1,132 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +//============================================================================== +class ScopedMessageBoxImpl +{ +public: + virtual ~ScopedMessageBoxImpl() = default; + virtual void close() = 0; +}; + +//============================================================================== +class ConcreteScopedMessageBoxImpl : public ScopedMessageBoxImpl, + private AsyncUpdater +{ +public: + static ScopedMessageBox show (std::unique_ptr&& native, + std::function callback) + { + return ScopedMessageBox (runAsync (std::move (native), + rawToUniquePtr (ModalCallbackFunction::create (std::move (callback))))); + } + + static int showUnmanaged (std::unique_ptr&& native, + ModalComponentManager::Callback* cb) + { + #if JUCE_MODAL_LOOPS_PERMITTED + if (cb == nullptr) + return runSync (std::move (native)); + #endif + + runAsync (std::move (native), rawToUniquePtr (cb)); + + return 0; + } + + ~ConcreteScopedMessageBoxImpl() override + { + cancelPendingUpdate(); + } + + void close() override + { + cancelPendingUpdate(); + nativeImplementation->close(); + self.reset(); + } + +private: + static std::shared_ptr runAsync (std::unique_ptr&& p, + std::unique_ptr&& c) + { + std::shared_ptr result (new ConcreteScopedMessageBoxImpl (std::move (p), std::move (c))); + result->self = result; + result->triggerAsyncUpdate(); + return result; + } + + static int runSync (std::unique_ptr&& p) + { + auto local = std::move (p); + return local != nullptr ? local->runSync() : 0; + } + + explicit ConcreteScopedMessageBoxImpl (std::unique_ptr&& p) + : ConcreteScopedMessageBoxImpl (std::move (p), nullptr) {} + + ConcreteScopedMessageBoxImpl (std::unique_ptr&& p, + std::unique_ptr&& c) + : callback (std::move (c)), nativeImplementation (std::move (p)) {} + + void handleAsyncUpdate() override + { + nativeImplementation->runAsync ([weakRecipient = std::weak_ptr (self)] (int result) + { + const auto notifyRecipient = [result, weakRecipient] + { + if (const auto locked = weakRecipient.lock()) + { + if (auto* cb = locked->callback.get()) + cb->modalStateFinished (result); + + locked->self.reset(); + } + }; + + if (MessageManager::getInstance()->isThisTheMessageThread()) + notifyRecipient(); + else + MessageManager::callAsync (notifyRecipient); + }); + } + + std::unique_ptr callback; + std::unique_ptr nativeImplementation; + + /* The 'old' native message box API doesn't have a concept of message box owners. + Instead, message boxes have to clean up after themselves, once they're done displaying. + To allow this mode of usage, the implementation keeps an owning reference to itself, + which is cleared once the message box is closed or asked to quit. To display a native + message box without a scoped lifetime, just create a Pimpl instance without using + the ScopedMessageBox wrapper, and the Pimpl will destroy itself after it is dismissed. + */ + std::shared_ptr self; +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h b/modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h new file mode 100644 index 000000000000..c7c1981cba41 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ScopedMessageBoxInterface.h @@ -0,0 +1,60 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +/* + Instances of this type can show and dismiss a message box. + + This is an interface rather than a concrete type so that platforms can pick an implementation at + runtime if necessary. +*/ +struct ScopedMessageBoxInterface +{ + virtual ~ScopedMessageBoxInterface() = default; + + /* Shows the message box. + + When the message box exits normally, it should send the result to the passed-in function. + The passed-in function is safe to call from any thread at any time. + */ + virtual void runAsync (std::function) = 0; + + /* Shows the message box and blocks. */ + virtual int runSync() = 0; + + /* Forcefully closes the message box. + + This will be called when the message box handle has fallen out of scope. + If the message box has already been closed by the user, this shouldn't do anything. + */ + virtual void close() = 0; + + /* Implemented differently for each platform. */ + static std::unique_ptr create (const MessageBoxOptions& options); +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h b/modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h new file mode 100644 index 000000000000..cbeb2bd74904 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ToolbarItemDragAndDropOverlayComponent.h @@ -0,0 +1,118 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +class ToolbarItemDragAndDropOverlayComponent : public Component +{ +public: + ToolbarItemDragAndDropOverlayComponent() + : isDragging (false) + { + setAlwaysOnTop (true); + setRepaintsOnMouseActivity (true); + setMouseCursor (MouseCursor::DraggingHandCursor); + } + + void paint (Graphics& g) override + { + if (ToolbarItemComponent* const tc = getToolbarItemComponent()) + { + if (isMouseOverOrDragging() + && tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar) + { + g.setColour (findColour (Toolbar::editingModeOutlineColourId, true)); + g.drawRect (getLocalBounds(), jmin (2, (getWidth() - 1) / 2, + (getHeight() - 1) / 2)); + } + } + } + + void mouseDown (const MouseEvent& e) override + { + isDragging = false; + + if (ToolbarItemComponent* const tc = getToolbarItemComponent()) + { + tc->dragOffsetX = e.x; + tc->dragOffsetY = e.y; + } + } + + void mouseDrag (const MouseEvent& e) override + { + if (e.mouseWasDraggedSinceMouseDown() && ! isDragging) + { + isDragging = true; + + if (DragAndDropContainer* const dnd = DragAndDropContainer::findParentDragContainerFor (this)) + { + dnd->startDragging (Toolbar::toolbarDragDescriptor, getParentComponent(), ScaledImage(), true, nullptr, &e.source); + + if (ToolbarItemComponent* const tc = getToolbarItemComponent()) + { + tc->isBeingDragged = true; + + if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar) + tc->setVisible (false); + } + } + } + } + + void mouseUp (const MouseEvent&) override + { + isDragging = false; + + if (ToolbarItemComponent* const tc = getToolbarItemComponent()) + { + tc->isBeingDragged = false; + + if (Toolbar* const tb = tc->getToolbar()) + tb->updateAllItemPositions (true); + else if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar) + delete tc; + } + } + + void parentSizeChanged() override + { + setBounds (0, 0, getParentWidth(), getParentHeight()); + } + +private: + //============================================================================== + bool isDragging; + + ToolbarItemComponent* getToolbarItemComponent() const noexcept + { + return dynamic_cast (getParentComponent()); + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarItemDragAndDropOverlayComponent) +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h b/modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h new file mode 100644 index 000000000000..797c696e788e --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_TopLevelWindowManager.h @@ -0,0 +1,136 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +/** Keeps track of the active top level window. */ +class TopLevelWindowManager : private Timer, + private DeletedAtShutdown +{ +public: + TopLevelWindowManager() = default; + + ~TopLevelWindowManager() override + { + clearSingletonInstance(); + } + + JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (TopLevelWindowManager) + + static void checkCurrentlyFocusedTopLevelWindow() + { + if (auto* wm = TopLevelWindowManager::getInstanceWithoutCreating()) + wm->checkFocusAsync(); + } + + void checkFocusAsync() + { + startTimer (10); + } + + void checkFocus() + { + startTimer (jmin (1731, getTimerInterval() * 2)); + + auto* newActive = findCurrentlyActiveWindow(); + + if (newActive != currentActive) + { + currentActive = newActive; + + for (int i = windows.size(); --i >= 0;) + if (auto* tlw = windows[i]) + tlw->setWindowActive (isWindowActive (tlw)); + + Desktop::getInstance().triggerFocusCallback(); + } + } + + bool addWindow (TopLevelWindow* const w) + { + windows.add (w); + checkFocusAsync(); + + return isWindowActive (w); + } + + void removeWindow (TopLevelWindow* const w) + { + checkFocusAsync(); + + if (currentActive == w) + currentActive = nullptr; + + windows.removeFirstMatchingValue (w); + + if (windows.isEmpty()) + deleteInstance(); + } + + Array windows; + +private: + TopLevelWindow* currentActive = nullptr; + + void timerCallback() override + { + checkFocus(); + } + + bool isWindowActive (TopLevelWindow* const tlw) const + { + return (tlw == currentActive + || tlw->isParentOf (currentActive) + || tlw->hasKeyboardFocus (true)) + && tlw->isShowing(); + } + + TopLevelWindow* findCurrentlyActiveWindow() const + { + if (Process::isForegroundProcess()) + { + auto* focusedComp = Component::getCurrentlyFocusedComponent(); + auto* w = dynamic_cast (focusedComp); + + if (w == nullptr && focusedComp != nullptr) + w = focusedComp->findParentComponentOfClass(); + + if (w == nullptr) + w = currentActive; + + if (w != nullptr && w->isShowing()) + return w; + } + + return nullptr; + } + + JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager) +}; + +JUCE_IMPLEMENT_SINGLETON (TopLevelWindowManager) + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_ViewportHelpers.h b/modules/juce_gui_basics/detail/juce_ViewportHelpers.h new file mode 100644 index 000000000000..2e9ab9197d34 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_ViewportHelpers.h @@ -0,0 +1,49 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct ViewportHelpers +{ + ViewportHelpers() = delete; + + static bool wouldScrollOnEvent (const Viewport* vp, const MouseInputSource& src) + { + if (vp != nullptr) + { + switch (vp->getScrollOnDragMode()) + { + case Viewport::ScrollOnDragMode::all: return true; + case Viewport::ScrollOnDragMode::nonHover: return ! src.canHover(); + case Viewport::ScrollOnDragMode::never: return false; + } + } + + return false; + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/detail/juce_WindowingHelpers.h b/modules/juce_gui_basics/detail/juce_WindowingHelpers.h new file mode 100644 index 000000000000..1947392d2e65 --- /dev/null +++ b/modules/juce_gui_basics/detail/juce_WindowingHelpers.h @@ -0,0 +1,52 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce::detail +{ + +struct WindowingHelpers +{ + WindowingHelpers() = delete; + + static Image createIconForFile (const File& file); + + #if JUCE_WINDOWS + static bool isEmbeddedInForegroundProcess (Component* c); + static bool isWindowOnCurrentVirtualDesktop (void*); + #else + static bool isEmbeddedInForegroundProcess (Component*) { return false; } + static bool isWindowOnCurrentVirtualDesktop (void*) { return true; } + #endif + + /* Returns true if this process is in the foreground, or if the viewComponent + is embedded into a window owned by the foreground process. + */ + static bool isForegroundOrEmbeddedProcess (Component* viewComponent) + { + return Process::isForegroundProcess() || isEmbeddedInForegroundProcess (viewComponent); + } +}; + +} // namespace juce::detail diff --git a/modules/juce_gui_basics/drawables/juce_DrawableImage.h b/modules/juce_gui_basics/drawables/juce_DrawableImage.h index 6e1bb162a8e1..f56a2d4df5d9 100644 --- a/modules/juce_gui_basics/drawables/juce_DrawableImage.h +++ b/modules/juce_gui_basics/drawables/juce_DrawableImage.h @@ -97,10 +97,11 @@ class JUCE_API DrawableImage : public Drawable Rectangle getDrawableBounds() const override; /** @internal */ Path getOutlineAsPath() const override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: //============================================================================== - std::unique_ptr createAccessibilityHandler() override; bool setImageInternal (const Image&); //============================================================================== diff --git a/modules/juce_gui_basics/drawables/juce_DrawableText.cpp b/modules/juce_gui_basics/drawables/juce_DrawableText.cpp index 361aad61e82f..9bf865aec7d0 100644 --- a/modules/juce_gui_basics/drawables/juce_DrawableText.cpp +++ b/modules/juce_gui_basics/drawables/juce_DrawableText.cpp @@ -108,7 +108,7 @@ void DrawableText::setBoundingBox (Parallelogram newBounds) void DrawableText::setFontHeight (float newHeight) { - if (fontHeight != newHeight) + if (! approximatelyEqual (fontHeight, newHeight)) { fontHeight = newHeight; refreshBounds(); @@ -117,7 +117,7 @@ void DrawableText::setFontHeight (float newHeight) void DrawableText::setFontHorizontalScale (float newScale) { - if (fontHScale != newScale) + if (! approximatelyEqual (fontHScale, newScale)) { fontHScale = newScale; refreshBounds(); diff --git a/modules/juce_gui_basics/drawables/juce_DrawableText.h b/modules/juce_gui_basics/drawables/juce_DrawableText.h index 76ba450d4c78..61c0680c9bfe 100644 --- a/modules/juce_gui_basics/drawables/juce_DrawableText.h +++ b/modules/juce_gui_basics/drawables/juce_DrawableText.h @@ -98,6 +98,8 @@ class JUCE_API DrawableText : public Drawable Path getOutlineAsPath() const override; /** @internal */ bool replaceColour (Colour originalColour, Colour replacementColour) override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: //============================================================================== @@ -108,7 +110,6 @@ class JUCE_API DrawableText : public Drawable Colour colour; Justification justification; - std::unique_ptr createAccessibilityHandler() override; void refreshBounds(); Rectangle getTextArea (float width, float height) const; AffineTransform getTextTransform (float width, float height) const; diff --git a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp index c96a86227a15..756e23291999 100644 --- a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp +++ b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp @@ -189,8 +189,8 @@ class SVGState } else { - if (viewBoxW == 0.0f) newState.viewBoxW = newState.width; - if (viewBoxH == 0.0f) newState.viewBoxH = newState.height; + if (approximatelyEqual (viewBoxW, 0.0f)) newState.viewBoxW = newState.width; + if (approximatelyEqual (viewBoxH, 0.0f)) newState.viewBoxH = newState.height; } newState.parseSubElements (xml, *drawable); diff --git a/modules/juce_gui_basics/filebrowser/juce_ContentSharer.cpp b/modules/juce_gui_basics/filebrowser/juce_ContentSharer.cpp index eb1c7514d27a..25136a263ed5 100644 --- a/modules/juce_gui_basics/filebrowser/juce_ContentSharer.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_ContentSharer.cpp @@ -26,247 +26,49 @@ namespace juce { -#if JUCE_CONTENT_SHARING -//============================================================================== -class ContentSharer::PrepareImagesThread : private Thread +ScopedMessageBox ContentSharer::shareFilesScoped (const Array& files, + Callback callback, + Component* parent) { -public: - PrepareImagesThread (ContentSharer& cs, const Array& imagesToUse, - ImageFileFormat* imageFileFormatToUse) - : Thread ("ContentSharer::PrepareImagesThread"), - owner (cs), - images (imagesToUse), - imageFileFormat (imageFileFormatToUse == nullptr ? new PNGImageFormat() - : imageFileFormatToUse), - extension (imageFileFormat->getFormatName().toLowerCase()) - { - startThread(); - } - - ~PrepareImagesThread() override - { - signalThreadShouldExit(); - waitForThreadToExit (10000); - } - -private: - void run() override - { - for (const auto& image : images) - { - if (threadShouldExit()) - return; - - File tempFile = File::createTempFile (extension); - - if (! tempFile.create().wasOk()) - break; - - std::unique_ptr outputStream (tempFile.createOutputStream()); - - if (outputStream == nullptr) - break; - - if (imageFileFormat->writeImageToStream (image, *outputStream)) - owner.temporaryFiles.add (tempFile); - } - - finish(); - } - - void finish() - { - MessageManager::callAsync ([this]() { owner.filesToSharePrepared(); }); - } - - ContentSharer& owner; - const Array images; - std::unique_ptr imageFileFormat; - String extension; -}; - -//============================================================================== -class ContentSharer::PrepareDataThread : private Thread -{ -public: - PrepareDataThread (ContentSharer& cs, const MemoryBlock& mb) - : Thread ("ContentSharer::PrepareDataThread"), - owner (cs), - data (mb) - { - startThread(); - } - - ~PrepareDataThread() override - { - signalThreadShouldExit(); - waitForThreadToExit (10000); - } - -private: - void run() override - { - File tempFile = File::createTempFile ("data"); - - if (tempFile.create().wasOk()) - { - if (auto outputStream = std::unique_ptr (tempFile.createOutputStream())) - { - size_t pos = 0; - size_t totalSize = data.getSize(); - - while (pos < totalSize) - { - if (threadShouldExit()) - return; - - size_t numToWrite = std::min ((size_t) 8192, totalSize - pos); - - outputStream->write (data.begin() + pos, numToWrite); - - pos += numToWrite; - } - - owner.temporaryFiles.add (tempFile); - } - } - - finish(); - } - - void finish() - { - MessageManager::callAsync ([this]() { owner.filesToSharePrepared(); }); - } - - ContentSharer& owner; - const MemoryBlock data; -}; -#endif - -//============================================================================== -JUCE_IMPLEMENT_SINGLETON (ContentSharer) - -ContentSharer::ContentSharer() {} -ContentSharer::~ContentSharer() { clearSingletonInstance(); } - -void ContentSharer::shareFiles ([[maybe_unused]] const Array& files, - std::function callbackToUse) -{ - #if JUCE_CONTENT_SHARING - startNewShare (callbackToUse); - pimpl->shareFiles (files); - #else - // Content sharing is not available on this platform! - jassertfalse; - - if (callbackToUse) - callbackToUse (false, "Content sharing is not available on this platform!"); - #endif -} - -#if JUCE_CONTENT_SHARING -void ContentSharer::startNewShare (std::function callbackToUse) -{ - // You should not start another sharing operation before the previous one is finished. - // Forcibly stopping a previous sharing operation is rarely a good idea! - jassert (pimpl == nullptr); - pimpl.reset(); - - prepareDataThread = nullptr; - prepareImagesThread = nullptr; - - deleteTemporaryFiles(); - - // You need to pass a valid callback. - jassert (callbackToUse); - callback = std::move (callbackToUse); - - pimpl.reset (createPimpl()); -} -#endif - -void ContentSharer::shareText ([[maybe_unused]] const String& text, - std::function callbackToUse) -{ - #if JUCE_CONTENT_SHARING - startNewShare (callbackToUse); - pimpl->shareText (text); - #else - // Content sharing is not available on this platform! - jassertfalse; - - if (callbackToUse) - callbackToUse (false, "Content sharing is not available on this platform!"); - #endif + auto impl = detail::ScopedContentSharerInterface::shareFiles (files, parent); + return detail::ConcreteScopedContentSharerImpl::show (std::move (impl), std::move (callback)); } -void ContentSharer::shareImages ([[maybe_unused]] const Array& images, - std::function callbackToUse, - [[maybe_unused]] ImageFileFormat* imageFileFormatToUse) +ScopedMessageBox ContentSharer::shareTextScoped (const String& text, + Callback callback, + Component* parent) { - #if JUCE_CONTENT_SHARING - startNewShare (callbackToUse); - prepareImagesThread.reset (new PrepareImagesThread (*this, images, imageFileFormatToUse)); - #else - // Content sharing is not available on this platform! - jassertfalse; - - if (callbackToUse) - callbackToUse (false, "Content sharing is not available on this platform!"); - #endif + auto impl = detail::ScopedContentSharerInterface::shareText (text, parent); + return detail::ConcreteScopedContentSharerImpl::show (std::move (impl), std::move (callback)); } -#if JUCE_CONTENT_SHARING -void ContentSharer::filesToSharePrepared() +ScopedMessageBox ContentSharer::shareImagesScoped (const Array& images, + std::unique_ptr format, + Callback callback, + Component* parent) { - Array urls; - - for (const auto& tempFile : temporaryFiles) - urls.add (URL (tempFile)); - - prepareImagesThread = nullptr; - prepareDataThread = nullptr; - - pimpl->shareFiles (urls); + auto impl = detail::ScopedContentSharerInterface::shareImages (images, std::move (format), parent); + return detail::ConcreteScopedContentSharerImpl::show (std::move (impl), std::move (callback)); } -#endif -void ContentSharer::shareData ([[maybe_unused]] const MemoryBlock& mb, - std::function callbackToUse) +ScopedMessageBox ContentSharer::shareDataScoped (const MemoryBlock& mb, + Callback callback, + Component* parent) { - #if JUCE_CONTENT_SHARING - startNewShare (callbackToUse); - prepareDataThread.reset (new PrepareDataThread (*this, mb)); - #else - if (callbackToUse) - callbackToUse (false, "Content sharing not available on this platform!"); - #endif + auto impl = detail::ScopedContentSharerInterface::shareData (mb, parent); + return detail::ConcreteScopedContentSharerImpl::show (std::move (impl), std::move (callback)); } -void ContentSharer::sharingFinished (bool succeeded, const String& errorDescription) +#if ! (JUCE_CONTENT_SHARING && (JUCE_IOS || JUCE_ANDROID)) +auto detail::ScopedContentSharerInterface::shareFiles (const Array&, Component*) -> std::unique_ptr { - deleteTemporaryFiles(); - - std::function cb; - std::swap (cb, callback); - - String error (errorDescription); - - #if JUCE_CONTENT_SHARING - pimpl.reset(); - #endif - - if (cb) - cb (succeeded, error); + return std::make_unique(); } -void ContentSharer::deleteTemporaryFiles() +auto detail::ScopedContentSharerInterface::shareText (const String&, Component*) -> std::unique_ptr { - for (auto& f : temporaryFiles) - f.deleteFile(); - - temporaryFiles.clear(); + return std::make_unique(); } +#endif } // namespace juce diff --git a/modules/juce_gui_basics/filebrowser/juce_ContentSharer.h b/modules/juce_gui_basics/filebrowser/juce_ContentSharer.h index 1edc79f31452..fee6b76fd26a 100644 --- a/modules/juce_gui_basics/filebrowser/juce_ContentSharer.h +++ b/modules/juce_gui_basics/filebrowser/juce_ContentSharer.h @@ -23,21 +23,30 @@ ============================================================================== */ -#pragma once - namespace juce { -/** A singleton class responsible for sharing content between apps and devices. +//============================================================================== +/** + Functions that allow sharing content between apps and devices. You can share text, images, files or an arbitrary data block. @tags{GUI} */ -class JUCE_API ContentSharer : public DeletedAtShutdown +class JUCE_API ContentSharer { public: - JUCE_DECLARE_SINGLETON (ContentSharer, false) + ContentSharer() = delete; + + /** A callback of this type is passed when starting a content sharing + session. + + When the session ends, the function will receive a flag indicating + whether the session was successful. In the case of failure, the + errorText argument may hold a string describing the problem. + */ + using Callback = std::function; /** Shares the given files. Each URL should be either a full file path or it should point to a resource within the application bundle. For @@ -50,9 +59,16 @@ class JUCE_API ContentSharer : public DeletedAtShutdown Sadly on Android the returned success flag may be wrong as there is no standard way the sharing targets report if the sharing operation succeeded. Also, the optional error message is always empty on Android. + + @param files the files to share + @param callback a callback that will be called on the main thread + when the sharing session ends + @param parent the component that should be used to host the + sharing view */ - void shareFiles (const Array& files, - std::function callback); + [[nodiscard]] static ScopedMessageBox shareFilesScoped (const Array& files, + Callback callback, + Component* parent = nullptr); /** Shares the given text. @@ -60,9 +76,16 @@ class JUCE_API ContentSharer : public DeletedAtShutdown Sadly on Android the returned success flag may be wrong as there is no standard way the sharing targets report if the sharing operation succeeded. Also, the optional error message is always empty on Android. + + @param text the text to share + @param callback a callback that will be called on the main thread + when the sharing session ends + @param parent the component that should be used to host the + sharing view */ - void shareText (const String& text, - std::function callback); + [[nodiscard]] static ScopedMessageBox shareTextScoped (const String& text, + Callback callback, + Component* parent = nullptr); /** A convenience function to share an image. This is useful when you have images loaded in memory. The images will be written to temporary files first, so if @@ -84,10 +107,20 @@ class JUCE_API ContentSharer : public DeletedAtShutdown Sadly on Android the returned success flag may be wrong as there is no standard way the sharing targets report if the sharing operation succeeded. Also, the optional error message is always empty on Android. + + @param images the images to share + @param format the file format to use when saving the images. + If no format is provided, a sensible default will + be used. + @param callback a callback that will be called on the main thread + when the sharing session ends + @param parent the component that should be used to host the + sharing view */ - void shareImages (const Array& images, - std::function callback, - ImageFileFormat* imageFileFormatToUse = nullptr); + [[nodiscard]] static ScopedMessageBox shareImagesScoped (const Array& images, + std::unique_ptr format, + Callback callback, + Component* parent = nullptr); /** A convenience function to share arbitrary data. The data will be written to a temporary file and then that file will be shared. If you have @@ -97,47 +130,16 @@ class JUCE_API ContentSharer : public DeletedAtShutdown Sadly on Android the returned success flag may be wrong as there is no standard way the sharing targets report if the sharing operation succeeded. Also, the optional error message is always empty on Android. - */ - void shareData (const MemoryBlock& mb, - std::function callback); - -private: - ContentSharer(); - ~ContentSharer(); - - Array temporaryFiles; - std::function callback; - - #if JUCE_CONTENT_SHARING - struct Pimpl - { - virtual ~Pimpl() {} - virtual void shareFiles (const Array& files) = 0; - virtual void shareText (const String& text) = 0; - }; - - std::unique_ptr pimpl; - Pimpl* createPimpl(); - - void startNewShare (std::function); - - class ContentSharerNativeImpl; - friend class ContentSharerNativeImpl; - - class PrepareImagesThread; - friend class PrepareImagesThread; - std::unique_ptr prepareImagesThread; - - class PrepareDataThread; - friend class PrepareDataThread; - std::unique_ptr prepareDataThread; - - void filesToSharePrepared(); - #endif - - void deleteTemporaryFiles(); - void sharingFinished (bool, const String&); + @param mb the data to share + @param callback a callback that will be called on the main thread + when the sharing session ends + @param parent the component that should be used to host the + sharing view + */ + [[nodiscard]] static ScopedMessageBox shareDataScoped (const MemoryBlock& mb, + Callback callback, + Component* parent = nullptr); }; } // namespace juce diff --git a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp index 13e4f9d764b4..d55d3db3223c 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.cpp @@ -371,7 +371,6 @@ void FileBrowserComponent::lookAndFeelChanged() filenameBox.applyColourToAllText (findColour (filenameBoxTextColourId)); resized(); - repaint(); } //============================================================================== @@ -605,7 +604,7 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa void FileBrowserComponent::timerCallback() { - const auto isProcessActive = isForegroundOrEmbeddedProcess (this); + const auto isProcessActive = detail::WindowingHelpers::isForegroundOrEmbeddedProcess (this); if (wasProcessActive != isProcessActive) { diff --git a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h index e70857bc08c1..dc4409a75003 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h @@ -252,6 +252,8 @@ class JUCE_API FileBrowserComponent : public Component, FilePreviewComponent* getPreviewComponent() const noexcept; /** @internal */ DirectoryContentsDisplayComponent* getDisplayComponent() const noexcept; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; protected: /** Returns a list of names and paths for the default places the user might want to look. @@ -283,7 +285,6 @@ class JUCE_API FileBrowserComponent : public Component, TimeSliceThread thread; bool wasProcessActive; - std::unique_ptr createAccessibilityHandler() override; void timerCallback() override; void sendListenerChangeMessage(); bool isFileOrDirSuitable (const File&) const; diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp b/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp index a85f57ee1686..00b111f09336 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp @@ -165,7 +165,7 @@ bool FileChooser::browseForDirectory() bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp) { - FocusRestorer focusRestorer; + detail::FocusRestorer focusRestorer; pimpl = createPimpl (flags, previewComp); pimpl->runModally(); diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp index 814c73ad3a98..8ec77d0b8501 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.cpp @@ -115,7 +115,7 @@ FileChooserDialogBox::FileChooserDialogBox (const String& name, if (parentComp != nullptr) parentComp->addAndMakeVisible (this); else - setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows()); + setAlwaysOnTop (WindowUtils::areThereAnyAlwaysOnTopWindows()); } FileChooserDialogBox::~FileChooserDialogBox() @@ -182,28 +182,26 @@ void FileChooserDialogBox::fileDoubleClicked (const File&) void FileChooserDialogBox::fileClicked (const File&, const MouseEvent&) {} void FileChooserDialogBox::browserRootChanged (const File&) {} -void FileChooserDialogBox::okToOverwriteFileCallback (int result, FileChooserDialogBox* box) -{ - if (result != 0 && box != nullptr) - box->exitModalState (1); -} - void FileChooserDialogBox::okButtonPressed() { if (warnAboutOverwritingExistingFiles && content->chooserComponent.isSaveMode() && content->chooserComponent.getSelectedFile(0).exists()) { - AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon, - TRANS("File already exists"), - TRANS("There's already a file called: FLNM") - .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName()) - + "\n\n" - + TRANS("Are you sure you want to overwrite it?"), - TRANS("Overwrite"), - TRANS("Cancel"), - this, - ModalCallbackFunction::forComponent (okToOverwriteFileCallback, this)); + auto options = MessageBoxOptions::makeOptionsOkCancel (MessageBoxIconType::WarningIcon, + TRANS ("File already exists"), + TRANS ("There's already a file called: FLNM") + .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName()) + + "\n\n" + + TRANS ("Are you sure you want to overwrite it?"), + TRANS ("Overwrite"), + TRANS ("Cancel"), + this); + messageBox = AlertWindow::showScopedAsync (options, [this] (int result) + { + if (result != 0) + exitModalState (1); + }); } else { @@ -251,9 +249,12 @@ void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialo auto parent = content->chooserComponent.getRoot(); if (! parent.getChildFile (name).createDirectory()) - AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon, - TRANS ("New Folder"), - TRANS ("Couldn't create the folder!")); + { + auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon, + TRANS ("New Folder"), + TRANS ("Couldn't create the folder!")); + messageBox = AlertWindow::showScopedAsync (options, nullptr); + } content->chooserComponent.refresh(); } diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h index bf1e147de5ae..972d0e5c6d10 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h @@ -158,9 +158,10 @@ class JUCE_API FileChooserDialogBox : public ResizableWindow, void createNewFolder(); void createNewFolderConfirmed (const String& name); - static void okToOverwriteFileCallback (int result, FileChooserDialogBox*); static void createNewFolderCallback (int result, FileChooserDialogBox*, Component::SafePointer); + ScopedMessageBox messageBox; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileChooserDialogBox) }; diff --git a/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp index 073feb9ed0f7..853ef484c087 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileListComponent.cpp @@ -26,9 +26,6 @@ namespace juce { -Image juce_createIconForFile (const File& file); - - //============================================================================== FileListComponent::FileListComponent (DirectoryContentsList& listToShow) : ListBox ({}, this), @@ -103,6 +100,7 @@ void FileListComponent::changeListenerCallback (ChangeBroadcaster*) //============================================================================== class FileListComponent::ItemComponent : public Component, + public TooltipClient, private TimeSliceClient, private AsyncUpdater { @@ -193,6 +191,11 @@ class FileListComponent::ItemComponent : public Component, repaint(); } + String getTooltip() override + { + return owner.getTooltipForRow (index); + } + private: //============================================================================== FileListComponent& owner; @@ -217,7 +220,7 @@ class FileListComponent::ItemComponent : public Component, if (im.isNull() && ! onlyUpdateIfCached) { - im = juce_createIconForFile (file); + im = detail::WindowingHelpers::createIconForFile (file); if (im.isValid()) ImageCache::addImageToCache (im, hashCode); diff --git a/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp index 65ceb66a3947..1799e7382b76 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.cpp @@ -129,7 +129,7 @@ void FileSearchPathListComponent::paintListBoxItem (int rowNumber, Graphics& g, f.setHorizontalScale (0.9f); g.setFont (f); - g.drawText (path[rowNumber].getFullPathName(), + g.drawText (path.getRawString (rowNumber), 4, 0, width - 6, height, Justification::centredLeft, true); } @@ -145,7 +145,7 @@ void FileSearchPathListComponent::deleteKeyPressed (int row) void FileSearchPathListComponent::returnKeyPressed (int row) { - chooser = std::make_unique (TRANS("Change folder..."), path[row], "*"); + chooser = std::make_unique (TRANS("Change folder..."), path.getRawString (row), "*"); auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories; chooser->launchAsync (chooserFlags, [this, row] (const FileChooser& fc) @@ -258,7 +258,7 @@ void FileSearchPathListComponent::moveSelection (int delta) if (currentRow != newRow) { - auto f = path[currentRow]; + const auto f = File::createFileWithoutCheckingPath (path.getRawString (currentRow)); path.remove (currentRow); path.add (f, newRow); listBox.selectRow (newRow); diff --git a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp index 916193cfd729..3ebc44c6863c 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp @@ -26,45 +26,83 @@ namespace juce { +template +int threeWayCompare (const T& a, const T& b) +{ + if (a < b) return -1; + if (b < a) return 1; + return 0; +} + +int threeWayCompare (const String& a, const String& b); +int threeWayCompare (const String& a, const String& b) +{ + return a.compare (b); +} + +struct ReverseCompareString +{ + String value; +}; + +int threeWayCompare (const ReverseCompareString& a, const ReverseCompareString& b); +int threeWayCompare (const ReverseCompareString& a, const ReverseCompareString& b) +{ + return b.value.compare (a.value); +} + +template +constexpr int threeWayCompareImpl (const std::tuple& a, const std::tuple& b) +{ + if constexpr (position == sizeof... (Ts)) + { + ignoreUnused (a, b); + return 0; + } + else + { + const auto head = threeWayCompare (std::get (a), std::get (b)); + + if (head != 0) + return head; + + return threeWayCompareImpl (a, b); + } +} + +template +constexpr int threeWayCompare (const std::tuple& a, const std::tuple& b) +{ + return threeWayCompareImpl<0> (a, b); +} + //============================================================================== class FileListTreeItem : public TreeViewItem, private TimeSliceClient, - private AsyncUpdater, - private ChangeListener + private AsyncUpdater { public: FileListTreeItem (FileTreeComponent& treeComp, - DirectoryContentsList* parentContents, - int indexInContents, const File& f, TimeSliceThread& t) : file (f), owner (treeComp), - parentContentsList (parentContents), - indexInContentsList (indexInContents), - subContentsList (nullptr, false), thread (t) { - DirectoryContentsList::FileInfo fileInfo; + } - if (parentContents != nullptr - && parentContents->getFileInfo (indexInContents, fileInfo)) - { - fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize); - modTime = fileInfo.modificationTime.formatted ("%d %b '%y %H:%M"); - isDirectory = fileInfo.isDirectory; - } - else - { - isDirectory = true; - } + void update (const DirectoryContentsList::FileInfo& fileInfo) + { + fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize); + modTime = fileInfo.modificationTime.formatted ("%d %b '%y %H:%M"); + isDirectory = fileInfo.isDirectory; + repaintItem(); } ~FileListTreeItem() override { thread.removeTimeSliceClient (this); clearSubItems(); - removeSubContentsList(); } //============================================================================== @@ -76,88 +114,7 @@ class FileListTreeItem : public TreeViewItem, void itemOpennessChanged (bool isNowOpen) override { - if (isNowOpen) - { - clearSubItems(); - - isDirectory = file.isDirectory(); - - if (isDirectory) - { - if (subContentsList == nullptr && parentContentsList != nullptr) - { - auto l = new DirectoryContentsList (parentContentsList->getFilter(), thread); - - l->setDirectory (file, - parentContentsList->isFindingDirectories(), - parentContentsList->isFindingFiles()); - - setSubContentsList (l, true); - } - - changeListenerCallback (nullptr); - } - } - } - - void removeSubContentsList() - { - if (subContentsList != nullptr) - { - subContentsList->removeChangeListener (this); - subContentsList.reset(); - } - } - - void setSubContentsList (DirectoryContentsList* newList, const bool canDeleteList) - { - removeSubContentsList(); - - subContentsList = OptionalScopedPointer (newList, canDeleteList); - newList->addChangeListener (this); - } - - void selectFile (const File& target) - { - if (file == target) - { - setSelected (true, true); - return; - } - - if (subContentsList != nullptr && subContentsList->isStillLoading()) - { - pendingFileSelection.emplace (*this, target); - return; - } - - pendingFileSelection.reset(); - - if (! target.isAChildOf (file)) - return; - - setOpen (true); - - for (int i = 0; i < getNumSubItems(); ++i) - if (auto* f = dynamic_cast (getSubItem (i))) - f->selectFile (target); - } - - void changeListenerCallback (ChangeBroadcaster*) override - { - rebuildItemsFromContentList(); - } - - void rebuildItemsFromContentList() - { - clearSubItems(); - - if (isOpen() && subContentsList != nullptr) - { - for (int i = 0; i < subContentsList->getNumFiles(); ++i) - addSubItem (new FileListTreeItem (owner, subContentsList, i, - subContentsList->getFile(i), thread)); - } + NullCheckedInvocation::invoke (onOpennessChanged, file, isNowOpen); } void paintItem (Graphics& g, int width, int height) override @@ -176,7 +133,7 @@ class FileListTreeItem : public TreeViewItem, file, file.getFileName(), &icon, fileSize, modTime, isDirectory, isSelected(), - indexInContentsList, owner); + getIndexInParent(), owner); } String getAccessibilityName() override @@ -213,40 +170,11 @@ class FileListTreeItem : public TreeViewItem, } const File file; + std::function onOpennessChanged; private: - class PendingFileSelection : private Timer - { - public: - PendingFileSelection (FileListTreeItem& item, const File& f) - : owner (item), fileToSelect (f) - { - startTimer (10); - } - - ~PendingFileSelection() override - { - stopTimer(); - } - - private: - void timerCallback() override - { - // Take a copy of the file here, in case this PendingFileSelection - // object is destroyed during the call to selectFile. - owner.selectFile (File { fileToSelect }); - } - - FileListTreeItem& owner; - File fileToSelect; - }; - - Optional pendingFileSelection; FileTreeComponent& owner; - DirectoryContentsList* parentContentsList; - int indexInContentsList; - OptionalScopedPointer subContentsList; - bool isDirectory; + bool isDirectory = false; TimeSliceThread& thread; CriticalSection iconUpdate; Image icon; @@ -261,7 +189,7 @@ class FileListTreeItem : public TreeViewItem, if (im.isNull() && ! onlyUpdateIfCached) { - im = juce_createIconForFile (file); + im = detail::WindowingHelpers::createIconForFile (file); if (im.isValid()) ImageCache::addImageToCache (im, hashCode); @@ -282,11 +210,349 @@ class FileListTreeItem : public TreeViewItem, JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileListTreeItem) }; +class DirectoryScanner : private ChangeListener +{ +public: + struct Listener + { + virtual ~Listener() = default; + + virtual void rootChanged() = 0; + virtual void directoryChanged (const DirectoryContentsList&) = 0; + }; + + DirectoryScanner (DirectoryContentsList& rootIn, Listener& listenerIn) + : root (rootIn), listener (listenerIn) + { + root.addChangeListener (this); + } + + ~DirectoryScanner() override + { + root.removeChangeListener (this); + } + + void refresh() + { + root.refresh(); + } + + void open (const File& f) + { + auto& contentsList = [&]() -> auto& + { + if (auto it = contentsLists.find (f); it != contentsLists.end()) + return it->second; + + auto insertion = contentsLists.emplace (std::piecewise_construct, + std::forward_as_tuple (f), + std::forward_as_tuple (root.getFilter(), + root.getTimeSliceThread())); + return insertion.first->second; + }(); + + contentsList.addChangeListener (this); + contentsList.setDirectory (f, true, true); + contentsList.refresh(); + } + + void close (const File& f) + { + if (auto it = contentsLists.find (f); it != contentsLists.end()) + contentsLists.erase (it); + } + + File getRootDirectory() const + { + return root.getDirectory(); + } + + bool isStillLoading() const + { + return std::any_of (contentsLists.begin(), + contentsLists.end(), + [] (const auto& it) + { + return it.second.isStillLoading(); + }); + } + +private: + void changeListenerCallback (ChangeBroadcaster* source) override + { + auto* sourceList = static_cast (source); + + if (sourceList == &root) + { + if (std::exchange (lastDirectory, root.getDirectory()) != root.getDirectory()) + { + contentsLists.clear(); + listener.rootChanged(); + } + else + { + for (auto& contentsList : contentsLists) + contentsList.second.refresh(); + } + } + + listener.directoryChanged (*sourceList); + } + + DirectoryContentsList& root; + Listener& listener; + File lastDirectory; + std::map contentsLists; +}; + +struct FileEntry +{ + String path; + bool isDirectory; + + int compareWindows (const FileEntry& other) const + { + const auto toTuple = [] (const auto& x) { return std::tuple (! x.isDirectory, x.path.toLowerCase()); }; + return threeWayCompare (toTuple (*this), toTuple (other)); + } + + int compareLinux (const FileEntry& other) const + { + const auto toTuple = [] (const auto& x) { return std::tuple (x.path.toUpperCase(), ReverseCompareString { x.path }); }; + return threeWayCompare (toTuple (*this), toTuple (other)); + } + + int compareDefault (const FileEntry& other) const + { + return threeWayCompare (path.toLowerCase(), other.path.toLowerCase()); + } +}; + +class OSDependentFileComparisonRules +{ +public: + explicit OSDependentFileComparisonRules (SystemStats::OperatingSystemType systemTypeIn) + : systemType (systemTypeIn) + {} + + int compare (const FileEntry& first, const FileEntry& second) const + { + if ((systemType & SystemStats::OperatingSystemType::Windows) != 0) + return first.compareWindows (second); + + if ((systemType & SystemStats::OperatingSystemType::Linux) != 0) + return first.compareLinux (second); + + return first.compareDefault (second); + } + + bool operator() (const FileEntry& first, const FileEntry& second) const + { + return compare (first, second) < 0; + } + +private: + SystemStats::OperatingSystemType systemType; +}; + +class FileTreeComponent::Controller : private DirectoryScanner::Listener +{ +public: + explicit Controller (FileTreeComponent& ownerIn) + : owner (ownerIn), + scanner (owner.directoryContentsList, *this) + { + refresh(); + } + + ~Controller() override + { + owner.deleteRootItem(); + } + + void refresh() + { + scanner.refresh(); + } + + void selectFile (const File& target) + { + pendingFileSelection.emplace (target); + tryResolvePendingFileSelection(); + } + +private: + template + static void forEachItemRecursive (TreeViewItem* item, ItemCallback&& cb) + { + if (item == nullptr) + return; + + if (auto* fileListItem = dynamic_cast (item)) + cb (fileListItem); + + for (int i = 0; i < item->getNumSubItems(); ++i) + forEachItemRecursive (item->getSubItem (i), cb); + } + + //============================================================================== + void rootChanged() override + { + owner.deleteRootItem(); + treeItemForFile.clear(); + owner.setRootItem (createNewItem (scanner.getRootDirectory()).release()); + } + + void directoryChanged (const DirectoryContentsList& contentsList) override + { + auto* parentItem = [&]() -> FileListTreeItem* + { + if (auto it = treeItemForFile.find (contentsList.getDirectory()); it != treeItemForFile.end()) + return it->second; + + return nullptr; + }(); + + if (parentItem == nullptr) + { + jassertfalse; + return; + } + + for (int i = 0; i < contentsList.getNumFiles(); ++i) + { + auto file = contentsList.getFile (i); + + DirectoryContentsList::FileInfo fileInfo; + contentsList.getFileInfo (i, fileInfo); + + auto* item = [&] + { + if (auto it = treeItemForFile.find (file); it != treeItemForFile.end()) + return it->second; + + auto* newItem = createNewItem (file).release(); + parentItem->addSubItem (newItem); + return newItem; + }(); + + if (item->isOpen() && fileInfo.isDirectory) + scanner.open (item->file); + + item->update (fileInfo); + } + + if (contentsList.isStillLoading()) + return; + + std::set allFiles; + + for (int i = 0; i < contentsList.getNumFiles(); ++i) + allFiles.insert (contentsList.getFile (i)); + + for (int i = 0; i < parentItem->getNumSubItems();) + { + auto* fileItem = dynamic_cast (parentItem->getSubItem (i)); + + if (fileItem != nullptr && allFiles.count (fileItem->file) == 0) + { + forEachItemRecursive (parentItem->getSubItem (i), + [this] (auto* item) + { + scanner.close (item->file); + treeItemForFile.erase (item->file); + }); + + parentItem->removeSubItem (i); + } + else + { + ++i; + } + } + + struct Comparator + { + // The different OSes compare and order files in different ways. This function aims + // to match these different rules of comparison to mimic other FileBrowserComponent + // view modes where we don't need to order the results, and can just rely on the + // ordering of the list provided by the OS. + static int compareElements (TreeViewItem* first, TreeViewItem* second) + { + auto* item1 = dynamic_cast (first); + auto* item2 = dynamic_cast (second); + + if (item1 == nullptr || item2 == nullptr) + return 0; + + static const OSDependentFileComparisonRules comparisonRules { SystemStats::getOperatingSystemType() }; + + return comparisonRules.compare ({ item1->file.getFullPathName(), item1->file.isDirectory() }, + { item2->file.getFullPathName(), item2->file.isDirectory() }); + } + }; + + static Comparator comparator; + parentItem->sortSubItems (comparator); + tryResolvePendingFileSelection(); + } + + std::unique_ptr createNewItem (const File& file) + { + auto newItem = std::make_unique (owner, + file, + owner.directoryContentsList.getTimeSliceThread()); + + newItem->onOpennessChanged = [this, itemPtr = newItem.get()] (const auto& f, auto isOpen) + { + if (isOpen) + { + scanner.open (f); + } + else + { + forEachItemRecursive (itemPtr, + [this] (auto* item) + { + scanner.close (item->file); + }); + } + }; + + treeItemForFile[file] = newItem.get(); + return newItem; + } + + void tryResolvePendingFileSelection() + { + if (! pendingFileSelection.has_value()) + return; + + if (auto item = treeItemForFile.find (*pendingFileSelection); item != treeItemForFile.end()) + { + item->second->setSelected (true, true); + pendingFileSelection.reset(); + return; + } + + if (owner.directoryContentsList.isStillLoading() || scanner.isStillLoading()) + return; + + owner.clearSelectedItems(); + } + + FileTreeComponent& owner; + std::map treeItemForFile; + DirectoryScanner scanner; + std::optional pendingFileSelection; +}; + //============================================================================== FileTreeComponent::FileTreeComponent (DirectoryContentsList& listToShow) : DirectoryContentsDisplayComponent (listToShow), itemHeight (22) { + controller = std::make_unique (*this); setRootItemVisible (false); refresh(); } @@ -298,13 +564,7 @@ FileTreeComponent::~FileTreeComponent() void FileTreeComponent::refresh() { - deleteRootItem(); - - auto root = new FileListTreeItem (*this, nullptr, 0, directoryContentsList.getDirectory(), - directoryContentsList.getTimeSliceThread()); - - root->setSubContentsList (&directoryContentsList, false); - setRootItem (root); + controller->refresh(); } //============================================================================== @@ -333,8 +593,7 @@ void FileTreeComponent::setDragAndDropDescription (const String& description) void FileTreeComponent::setSelectedFile (const File& target) { - if (auto* t = dynamic_cast (getRootItem())) - t->selectFile (target); + controller->selectFile (target); } void FileTreeComponent::setItemHeight (int newHeight) @@ -348,4 +607,75 @@ void FileTreeComponent::setItemHeight (int newHeight) } } +#if JUCE_UNIT_TESTS + +class FileTreeComponentTests : public UnitTest +{ +public: + //============================================================================== + FileTreeComponentTests() : UnitTest ("FileTreeComponentTests", UnitTestCategories::gui) {} + + void runTest() override + { + const auto checkOrder = [] (const auto& orderedFiles, const std::vector& expected) + { + return std::equal (orderedFiles.begin(), orderedFiles.end(), + expected.begin(), expected.end(), + [] (const auto& entry, const auto& expectedPath) { return entry.path == expectedPath; }); + }; + + const auto doSort = [] (const auto platform, auto& range) + { + std::sort (range.begin(), range.end(), OSDependentFileComparisonRules { platform }); + }; + + beginTest ("Test Linux filename ordering"); + { + std::vector filesToOrder { { "_test", false }, + { "Atest", false }, + { "atest", false } }; + + doSort (SystemStats::OperatingSystemType::Linux, filesToOrder); + + expect (checkOrder (filesToOrder, { "atest", "Atest", "_test" })); + } + + beginTest ("Test Windows filename ordering"); + { + std::vector filesToOrder { { "cmake_install.cmake", false }, + { "CMakeFiles", true }, + { "JUCEConfig.cmake", false }, + { "tools", true }, + { "cmakefiles.cmake", false } }; + + doSort (SystemStats::OperatingSystemType::Windows, filesToOrder); + + expect (checkOrder (filesToOrder, { "CMakeFiles", + "tools", + "cmake_install.cmake", + "cmakefiles.cmake", + "JUCEConfig.cmake" })); + } + + beginTest ("Test MacOS filename ordering"); + { + std::vector filesToOrder { { "cmake_install.cmake", false }, + { "CMakeFiles", true }, + { "tools", true }, + { "JUCEConfig.cmake", false } }; + + doSort (SystemStats::OperatingSystemType::MacOSX, filesToOrder); + + expect (checkOrder (filesToOrder, { "cmake_install.cmake", + "CMakeFiles", + "JUCEConfig.cmake", + "tools" })); + } + } +}; + +static FileTreeComponentTests fileTreeComponentTests; + +#endif + } // namespace juce diff --git a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.h b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.h index b021bc758293..192ce88f684c 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.h @@ -99,6 +99,9 @@ class JUCE_API FileTreeComponent : public TreeView, String dragAndDropDescription; int itemHeight; + class Controller; + std::unique_ptr controller; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileTreeComponent) }; diff --git a/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h b/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h index 2c354a73ebb3..874fb54f130c 100644 --- a/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h +++ b/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h @@ -52,13 +52,14 @@ class JUCE_API ImagePreviewComponent : public FilePreviewComponent, void paint (Graphics&) override; /** @internal */ void timerCallback() override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: File fileToLoad; Image currentThumbnail; String currentDetails; - std::unique_ptr createAccessibilityHandler() override; void getThumbSize (int& w, int& h) const; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePreviewComponent) diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index daa711279fa0..380fe88cad1c 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -107,70 +107,123 @@ #endif //============================================================================== -#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \ - jassert ((MessageManager::getInstanceWithoutCreating() != nullptr \ - && MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager()) \ - || getPeer() == nullptr); +#include "detail/juce_AccessibilityHelpers.h" +#include "detail/juce_ButtonAccessibilityHandler.h" +#include "detail/juce_ScalingHelpers.h" +#include "detail/juce_ComponentHelpers.h" +#include "detail/juce_FocusHelpers.h" +#include "detail/juce_FocusRestorer.h" +#include "detail/juce_ViewportHelpers.h" +#include "detail/juce_LookAndFeelHelpers.h" +#include "detail/juce_PointerState.h" +#include "detail/juce_CustomMouseCursorInfo.h" +#include "detail/juce_MouseInputSourceImpl.h" +#include "detail/juce_MouseInputSourceList.h" +#include "detail/juce_ToolbarItemDragAndDropOverlayComponent.h" +#include "detail/juce_ScopedMessageBoxInterface.h" +#include "detail/juce_ScopedMessageBoxImpl.h" +#include "detail/juce_ScopedContentSharerInterface.h" +#include "detail/juce_ScopedContentSharerImpl.h" +#include "detail/juce_WindowingHelpers.h" +#include "detail/juce_AlertWindowHelpers.h" +#include "detail/juce_TopLevelWindowManager.h" -namespace juce -{ - bool juce_areThereAnyAlwaysOnTopWindows(); +//============================================================================== +#if JUCE_IOS || JUCE_WINDOWS + #include "native/juce_MultiTouchMapper.h" +#endif + +#if JUCE_ANDROID || JUCE_WINDOWS || JUCE_IOS || JUCE_UNIT_TESTS + #include "native/accessibility/juce_AccessibilityTextHelpers.h" +#endif + +#if JUCE_MAC || JUCE_IOS + #include "native/accessibility/juce_AccessibilitySharedCode_mac.mm" + + #if JUCE_IOS + #include "native/juce_UIViewComponentPeer_ios.mm" + #include "native/accessibility/juce_Accessibility_ios.mm" + #include "native/juce_WindowUtils_ios.mm" + #include "native/juce_Windowing_ios.mm" + #include "native/juce_NativeMessageBox_ios.mm" + #include "native/juce_NativeModalWrapperComponent_ios.h" + #include "native/juce_FileChooser_ios.mm" + + #if JUCE_CONTENT_SHARING + #include "native/juce_ContentSharer_ios.cpp" + #endif + + #else + #include "native/accessibility/juce_Accessibility_mac.mm" + #include "native/juce_PerScreenDisplayLinks_mac.h" + #include "native/juce_NSViewComponentPeer_mac.mm" + #include "native/juce_WindowUtils_mac.mm" + #include "native/juce_Windowing_mac.mm" + #include "native/juce_NativeMessageBox_mac.mm" + #include "native/juce_MainMenu_mac.mm" + #include "native/juce_FileChooser_mac.mm" + #endif + + #include "native/juce_MouseCursor_mac.mm" + +#elif JUCE_WINDOWS + #include "native/accessibility/juce_ComInterfaces_windows.h" + #include "native/accessibility/juce_WindowsUIAWrapper_windows.h" + #include "native/accessibility/juce_AccessibilityElement_windows.h" + #include "native/accessibility/juce_UIAHelpers_windows.h" + #include "native/accessibility/juce_UIAProviders_windows.h" + #include "native/accessibility/juce_AccessibilityElement_windows.cpp" + #include "native/accessibility/juce_Accessibility_windows.cpp" + #include "native/juce_WindowsHooks_windows.h" + #include "native/juce_WindowUtils_windows.cpp" + #include "native/juce_Windowing_windows.cpp" + #include "native/juce_WindowsHooks_windows.cpp" + #include "native/juce_NativeMessageBox_windows.cpp" + #include "native/juce_DragAndDrop_windows.cpp" + #include "native/juce_FileChooser_windows.cpp" + +#elif JUCE_LINUX || JUCE_BSD + #include "native/juce_XSymbols_linux.cpp" + #include "native/juce_DragAndDrop_linux.cpp" - bool isEmbeddedInForegroundProcess (Component* c); + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant") - #if ! JUCE_WINDOWS - bool isEmbeddedInForegroundProcess (Component*) { return false; } - #endif + #include "native/juce_ScopedWindowAssociation_linux.h" + #include "native/juce_WindowUtils_linux.cpp" + #include "native/juce_Windowing_linux.cpp" + #include "native/juce_NativeMessageBox_linux.cpp" + #include "native/juce_XWindowSystem_linux.cpp" - /* Returns true if this process is in the foreground, or if the viewComponent - is embedded into a window owned by the foreground process. - */ - static bool isForegroundOrEmbeddedProcess (Component* viewComponent) - { - return Process::isForegroundProcess() || isEmbeddedInForegroundProcess (viewComponent); - } + JUCE_END_IGNORE_WARNINGS_GCC_LIKE - bool isWindowOnCurrentVirtualDesktop (void*); + #include "native/juce_FileChooser_linux.cpp" - struct CustomMouseCursorInfo - { - ScaledImage image; - Point hotspot; - }; +#elif JUCE_ANDROID - template - static const AccessibilityHandler* getEnclosingHandlerWithInterface (const AccessibilityHandler* handler, MemberFn fn) - { - if (handler == nullptr) - return nullptr; + #include "juce_core/files/juce_common_MimeTypes.h" + #include "native/accessibility/juce_Accessibility_android.cpp" + #include "native/juce_WindowUtils_android.cpp" + #include "native/juce_Windowing_android.cpp" + #include "native/juce_NativeMessageBox_android.cpp" + #include "native/juce_FileChooser_android.cpp" - if ((handler->*fn)() != nullptr) - return handler; + #if JUCE_CONTENT_SHARING + #include "native/juce_ContentSharer_android.cpp" + #endif + +#endif - return getEnclosingHandlerWithInterface (handler->getParent(), fn); - } -} // namespace juce +//============================================================================== +// Depends on types defined in platform-specific windowing files +#include "mouse/juce_MouseCursor.cpp" -#include "mouse/juce_PointerState.h" +#if JUCE_UNIT_TESTS + #include "native/accessibility/juce_AccessibilityTextHelpers_test.cpp" +#endif +//============================================================================== #include "accessibility/juce_AccessibilityHandler.cpp" -#include "components/juce_Component.cpp" -#include "components/juce_ComponentListener.cpp" -#include "components/juce_FocusTraverser.cpp" -#include "mouse/juce_MouseInputSource.cpp" -#include "desktop/juce_Displays.cpp" -#include "desktop/juce_Desktop.cpp" -#include "components/juce_ModalComponentManager.cpp" -#include "mouse/juce_ComponentDragger.cpp" -#include "mouse/juce_DragAndDropContainer.cpp" -#include "mouse/juce_MouseEvent.cpp" -#include "mouse/juce_MouseInactivityDetector.cpp" -#include "mouse/juce_MouseListener.cpp" -#include "keyboard/juce_CaretComponent.cpp" -#include "keyboard/juce_KeyboardFocusTraverser.cpp" -#include "keyboard/juce_KeyListener.cpp" -#include "keyboard/juce_KeyPress.cpp" -#include "keyboard/juce_ModifierKeys.cpp" +#include "application/juce_Application.cpp" #include "buttons/juce_ArrowButton.cpp" #include "buttons/juce_Button.cpp" #include "buttons/juce_DrawableButton.cpp" @@ -180,6 +233,17 @@ namespace juce #include "buttons/juce_TextButton.cpp" #include "buttons/juce_ToggleButton.cpp" #include "buttons/juce_ToolbarButton.cpp" +#include "commands/juce_ApplicationCommandInfo.cpp" +#include "commands/juce_ApplicationCommandManager.cpp" +#include "commands/juce_ApplicationCommandTarget.cpp" +#include "commands/juce_KeyPressMappingSet.cpp" +#include "components/juce_Component.cpp" +#include "components/juce_ComponentListener.cpp" +#include "components/juce_FocusTraverser.cpp" +#include "components/juce_ModalComponentManager.cpp" +#include "desktop/juce_Desktop.cpp" +#include "desktop/juce_Displays.cpp" +#include "detail/juce_AccessibilityHelpers.cpp" #include "drawables/juce_Drawable.cpp" #include "drawables/juce_DrawableComposite.cpp" #include "drawables/juce_DrawableImage.cpp" @@ -188,22 +252,31 @@ namespace juce #include "drawables/juce_DrawableShape.cpp" #include "drawables/juce_DrawableText.cpp" #include "drawables/juce_SVGParser.cpp" +#include "filebrowser/juce_ContentSharer.cpp" #include "filebrowser/juce_DirectoryContentsDisplayComponent.cpp" #include "filebrowser/juce_DirectoryContentsList.cpp" #include "filebrowser/juce_FileBrowserComponent.cpp" #include "filebrowser/juce_FileChooser.cpp" #include "filebrowser/juce_FileChooserDialogBox.cpp" #include "filebrowser/juce_FileListComponent.cpp" -#include "filebrowser/juce_FilenameComponent.cpp" #include "filebrowser/juce_FileSearchPathListComponent.cpp" #include "filebrowser/juce_FileTreeComponent.cpp" +#include "filebrowser/juce_FilenameComponent.cpp" #include "filebrowser/juce_ImagePreviewComponent.cpp" -#include "filebrowser/juce_ContentSharer.cpp" +#include "keyboard/juce_CaretComponent.cpp" +#include "keyboard/juce_KeyListener.cpp" +#include "keyboard/juce_KeyPress.cpp" +#include "keyboard/juce_KeyboardFocusTraverser.cpp" +#include "keyboard/juce_ModifierKeys.cpp" #include "layout/juce_ComponentAnimator.cpp" #include "layout/juce_ComponentBoundsConstrainer.cpp" +#include "layout/juce_BorderedComponentBoundsConstrainer.cpp" #include "layout/juce_ComponentBuilder.cpp" #include "layout/juce_ComponentMovementWatcher.cpp" #include "layout/juce_ConcertinaPanel.cpp" +#include "layout/juce_FlexBox.cpp" +#include "layout/juce_Grid.cpp" +#include "layout/juce_GridItem.cpp" #include "layout/juce_GroupComponent.cpp" #include "layout/juce_MultiDocumentPanel.cpp" #include "layout/juce_ResizableBorderComponent.cpp" @@ -218,14 +291,26 @@ namespace juce #include "layout/juce_TabbedComponent.cpp" #include "layout/juce_Viewport.cpp" #include "lookandfeel/juce_LookAndFeel.cpp" -#include "lookandfeel/juce_LookAndFeel_V2.cpp" #include "lookandfeel/juce_LookAndFeel_V1.cpp" +#include "lookandfeel/juce_LookAndFeel_V2.cpp" #include "lookandfeel/juce_LookAndFeel_V3.cpp" #include "lookandfeel/juce_LookAndFeel_V4.cpp" -#include "menus/juce_MenuBarComponent.cpp" #include "menus/juce_BurgerMenuComponent.cpp" +#include "menus/juce_MenuBarComponent.cpp" #include "menus/juce_MenuBarModel.cpp" #include "menus/juce_PopupMenu.cpp" +#include "misc/juce_BubbleComponent.cpp" +#include "misc/juce_DropShadower.cpp" +#include "misc/juce_FocusOutline.cpp" +#include "misc/juce_JUCESplashScreen.cpp" +#include "mouse/juce_ComponentDragger.cpp" +#include "mouse/juce_DragAndDropContainer.cpp" +#include "mouse/juce_MouseEvent.cpp" +#include "mouse/juce_MouseInactivityDetector.cpp" +#include "mouse/juce_MouseInputSource.cpp" +#include "mouse/juce_MouseListener.cpp" +#include "native/accessibility/juce_Accessibility.cpp" +#include "native/juce_ScopedDPIAwarenessDisabler.cpp" #include "positioning/juce_MarkerList.cpp" #include "positioning/juce_RelativeCoordinate.cpp" #include "positioning/juce_RelativeCoordinatePositioner.cpp" @@ -236,11 +321,11 @@ namespace juce #include "properties/juce_BooleanPropertyComponent.cpp" #include "properties/juce_ButtonPropertyComponent.cpp" #include "properties/juce_ChoicePropertyComponent.cpp" +#include "properties/juce_MultiChoicePropertyComponent.cpp" #include "properties/juce_PropertyComponent.cpp" #include "properties/juce_PropertyPanel.cpp" #include "properties/juce_SliderPropertyComponent.cpp" #include "properties/juce_TextPropertyComponent.cpp" -#include "properties/juce_MultiChoicePropertyComponent.cpp" #include "widgets/juce_ComboBox.cpp" #include "widgets/juce_ImageComponent.cpp" #include "widgets/juce_Label.cpp" @@ -250,213 +335,20 @@ namespace juce #include "widgets/juce_TableHeaderComponent.cpp" #include "widgets/juce_TableListBox.cpp" #include "widgets/juce_TextEditor.cpp" -#include "widgets/juce_ToolbarItemComponent.cpp" #include "widgets/juce_Toolbar.cpp" +#include "widgets/juce_ToolbarItemComponent.cpp" #include "widgets/juce_ToolbarItemPalette.cpp" #include "widgets/juce_TreeView.cpp" +#include "windows/juce_NativeMessageBox.cpp" #include "windows/juce_AlertWindow.cpp" #include "windows/juce_CallOutBox.cpp" #include "windows/juce_ComponentPeer.cpp" #include "windows/juce_DialogWindow.cpp" #include "windows/juce_DocumentWindow.cpp" +#include "windows/juce_MessageBoxOptions.cpp" #include "windows/juce_ResizableWindow.cpp" +#include "windows/juce_ScopedMessageBox.cpp" #include "windows/juce_ThreadWithProgressWindow.cpp" #include "windows/juce_TooltipWindow.cpp" #include "windows/juce_TopLevelWindow.cpp" -#include "windows/juce_VBlankAttachement.cpp" -#include "commands/juce_ApplicationCommandInfo.cpp" -#include "commands/juce_ApplicationCommandManager.cpp" -#include "commands/juce_ApplicationCommandTarget.cpp" -#include "commands/juce_KeyPressMappingSet.cpp" -#include "application/juce_Application.cpp" -#include "misc/juce_BubbleComponent.cpp" -#include "misc/juce_DropShadower.cpp" -#include "misc/juce_FocusOutline.cpp" -#include "misc/juce_JUCESplashScreen.cpp" - -#include "layout/juce_FlexBox.cpp" -#include "layout/juce_GridItem.cpp" -#include "layout/juce_Grid.cpp" - -#if JUCE_IOS || JUCE_WINDOWS - #include "native/juce_MultiTouchMapper.h" -#endif - -#if JUCE_ANDROID || JUCE_WINDOWS || JUCE_IOS || JUCE_UNIT_TESTS - #include "native/accessibility/juce_AccessibilityTextHelpers.h" -#endif - -#if JUCE_MAC || JUCE_IOS - #include "native/accessibility/juce_mac_AccessibilitySharedCode.mm" - - #if JUCE_IOS - #include "native/juce_ios_UIViewComponentPeer.mm" - #include "native/accessibility/juce_ios_Accessibility.mm" - #include "native/juce_ios_Windowing.mm" - #include "native/juce_ios_FileChooser.mm" - - #if JUCE_CONTENT_SHARING - #include "native/juce_ios_ContentSharer.cpp" - #endif - - #else - #include "native/accessibility/juce_mac_Accessibility.mm" - #include "native/juce_mac_PerScreenDisplayLinks.h" - #include "native/juce_mac_NSViewComponentPeer.mm" - #include "native/juce_mac_Windowing.mm" - #include "native/juce_mac_MainMenu.mm" - #include "native/juce_mac_FileChooser.mm" - #endif - - #include "native/juce_mac_MouseCursor.mm" - -#elif JUCE_WINDOWS - #include "native/accessibility/juce_win32_ComInterfaces.h" - #include "native/accessibility/juce_win32_WindowsUIAWrapper.h" - #include "native/accessibility/juce_win32_AccessibilityElement.h" - #include "native/accessibility/juce_win32_UIAHelpers.h" - #include "native/accessibility/juce_win32_UIAProviders.h" - #include "native/accessibility/juce_win32_AccessibilityElement.cpp" - #include "native/accessibility/juce_win32_Accessibility.cpp" - #include "native/juce_win32_Windowing.cpp" - #include "native/juce_win32_DragAndDrop.cpp" - #include "native/juce_win32_FileChooser.cpp" - -#elif JUCE_LINUX || JUCE_BSD - #include "native/x11/juce_linux_X11_Symbols.cpp" - #include "native/x11/juce_linux_X11_DragAndDrop.cpp" - - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant") - - #include "native/x11/juce_linux_ScopedWindowAssociation.h" - #include "native/juce_linux_Windowing.cpp" - #include "native/x11/juce_linux_XWindowSystem.cpp" - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - #include "native/juce_linux_FileChooser.cpp" - -#elif JUCE_ANDROID - -namespace juce -{ -static jobject makeAndroidRect (Rectangle r) -{ - return getEnv()->NewObject (AndroidRect, - AndroidRect.constructor, - r.getX(), - r.getY(), - r.getRight(), - r.getBottom()); -} - -static jobject makeAndroidPoint (Point p) -{ - return getEnv()->NewObject (AndroidPoint, - AndroidPoint.create, - p.getX(), - p.getY()); -} -} // namespace juce - - #include "juce_core/files/juce_common_MimeTypes.h" - #include "native/accessibility/juce_android_Accessibility.cpp" - #include "native/juce_android_Windowing.cpp" - #include "native/juce_android_FileChooser.cpp" - - #if JUCE_CONTENT_SHARING - #include "native/juce_android_ContentSharer.cpp" - #endif - -#endif - -namespace juce -{ - #if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED - class AccessibilityHandler::AccessibilityNativeImpl { public: AccessibilityNativeImpl (AccessibilityHandler&) {} }; - void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {} - void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {} - AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; } - void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent) {} - std::unique_ptr AccessibilityHandler::createNativeImpl (AccessibilityHandler&) - { - return nullptr; - } - #else - std::unique_ptr AccessibilityHandler::createNativeImpl (AccessibilityHandler& handler) - { - return std::make_unique (handler); - } - #endif -} - -//============================================================================== -#if JUCE_WINDOWS -namespace juce -{ - -JUCE_COMCLASS (JuceIVirtualDesktopManager, "a5cd92ff-29be-454c-8d04-d82879fb3f1b") : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE IsWindowOnCurrentVirtualDesktop( - __RPC__in HWND topLevelWindow, - __RPC__out BOOL * onCurrentDesktop) = 0; - - virtual HRESULT STDMETHODCALLTYPE GetWindowDesktopId( - __RPC__in HWND topLevelWindow, - __RPC__out GUID * desktopId) = 0; - - virtual HRESULT STDMETHODCALLTYPE MoveWindowToDesktop( - __RPC__in HWND topLevelWindow, - __RPC__in REFGUID desktopId) = 0; -}; - -JUCE_COMCLASS (JuceVirtualDesktopManager, "aa509086-5ca9-4c25-8f95-589d3c07b48a"); - -} // namespace juce - -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL (juce::JuceIVirtualDesktopManager, 0xa5cd92ff, 0x29be, 0x454c, 0x8d, 0x04, 0xd8, 0x28, 0x79, 0xfb, 0x3f, 0x1b) -__CRT_UUID_DECL (juce::JuceVirtualDesktopManager, 0xaa509086, 0x5ca9, 0x4c25, 0x8f, 0x95, 0x58, 0x9d, 0x3c, 0x07, 0xb4, 0x8a) -#endif - -bool juce::isWindowOnCurrentVirtualDesktop (void* x) -{ - if (x == nullptr) - return false; - - static auto* desktopManager = [] - { - JuceIVirtualDesktopManager* result = nullptr; - - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token") - - if (SUCCEEDED (CoCreateInstance (__uuidof (JuceVirtualDesktopManager), nullptr, CLSCTX_ALL, IID_PPV_ARGS (&result)))) - return result; - - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - return static_cast (nullptr); - }(); - - BOOL current = false; - - if (auto* dm = desktopManager) - if (SUCCEEDED (dm->IsWindowOnCurrentVirtualDesktop (static_cast (x), ¤t))) - return current != false; - - return true; -} - -#else - bool juce::isWindowOnCurrentVirtualDesktop (void*) { return true; } - juce::ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler() { ignoreUnused (previousContext); } - juce::ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler() {} -#endif - -// Depends on types defined in platform-specific windowing files -#include "mouse/juce_MouseCursor.cpp" - -#if JUCE_UNIT_TESTS -#include "native/accessibility/juce_AccessibilityTextHelpers_test.cpp" -#endif +#include "windows/juce_VBlankAttachment.cpp" diff --git a/modules/juce_gui_basics/juce_gui_basics.h b/modules/juce_gui_basics/juce_gui_basics.h index bd29a18245fb..161c03cd59e4 100644 --- a/modules/juce_gui_basics/juce_gui_basics.h +++ b/modules/juce_gui_basics/juce_gui_basics.h @@ -35,7 +35,7 @@ ID: juce_gui_basics vendor: juce - version: 7.0.5 + version: 7.0.7 name: JUCE GUI core classes description: Basic user-interface components and related classes. website: http://www.juce.com/juce @@ -127,7 +127,6 @@ namespace juce class Component; class LookAndFeel; class MouseInputSource; - class MouseInputSourceInternal; class ComponentPeer; class MouseEvent; struct MouseWheelDetails; @@ -161,16 +160,27 @@ namespace juce class Displays; class AccessibilityHandler; class KeyboardFocusTraverser; - class PointerState; class FlexBox; class Grid; class FocusOutline; - #if JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX + #if JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD Image createSnapshotOfNativeWindow (void* nativeWindowHandle); #endif -} + + namespace detail + { + struct ComponentHelpers; + class MouseInputSourceImpl; + class MouseInputSourceList; + class PointerState; + class ScopedMessageBoxImpl; + class ToolbarItemDragAndDropOverlayComponent; + class TopLevelWindowManager; + } // namespace detail + +} // namespace juce #include "mouse/juce_MouseCursor.h" #include "mouse/juce_MouseListener.h" @@ -189,6 +199,7 @@ namespace juce #include "desktop/juce_Desktop.h" #include "desktop/juce_Displays.h" #include "layout/juce_ComponentBoundsConstrainer.h" +#include "layout/juce_BorderedComponentBoundsConstrainer.h" #include "mouse/juce_ComponentDragger.h" #include "mouse/juce_DragAndDropTarget.h" #include "mouse/juce_DragAndDropContainer.h" @@ -269,6 +280,7 @@ namespace juce #include "widgets/juce_TreeView.h" #include "windows/juce_TopLevelWindow.h" #include "windows/juce_MessageBoxOptions.h" +#include "windows/juce_ScopedMessageBox.h" #include "windows/juce_AlertWindow.h" #include "windows/juce_CallOutBox.h" #include "windows/juce_ComponentPeer.h" @@ -278,7 +290,8 @@ namespace juce #include "windows/juce_NativeMessageBox.h" #include "windows/juce_ThreadWithProgressWindow.h" #include "windows/juce_TooltipWindow.h" -#include "windows/juce_VBlankAttachement.h" +#include "windows/juce_VBlankAttachment.h" +#include "windows/juce_WindowUtils.h" #include "layout/juce_MultiDocumentPanel.h" #include "layout/juce_SidePanel.h" #include "filebrowser/juce_FileBrowserListener.h" @@ -323,7 +336,9 @@ namespace juce #if JUCE_LINUX || JUCE_BSD #if JUCE_GUI_BASICS_INCLUDE_XHEADERS // If you're missing these headers, you need to install the libx11-dev package + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wvariadic-macros") #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE #include #include #include @@ -363,13 +378,13 @@ namespace juce #undef SIZEOF #undef KeyPress - #include "native/x11/juce_linux_XWindowSystem.h" - #include "native/x11/juce_linux_X11_Symbols.h" + #include "native/juce_XWindowSystem_linux.h" + #include "native/juce_XSymbols_linux.h" #endif #endif #if JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER && JUCE_WINDOWS - #include "native/juce_win32_ScopedThreadDPIAwarenessSetter.h" + #include "native/juce_ScopedThreadDPIAwarenessSetter_windows.h" #endif #include "layout/juce_FlexItem.h" diff --git a/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp b/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp index 0aab730be036..f0d5e681b705 100644 --- a/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp +++ b/modules/juce_gui_basics/keyboard/juce_KeyboardFocusTraverser.cpp @@ -35,10 +35,10 @@ namespace KeyboardFocusTraverserHelpers } static Component* traverse (Component* current, Component* container, - FocusHelpers::NavigationDirection direction) + detail::FocusHelpers::NavigationDirection direction) { - if (auto* comp = FocusHelpers::navigateFocus (current, container, direction, - &Component::isKeyboardFocusContainer)) + if (auto* comp = detail::FocusHelpers::navigateFocus (current, container, direction, + &Component::isKeyboardFocusContainer)) { if (isKeyboardFocusable (comp, container)) return comp; @@ -53,13 +53,13 @@ namespace KeyboardFocusTraverserHelpers Component* KeyboardFocusTraverser::getNextComponent (Component* current) { return KeyboardFocusTraverserHelpers::traverse (current, current->findKeyboardFocusContainer(), - FocusHelpers::NavigationDirection::forwards); + detail::FocusHelpers::NavigationDirection::forwards); } Component* KeyboardFocusTraverser::getPreviousComponent (Component* current) { return KeyboardFocusTraverserHelpers::traverse (current, current->findKeyboardFocusContainer(), - FocusHelpers::NavigationDirection::backwards); + detail::FocusHelpers::NavigationDirection::backwards); } Component* KeyboardFocusTraverser::getDefaultComponent (Component* parentComponent) @@ -74,9 +74,9 @@ Component* KeyboardFocusTraverser::getDefaultComponent (Component* parentCompone std::vector KeyboardFocusTraverser::getAllComponents (Component* parentComponent) { std::vector components; - FocusHelpers::findAllComponents (parentComponent, - components, - &Component::isKeyboardFocusContainer); + detail::FocusHelpers::findAllComponents (parentComponent, + components, + &Component::isKeyboardFocusContainer); auto removePredicate = [parentComponent] (const Component* comp) { diff --git a/modules/juce_gui_basics/layout/juce_AnimatedPosition.h b/modules/juce_gui_basics/layout/juce_AnimatedPosition.h index 20d9f9f67cee..856078071924 100644 --- a/modules/juce_gui_basics/layout/juce_AnimatedPosition.h +++ b/modules/juce_gui_basics/layout/juce_AnimatedPosition.h @@ -179,7 +179,7 @@ class AnimatedPosition : private Timer { newPosition = range.clipValue (newPosition); - if (position != newPosition) + if (! approximatelyEqual (position, newPosition)) { position = newPosition; listeners.call ([this, newPosition] (Listener& l) { l.positionChanged (*this, newPosition); }); diff --git a/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h b/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h index 107138c77972..5786d780bf15 100644 --- a/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h +++ b/modules/juce_gui_basics/layout/juce_AnimatedPositionBehaviours.h @@ -89,7 +89,7 @@ namespace AnimatedPositionBehaviours */ bool isStopped (double /*position*/) const noexcept { - return velocity == 0.0; + return approximatelyEqual (velocity, 0.0); } private: diff --git a/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp b/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp new file mode 100644 index 000000000000..7e1268a07862 --- /dev/null +++ b/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.cpp @@ -0,0 +1,77 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce +{ + +void BorderedComponentBoundsConstrainer::checkBounds (Rectangle& bounds, + const Rectangle& previousBounds, + const Rectangle& limits, + bool isStretchingTop, + bool isStretchingLeft, + bool isStretchingBottom, + bool isStretchingRight) +{ + if (auto* decorated = getWrappedConstrainer()) + { + const auto border = getAdditionalBorder(); + const auto requestedBounds = bounds; + + border.subtractFrom (bounds); + decorated->checkBounds (bounds, + border.subtractedFrom (previousBounds), + limits, + isStretchingTop, + isStretchingLeft, + isStretchingBottom, + isStretchingRight); + border.addTo (bounds); + bounds = bounds.withPosition (requestedBounds.getPosition()); + + if (isStretchingTop && ! isStretchingBottom) + bounds = bounds.withBottomY (previousBounds.getBottom()); + + if (! isStretchingTop && isStretchingBottom) + bounds = bounds.withY (previousBounds.getY()); + + if (isStretchingLeft && ! isStretchingRight) + bounds = bounds.withRightX (previousBounds.getRight()); + + if (! isStretchingLeft && isStretchingRight) + bounds = bounds.withX (previousBounds.getX()); + } + else + { + ComponentBoundsConstrainer::checkBounds (bounds, + previousBounds, + limits, + isStretchingTop, + isStretchingLeft, + isStretchingBottom, + isStretchingRight); + } +} + +} // namespace juce diff --git a/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h b/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h new file mode 100644 index 000000000000..c759e6e7a2b6 --- /dev/null +++ b/modules/juce_gui_basics/layout/juce_BorderedComponentBoundsConstrainer.h @@ -0,0 +1,69 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + 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 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-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. + + ============================================================================== +*/ + +namespace juce +{ + +//============================================================================== +/** + A ComponentBoundsConstrainer that can be used to add a constant border onto another + ComponentBoundsConstrainer. + + This is useful when trying to constrain the size of a resizable window or + other component that wraps a constrained component, such as a plugin + editor. + + @see ResizableCornerComponent, ResizableBorderComponent, ResizableWindow, + ComponentBoundsConstrainer + + @tags{GUI} +*/ +class JUCE_API BorderedComponentBoundsConstrainer : public ComponentBoundsConstrainer +{ +public: + /** Default constructor. */ + BorderedComponentBoundsConstrainer() = default; + + /** Returns a pointer to another constrainer that will be used as the + base for any resizing operations. + */ + virtual ComponentBoundsConstrainer* getWrappedConstrainer() const = 0; + + /** Returns the border that should be applied to the constrained bounds. */ + virtual BorderSize getAdditionalBorder() const = 0; + + /** @internal */ + void checkBounds (Rectangle& bounds, + const Rectangle& previousBounds, + const Rectangle& limits, + bool isStretchingTop, + bool isStretchingLeft, + bool isStretchingBottom, + bool isStretchingRight) override; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BorderedComponentBoundsConstrainer) +}; + +} // namespace juce diff --git a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp index 3095bde9b1d2..42732fbdc2e1 100644 --- a/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp +++ b/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp @@ -49,7 +49,7 @@ class ComponentAnimator::AnimationTask destAlpha = finalAlpha; isMoving = (finalBounds != component->getBounds()); - isChangingAlpha = (finalAlpha != component->getAlpha()); + isChangingAlpha = ! approximatelyEqual (finalAlpha, component->getAlpha()); left = component->getX(); top = component->getY(); @@ -273,7 +273,7 @@ void ComponentAnimator::fadeOut (Component* component, int millisecondsToTake) void ComponentAnimator::fadeIn (Component* component, int millisecondsToTake) { - if (component != nullptr && ! (component->isVisible() && component->getAlpha() == 1.0f)) + if (component != nullptr && ! (component->isVisible() && approximatelyEqual (component->getAlpha(), 1.0f))) { component->setAlpha (0.0f); component->setVisible (true); diff --git a/modules/juce_gui_basics/layout/juce_ConcertinaPanel.h b/modules/juce_gui_basics/layout/juce_ConcertinaPanel.h index db959f34d095..d6aa4a9fc9f3 100644 --- a/modules/juce_gui_basics/layout/juce_ConcertinaPanel.h +++ b/modules/juce_gui_basics/layout/juce_ConcertinaPanel.h @@ -119,8 +119,10 @@ class JUCE_API ConcertinaPanel : public Component ConcertinaPanel&, Component&) = 0; }; -private: + /** @internal */ std::unique_ptr createAccessibilityHandler() override; + +private: void resized() override; class PanelHolder; diff --git a/modules/juce_gui_basics/layout/juce_FlexBox.cpp b/modules/juce_gui_basics/layout/juce_FlexBox.cpp index 9a7a2469ae5c..ed5443b68f45 100644 --- a/modules/juce_gui_basics/layout/juce_FlexBox.cpp +++ b/modules/juce_gui_basics/layout/juce_FlexBox.cpp @@ -84,8 +84,16 @@ struct FlexBoxLayoutCalculation ItemWithState& getItem (int x, int y) const noexcept { return *lineItems[y * numItems + x]; } - static bool isAuto (Coord value) noexcept { return value == FlexItem::autoValue; } - static bool isAssigned (Coord value) noexcept { return value != FlexItem::notAssigned; } + static bool isAuto (Coord value) noexcept + { + return exactlyEqual (value, static_cast (FlexItem::autoValue)); + } + + static bool isAssigned (Coord value) noexcept + { + return ! exactlyEqual (value, static_cast (FlexItem::notAssigned)); + } + static Coord getValueOrZeroIfAuto (Coord value) noexcept { return isAuto (value) ? Coord() : value; } //============================================================================== @@ -604,12 +612,12 @@ struct FlexBoxLayoutCalculation if (positiveFlexibility) { - if (totalFlexGrow != 0.0) + if (! approximatelyEqual (totalFlexGrow, 0.0)) changeUnit = difference / totalFlexGrow; } else { - if (totalFlexShrink != 0.0) + if (! approximatelyEqual (totalFlexShrink, 0.0)) changeUnit = difference / totalFlexShrink; } diff --git a/modules/juce_gui_basics/layout/juce_Grid.cpp b/modules/juce_gui_basics/layout/juce_Grid.cpp index b012520d5f24..8534fde615fb 100644 --- a/modules/juce_gui_basics/layout/juce_Grid.cpp +++ b/modules/juce_gui_basics/layout/juce_Grid.cpp @@ -26,942 +26,1026 @@ namespace juce { -struct AllTracksIncludingImplicit +template +static Array operator+ (const Array& a, const Array& b) { - Array items; - int numImplicitLeading; // The number of implicit items before the explicit items -}; + auto copy = a; + copy.addArray (b); + return copy; +} -struct Tracks +struct Grid::Helpers { - AllTracksIncludingImplicit columns, rows; -}; -struct Grid::SizeCalculation -{ - static float getTotalAbsoluteSize (const Array& tracks, Px gapSize) noexcept + struct AllTracksIncludingImplicit { - float totalCellSize = 0.0f; - - for (const auto& trackInfo : tracks) - if (! trackInfo.isFractional() || trackInfo.isAuto()) - totalCellSize += trackInfo.getSize(); - - float totalGap = tracks.size() > 1 ? static_cast ((tracks.size() - 1) * gapSize.pixels) - : 0.0f; - - return totalCellSize + totalGap; - } + Array items; + int numImplicitLeading; // The number of implicit items before the explicit items + }; - static float getRelativeUnitSize (float size, float totalAbsolute, const Array& tracks) noexcept + struct Tracks { - const float totalRelative = jlimit (0.0f, size, size - totalAbsolute); - float factorsSum = 0.0f; - - for (const auto& trackInfo : tracks) - if (trackInfo.isFractional()) - factorsSum += trackInfo.getSize(); - - jassert (factorsSum != 0.0f); - return totalRelative / factorsSum; - } + AllTracksIncludingImplicit columns, rows; + }; - //============================================================================== - static float getTotalAbsoluteHeight (const Array& rowTracks, Px rowGap) + struct NoRounding { - return getTotalAbsoluteSize (rowTracks, rowGap); - } + template + T operator() (T t) const { return t; } + }; - static float getTotalAbsoluteWidth (const Array& columnTracks, Px columnGap) + struct StandardRounding { - return getTotalAbsoluteSize (columnTracks, columnGap); - } + template + T operator() (T t) const { return std::round (t); } + }; - static float getRelativeWidthUnit (float gridWidth, Px columnGap, const Array& columnTracks) + template + struct SizeCalculation { - return getRelativeUnitSize (gridWidth, getTotalAbsoluteWidth (columnTracks, columnGap), columnTracks); - } + float getTotalAbsoluteSize (const Array& tracks, Px gapSize) noexcept + { + float totalCellSize = 0.0f; - static float getRelativeHeightUnit (float gridHeight, Px rowGap, const Array& rowTracks) - { - return getRelativeUnitSize (gridHeight, getTotalAbsoluteHeight (rowTracks, rowGap), rowTracks); - } + for (const auto& trackInfo : tracks) + if (! trackInfo.isFractional() || trackInfo.isAuto()) + totalCellSize += roundingFunction (trackInfo.getSize()); - //============================================================================== - static bool hasAnyFractions (const Array& tracks) - { - return std::any_of (tracks.begin(), - tracks.end(), - [] (const auto& t) { return t.isFractional(); }); - } + float totalGap = tracks.size() > 1 ? (float) (tracks.size() - 1) * roundingFunction ((float) gapSize.pixels) + : 0.0f; - void computeSizes (float gridWidth, float gridHeight, - Px columnGapToUse, Px rowGapToUse, - const Tracks& tracks) - { - if (hasAnyFractions (tracks.columns.items)) - relativeWidthUnit = getRelativeWidthUnit (gridWidth, columnGapToUse, tracks.columns.items); - else - remainingWidth = gridWidth - getTotalAbsoluteSize (tracks.columns.items, columnGapToUse); - - if (hasAnyFractions (tracks.rows.items)) - relativeHeightUnit = getRelativeHeightUnit (gridHeight, rowGapToUse, tracks.rows.items); - else - remainingHeight = gridHeight - getTotalAbsoluteSize (tracks.rows.items, rowGapToUse); - } + return totalCellSize + totalGap; + } - float relativeWidthUnit = 0.0f; - float relativeHeightUnit = 0.0f; - float remainingWidth = 0.0f; - float remainingHeight = 0.0f; -}; + static float getRelativeUnitSize (float size, float totalAbsolute, const Array& tracks) noexcept + { + const float totalRelative = jlimit (0.0f, size, size - totalAbsolute); + float factorsSum = 0.0f; -//============================================================================== -struct Grid::PlacementHelpers -{ - enum { invalid = -999999 }; - static constexpr auto emptyAreaCharacter = "."; + for (const auto& trackInfo : tracks) + if (trackInfo.isFractional()) + factorsSum += trackInfo.getSize(); - //============================================================================== - struct LineRange { int start, end; }; - struct LineArea { LineRange column, row; }; - struct LineInfo { StringArray lineNames; }; + jassert (! approximatelyEqual (factorsSum, 0.0f)); + return totalRelative / factorsSum; + } - struct NamedArea - { - String name; - LineArea lines; - }; + //============================================================================== + float getTotalAbsoluteHeight (const Array& rowTracks, Px rowGapSize) + { + return getTotalAbsoluteSize (rowTracks, rowGapSize); + } - //============================================================================== - static Array getArrayOfLinesFromTracks (const Array& tracks) - { - // fill line info array - Array lines; + float getTotalAbsoluteWidth (const Array& columnTracks, Px columnGapSize) + { + return getTotalAbsoluteSize (columnTracks, columnGapSize); + } + + float getRelativeWidthUnit (float gridWidth, Px columnGapSize, const Array& columnTracks) + { + return getRelativeUnitSize (gridWidth, getTotalAbsoluteWidth (columnTracks, columnGapSize), columnTracks); + } + + float getRelativeHeightUnit (float gridHeight, Px rowGapSize, const Array& rowTracks) + { + return getRelativeUnitSize (gridHeight, getTotalAbsoluteHeight (rowTracks, rowGapSize), rowTracks); + } - for (int i = 1; i <= tracks.size(); ++i) + //============================================================================== + static bool hasAnyFractions (const Array& tracks) { - const auto& currentTrack = tracks.getReference (i - 1); + return std::any_of (tracks.begin(), + tracks.end(), + [] (const auto& t) { return t.isFractional(); }); + } - if (i == 1) // start line + void computeSizes (float gridWidth, float gridHeight, + Px columnGapToUse, Px rowGapToUse, + const Tracks& tracks) + { + if (hasAnyFractions (tracks.columns.items)) { - LineInfo li; - li.lineNames.add (currentTrack.getStartLineName()); - lines.add (li); + relativeWidthUnit = getRelativeWidthUnit (gridWidth, columnGapToUse, tracks.columns.items); + fractionallyDividedWidth = gridWidth - getTotalAbsoluteSize (tracks.columns.items, columnGapToUse); } - - if (i > 1 && i <= tracks.size()) // two lines in between tracks + else { - const auto& prevTrack = tracks.getReference (i - 2); - - LineInfo li; - li.lineNames.add (prevTrack.getEndLineName()); - li.lineNames.add (currentTrack.getStartLineName()); - - lines.add (li); + remainingWidth = gridWidth - getTotalAbsoluteSize (tracks.columns.items, columnGapToUse); } - if (i == tracks.size()) // end line + if (hasAnyFractions (tracks.rows.items)) { - LineInfo li; - li.lineNames.add (currentTrack.getEndLineName()); - lines.add (li); + relativeHeightUnit = getRelativeHeightUnit (gridHeight, rowGapToUse, tracks.rows.items); + fractionallyDividedHeight = gridHeight - getTotalAbsoluteSize (tracks.rows.items, rowGapToUse); } + else + { + remainingHeight = gridHeight - getTotalAbsoluteSize (tracks.rows.items, rowGapToUse); + } + + const auto calculateTrackBounds = [&] (auto& outBounds, + const auto& trackItems, + auto relativeUnit, + auto totalSizeForFractionalItems, + auto gap) + { + const auto lastFractionalIndex = [&] + { + for (int i = trackItems.size() - 1; 0 <= i; --i) + if (trackItems[i].isFractional()) + return i; + + return -1; + }(); + + float start = 0.0f; + float carriedError = 0.0f; + + for (int i = 0; i < trackItems.size(); ++i) + { + const auto& currentItem = trackItems[i]; + + const auto currentTrackSize = [&] + { + if (i == lastFractionalIndex) + return totalSizeForFractionalItems; + + const auto absoluteSize = currentItem.getAbsoluteSize (relativeUnit); + + if (! currentItem.isFractional()) + return roundingFunction (absoluteSize); + + const auto result = roundingFunction (absoluteSize - carriedError); + carriedError += result - absoluteSize; + return result; + }(); + + if (currentItem.isFractional()) + totalSizeForFractionalItems -= currentTrackSize; + + const auto end = start + currentTrackSize; + outBounds.emplace_back (start, end); + start = end + roundingFunction (static_cast (gap.pixels)); + } + }; + + calculateTrackBounds (columnTrackBounds, + tracks.columns.items, + relativeWidthUnit, + fractionallyDividedWidth, + columnGapToUse); + + calculateTrackBounds (rowTrackBounds, + tracks.rows.items, + relativeHeightUnit, + fractionallyDividedHeight, + rowGapToUse); } - jassert (lines.size() == tracks.size() + 1); + float relativeWidthUnit = 0.0f; + float relativeHeightUnit = 0.0f; + float fractionallyDividedWidth = 0.0f; + float fractionallyDividedHeight = 0.0f; + float remainingWidth = 0.0f; + float remainingHeight = 0.0f; - return lines; - } + std::vector> columnTrackBounds; + std::vector> rowTrackBounds; + RoundingFunction roundingFunction; + }; //============================================================================== - static int deduceAbsoluteLineNumberFromLineName (GridItem::Property prop, - const Array& tracks) + struct PlacementHelpers { - jassert (prop.hasAbsolute()); + enum { invalid = -999999 }; + static constexpr auto emptyAreaCharacter = "."; + + //============================================================================== + struct LineRange { int start, end; }; + struct LineArea { LineRange column, row; }; + struct LineInfo { StringArray lineNames; }; - const auto lines = getArrayOfLinesFromTracks (tracks); - int count = 0; + struct NamedArea + { + String name; + LineArea lines; + }; - for (int i = 0; i < lines.size(); i++) + //============================================================================== + static Array getArrayOfLinesFromTracks (const Array& tracks) { - for (const auto& name : lines.getReference (i).lineNames) + // fill line info array + Array lines; + + for (int i = 1; i <= tracks.size(); ++i) { - if (prop.getName() == name) + const auto& currentTrack = tracks.getReference (i - 1); + + if (i == 1) // start line { - ++count; - break; + LineInfo li; + li.lineNames.add (currentTrack.getStartLineName()); + lines.add (li); } - } - if (count == prop.getNumber()) - return i + 1; - } - - jassertfalse; - return count; - } + if (i > 1 && i <= tracks.size()) // two lines in between tracks + { + const auto& prevTrack = tracks.getReference (i - 2); - static int deduceAbsoluteLineNumber (GridItem::Property prop, - const Array& tracks) - { - jassert (prop.hasAbsolute()); + LineInfo li; + li.lineNames.add (prevTrack.getEndLineName()); + li.lineNames.add (currentTrack.getStartLineName()); - if (prop.hasName()) - return deduceAbsoluteLineNumberFromLineName (prop, tracks); + lines.add (li); + } - if (prop.getNumber() > 0) - return prop.getNumber(); + if (i == tracks.size()) // end line + { + LineInfo li; + li.lineNames.add (currentTrack.getEndLineName()); + lines.add (li); + } + } - if (prop.getNumber() < 0) - return tracks.size() + 2 + prop.getNumber(); + jassert (lines.size() == tracks.size() + 1); - // An integer value of 0 is invalid - jassertfalse; - return 1; - } + return lines; + } - static int deduceAbsoluteLineNumberFromNamedSpan (int startLineNumber, - GridItem::Property propertyWithSpan, - const Array& tracks) - { - jassert (propertyWithSpan.hasSpan()); + //============================================================================== + static int deduceAbsoluteLineNumberFromLineName (GridItem::Property prop, + const Array& tracks) + { + jassert (prop.hasAbsolute()); - const auto lines = getArrayOfLinesFromTracks (tracks); - int count = 0; + const auto lines = getArrayOfLinesFromTracks (tracks); + int count = 0; - for (int i = startLineNumber; i < lines.size(); i++) - { - for (const auto& name : lines.getReference (i).lineNames) + for (int i = 0; i < lines.size(); i++) { - if (propertyWithSpan.getName() == name) + for (const auto& name : lines.getReference (i).lineNames) { - ++count; - break; + if (prop.getName() == name) + { + ++count; + break; + } } + + if (count == prop.getNumber()) + return i + 1; } - if (count == propertyWithSpan.getNumber()) - return i + 1; + jassertfalse; + return count; } - jassertfalse; - return count; - } + static int deduceAbsoluteLineNumber (GridItem::Property prop, + const Array& tracks) + { + jassert (prop.hasAbsolute()); - static int deduceAbsoluteLineNumberBasedOnSpan (int startLineNumber, - GridItem::Property propertyWithSpan, - const Array& tracks) - { - jassert (propertyWithSpan.hasSpan()); + if (prop.hasName()) + return deduceAbsoluteLineNumberFromLineName (prop, tracks); - if (propertyWithSpan.hasName()) - return deduceAbsoluteLineNumberFromNamedSpan (startLineNumber, propertyWithSpan, tracks); + if (prop.getNumber() > 0) + return prop.getNumber(); - return startLineNumber + propertyWithSpan.getNumber(); - } + if (prop.getNumber() < 0) + return tracks.size() + 2 + prop.getNumber(); - //============================================================================== - static LineRange deduceLineRange (GridItem::StartAndEndProperty prop, const Array& tracks) - { - jassert (! (prop.start.hasAuto() && prop.end.hasAuto())); + // An integer value of 0 is invalid + jassertfalse; + return 1; + } - if (prop.start.hasAbsolute() && prop.end.hasAuto()) + static int deduceAbsoluteLineNumberFromNamedSpan (int startLineNumber, + GridItem::Property propertyWithSpan, + const Array& tracks) { - prop.end = GridItem::Span (1); + jassert (propertyWithSpan.hasSpan()); + + const auto lines = getArrayOfLinesFromTracks (tracks); + int count = 0; + + for (int i = startLineNumber; i < lines.size(); i++) + { + for (const auto& name : lines.getReference (i).lineNames) + { + if (propertyWithSpan.getName() == name) + { + ++count; + break; + } + } + + if (count == propertyWithSpan.getNumber()) + return i + 1; + } + + jassertfalse; + return count; } - else if (prop.start.hasAuto() && prop.end.hasAbsolute()) + + static int deduceAbsoluteLineNumberBasedOnSpan (int startLineNumber, + GridItem::Property propertyWithSpan, + const Array& tracks) { - prop.start = GridItem::Span (1); + jassert (propertyWithSpan.hasSpan()); + + if (propertyWithSpan.hasName()) + return deduceAbsoluteLineNumberFromNamedSpan (startLineNumber, propertyWithSpan, tracks); + + return startLineNumber + propertyWithSpan.getNumber(); } - auto s = [&]() -> LineRange + //============================================================================== + static LineRange deduceLineRange (GridItem::StartAndEndProperty prop, const Array& tracks) { - if (prop.start.hasAbsolute() && prop.end.hasAbsolute()) + jassert (! (prop.start.hasAuto() && prop.end.hasAuto())); + + if (prop.start.hasAbsolute() && prop.end.hasAuto()) { - return { deduceAbsoluteLineNumber (prop.start, tracks), - deduceAbsoluteLineNumber (prop.end, tracks) }; + prop.end = GridItem::Span (1); } - - if (prop.start.hasAbsolute() && prop.end.hasSpan()) + else if (prop.start.hasAuto() && prop.end.hasAbsolute()) { - const auto start = deduceAbsoluteLineNumber (prop.start, tracks); - return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.end, tracks) }; + prop.start = GridItem::Span (1); } - if (prop.start.hasSpan() && prop.end.hasAbsolute()) + auto s = [&]() -> LineRange { - const auto start = deduceAbsoluteLineNumber (prop.end, tracks); - return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.start, tracks) }; - } + if (prop.start.hasAbsolute() && prop.end.hasAbsolute()) + { + return { deduceAbsoluteLineNumber (prop.start, tracks), + deduceAbsoluteLineNumber (prop.end, tracks) }; + } - // Can't have an item with spans on both start and end. - jassertfalse; - return {}; - }(); + if (prop.start.hasAbsolute() && prop.end.hasSpan()) + { + const auto start = deduceAbsoluteLineNumber (prop.start, tracks); + return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.end, tracks) }; + } - // swap if start overtakes end - if (s.start > s.end) - std::swap (s.start, s.end); - else if (s.start == s.end) - s.end = s.start + 1; + if (prop.start.hasSpan() && prop.end.hasAbsolute()) + { + const auto start = deduceAbsoluteLineNumber (prop.end, tracks); + return { start, deduceAbsoluteLineNumberBasedOnSpan (start, prop.start, tracks) }; + } - return s; - } + // Can't have an item with spans on both start and end. + jassertfalse; + return {}; + }(); - static LineArea deduceLineArea (const GridItem& item, - const Grid& grid, - const std::map& namedAreas) - { - if (item.area.isNotEmpty() && ! grid.templateAreas.isEmpty()) - { - // Must be a named area! - jassert (namedAreas.count (item.area) != 0); + // swap if start overtakes end + if (s.start > s.end) + std::swap (s.start, s.end); + else if (s.start == s.end) + s.end = s.start + 1; - return namedAreas.at (item.area); + return s; } - return { deduceLineRange (item.column, grid.templateColumns), - deduceLineRange (item.row, grid.templateRows) }; - } + static LineArea deduceLineArea (const GridItem& item, + const Grid& grid, + const std::map& namedAreas) + { + if (item.area.isNotEmpty() && ! grid.templateAreas.isEmpty()) + { + // Must be a named area! + jassert (namedAreas.count (item.area) != 0); - //============================================================================== - static Array parseAreasProperty (const StringArray& areasStrings) - { - Array strings; + return namedAreas.at (item.area); + } - for (const auto& areaString : areasStrings) - strings.add (StringArray::fromTokens (areaString, false)); + return { deduceLineRange (item.column, grid.templateColumns), + deduceLineRange (item.row, grid.templateRows) }; + } - if (strings.size() > 0) + //============================================================================== + static Array parseAreasProperty (const StringArray& areasStrings) { - for (auto s : strings) + Array strings; + + for (const auto& areaString : areasStrings) + strings.add (StringArray::fromTokens (areaString, false)); + + if (strings.size() > 0) { - jassert (s.size() == strings[0].size()); // all rows must have the same number of columns + for (auto s : strings) + { + jassert (s.size() == strings[0].size()); // all rows must have the same number of columns + } } - } - return strings; - } - - static NamedArea findArea (Array& stringsArrays) - { - NamedArea area; + return strings; + } - for (auto& stringArray : stringsArrays) + static NamedArea findArea (Array& stringsArrays) { - for (auto& string : stringArray) + NamedArea area; + + for (auto& stringArray : stringsArrays) { - // find anchor - if (area.name.isEmpty()) + for (auto& string : stringArray) { - if (string != emptyAreaCharacter) + // find anchor + if (area.name.isEmpty()) { - area.name = string; - area.lines.row.start = stringsArrays.indexOf (stringArray) + 1; // non-zero indexed; - area.lines.column.start = stringArray.indexOf (string) + 1; // non-zero indexed; - - area.lines.row.end = stringsArrays.indexOf (stringArray) + 2; - area.lines.column.end = stringArray.indexOf (string) + 2; - - // mark as visited - string = emptyAreaCharacter; + if (string != emptyAreaCharacter) + { + area.name = string; + area.lines.row.start = stringsArrays.indexOf (stringArray) + 1; // non-zero indexed; + area.lines.column.start = stringArray.indexOf (string) + 1; // non-zero indexed; + + area.lines.row.end = stringsArrays.indexOf (stringArray) + 2; + area.lines.column.end = stringArray.indexOf (string) + 2; + + // mark as visited + string = emptyAreaCharacter; + } } - } - else - { - if (string == area.name) + else { - area.lines.row.end = stringsArrays.indexOf (stringArray) + 2; - area.lines.column.end = stringArray.indexOf (string) + 2; - - // mark as visited - string = emptyAreaCharacter; + if (string == area.name) + { + area.lines.row.end = stringsArrays.indexOf (stringArray) + 2; + area.lines.column.end = stringArray.indexOf (string) + 2; + + // mark as visited + string = emptyAreaCharacter; + } } } } + + return area; } - return area; - } + //============================================================================== + static std::map deduceNamedAreas (const StringArray& areasStrings) + { + auto stringsArrays = parseAreasProperty (areasStrings); - //============================================================================== - static std::map deduceNamedAreas (const StringArray& areasStrings) - { - auto stringsArrays = parseAreasProperty (areasStrings); + std::map areas; + + for (auto area = findArea (stringsArrays); area.name.isNotEmpty(); area = findArea (stringsArrays)) + { + if (areas.count (area.name) == 0) + areas[area.name] = area.lines; + else + // Make sure your template-areas property only has one area with the same name and is well-formed + jassertfalse; + } - std::map areas; + return areas; + } - for (auto area = findArea (stringsArrays); area.name.isNotEmpty(); area = findArea (stringsArrays)) + //============================================================================== + template + static Rectangle getCellBounds (int columnNumber, int rowNumber, + const Tracks& tracks, + const SizeCalculation& calculation) { - if (areas.count (area.name) == 0) - areas[area.name] = area.lines; - else - // Make sure your template-areas property only has one area with the same name and is well-formed - jassertfalse; + const auto correctedColumn = columnNumber - 1 + tracks.columns.numImplicitLeading; + const auto correctedRow = rowNumber - 1 + tracks.rows .numImplicitLeading; + + jassert (isPositiveAndBelow (correctedColumn, tracks.columns.items.size())); + jassert (isPositiveAndBelow (correctedRow, tracks.rows .items.size())); + + return + { + calculation.columnTrackBounds[(size_t) correctedColumn].getStart(), + calculation.rowTrackBounds[(size_t) correctedRow].getStart(), + calculation.columnTrackBounds[(size_t) correctedColumn].getEnd() - calculation.columnTrackBounds[(size_t) correctedColumn].getStart(), + calculation.rowTrackBounds[(size_t) correctedRow].getEnd() - calculation.rowTrackBounds[(size_t) correctedRow].getStart() + }; } - return areas; - } + template + static Rectangle alignCell (Rectangle area, + int columnNumber, int rowNumber, + int numberOfColumns, int numberOfRows, + const SizeCalculation& calculation, + AlignContent alignContent, + JustifyContent justifyContent) + { + if (alignContent == AlignContent::end) + area.setY (area.getY() + calculation.remainingHeight); - //============================================================================== - static float getCoord (int trackNumber, float relativeUnit, Px gap, const Array& tracks) - { - float c = 0; + if (justifyContent == JustifyContent::end) + area.setX (area.getX() + calculation.remainingWidth); - for (const auto* it = tracks.begin(); it != tracks.begin() + trackNumber; ++it) - c += it->getAbsoluteSize (relativeUnit) + static_cast (gap.pixels); + if (alignContent == AlignContent::center) + area.setY (area.getY() + calculation.remainingHeight / 2); - return c; - } + if (justifyContent == JustifyContent::center) + area.setX (area.getX() + calculation.remainingWidth / 2); - static Rectangle getCellBounds (int columnNumber, int rowNumber, - const Tracks& tracks, - SizeCalculation calculation, - Px columnGap, Px rowGap) - { - const auto correctedColumn = columnNumber - 1 + tracks.columns.numImplicitLeading; - const auto correctedRow = rowNumber - 1 + tracks.rows .numImplicitLeading; + if (alignContent == AlignContent::spaceBetween) + { + const auto shift = ((float) (rowNumber - 1) * (calculation.remainingHeight / float(numberOfRows - 1))); + area.setY (area.getY() + shift); + } - jassert (isPositiveAndBelow (correctedColumn, tracks.columns.items.size())); - jassert (isPositiveAndBelow (correctedRow, tracks.rows .items.size())); + if (justifyContent == JustifyContent::spaceBetween) + { + const auto shift = ((float) (columnNumber - 1) * (calculation.remainingWidth / float(numberOfColumns - 1))); + area.setX (area.getX() + shift); + } - return { getCoord (correctedColumn, calculation.relativeWidthUnit, columnGap, tracks.columns.items), - getCoord (correctedRow, calculation.relativeHeightUnit, rowGap, tracks.rows .items), - tracks.columns.items.getReference (correctedColumn).getAbsoluteSize (calculation.relativeWidthUnit), - tracks.rows .items.getReference (correctedRow) .getAbsoluteSize (calculation.relativeHeightUnit) }; - } + if (alignContent == AlignContent::spaceEvenly) + { + const auto shift = ((float) rowNumber * (calculation.remainingHeight / float(numberOfRows + 1))); + area.setY (area.getY() + shift); + } - static Rectangle alignCell (Rectangle area, - int columnNumber, int rowNumber, - int numberOfColumns, int numberOfRows, - SizeCalculation calculation, - AlignContent alignContent, - JustifyContent justifyContent) - { - if (alignContent == AlignContent::end) - area.setY (area.getY() + calculation.remainingHeight); + if (justifyContent == JustifyContent::spaceEvenly) + { + const auto shift = ((float) columnNumber * (calculation.remainingWidth / float(numberOfColumns + 1))); + area.setX (area.getX() + shift); + } - if (justifyContent == JustifyContent::end) - area.setX (area.getX() + calculation.remainingWidth); + if (alignContent == AlignContent::spaceAround) + { + const auto inbetweenShift = calculation.remainingHeight / float(numberOfRows); + const auto sidesShift = inbetweenShift / 2; + auto shift = (float) (rowNumber - 1) * inbetweenShift + sidesShift; - if (alignContent == AlignContent::center) - area.setY (area.getY() + calculation.remainingHeight / 2); + area.setY (area.getY() + shift); + } - if (justifyContent == JustifyContent::center) - area.setX (area.getX() + calculation.remainingWidth / 2); + if (justifyContent == JustifyContent::spaceAround) + { + const auto inbetweenShift = calculation.remainingWidth / float(numberOfColumns); + const auto sidesShift = inbetweenShift / 2; + auto shift = (float) (columnNumber - 1) * inbetweenShift + sidesShift; - if (alignContent == AlignContent::spaceBetween) - { - const auto shift = ((float) (rowNumber - 1) * (calculation.remainingHeight / float(numberOfRows - 1))); - area.setY (area.getY() + shift); - } + area.setX (area.getX() + shift); + } - if (justifyContent == JustifyContent::spaceBetween) - { - const auto shift = ((float) (columnNumber - 1) * (calculation.remainingWidth / float(numberOfColumns - 1))); - area.setX (area.getX() + shift); + return area; } - if (alignContent == AlignContent::spaceEvenly) + template + static Rectangle getAreaBounds (PlacementHelpers::LineRange columnRange, + PlacementHelpers::LineRange rowRange, + const Tracks& tracks, + const SizeCalculation& calculation, + AlignContent alignContent, + JustifyContent justifyContent) { - const auto shift = ((float) rowNumber * (calculation.remainingHeight / float(numberOfRows + 1))); - area.setY (area.getY() + shift); + const auto findAlignedCell = [&] (int column, int row) + { + const auto cell = getCellBounds (column, row, tracks, calculation); + return alignCell (cell, + column, + row, + tracks.columns.items.size(), + tracks.rows.items.size(), + calculation, + alignContent, + justifyContent); + }; + + const auto startCell = findAlignedCell (columnRange.start, rowRange.start); + const auto endCell = findAlignedCell (columnRange.end - 1, rowRange.end - 1); + + const auto horizontalRange = startCell.getHorizontalRange().getUnionWith (endCell.getHorizontalRange()); + const auto verticalRange = startCell.getVerticalRange() .getUnionWith (endCell.getVerticalRange()); + return { horizontalRange.getStart(), verticalRange.getStart(), + horizontalRange.getLength(), verticalRange.getLength() }; } + }; - if (justifyContent == JustifyContent::spaceEvenly) - { - const auto shift = ((float) columnNumber * (calculation.remainingWidth / float(numberOfColumns + 1))); - area.setX (area.getX() + shift); - } + //============================================================================== + struct AutoPlacement + { + using ItemPlacementArray = Array>; - if (alignContent == AlignContent::spaceAround) + //============================================================================== + struct OccupancyPlane { - const auto inbetweenShift = calculation.remainingHeight / float(numberOfRows); - const auto sidesShift = inbetweenShift / 2; - auto shift = (float) (rowNumber - 1) * inbetweenShift + sidesShift; + struct Cell { int column, row; }; - area.setY (area.getY() + shift); - } + OccupancyPlane (int highestColumnToUse, int highestRowToUse, bool isColumnFirst) + : highestCrossDimension (isColumnFirst ? highestRowToUse : highestColumnToUse), + columnFirst (isColumnFirst) + {} - if (justifyContent == JustifyContent::spaceAround) - { - const auto inbetweenShift = calculation.remainingWidth / float(numberOfColumns); - const auto sidesShift = inbetweenShift / 2; - auto shift = (float) (columnNumber - 1) * inbetweenShift + sidesShift; + PlacementHelpers::LineArea setCell (Cell cell, int columnSpan, int rowSpan) + { + for (int i = 0; i < columnSpan; i++) + for (int j = 0; j < rowSpan; j++) + setCell (cell.column + i, cell.row + j); - area.setX (area.getX() + shift); - } + return { { cell.column, cell.column + columnSpan }, { cell.row, cell.row + rowSpan } }; + } - return area; - } + PlacementHelpers::LineArea setCell (Cell start, Cell end) + { + return setCell (start, std::abs (end.column - start.column), + std::abs (end.row - start.row)); + } - static Rectangle getAreaBounds (PlacementHelpers::LineRange columnRange, - PlacementHelpers::LineRange rowRange, - const Tracks& tracks, - SizeCalculation calculation, - AlignContent alignContent, - JustifyContent justifyContent, - Px columnGap, Px rowGap) - { - const auto findAlignedCell = [&] (int column, int row) - { - const auto cell = getCellBounds (column, row, tracks, calculation, columnGap, rowGap); - return alignCell (cell, - column, - row, - tracks.columns.items.size(), - tracks.rows.items.size(), - calculation, - alignContent, - justifyContent); - }; + Cell nextAvailable (Cell referenceCell, int columnSpan, int rowSpan) + { + while (isOccupied (referenceCell, columnSpan, rowSpan) || isOutOfBounds (referenceCell, columnSpan, rowSpan)) + referenceCell = advance (referenceCell); - const auto startCell = findAlignedCell (columnRange.start, rowRange.start); - const auto endCell = findAlignedCell (columnRange.end - 1, rowRange.end - 1); + return referenceCell; + } - const auto horizontalRange = startCell.getHorizontalRange().getUnionWith (endCell.getHorizontalRange()); - const auto verticalRange = startCell.getVerticalRange() .getUnionWith (endCell.getVerticalRange()); - return { horizontalRange.getStart(), verticalRange.getStart(), - horizontalRange.getLength(), verticalRange.getLength() }; - } -}; + Cell nextAvailableOnRow (Cell referenceCell, int columnSpan, int rowSpan, int rowNumber) + { + if (columnFirst && (rowNumber + rowSpan) > highestCrossDimension) + highestCrossDimension = rowNumber + rowSpan; -template -static Array operator+ (const Array& a, const Array& b) -{ - auto copy = a; - copy.addArray (b); - return copy; -} + while (isOccupied (referenceCell, columnSpan, rowSpan) + || (referenceCell.row != rowNumber)) + referenceCell = advance (referenceCell); -//============================================================================== -struct Grid::AutoPlacement -{ - using ItemPlacementArray = Array>; + return referenceCell; + } - //============================================================================== - struct OccupancyPlane - { - struct Cell { int column, row; }; + Cell nextAvailableOnColumn (Cell referenceCell, int columnSpan, int rowSpan, int columnNumber) + { + if (! columnFirst && (columnNumber + columnSpan) > highestCrossDimension) + highestCrossDimension = columnNumber + columnSpan; - OccupancyPlane (int highestColumnToUse, int highestRowToUse, bool isColumnFirst) - : highestCrossDimension (isColumnFirst ? highestRowToUse : highestColumnToUse), - columnFirst (isColumnFirst) - {} + while (isOccupied (referenceCell, columnSpan, rowSpan) + || (referenceCell.column != columnNumber)) + referenceCell = advance (referenceCell); - PlacementHelpers::LineArea setCell (Cell cell, int columnSpan, int rowSpan) - { - for (int i = 0; i < columnSpan; i++) - for (int j = 0; j < rowSpan; j++) - setCell (cell.column + i, cell.row + j); + return referenceCell; + } - return { { cell.column, cell.column + columnSpan }, { cell.row, cell.row + rowSpan } }; - } + void updateMaxCrossDimensionFromAutoPlacementItem (int columnSpan, int rowSpan) + { + highestCrossDimension = jmax (highestCrossDimension, 1 + getCrossDimension ({ columnSpan, rowSpan })); + } - PlacementHelpers::LineArea setCell (Cell start, Cell end) - { - return setCell (start, std::abs (end.column - start.column), - std::abs (end.row - start.row)); - } + private: + struct SortableCell + { + int column, row; + bool columnFirst; - Cell nextAvailable (Cell referenceCell, int columnSpan, int rowSpan) - { - while (isOccupied (referenceCell, columnSpan, rowSpan) || isOutOfBounds (referenceCell, columnSpan, rowSpan)) - referenceCell = advance (referenceCell); + bool operator< (const SortableCell& other) const + { + if (columnFirst) + { + if (row == other.row) + return column < other.column; - return referenceCell; - } + return row < other.row; + } - Cell nextAvailableOnRow (Cell referenceCell, int columnSpan, int rowSpan, int rowNumber) - { - if (columnFirst && (rowNumber + rowSpan) > highestCrossDimension) - highestCrossDimension = rowNumber + rowSpan; + if (row == other.row) + return column < other.column; - while (isOccupied (referenceCell, columnSpan, rowSpan) - || (referenceCell.row != rowNumber)) - referenceCell = advance (referenceCell); + return row < other.row; + } + }; - return referenceCell; - } + void setCell (int column, int row) + { + occupiedCells.insert ({ column, row, columnFirst }); + } - Cell nextAvailableOnColumn (Cell referenceCell, int columnSpan, int rowSpan, int columnNumber) - { - if (! columnFirst && (columnNumber + columnSpan) > highestCrossDimension) - highestCrossDimension = columnNumber + columnSpan; + bool isOccupied (Cell cell) const + { + return occupiedCells.count ({ cell.column, cell.row, columnFirst }) > 0; + } - while (isOccupied (referenceCell, columnSpan, rowSpan) - || (referenceCell.column != columnNumber)) - referenceCell = advance (referenceCell); + bool isOccupied (Cell cell, int columnSpan, int rowSpan) const + { + for (int i = 0; i < columnSpan; i++) + for (int j = 0; j < rowSpan; j++) + if (isOccupied ({ cell.column + i, cell.row + j })) + return true; - return referenceCell; - } + return false; + } - void updateMaxCrossDimensionFromAutoPlacementItem (int columnSpan, int rowSpan) - { - highestCrossDimension = jmax (highestCrossDimension, 1 + getCrossDimension ({ columnSpan, rowSpan })); - } + bool isOutOfBounds (Cell cell, int columnSpan, int rowSpan) const + { + const auto highestIndexOfCell = getCrossDimension (cell) + getCrossDimension ({ columnSpan, rowSpan }); + const auto highestIndexOfGrid = getHighestCrossDimension(); - private: - struct SortableCell - { - int column, row; - bool columnFirst; + return highestIndexOfGrid < highestIndexOfCell; + } - bool operator< (const SortableCell& other) const + int getHighestCrossDimension() const { - if (columnFirst) - { - if (row == other.row) - return column < other.column; + Cell cell { 1, 1 }; - return row < other.row; - } + if (occupiedCells.size() > 0) + cell = { occupiedCells.crbegin()->column, occupiedCells.crbegin()->row }; - if (row == other.row) - return column < other.column; + return std::max (getCrossDimension (cell), highestCrossDimension); + } + + Cell advance (Cell cell) const + { + if ((getCrossDimension (cell) + 1) >= getHighestCrossDimension()) + return fromDimensions (getMainDimension (cell) + 1, 1); - return row < other.row; + return fromDimensions (getMainDimension (cell), getCrossDimension (cell) + 1); } + + int getMainDimension (Cell cell) const { return columnFirst ? cell.column : cell.row; } + int getCrossDimension (Cell cell) const { return columnFirst ? cell.row : cell.column; } + + Cell fromDimensions (int mainDimension, int crossDimension) const + { + if (columnFirst) + return { mainDimension, crossDimension }; + + return { crossDimension, mainDimension }; + } + + int highestCrossDimension; + bool columnFirst; + std::set occupiedCells; }; - void setCell (int column, int row) + //============================================================================== + static bool isFixed (GridItem::StartAndEndProperty prop) { - occupiedCells.insert ({ column, row, columnFirst }); + return prop.start.hasName() || prop.start.hasAbsolute() || prop.end.hasName() || prop.end.hasAbsolute(); } - bool isOccupied (Cell cell) const + static bool hasFullyFixedPlacement (const GridItem& item) { - return occupiedCells.count ({ cell.column, cell.row, columnFirst }) > 0; - } + if (item.area.isNotEmpty()) + return true; - bool isOccupied (Cell cell, int columnSpan, int rowSpan) const - { - for (int i = 0; i < columnSpan; i++) - for (int j = 0; j < rowSpan; j++) - if (isOccupied ({ cell.column + i, cell.row + j })) - return true; + if (isFixed (item.column) && isFixed (item.row)) + return true; return false; } - bool isOutOfBounds (Cell cell, int columnSpan, int rowSpan) const + static bool hasPartialFixedPlacement (const GridItem& item) { - const auto highestIndexOfCell = getCrossDimension (cell) + getCrossDimension ({ columnSpan, rowSpan }); - const auto highestIndexOfGrid = getHighestCrossDimension(); + if (item.area.isNotEmpty()) + return false; + + if (isFixed (item.column) ^ isFixed (item.row)) + return true; - return highestIndexOfGrid < highestIndexOfCell; + return false; } - int getHighestCrossDimension() const + static bool hasAutoPlacement (const GridItem& item) { - Cell cell { 1, 1 }; - - if (occupiedCells.size() > 0) - cell = { occupiedCells.crbegin()->column, occupiedCells.crbegin()->row }; - - return std::max (getCrossDimension (cell), highestCrossDimension); + return ! hasFullyFixedPlacement (item) && ! hasPartialFixedPlacement (item); } - Cell advance (Cell cell) const + //============================================================================== + static bool hasDenseAutoFlow (AutoFlow autoFlow) { - if ((getCrossDimension (cell) + 1) >= getHighestCrossDimension()) - return fromDimensions (getMainDimension (cell) + 1, 1); - - return fromDimensions (getMainDimension (cell), getCrossDimension (cell) + 1); + return autoFlow == AutoFlow::columnDense + || autoFlow == AutoFlow::rowDense; } - int getMainDimension (Cell cell) const { return columnFirst ? cell.column : cell.row; } - int getCrossDimension (Cell cell) const { return columnFirst ? cell.row : cell.column; } - - Cell fromDimensions (int mainDimension, int crossDimension) const + static bool isColumnAutoFlow (AutoFlow autoFlow) { - if (columnFirst) - return { mainDimension, crossDimension }; - - return { crossDimension, mainDimension }; + return autoFlow == AutoFlow::column + || autoFlow == AutoFlow::columnDense; } - int highestCrossDimension; - bool columnFirst; - std::set occupiedCells; - }; - - //============================================================================== - static bool isFixed (GridItem::StartAndEndProperty prop) - { - return prop.start.hasName() || prop.start.hasAbsolute() || prop.end.hasName() || prop.end.hasAbsolute(); - } - - static bool hasFullyFixedPlacement (const GridItem& item) - { - if (item.area.isNotEmpty()) - return true; + //============================================================================== + static int getSpanFromAuto (GridItem::StartAndEndProperty prop) + { + if (prop.end.hasSpan()) + return prop.end.getNumber(); - if (isFixed (item.column) && isFixed (item.row)) - return true; + if (prop.start.hasSpan()) + return prop.start.getNumber(); - return false; - } - - static bool hasPartialFixedPlacement (const GridItem& item) - { - if (item.area.isNotEmpty()) - return false; + return 1; + } - if (isFixed (item.column) ^ isFixed (item.row)) - return true; + //============================================================================== + ItemPlacementArray deduceAllItems (Grid& grid) const + { + const auto namedAreas = PlacementHelpers::deduceNamedAreas (grid.templateAreas); - return false; - } + OccupancyPlane plane (jmax (grid.templateColumns.size() + 1, 2), + jmax (grid.templateRows.size() + 1, 2), + isColumnAutoFlow (grid.autoFlow)); - static bool hasAutoPlacement (const GridItem& item) - { - return ! hasFullyFixedPlacement (item) && ! hasPartialFixedPlacement (item); - } + ItemPlacementArray itemPlacementArray; + Array sortedItems; - //============================================================================== - static bool hasDenseAutoFlow (AutoFlow autoFlow) - { - return autoFlow == AutoFlow::columnDense - || autoFlow == AutoFlow::rowDense; - } + for (auto& item : grid.items) + sortedItems.add (&item); - static bool isColumnAutoFlow (AutoFlow autoFlow) - { - return autoFlow == AutoFlow::column - || autoFlow == AutoFlow::columnDense; - } + std::stable_sort (sortedItems.begin(), sortedItems.end(), + [] (const GridItem* i1, const GridItem* i2) { return i1->order < i2->order; }); - //============================================================================== - static int getSpanFromAuto (GridItem::StartAndEndProperty prop) - { - if (prop.end.hasSpan()) - return prop.end.getNumber(); + // place fixed items first + for (auto* item : sortedItems) + { + if (hasFullyFixedPlacement (*item)) + { + const auto a = PlacementHelpers::deduceLineArea (*item, grid, namedAreas); + plane.setCell ({ a.column.start, a.row.start }, { a.column.end, a.row.end }); + itemPlacementArray.add ({ item, a }); + } + } - if (prop.start.hasSpan()) - return prop.start.getNumber(); + OccupancyPlane::Cell lastInsertionCell = { 1, 1 }; - return 1; - } + for (auto* item : sortedItems) + { + if (hasPartialFixedPlacement (*item)) + { + if (isFixed (item->column)) + { + const auto p = PlacementHelpers::deduceLineRange (item->column, grid.templateColumns); + const auto columnSpan = std::abs (p.start - p.end); + const auto rowSpan = getSpanFromAuto (item->row); - //============================================================================== - ItemPlacementArray deduceAllItems (Grid& grid) const - { - const auto namedAreas = PlacementHelpers::deduceNamedAreas (grid.templateAreas); + const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { p.start, 1 } + : lastInsertionCell; + const auto nextAvailableCell = plane.nextAvailableOnColumn (insertionCell, columnSpan, rowSpan, p.start); + const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan); + lastInsertionCell = nextAvailableCell; - OccupancyPlane plane (jmax (grid.templateColumns.size() + 1, 2), - jmax (grid.templateRows.size() + 1, 2), - isColumnAutoFlow (grid.autoFlow)); + itemPlacementArray.add ({ item, lineArea }); + } + else if (isFixed (item->row)) + { + const auto p = PlacementHelpers::deduceLineRange (item->row, grid.templateRows); + const auto columnSpan = getSpanFromAuto (item->column); + const auto rowSpan = std::abs (p.start - p.end); - ItemPlacementArray itemPlacementArray; - Array sortedItems; + const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { 1, p.start } + : lastInsertionCell; - for (auto& item : grid.items) - sortedItems.add (&item); + const auto nextAvailableCell = plane.nextAvailableOnRow (insertionCell, columnSpan, rowSpan, p.start); + const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan); - std::stable_sort (sortedItems.begin(), sortedItems.end(), - [] (const GridItem* i1, const GridItem* i2) { return i1->order < i2->order; }); + lastInsertionCell = nextAvailableCell; - // place fixed items first - for (auto* item : sortedItems) - { - if (hasFullyFixedPlacement (*item)) - { - const auto a = PlacementHelpers::deduceLineArea (*item, grid, namedAreas); - plane.setCell ({ a.column.start, a.row.start }, { a.column.end, a.row.end }); - itemPlacementArray.add ({ item, a }); + itemPlacementArray.add ({ item, lineArea }); + } + } } - } - OccupancyPlane::Cell lastInsertionCell = { 1, 1 }; + // https://www.w3.org/TR/css-grid-1/#auto-placement-algo step 3.3 + for (auto* item : sortedItems) + if (hasAutoPlacement (*item)) + plane.updateMaxCrossDimensionFromAutoPlacementItem (getSpanFromAuto (item->column), getSpanFromAuto (item->row)); - for (auto* item : sortedItems) - { - if (hasPartialFixedPlacement (*item)) - { - if (isFixed (item->column)) - { - const auto p = PlacementHelpers::deduceLineRange (item->column, grid.templateColumns); - const auto columnSpan = std::abs (p.start - p.end); - const auto rowSpan = getSpanFromAuto (item->row); + lastInsertionCell = { 1, 1 }; - const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { p.start, 1 } - : lastInsertionCell; - const auto nextAvailableCell = plane.nextAvailableOnColumn (insertionCell, columnSpan, rowSpan, p.start); - const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan); - lastInsertionCell = nextAvailableCell; - - itemPlacementArray.add ({ item, lineArea }); - } - else if (isFixed (item->row)) + for (auto* item : sortedItems) + { + if (hasAutoPlacement (*item)) { - const auto p = PlacementHelpers::deduceLineRange (item->row, grid.templateRows); const auto columnSpan = getSpanFromAuto (item->column); - const auto rowSpan = std::abs (p.start - p.end); - - const auto insertionCell = hasDenseAutoFlow (grid.autoFlow) ? OccupancyPlane::Cell { 1, p.start } - : lastInsertionCell; + const auto rowSpan = getSpanFromAuto (item->row); - const auto nextAvailableCell = plane.nextAvailableOnRow (insertionCell, columnSpan, rowSpan, p.start); + const auto nextAvailableCell = plane.nextAvailable (lastInsertionCell, columnSpan, rowSpan); const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan); - lastInsertionCell = nextAvailableCell; + if (! hasDenseAutoFlow (grid.autoFlow)) + lastInsertionCell = nextAvailableCell; - itemPlacementArray.add ({ item, lineArea }); + itemPlacementArray.add ({ item, lineArea }); } } - } - // https://www.w3.org/TR/css-grid-1/#auto-placement-algo step 3.3 - for (auto* item : sortedItems) - if (hasAutoPlacement (*item)) - plane.updateMaxCrossDimensionFromAutoPlacementItem (getSpanFromAuto (item->column), getSpanFromAuto (item->row)); - - lastInsertionCell = { 1, 1 }; + return itemPlacementArray; + } - for (auto* item : sortedItems) + //============================================================================== + template + static PlacementHelpers::LineRange findFullLineRange (const ItemPlacementArray& items, Accessor&& accessor) { - if (hasAutoPlacement (*item)) - { - const auto columnSpan = getSpanFromAuto (item->column); - const auto rowSpan = getSpanFromAuto (item->row); + if (items.isEmpty()) + return { 1, 1 }; - const auto nextAvailableCell = plane.nextAvailable (lastInsertionCell, columnSpan, rowSpan); - const auto lineArea = plane.setCell (nextAvailableCell, columnSpan, rowSpan); - - if (! hasDenseAutoFlow (grid.autoFlow)) - lastInsertionCell = nextAvailableCell; + const auto combine = [&accessor] (const auto& acc, const auto& item) + { + const auto newRange = accessor (item); + return PlacementHelpers::LineRange { std::min (acc.start, newRange.start), + std::max (acc.end, newRange.end) }; + }; - itemPlacementArray.add ({ item, lineArea }); - } + return std::accumulate (std::next (items.begin()), items.end(), accessor (*items.begin()), combine); } - return itemPlacementArray; - } + static PlacementHelpers::LineArea findFullLineArea (const ItemPlacementArray& items) + { + return { findFullLineRange (items, [] (const auto& item) { return item.second.column; }), + findFullLineRange (items, [] (const auto& item) { return item.second.row; }) }; + } - //============================================================================== - template - static PlacementHelpers::LineRange findFullLineRange (const ItemPlacementArray& items, Accessor&& accessor) - { - if (items.isEmpty()) - return { 1, 1 }; + template + static Array repeated (int repeats, const Item& item) + { + Array result; + result.insertMultiple (-1, item, repeats); + return result; + } - const auto combine = [&accessor] (const auto& acc, const auto& item) + static Tracks createImplicitTracks (const Grid& grid, const ItemPlacementArray& items) { - const auto newRange = accessor (item); - return PlacementHelpers::LineRange { std::min (acc.start, newRange.start), - std::max (acc.end, newRange.end) }; - }; + const auto fullArea = findFullLineArea (items); - return std::accumulate (std::next (items.begin()), items.end(), accessor (*items.begin()), combine); - } + const auto leadingColumns = std::max (0, 1 - fullArea.column.start); + const auto leadingRows = std::max (0, 1 - fullArea.row.start); - static PlacementHelpers::LineArea findFullLineArea (const ItemPlacementArray& items) - { - return { findFullLineRange (items, [] (const auto& item) { return item.second.column; }), - findFullLineRange (items, [] (const auto& item) { return item.second.row; }) }; - } + const auto trailingColumns = std::max (0, fullArea.column.end - grid.templateColumns.size() - 1); + const auto trailingRows = std::max (0, fullArea.row .end - grid.templateRows .size() - 1); - template - static Array repeated (int repeats, const Item& item) - { - Array result; - result.insertMultiple (-1, item, repeats); - return result; - } + return { { repeated (leadingColumns, grid.autoColumns) + grid.templateColumns + repeated (trailingColumns, grid.autoColumns), + leadingColumns }, + { repeated (leadingRows, grid.autoRows) + grid.templateRows + repeated (trailingRows, grid.autoRows), + leadingRows } }; + } - static Tracks createImplicitTracks (const Grid& grid, const ItemPlacementArray& items) - { - const auto fullArea = findFullLineArea (items); + //============================================================================== + static void applySizeForAutoTracks (Tracks& tracks, const ItemPlacementArray& placements) + { + const auto setSizes = [&placements] (auto& tracksInDirection, const auto& getItem, const auto& getItemSize) + { + auto& array = tracksInDirection.items; - const auto leadingColumns = std::max (0, 1 - fullArea.column.start); - const auto leadingRows = std::max (0, 1 - fullArea.row.start); + for (int index = 0; index < array.size(); ++index) + { + if (array.getReference (index).isAuto()) + { + const auto combiner = [&] (const auto acc, const auto& element) + { + const auto item = getItem (element.second); + const auto isNotSpan = std::abs (item.end - item.start) <= 1; + return isNotSpan && item.start == index + 1 - tracksInDirection.numImplicitLeading + ? std::max (acc, getItemSize (*element.first)) + : acc; + }; + + array.getReference (index).size = std::accumulate (placements.begin(), placements.end(), 0.0f, combiner); + } + } + }; - const auto trailingColumns = std::max (0, fullArea.column.end - grid.templateColumns.size() - 1); - const auto trailingRows = std::max (0, fullArea.row .end - grid.templateRows .size() - 1); + setSizes (tracks.rows, + [] (const auto& i) { return i.row; }, + [] (const auto& i) { return i.height + i.margin.top + i.margin.bottom; }); - return { { repeated (leadingColumns, grid.autoColumns) + grid.templateColumns + repeated (trailingColumns, grid.autoColumns), - leadingColumns }, - { repeated (leadingRows, grid.autoRows) + grid.templateRows + repeated (trailingRows, grid.autoRows), - leadingRows } }; - } + setSizes (tracks.columns, + [] (const auto& i) { return i.column; }, + [] (const auto& i) { return i.width + i.margin.left + i.margin.right; }); + } + }; //============================================================================== - static void applySizeForAutoTracks (Tracks& tracks, const ItemPlacementArray& placements) + struct BoxAlignment { - const auto setSizes = [&placements] (auto& tracksInDirection, const auto& getItem, const auto& getItemSize) + static Rectangle alignItem (const GridItem& item, const Grid& grid, Rectangle area) { - auto& array = tracksInDirection.items; + // if item align is auto, inherit value from grid + const auto alignType = item.alignSelf == GridItem::AlignSelf::autoValue + ? grid.alignItems + : static_cast (item.alignSelf); - for (int index = 0; index < array.size(); ++index) - { - if (array.getReference (index).isAuto()) - { - const auto combiner = [&] (const auto acc, const auto& element) - { - const auto item = getItem (element.second); - const auto isNotSpan = std::abs (item.end - item.start) <= 1; - return isNotSpan && item.start == index + 1 - tracksInDirection.numImplicitLeading - ? std::max (acc, getItemSize (*element.first)) - : acc; - }; - - array.getReference (index).size = std::accumulate (placements.begin(), placements.end(), 0.0f, combiner); - } - } - }; + const auto justifyType = item.justifySelf == GridItem::JustifySelf::autoValue + ? grid.justifyItems + : static_cast (item.justifySelf); - setSizes (tracks.rows, - [] (const auto& i) { return i.row; }, - [] (const auto& i) { return i.height + i.margin.top + i.margin.bottom; }); + // subtract margin from area + area = BorderSize (item.margin.top, item.margin.left, item.margin.bottom, item.margin.right) + .subtractedFrom (area); - setSizes (tracks.columns, - [] (const auto& i) { return i.column; }, - [] (const auto& i) { return i.width + i.margin.left + i.margin.right; }); - } -}; + // align and justify + auto r = area; -//============================================================================== -struct Grid::BoxAlignment -{ - static Rectangle alignItem (const GridItem& item, - const Grid& grid, - Rectangle area) - { - // if item align is auto, inherit value from grid - const auto alignType = item.alignSelf == GridItem::AlignSelf::autoValue - ? grid.alignItems - : static_cast (item.alignSelf); - - const auto justifyType = item.justifySelf == GridItem::JustifySelf::autoValue - ? grid.justifyItems - : static_cast (item.justifySelf); - - // subtract margin from area - area = BorderSize (item.margin.top, item.margin.left, item.margin.bottom, item.margin.right) - .subtractedFrom (area); - - // align and justify - auto r = area; - - if (item.width != (float) GridItem::notAssigned) r.setWidth (item.width); - if (item.height != (float) GridItem::notAssigned) r.setHeight (item.height); - if (item.maxWidth != (float) GridItem::notAssigned) r.setWidth (jmin (item.maxWidth, r.getWidth())); - if (item.minWidth > 0.0f) r.setWidth (jmax (item.minWidth, r.getWidth())); - if (item.maxHeight != (float) GridItem::notAssigned) r.setHeight (jmin (item.maxHeight, r.getHeight())); - if (item.minHeight > 0.0f) r.setHeight (jmax (item.minHeight, r.getHeight())); - - if (alignType == AlignItems::start && justifyType == JustifyItems::start) - return r; + if (! approximatelyEqual (item.width, (float) GridItem::notAssigned)) r.setWidth (item.width); + if (! approximatelyEqual (item.height, (float) GridItem::notAssigned)) r.setHeight (item.height); + if (! approximatelyEqual (item.maxWidth, (float) GridItem::notAssigned)) r.setWidth (jmin (item.maxWidth, r.getWidth())); + if (item.minWidth > 0.0f) r.setWidth (jmax (item.minWidth, r.getWidth())); + if (! approximatelyEqual (item.maxHeight, (float) GridItem::notAssigned)) r.setHeight (jmin (item.maxHeight, r.getHeight())); + if (item.minHeight > 0.0f) r.setHeight (jmax (item.minHeight, r.getHeight())); - if (alignType == AlignItems::end) r.setY (r.getY() + (area.getHeight() - r.getHeight())); - if (justifyType == JustifyItems::end) r.setX (r.getX() + (area.getWidth() - r.getWidth())); - if (alignType == AlignItems::center) r.setCentre (r.getCentreX(), area.getCentreY()); - if (justifyType == JustifyItems::center) r.setCentre (area.getCentreX(), r.getCentreY()); + if (alignType == AlignItems::start && justifyType == JustifyItems::start) + return r; + + if (alignType == AlignItems::end) r.setY (r.getY() + (area.getHeight() - r.getHeight())); + if (justifyType == JustifyItems::end) r.setX (r.getX() + (area.getWidth() - r.getWidth())); + if (alignType == AlignItems::center) r.setCentre (r.getCentreX(), area.getCentreY()); + if (justifyType == JustifyItems::center) r.setCentre (area.getCentreX(), r.getCentreY()); + + return r; + } + }; - return r; - } }; //============================================================================== @@ -1004,7 +1088,7 @@ Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Px sizeInPixels, c } Grid::TrackInfo::TrackInfo (const String& startLineNameToUse, Fr fractionOfFreeSpace, const String& endLineNameToUse) noexcept - : TrackInfo (startLineNameToUse, fractionOfFreeSpace) + : TrackInfo (startLineNameToUse, fractionOfFreeSpace) { endLineName = endLineNameToUse; } @@ -1017,37 +1101,57 @@ float Grid::TrackInfo::getAbsoluteSize (float relativeFractionalUnit) const //============================================================================== void Grid::performLayout (Rectangle targetArea) { - const auto itemsAndAreas = AutoPlacement().deduceAllItems (*this); + const auto itemsAndAreas = Helpers::AutoPlacement().deduceAllItems (*this); - auto implicitTracks = AutoPlacement::createImplicitTracks (*this, itemsAndAreas); + auto implicitTracks = Helpers::AutoPlacement::createImplicitTracks (*this, itemsAndAreas); - AutoPlacement::applySizeForAutoTracks (implicitTracks, itemsAndAreas); + Helpers::AutoPlacement::applySizeForAutoTracks (implicitTracks, itemsAndAreas); - SizeCalculation calculation; - calculation.computeSizes (targetArea.toFloat().getWidth(), - targetArea.toFloat().getHeight(), - columnGap, - rowGap, - implicitTracks); + Helpers::SizeCalculation calculation; + Helpers::SizeCalculation roundedCalculation; - for (auto& itemAndArea : itemsAndAreas) + const auto doComputeSizes = [&] (auto& sizeCalculation) { - const auto a = itemAndArea.second; - const auto areaBounds = PlacementHelpers::getAreaBounds (a.column, - a.row, - implicitTracks, - calculation, - alignContent, - justifyContent, - columnGap, - rowGap); + sizeCalculation.computeSizes (targetArea.toFloat().getWidth(), + targetArea.toFloat().getHeight(), + columnGap, + rowGap, + implicitTracks); + }; + doComputeSizes (calculation); + doComputeSizes (roundedCalculation); + + for (auto& itemAndArea : itemsAndAreas) + { auto* item = itemAndArea.first; - item->currentBounds = BoxAlignment::alignItem (*item, *this, areaBounds) - + targetArea.toFloat().getPosition(); + + const auto getBounds = [&] (const auto& sizeCalculation) + { + const auto a = itemAndArea.second; + + const auto areaBounds = Helpers::PlacementHelpers::getAreaBounds (a.column, + a.row, + implicitTracks, + sizeCalculation, + alignContent, + justifyContent); + + const auto rounded = [&] (auto rect) -> decltype (rect) + { + return { sizeCalculation.roundingFunction (rect.getX()), + sizeCalculation.roundingFunction (rect.getY()), + sizeCalculation.roundingFunction (rect.getWidth()), + sizeCalculation.roundingFunction (rect.getHeight()) }; + }; + + return rounded (Helpers::BoxAlignment::alignItem (*item, *this, areaBounds)); + }; + + item->currentBounds = getBounds (calculation) + targetArea.toFloat().getPosition(); if (auto* c = item->associatedComponent) - c->setBounds (item->currentBounds.getSmallestIntegerContainer()); + c->setBounds (getBounds (roundedCalculation).toNearestIntEdges() + targetArea.getPosition()); } } @@ -1355,6 +1459,177 @@ struct GridTests : public UnitTest expect (grid.items[1].currentBounds == Rect (420.0f, 70.0f, 60.0f, 70.0f)); expect (grid.items[2].currentBounds == Rect (200.0f, 330.0f, 200.0f, 70.0f)); } + + { + beginTest ("Items with specified sizes should translate to correctly rounded Component dimensions"); + + static constexpr int targetSize = 100; + + juce::Component component; + juce::GridItem item { component }; + item.alignSelf = juce::GridItem::AlignSelf::center; + item.justifySelf = juce::GridItem::JustifySelf::center; + item.width = (float) targetSize; + item.height = (float) targetSize; + + juce::Grid grid; + grid.templateColumns = { juce::Grid::Fr { 1 } }; + grid.templateRows = { juce::Grid::Fr { 1 } }; + grid.items = { item }; + + for (int totalSize = 100 - 20; totalSize < 100 + 20; ++totalSize) + { + Rectangle bounds { 0, 0, totalSize, totalSize }; + grid.performLayout (bounds); + + expectEquals (component.getWidth(), targetSize); + expectEquals (component.getHeight(), targetSize); + } + } + + { + beginTest ("Track sizes specified in Px should translate to correctly rounded Component dimensions"); + + static constexpr int targetSize = 100; + + juce::Component component; + juce::GridItem item { component }; + item.alignSelf = juce::GridItem::AlignSelf::center; + item.justifySelf = juce::GridItem::JustifySelf::center; + item.setArea (1, 3); + + juce::Grid grid; + grid.templateColumns = { juce::Grid::Fr { 1 }, + juce::Grid::Fr { 1 }, + juce::Grid::Px { targetSize }, + juce::Grid::Fr { 1 } }; + grid.templateRows = { juce::Grid::Fr { 1 } }; + grid.items = { item }; + + for (int totalSize = 100 - 20; totalSize < 100 + 20; ++totalSize) + { + Rectangle bounds { 0, 0, totalSize, totalSize }; + grid.performLayout (bounds); + + expectEquals (component.getWidth(), targetSize); + } + } + + { + beginTest ("Evaluate invariants on randomised Grid layouts"); + + struct Solution + { + Grid grid; + std::deque components; + int absoluteWidth; + Rectangle bounds; + }; + + auto createSolution = [this] (int numColumns, + float probabilityOfFractionalColumn, + Rectangle bounds) -> Solution + { + auto random = getRandom(); + + Grid grid; + grid.templateRows = { Grid::Fr { 1 } }; + + // Ensuring that the sum of absolute item widths never exceed total width + const auto widthOfAbsolute = (int) ((float) bounds.getWidth() / (float) (numColumns + 1)); + + for (int i = 0; i < numColumns; ++i) + { + if (random.nextFloat() < probabilityOfFractionalColumn) + grid.templateColumns.add (Grid::Fr { 1 }); + else + grid.templateColumns.add (Grid::Px { widthOfAbsolute }); + } + + std::deque itemComponents (static_cast (grid.templateColumns.size())); + + for (auto& c : itemComponents) + grid.items.add (GridItem { c }); + + grid.performLayout (bounds); + + return { std::move (grid), std::move (itemComponents), widthOfAbsolute, bounds }; + }; + + const auto getFractionalComponentWidths = [] (const Solution& solution) + { + std::vector result; + + for (int i = 0; i < solution.grid.templateColumns.size(); ++i) + if (solution.grid.templateColumns[i].isFractional()) + result.push_back (solution.components[(size_t) i].getWidth()); + + return result; + }; + + const auto getAbsoluteComponentWidths = [] (const Solution& solution) + { + std::vector result; + + for (int i = 0; i < solution.grid.templateColumns.size(); ++i) + if (! solution.grid.templateColumns[i].isFractional()) + result.push_back (solution.components[(size_t) i].getWidth()); + + return result; + }; + + const auto evaluateInvariants = [&] (const Solution& solution) + { + const auto fractionalWidths = getFractionalComponentWidths (solution); + + if (! fractionalWidths.empty()) + { + const auto [min, max] = std::minmax_element (fractionalWidths.begin(), + fractionalWidths.end()); + expectLessOrEqual (*max - *min, 1, "Fr { 1 } items are expected to share the " + "rounding errors equally and hence couldn't " + "deviate in size by more than 1 px"); + } + + const auto absoluteWidths = getAbsoluteComponentWidths (solution); + + for (const auto& w : absoluteWidths) + expectEquals (w, solution.absoluteWidth, "Sizes specified in absolute dimensions should " + "be preserved"); + + Rectangle unionOfComponentBounds; + + for (const auto& c : solution.components) + unionOfComponentBounds = unionOfComponentBounds.getUnion (c.getBoundsInParent()); + + if ((size_t) solution.grid.templateColumns.size() == absoluteWidths.size()) + expect (solution.bounds.contains (unionOfComponentBounds), "Non-oversized absolute Components " + "should never be placed outside the " + "provided bounds."); + else + expect (unionOfComponentBounds == solution.bounds, "With fractional items, positioned items " + "should cover the provided bounds exactly"); + }; + + const auto knownPreviousBad = createSolution (5, 1.0f, Rectangle { 0, 0, 600, 200 }.reduced (16)); + evaluateInvariants (knownPreviousBad); + + auto random = getRandom(); + + for (int i = 0; i < 1000; ++i) + { + const auto numColumns = random.nextInt (Range { 1, 26 }); + const auto probabilityOfFractionalColumn = random.nextFloat(); + const auto bounds = Rectangle { random.nextInt (Range { 0, 3 }), + random.nextInt (Range { 0, 3 }), + random.nextInt (Range { 300, 1200 }), + random.nextInt (Range { 100, 500 }) } + .reduced (random.nextInt (Range { 0, 16 })); + + const auto randomSolution = createSolution (numColumns, probabilityOfFractionalColumn, bounds); + evaluateInvariants (randomSolution); + } + } } }; diff --git a/modules/juce_gui_basics/layout/juce_Grid.h b/modules/juce_gui_basics/layout/juce_Grid.h index ce261d2199c2..437f4657ff29 100644 --- a/modules/juce_gui_basics/layout/juce_Grid.h +++ b/modules/juce_gui_basics/layout/juce_Grid.h @@ -156,9 +156,6 @@ class JUCE_API Grid final /** Creates an empty Grid container with default parameters. */ Grid() = default; - /** Destructor */ - ~Grid() noexcept = default; - //============================================================================== /** Specifies the alignment of content inside the items along the rows. */ JustifyItems justifyItems = JustifyItems::stretch; @@ -216,10 +213,7 @@ class JUCE_API Grid final private: //============================================================================== - struct SizeCalculation; - struct PlacementHelpers; - struct AutoPlacement; - struct BoxAlignment; + struct Helpers; }; constexpr Grid::Px operator"" _px (long double px) { return Grid::Px { px }; } diff --git a/modules/juce_gui_basics/layout/juce_GroupComponent.h b/modules/juce_gui_basics/layout/juce_GroupComponent.h index e45b15f9204e..31b343776797 100644 --- a/modules/juce_gui_basics/layout/juce_GroupComponent.h +++ b/modules/juce_gui_basics/layout/juce_GroupComponent.h @@ -98,10 +98,10 @@ class JUCE_API GroupComponent : public Component void enablementChanged() override; /** @internal */ void colourChanged() override; - -private: + /** @internal */ std::unique_ptr createAccessibilityHandler() override; +private: String text; Justification justification; diff --git a/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp b/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp index 36fcbf343de0..b835c270e361 100644 --- a/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp +++ b/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp @@ -125,6 +125,10 @@ void ResizableBorderComponent::mouseDown (const MouseEvent& e) originalBounds = component->getBounds(); + if (auto* peer = component->getPeer()) + if (&peer->getComponent() == component) + peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), mouseZone); + if (constrainer != nullptr) constrainer->resizeStart(); } diff --git a/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.h b/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.h index bdab8b985e82..fc3c989c0ec2 100644 --- a/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.h +++ b/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.h @@ -125,7 +125,7 @@ class JUCE_API ResizableBorderComponent : public Component /** Returns an appropriate mouse-cursor for this resize zone. */ MouseCursor getMouseCursor() const noexcept; - /** Returns true if dragging this zone will move the enire object without resizing it. */ + /** Returns true if dragging this zone will move the entire object without resizing it. */ bool isDraggingWholeObject() const noexcept { return zone == centre; } /** Returns true if dragging this zone will move the object's left edge. */ bool isDraggingLeftEdge() const noexcept { return (zone & left) != 0; } diff --git a/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp b/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp index 83535a078336..8bcd024d3d15 100644 --- a/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp +++ b/modules/juce_gui_basics/layout/juce_ResizableCornerComponent.cpp @@ -45,7 +45,7 @@ void ResizableCornerComponent::paint (Graphics& g) isMouseButtonDown()); } -void ResizableCornerComponent::mouseDown (const MouseEvent&) +void ResizableCornerComponent::mouseDown (const MouseEvent& e) { if (component == nullptr) { @@ -55,6 +55,13 @@ void ResizableCornerComponent::mouseDown (const MouseEvent&) originalBounds = component->getBounds(); + using Zone = ResizableBorderComponent::Zone; + const Zone zone { Zone::bottom | Zone::right }; + + if (auto* peer = component->getPeer()) + if (&peer->getComponent() == component) + peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), zone); + if (constrainer != nullptr) constrainer->resizeStart(); } diff --git a/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.cpp b/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.cpp index 8629e5fc1fb2..85f164048078 100644 --- a/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.cpp +++ b/modules/juce_gui_basics/layout/juce_ResizableEdgeComponent.cpp @@ -52,7 +52,7 @@ void ResizableEdgeComponent::paint (Graphics& g) isMouseOver(), isMouseButtonDown()); } -void ResizableEdgeComponent::mouseDown (const MouseEvent&) +void ResizableEdgeComponent::mouseDown (const MouseEvent& e) { if (component == nullptr) { @@ -62,6 +62,25 @@ void ResizableEdgeComponent::mouseDown (const MouseEvent&) originalBounds = component->getBounds(); + using Zone = ResizableBorderComponent::Zone; + + const Zone zone { [&] + { + switch (edge) + { + case Edge::leftEdge: return Zone::left; + case Edge::rightEdge: return Zone::right; + case Edge::topEdge: return Zone::top; + case Edge::bottomEdge: return Zone::bottom; + } + + return Zone::centre; + }() }; + + if (auto* peer = component->getPeer()) + if (&peer->getComponent() == component) + peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), zone); + if (constrainer != nullptr) constrainer->resizeStart(); } diff --git a/modules/juce_gui_basics/layout/juce_ScrollBar.h b/modules/juce_gui_basics/layout/juce_ScrollBar.h index a6d94185a795..1c151ff5a5e0 100644 --- a/modules/juce_gui_basics/layout/juce_ScrollBar.h +++ b/modules/juce_gui_basics/layout/juce_ScrollBar.h @@ -414,6 +414,8 @@ class JUCE_API ScrollBar : public Component, void parentHierarchyChanged() override; /** @internal */ void setVisible (bool) override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: //============================================================================== @@ -427,7 +429,6 @@ class JUCE_API ScrollBar : public Component, std::unique_ptr upButton, downButton; ListenerList listeners; - std::unique_ptr createAccessibilityHandler() override; void handleAsyncUpdate() override; void updateThumbPosition(); void timerCallback() override; diff --git a/modules/juce_gui_basics/layout/juce_SidePanel.h b/modules/juce_gui_basics/layout/juce_SidePanel.h index 59395f10dd1f..a425bb9d3959 100644 --- a/modules/juce_gui_basics/layout/juce_SidePanel.h +++ b/modules/juce_gui_basics/layout/juce_SidePanel.h @@ -195,6 +195,8 @@ class SidePanel : public Component, void mouseDrag (const MouseEvent&) override; /** @internal */ void mouseUp (const MouseEvent&) override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; private: //============================================================================== @@ -221,7 +223,6 @@ class SidePanel : public Component, bool shouldShowDismissButton = true; //============================================================================== - std::unique_ptr createAccessibilityHandler() override; void lookAndFeelChanged() override; void componentMovedOrResized (Component&, bool wasMoved, bool wasResized) override; void changeListenerCallback (ChangeBroadcaster*) override; diff --git a/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.cpp b/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.cpp index 4505a179f767..368e2cba633f 100644 --- a/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.cpp +++ b/modules/juce_gui_basics/layout/juce_StretchableLayoutManager.cpp @@ -336,7 +336,7 @@ int StretchableLayoutManager::sizeToRealSize (double size, int totalSpace) if (size < 0) size *= -totalSpace; - return roundToInt (size); + return roundToInt (jmax (1.0, size)); } } // namespace juce diff --git a/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h b/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h index c4ab1a434953..5d52af15c908 100644 --- a/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h +++ b/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h @@ -334,6 +334,8 @@ class JUCE_API TabbedButtonBar : public Component, void resized() override; /** @internal */ void lookAndFeelChanged() override; + /** @internal */ + std::unique_ptr createAccessibilityHandler() override; protected: //============================================================================== @@ -362,7 +364,6 @@ class JUCE_API TabbedButtonBar : public Component, std::unique_ptr behindFrontTab; std::unique_ptr