From 693ab9eb160909fc6f1fb6dd9297c97aef2fc2a3 Mon Sep 17 00:00:00 2001 From: Anjal Doshi Date: Fri, 14 Jun 2024 18:27:08 -0700 Subject: [PATCH] Merge latest stable JUCE 8 JUCE repo commit SHA: 4e106a76e834f701858328af3dade2b388669b84 --- JuceLibraryCode/include_juce_core.cpp | 1 + .../buffers/juce_AudioChannelSet.cpp | 155 ++--- .../buffers/juce_AudioChannelSet.h | 64 +- .../native/juce_CoreAudio_mac.cpp | 13 +- .../format_types/VST3_SDK/LICENSE.txt | 2 +- .../format_types/VST3_SDK/README.md | 24 +- .../VST3_SDK/VST3_License_Agreement.pdf | Bin 135822 -> 196498 bytes .../format_types/VST3_SDK/base/LICENSE.txt | 2 +- .../VST3_SDK/base/source/baseiids.cpp | 2 +- .../base/source/classfactoryhelpers.h | 2 +- .../VST3_SDK/base/source/fbuffer.cpp | 2 +- .../VST3_SDK/base/source/fbuffer.h | 2 +- .../VST3_SDK/base/source/fcommandline.h | 580 +++++++++--------- .../VST3_SDK/base/source/fdebug.cpp | 2 +- .../VST3_SDK/base/source/fdebug.h | 2 +- .../VST3_SDK/base/source/fobject.cpp | 2 +- .../VST3_SDK/base/source/fobject.h | 66 +- .../VST3_SDK/base/source/fstreamer.cpp | 6 +- .../VST3_SDK/base/source/fstreamer.h | 2 +- .../VST3_SDK/base/source/fstring.cpp | 5 +- .../VST3_SDK/base/source/fstring.h | 2 +- .../VST3_SDK/base/source/updatehandler.cpp | 7 +- .../VST3_SDK/base/source/updatehandler.h | 2 +- .../VST3_SDK/base/thread/include/flock.h | 9 +- .../VST3_SDK/base/thread/source/flock.cpp | 10 +- .../VST3_SDK/pluginterfaces/LICENSE.txt | 2 +- .../VST3_SDK/pluginterfaces/base/coreiids.cpp | 2 +- .../VST3_SDK/pluginterfaces/base/fplatform.h | 4 + .../VST3_SDK/pluginterfaces/base/fstrdefs.h | 2 +- .../VST3_SDK/pluginterfaces/base/ftypes.h | 2 +- .../pluginterfaces/base/smartpointer.h | 4 +- .../VST3_SDK/pluginterfaces/gui/iplugview.h | 6 +- .../pluginterfaces/vst/ivstaudioprocessor.h | 7 +- .../pluginterfaces/vst/ivstdataexchange.h | 221 +++++++ .../pluginterfaces/vst/ivsteditcontroller.h | 61 +- .../pluginterfaces/vst/ivstremapparamid.h | 75 +++ .../VST3_SDK/pluginterfaces/vst/vstspeaker.h | 74 ++- .../VST3_SDK/pluginterfaces/vst/vsttypes.h | 23 +- .../VST3_SDK/public.sdk/LICENSE.txt | 2 +- .../VST3_SDK/public.sdk/README.md | 1 - .../moduleinfotool/source/main.cpp | 24 +- .../public.sdk/source/common/memorystream.cpp | 2 +- .../public.sdk/source/common/memorystream.h | 2 +- .../public.sdk/source/common/pluginview.cpp | 3 +- .../public.sdk/source/common/pluginview.h | 5 +- .../public.sdk/source/common/readfile.cpp | 7 +- .../public.sdk/source/common/readfile.h | 1 - .../source/vst/hosting/hostclasses.cpp | 2 +- .../source/vst/hosting/hostclasses.h | 2 +- .../public.sdk/source/vst/hosting/module.cpp | 2 +- .../public.sdk/source/vst/hosting/module.h | 2 +- .../source/vst/hosting/module_linux.cpp | 2 +- .../source/vst/hosting/module_mac.mm | 9 +- .../source/vst/hosting/module_win32.cpp | 2 +- .../vst/hosting/pluginterfacesupport.cpp | 2 +- .../source/vst/hosting/pluginterfacesupport.h | 2 +- .../source/vst/moduleinfo/jsoncxx.h | 2 +- .../source/vst/moduleinfo/moduleinfo.h | 2 +- .../vst/moduleinfo/moduleinfocreator.cpp | 2 +- .../source/vst/moduleinfo/moduleinfocreator.h | 2 +- .../vst/moduleinfo/moduleinfoparser.cpp | 2 +- .../source/vst/moduleinfo/moduleinfoparser.h | 2 +- .../public.sdk/source/vst/utility/optional.h | 4 +- .../source/vst/utility/stringconvert.cpp | 2 +- .../source/vst/utility/stringconvert.h | 4 +- .../public.sdk/source/vst/utility/uid.h | 14 +- .../VST3_SDK/public.sdk/source/vst/vstbus.cpp | 2 +- .../VST3_SDK/public.sdk/source/vst/vstbus.h | 2 +- .../public.sdk/source/vst/vstcomponent.cpp | 2 +- .../public.sdk/source/vst/vstcomponent.h | 2 +- .../source/vst/vstcomponentbase.cpp | 2 +- .../public.sdk/source/vst/vstcomponentbase.h | 2 +- .../source/vst/vsteditcontroller.cpp | 2 +- .../public.sdk/source/vst/vsteditcontroller.h | 2 +- .../public.sdk/source/vst/vstinitiids.cpp | 13 +- .../public.sdk/source/vst/vstparameters.cpp | 4 +- .../public.sdk/source/vst/vstparameters.h | 4 +- .../public.sdk/source/vst/vstpresetfile.cpp | 2 +- .../public.sdk/source/vst/vstpresetfile.h | 2 +- .../format_types/juce_AU_Shared.h | 17 +- .../juce_AudioUnitPluginFormat.mm | 239 ++++---- .../format_types/juce_VST3Common.h | 20 +- .../format_types/juce_VST3PluginFormat.cpp | 71 ++- .../juce_VST3PluginFormat_test.cpp | 86 ++- .../utilities/juce_ParameterAttachments.cpp | 3 + .../juce_core/containers/juce_ListenerList.h | 81 ++- .../juce_core/javascript/juce_Javascript.cpp | 10 +- .../juce_core/juce_core_CompilationTime.cpp | 41 ++ .../juce_core/misc/juce_OptionsHelpers.h | 4 + .../modules/juce_core/threads/juce_Thread.h | 2 +- .../juce_core/threads/juce_ThreadPool.h | 2 +- .../modules/juce_core/time/juce_Time.cpp | 8 +- .../values/juce_ValueTree.cpp | 20 +- .../modules/juce_events/timers/juce_Timer.cpp | 2 +- .../modules/juce_graphics/fonts/juce_Font.cpp | 123 +++- .../juce_graphics/fonts/juce_FontOptions.h | 32 +- .../fonts/juce_FunctionPointerDestructor.h | 4 + .../fonts/juce_JustifiedText.cpp | 1 - .../juce_graphics/fonts/juce_LruCache.h | 4 + .../fonts/juce_SimpleShapedText.cpp | 40 +- .../juce_graphics/fonts/juce_Typeface.h | 9 + .../fonts/juce_TypefaceFileCache.h | 4 + .../juce_graphics/juce_graphics_Harfbuzz.cpp | 2 + .../juce_Direct2DGraphicsContext_windows.cpp | 106 ++-- .../juce_gui_basics/desktop/juce_Desktop.cpp | 2 +- .../juce_gui_basics/juce_gui_basics.cpp | 2 - .../native/juce_Windowing_windows.cpp | 425 +++++-------- .../juce_gui_basics/widgets/juce_Slider.cpp | 5 +- .../juce_gui_basics/widgets/juce_Slider.h | 2 + .../windows/juce_DocumentWindow.cpp | 6 +- .../windows/juce_ResizableWindow.cpp | 5 +- .../modules/juce_gui_extra/juce_gui_extra.h | 1 + .../misc/juce_WebBrowserComponent.h | 48 ++ .../juce_WebControlParameterIndexReceiver.h | 76 +++ .../misc/juce_WebControlRelays.h | 6 + .../juce_gui_extra/native/javascript/index.js | 71 +++ .../native/juce_WebBrowserComponent_linux.cpp | 31 +- .../native/juce_WebBrowserComponent_mac.mm | 45 +- 118 files changed, 2105 insertions(+), 1147 deletions(-) create mode 100644 JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstdataexchange.h create mode 100644 JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstremapparamid.h create mode 100644 JuceLibraryCode/modules/juce_core/juce_core_CompilationTime.cpp create mode 100644 JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlParameterIndexReceiver.h diff --git a/JuceLibraryCode/include_juce_core.cpp b/JuceLibraryCode/include_juce_core.cpp index 862edad7da..18fa68e1a4 100644 --- a/JuceLibraryCode/include_juce_core.cpp +++ b/JuceLibraryCode/include_juce_core.cpp @@ -7,3 +7,4 @@ #include "AppConfig.h" #include +#include diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp index 807fcf7f5f..de6e79d913 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.cpp @@ -421,44 +421,48 @@ AudioChannelSet AudioChannelSet::fromAbbreviatedString (const String& str) String AudioChannelSet::getDescription() const { - if (isDiscreteLayout()) return "Discrete #" + String (size()); - if (*this == disabled()) return "Disabled"; - if (*this == mono()) return "Mono"; - if (*this == stereo()) return "Stereo"; - - if (*this == createLCR()) return "LCR"; - if (*this == createLRS()) return "LRS"; - 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"; - if (*this == create6point0()) return "6.0 Surround"; - if (*this == create6point1()) return "6.1 Surround"; - if (*this == create6point0Music()) return "6.0 (Music) Surround"; - if (*this == create6point1Music()) return "6.1 (Music) Surround"; - if (*this == create7point0()) return "7.0 Surround"; - if (*this == create7point1()) return "7.1 Surround"; - if (*this == create7point0SDDS()) return "7.0 Surround SDDS"; - 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"; - if (*this == pentagonal()) return "Pentagonal"; - if (*this == hexagonal()) return "Hexagonal"; - if (*this == octagonal()) return "Octagonal"; + if (isDiscreteLayout()) return "Discrete #" + String (size()); + if (*this == disabled()) return "Disabled"; + if (*this == mono()) return "Mono"; + if (*this == stereo()) return "Stereo"; + + if (*this == createLCR()) return "LCR"; + if (*this == createLRS()) return "LRS"; + 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"; + if (*this == create6point0()) return "6.0 Surround"; + if (*this == create6point1()) return "6.1 Surround"; + if (*this == create6point0Music()) return "6.0 (Music) Surround"; + if (*this == create6point1Music()) return "6.1 (Music) Surround"; + if (*this == create7point0()) return "7.0 Surround"; + if (*this == create7point1()) return "7.1 Surround"; + if (*this == create7point0SDDS()) return "7.0 Surround SDDS"; + 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 (Atmos)"; + if (*this == create9point1point4()) return "9.1.4 Surround (Atmos)"; + if (*this == create9point0point6()) return "9.0.6 Surround (Atmos)"; + if (*this == create9point1point6()) return "9.1.6 Surround (Atmos)"; + if (*this == create9point0point4ITU()) return "9.0.4 Surround (ITU)"; + if (*this == create9point1point4ITU()) return "9.1.4 Surround (ITU)"; + if (*this == create9point0point6ITU()) return "9.0.6 Surround (ITU)"; + if (*this == create9point1point6ITU()) return "9.1.6 Surround (ITU)"; + + if (*this == quadraphonic()) return "Quadraphonic"; + if (*this == pentagonal()) return "Pentagonal"; + if (*this == hexagonal()) return "Hexagonal"; + if (*this == octagonal()) return "Octagonal"; // ambisonics { @@ -546,40 +550,44 @@ void AudioChannelSet::removeChannel (ChannelType newChannel) channels.clearBit (bit); } -AudioChannelSet AudioChannelSet::disabled() { return {}; } -AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet ({ centre }); } -AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ({ left, right }); } -AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ({ left, right, centre }); } -AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ({ left, right, surround }); } -AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ({ left, right, centre, surround }); } -AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround }); } -AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround }); } -AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround }); } -AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, centreSurround }); } -AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ({ left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } -AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ({ left, right, LFE, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } -AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } -AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre }); } -AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } -AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre }); } -AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ({ left, right, leftSurround, rightSurround }); } -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::disabled() { return {}; } +AudioChannelSet AudioChannelSet::mono() { return AudioChannelSet ({ centre }); } +AudioChannelSet AudioChannelSet::stereo() { return AudioChannelSet ({ left, right }); } +AudioChannelSet AudioChannelSet::createLCR() { return AudioChannelSet ({ left, right, centre }); } +AudioChannelSet AudioChannelSet::createLRS() { return AudioChannelSet ({ left, right, surround }); } +AudioChannelSet AudioChannelSet::createLCRS() { return AudioChannelSet ({ left, right, centre, surround }); } +AudioChannelSet AudioChannelSet::create5point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround }); } +AudioChannelSet AudioChannelSet::create5point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround }); } +AudioChannelSet AudioChannelSet::create6point0() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, centreSurround }); } +AudioChannelSet AudioChannelSet::create6point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, centreSurround }); } +AudioChannelSet AudioChannelSet::create6point0Music() { return AudioChannelSet ({ left, right, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } +AudioChannelSet AudioChannelSet::create6point1Music() { return AudioChannelSet ({ left, right, LFE, leftSurround, rightSurround, leftSurroundSide, rightSurroundSide }); } +AudioChannelSet AudioChannelSet::create7point0() { return AudioChannelSet ({ left, right, centre, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::create7point0SDDS() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre }); } +AudioChannelSet AudioChannelSet::create7point1() { return AudioChannelSet ({ left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear }); } +AudioChannelSet AudioChannelSet::create7point1SDDS() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre }); } +AudioChannelSet AudioChannelSet::quadraphonic() { return AudioChannelSet ({ left, right, leftSurround, rightSurround }); } +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::create9point0point4ITU() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point1point4ITU() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight }); } +AudioChannelSet AudioChannelSet::create9point0point6ITU() { return AudioChannelSet ({ left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight, topSideLeft, topSideRight }); } +AudioChannelSet AudioChannelSet::create9point1point6ITU() { return AudioChannelSet ({ left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight, topSideLeft, topSideRight }); } AudioChannelSet AudioChannelSet::ambisonic (int order) { @@ -705,7 +713,8 @@ Array AudioChannelSet::channelSetsWithNumberOfChannels (int num case 14: return { AudioChannelSet::create7point1point6() }; case 16: - return { AudioChannelSet::create9point1point6() }; + return { AudioChannelSet::create9point1point6(), + AudioChannelSet::create9point1point6ITU() }; } return {}; diff --git a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h index 8da151d79b..411726731a 100644 --- a/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h +++ b/JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioChannelSet.h @@ -268,36 +268,74 @@ class JUCE_API AudioChannelSet */ 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). + /** Creates a set for a 9.0.4 Atmos 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). + Is equivalent to: k90_4_W (VST3), AAX_eStemFormat_9_0_4 (AAX). + + @see create9point0point4ITU() */ 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). + /** Creates a set for a 9.1.4 Atmos surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topRearLeft, topRearRight). + + Is equivalent to: k91_4_W (VST3), AAX_eStemFormat_9_1_4 (AAX). - Is equivalent to: k91_4 (VST3), AAX_eStemFormat_9_1_4 (AAX). + @see create9point1point4ITU() */ 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). + /** Creates a set for a 9.0.6 Atmos 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). + Is equivalent to: k90_6_W (VST3), AAX_eStemFormat_9_0_6 (AAX). + + @see create9point0point6ITU() */ 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). + /** Creates a set for a 9.1.6 Atmos surround setup (left, right, centre, LFE, leftSurroundSide, rightSurroundSide, leftSurroundRear, rightSurroundRear, wideLeft, wideRight, topFrontLeft, topFrontRight, topSideLeft, topSideRight, topRearLeft, topRearRight). + + Older versions of the VST3 SDK only supported ITU versions of the 9.0.4, 9.1.4, 9.0.6, and + 9.1.6 layouts, which have the front-channel ordering "L Lc C Rc R". + To maintain the correct relative channel ordering, JUCE would perform the following mapping: + L -> wideLeft, Lc -> left, Rc -> right, R -> wideRight - Note that the VST3 layout arranges the front speakers "L Lc C Rc R", but the JUCE layout - uses the arrangement "wideLeft left centre right wideRight". To maintain the relative - positions of the speakers, the channels will be remapped accordingly. This means that the - VST3 host's "L" channel will be received on a JUCE plugin's "wideLeft" channel, the - "Lc" channel will be received on a JUCE plugin's "left" channel, and so on. + The version of the VST3 SDK bundled with JUCE now supports Atmos versions of the above + layouts, which have the front-channel ordering "Lw L C R Rw". This order matches the + JUCE ordering, so no remapping is required. - Is equivalent to: k91_6 (VST3), kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio). + create9point0point4(), create9point1point4(), create9point0point6(), and + create9point1point6() now correspond to the VST3 k90_4_W, k91_4_W, k90_6_W, and k91_6_W + Atmos layouts respectively. + + If you need to support the old ITU layouts, use create9point0point4ITU(), + create9point1point4ITU(), create9point0point6ITU(), and create9point1point6ITU() instead. + + Is equivalent to: k91_6_W (VST3), kAudioChannelLayoutTag_Atmos_9_1_6 (CoreAudio). + + @see create9point1point6ITU() */ static AudioChannelSet JUCE_CALLTYPE create9point1point6(); + /** Creates a set for a 9.0.4 ITU surround setup: + left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight + */ + static AudioChannelSet JUCE_CALLTYPE create9point0point4ITU(); + + /** Creates a set for a 9.1.4 ITU surround setup. + left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight + */ + static AudioChannelSet JUCE_CALLTYPE create9point1point4ITU(); + + /** Creates a set for a 9.0.6 ITU surround setup. + left, right, centre, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight, topSideLeft, topSideRight + */ + static AudioChannelSet JUCE_CALLTYPE create9point0point6ITU(); + + /** Creates a set for a 9.1.6 ITU surround setup. + left, right, centre, LFE, leftSurround, rightSurround, leftCentre, rightCentre, leftSurroundSide, rightSurroundSide, topFrontLeft, topFrontRight, topRearLeft, topRearRight, topSideLeft, topSideRight + */ + static AudioChannelSet JUCE_CALLTYPE create9point1point6ITU(); + //============================================================================== /** Creates a set for quadraphonic surround setup (left, right, leftSurround, rightSurround) diff --git a/JuceLibraryCode/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp b/JuceLibraryCode/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp index 78db3ac5cd..261edd2295 100644 --- a/JuceLibraryCode/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp +++ b/JuceLibraryCode/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp @@ -1051,7 +1051,7 @@ class CoreAudioInternal final : private Timer, CoreAudioIODevice& owner; int bitDepth = 32; - int xruns = 0; + std::atomic xruns = 0; Array sampleRates; Array bufferSizes; AudioDeviceID deviceID; @@ -1159,7 +1159,7 @@ class CoreAudioInternal final : private Timer, return x.mSelector == kAudioDeviceProcessorOverload; }); - intern.xruns += xruns; + intern.xruns += (int) xruns; const auto detailsChanged = std::any_of (pa, pa + numAddresses, [] (const AudioObjectPropertyAddress& x) { @@ -1325,6 +1325,8 @@ class CoreAudioIODevice final : public AudioIODevice, void start (AudioIODeviceCallback* callback) override { + const ScopedLock sl (startStopLock); + if (internal->start (callback)) pendingCallback = nullptr; } @@ -1332,12 +1334,14 @@ class CoreAudioIODevice final : public AudioIODevice, void stop() override { stopAndGetLastCallback(); + + const ScopedLock sl (startStopLock); pendingCallback = nullptr; } void stopWithPendingCallback() { - const ScopedLock sl (closeLock); + const ScopedLock sl (startStopLock); if (pendingCallback == nullptr) pendingCallback = stopAndGetLastCallback(); @@ -1399,7 +1403,7 @@ class CoreAudioIODevice final : public AudioIODevice, AudioIODeviceCallback* pendingCallback = nullptr; AsyncRestarter* restarter = nullptr; BigInteger inputChannelsRequested, outputChannelsRequested; - CriticalSection closeLock; + CriticalSection startStopLock; AudioIODeviceCallback* stopAndGetLastCallback() const { @@ -1424,6 +1428,7 @@ class CoreAudioIODevice final : public AudioIODevice, getCurrentSampleRate(), getCurrentBufferSizeSamples()); + const ScopedLock sl { startStopLock }; start (pendingCallback); } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt index 6daa072e68..f5df1de438 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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 diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/README.md b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/README.md index 191fe79948..3befbc0642 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/README.md +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/README.md @@ -19,10 +19,10 @@ - VST 3 API - VST 3 Implementation Helper Classes -- AAX, AU, AUv3 and VST 2 wrappers +- AAX, AUv3 and AU Wrappers - VST 3 plug-ins Examples -The full VST 3 SDK is available [here!](https://www.steinberg.net/en/company/developers.html). It contains : +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. @@ -146,25 +146,6 @@ Some more features implemented specifically for developers include: 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): @@ -192,6 +173,7 @@ msbuild.exe vstsdk.sln // (or alternatively for example for release) cmake --build . --config Release ``` +Note: If you have any issue with symbolic links, check [Preparation on Windows](https://steinbergmedia.github.io/vst3_dev_portal/pages/Getting+Started/Preparation+on+Windows.html) for potential solutions. ### Build the examples on macOS diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/VST3_License_Agreement.pdf index ad8c399b48ea9a2c29ff06d8457a76abe6c5fdfc..ec7da498273fddabadaec5a88e8fb1243c71196d 100644 GIT binary patch literal 196498 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

IYirsE16SCmu3^wVOxEX#Jq^jEfJ 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 Rk{?!F0Y}}saS8E`{|A76o$3Gp delta 109714 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%0D;~|B~GTZ#V(S z*H~4s+AxV0@!vs4LbQFdDPC#u72)xWhJgv8d+ARlKZJ%xE&nJ50=E+@7~7}T`6%+3 zW~SvZylz%W(DwyN)LqIz^>S5la7NGaMi@R0e-C5BYK736TtmXQ7m7xUCcNK-^1cYW zf?U;O{<@{%Zf#U%mIAIEm$z$gZ(&HTL=Kq_zI&_mMyY~U1wK@cETOUFv?M)1%&Z2d z9vSA)S^qa81_h4!zvrl!895l!Z(o7Yp#BdNhK2FJY;z5{Xc7*@o)3*vUc=fd>HK-t z_A7TudlXnMS}wA6K|>UChPMwdvX;%~lFcTYu$-VmyUNm+^FuW$_q6HVY>dO0rnn|3 zGEMmbQw4SjW&{7t&qvemElwR@C)FaE^%{iU&t9kz^5nHm(vjC3+IdbLi~uu!K42;e z3}-K#FbVMSUm z5CIlfKAV!V0St#^T%j)uL4x^c=4@$fHW9}gaGh~Wc;2??bX{3|=#@kghWl=Jt-HUB z?%WsKsmm?xH_yTMb{#ZalkMAA3T40ib>w!VX%Wm%BfPyQn43cQ2sHbJu7U(4kng`1 zQ$F)x6V56+VWu++-#`@h4~0s98&@m|csH@4DQ$0jF@b#1b<2cEH)QYEys{1EgUh)C zJmkqSL1ur4R*OHSaC1K*bGI!ql9DO26B1|q_5g3g>V}o&iABB2_Iej99W+txr)EoV zBi5i`eQ!wY8aV#w6>a>ETAb?z!cg?-U*0n$o){p*_Trpd_#w0TrM)&L%Gb$}_N>#`eTbPZg zBT!yeXkps4)ckXZC_=jDy{&m1Tci+4Lj%OjQl;H4GD=U&N8M{i@Wr>hq15O*h>p#%np*($pPL6;hyPB@9}^ z6`01ZhmZIvAXdZD|Ky+%+49{&wN(H01VK`ET+!zQEy@?-UK>gB1_{kKi|J3xdE`KS zhKy@qV>P!VMHEk^k<`{4u^YY&h}4J+JSiXsX%RejgL$>)2ixg6$aaSFDg;+msEeDg zham4r*<<^S&|Kg11gvQ3ef(R{A*F64?^!PFG{&>8Z8Sg8%>l0F0**JeHLOj@g4s zzuOKnmP$9iJc;h);M9C9;NK>++F!1BX2*zhW|!`b8_*ub)1!V!&Ce?b19JTa-Q63o z_U`kmS5fWo9Ymw1E1a;GU>cQ>w(9v}^%c}9UC`05)CVjkc$a~MHyZ%-DJJs$U-E?I zzq@If7+L?P$CmZKD|G);i(_T}cc@^rkxT$5BE$YSo{E)&i81{e6a+ina0eJHeQy&u z1NlF%Dns-0|6i@c+7`0~Oa`1@2?~PnpXcDy=eB``LD(77k#>Nwkp5HlQ-)?xbx^an zGI209BTTgcqCjkd=Tz2Ci^iEA3_P)^R%k-2i{0EGwx=o*TH)TqUwoOmZQgHHJ{ka1 z;nU-nf|yaa1jmaC7?+0Ar-9Dsi0bj0_ z`wQ>*${kgr$0&rl(&}`BmiOwZm*flekn_5$ZO@r9HA?QFc>(yukDjk;pDqW7cVykZ zxP-IlMs#Y`Rx#@Ekb{y9D8NdX})|Fiv(nB~!`V@}{< z&%PE(eg%8M_-!glxfYG-xA?IjW!SZtj}mI`klQKGDQ8ybzaTp$o=zM&iTXl|1SGqW zdSZC7dDKVFsC`1?dDf$0YF7bo7`?dn1&0Nz6w#&yK>cs<$;>G4M9@_6o$v=+*N<_g z@lvtm1&)QLc1Q+6u8289W==SV9X@AVE+yxqqw#FVC$mQ#T)g#obHPhJQ*o$fJU@J` z`P5TLl6*nAVoPvu*xiU-38LlL>pkptJrbOGPFKt?)VZ)V-Db6?vJ=Mh!1CU(+}GD} z9+Ey0!0rj7HXPY@hre z)(`Q>8S@$kbub*dB&YAUQ(i&vL+^D&^Zu19ED+}X3BB>faO%(w;ooP@KV(aw#eDxd z?odb%0$pUzNHG%3a!ZHYA7_qst_hq0zY`fKo$%10?o4#2WdRBW**DaQ2TLdBF zQUuz;5t5nbJ`J1`v;hG3zBoN1dxLK};jRv1^Z?HRhGR_1`fqHeZKmtjbk?`GD5^HY z6c7N6pLgT*!=Nd0;qGfOc_HerB<_L$JmptuU$}3DiZ}cdL>p5v_CfUZ$V=hY@WTglDd4KsE-coGV6|WD*w0Jl_3HAOg?8AVohPVC+PxMYe6|60UMw!cEK<2{ndDT z(R{J4c|9No1Hq4ZmD_EG0*!fvh0RluQ{WI0#lKIt&(%QZ_9GqxH~ycj{z!d*5QBlf zQG!GQlrV!NE7OgPiD_1IIv1MHYjb%f2gaKQes{92T)cqYp-ZG^I(R2sj-smYUDy@8 zs-Fz#@FwwN%!p>()ip3j5Z8*%h_+tBwhMY>60IS)a)8%RuF zFnK&J9=DT%W=W_mi;qN^3Rilw_6>sJ~B_L&$L4{PrQHL z5U?*wFV=35K=@5z-^bo2{(!*B<; zt2w?4)#o2(oc-0QM;4ueaC{SZ=CKS8O&S~%oAqN`0v~}7xo4isi_2XASJ;#zS6!;k zbnUVIiTSM1c-t~f8q(a`8CwX6QcfKy8 zBb!Us6NgLj?hG&B@bv;fRj6L@wJ6Ce)ye9=s11)CJOA^x7|A|S4Y!DJ1udKi z&PQGdu>`_*N6kX+4lhkS;fup}uuWmxp(J;u*h35~S}Ky4k;bri>@8-QqSyYel&=ww z29SM&>cwm2NN~ipt}=FFi}!EKf;eud_LB3VdupUZCmgc9{MM>;{Be9?)TT zZZ>en%T6NAKFlg;Y!)c%9a^*hk&Gqt<8~y7p$Yj=6EiNfS9{w zJY(}bbU_ioVqWbOVcwo)?XZH;7pe(hioFSgdXC2mIBG~F{8Qvc!WZC`FA@Lmv+#jZ z7I=dhzQEhVC5OM4C4l}Vd~#mVf3~>HZ{PVTpC0q}$Ug9YKOwU^h2%~; zXx}n;&H{6Skp?hED>`ZY)9ogZ?vD6gbgSaojrLwRKPc`x&^R{-aCkGQf0tlZ56scG zPaw-X@~y&$p!g@Yqm2S+x(gy{G&6TtFI?k%w5q)?6lv@YFyss9BlWE@KtNOgQ)=c{Aj$ z_E1}TMlNS+9EWn%+&qkct56|zCdqQpbMUA~`nkh8oMaA}cX7$6PjO{`J| z-$|k(2?w#hwtQR-vH90SHunH7l-q_S*zPlhsmsiPnGTeo>0Mnq?W=U z_&VX)BJQTMiM9xB+v=-oyy`gJ1GaIBXM$(i%JU{g=~(x}J*O z1(|b)%__W=O{>*~^HBHOq%s(_+m>Y?-vE1163ZpLhJIr8{yq!0*hm%UHR1Tox!?$f^{K z?JT07gDrXK+`QSwjKws#PaakQt}f_XQ=lSqt4GE*&^3`)pdu;~$!gUA@ey!z8IDm- zTVGOPa$tZMiA;$F&f0Dei%_-{%*F;L_&PCPtT+bs*r}Plu51oL(o+Nm%t~M#-m15= zo)kQa5Gwfs*ilMbfNsac&Dbr}m9Y$c0ZMW?n-wa{-r~~lF)3j2fg=lzmPN`7M_Nt&!>l43tr3XthzW#wWt%VJ%YlvoCU-=yF7bt?OBHFBeRA7F|E4=jx~Q^w_0Y z!H8jD&Y;_Alm1-fvjn8|FBgK2SZ;Hr$HvRc)KE+mnWQVO0nc`f zh>2iy5m>z7t!KSay`DXg0@dpd|gtG(gm2oiLEhUF{^ zAO?UL2$PM*fko+$Qx>$lk|F+PLrfyt!V6Tw%WTQ-Ae9r59nxzeR?!fGcLoZj6s{Fs ztddWn5iSURyzQF_88apJj7RU4!PV#)Or>cL_|XftVd&N6@aBre6;w3QG7A9WRat|D z(?7$zJd=$#*W%~=ExZ9PxFt;35z5aC$i>}e{9TR!U!yBO$_e|PiX@o<4y8N>?NEUN zP3mffLG(bAK4hZn`zRNzQO-b(96-PjqQSy+&lL=MrR-6@3>OSOcM}ju4Oc~&@&~9k zo|Xc%MDH!nynls~=?8{63syQ%Qa;Msm zIp57Jn3~Q@2geLUlcDV8Pwus>bH#YfBv~kuoTSpv$K>ntu|@=VD{y-*P4_A^vVr=U zHY5 z+=F|CK9Y_mXn}9hC(d)orfxv*2tRQ&N9 z?RSv+Lp#$}-RL>+<{*tEfUI*CzNIxvF}TUj;^Mvn#={H2nC8f%rDcGofiEwDMGT2; zeZ_jz-UR~lWR#(H=K-MfDPC8P<#=e{$H4nAQ!k!R z(3*|$-bTK3BOojD!>V>G&4+m{L@p*yjGR7Fx$2RZH+~@lcuFoApuon?;jPKgHr+Da zGu<>@t&XKCuIkbqx>>Smx@Nj%d=B>r;p5WtmOE(Ii5G@9sw2y@81E8~AsSt1Xvv8B z1r7-A%NXJ+OG^e(W=yT3lkE?%=;-Dl7>9f)yn{Q8W`Sj~Mn6Z#NsEY9iC+39glFCn z{(Wkvd#Zh^e|lB}=<9a$8af`C!bxYx(#oYbTk%ps%3WrrPjxtJd(`m|zd5{_+Rg{? zdhos(&rF>i(*4!8P5(8c-<){IA8arLyA#LckDj`|-dOl5m^*i|i}?rvGWRYe9sB{T zBgeg6#j)||ZK7>pa&&-=T|wgci^#1pE|$~|`^1VCau5y^0C~u%KZ>L^ooT?xa+A?u z>OcA!m&ul%i6;@P0J&HMVIvu~w?pes^f7iRnKm=I6z%-X)^4bzK6%nK)};IF#S52u z%L;p7fNfY`O|!i!@M8P()+D0m_a*XGs{2kG8lrwzvwlEp`}Yi;ucUb1Ad2-Q#)AUCQi zH;qh1NK{U5m?9qyd5Z$E+SUrN*YEo_+{jIK>dD6+<GK=A6yO)ABYM?~-<%sW&Wju3+vML}PQv_t$M~D`Ek5_hyquy$%??xk zX3b;d`3(iSsjar-{Q3={yI83O-1&9P;MMnqPUd3O6l8bX_3t3VXUQr23D8`@uf5FL zDlWqM@LN=FZ*DjJ+#mKk{JZjh5WRN5NUKQqoOj)I!9TH7IB-X^H5 zvLd8VFT#URJrSx?*w#SFf~Db>R5&P9?;kJp7}_GS#v{5$F*B<8&+~|Ze%i+Am=uY) zDU^*UXD}J0Eu3`>E<7U=qVf%EGjy&eaulxQnpwvBKheZZl5!|3_(>K1oZY?vvQWBH z3_-g`S`f!l0cj853g9x7xuhXo>e3}t_kW0<3HnjnyMT!{OrJ}~`|RN8hShU@*q&&# z3PC-;_P*-5u3bcGnCU=#k>Arlz#x8^Uo(aHpust2{-=Tn&gpLmMEwb{fr9V6x#W

t=T$!J&+}$|{q2CIvoS~B0i-QP7`_jRw=MGn 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 diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt index f9c531e745..ec797c8bd3 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/LICENSE.txt @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp index 7d12c713a4..0169c2ec20 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/baseiids.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h index 5a531e93d3..e4231358b3 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/classfactoryhelpers.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp index 83866ea9bb..45dd41940a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h index 0a8c1ff6b5..e1efd2c5c2 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fbuffer.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h index 653fb7c629..dfbe364bda 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fcommandline.h @@ -9,36 +9,36 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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. //----------------------------------------------------------------------------- //------------------------------------------------------------------------ /** @file base/source/fcommandline.h - Very simple command-line parser. - @see Steinberg::CommandLine */ + Very simple command-line parser. + @see Steinberg::CommandLine */ //------------------------------------------------------------------------ #pragma once @@ -57,310 +57,336 @@ namespace Steinberg { Parses the command-line into a CommandLine::VariablesMap.\n The command-line parser uses CommandLine::Descriptions to define the available options. -@b Example: +@b Example: \code #include "base/source/fcommandline.h" #include int main (int argc, char* argv[]) { - using namespace std; + using namespace std; - CommandLine::Descriptions desc; - CommandLine::VariablesMap valueMap; + 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); + 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; + 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 +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. - //------------------------------------------------------------------------ - /** 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. + /** Retrieve the value of option @c k.*/ + std::string& operator[] (const VariablesMapContainer::key_type k); - 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); - }; + /** Retrieve the value of option @c k. */ + const std::string& operator[] (const VariablesMapContainer::key_type k) const; + + /** Returns @c != @c 0 if command-line contains option @c k. */ + VariablesMapContainer::size_type count (const VariablesMapContainer::key_type k) const; +}; + +//! 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: + /** Construct a Description */ + Description (const std::string& name, const std::string& help, + const std::string& valueType); + 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. */ +//------------------------------------------------------------------------ +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); - } +//------------------------------------------------------------------------ +/*! 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]; +} - //------------------------------------------------------------------------ - /** 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) - { - } +//------------------------------------------------------------------------ +VariablesMap::VariablesMapContainer::size_type VariablesMap::count ( + const VariablesMapContainer::key_type k) const +{ + return mVariablesMapContainer.count (k); +} //------------------------------------------------------------------------ - /*! 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; - } +/** 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; +} + +/** Parse the command - line. */ +bool parse (int ac, char* av[], const Descriptions& desc, VariablesMap& result, + FilesVector* files = nullptr); + +/** Make Descriptions stream able. */ +std::ostream& operator<< (std::ostream& os, const Descriptions& desc); + +const std::string Description::kBool = "bool"; +const std::string Description::kString = "string"; //------------------------------------------------------------------------ - /*! 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; - } +/*! 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) +{ +} - //------------------------------------------------------------------------ - /*! @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; - } +//------------------------------------------------------------------------ +/*! 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; +} //------------------------------------------------------------------------ - /*! 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"; - } - } +/*! 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; +} //------------------------------------------------------------------------ - std::ostream& operator<< (std::ostream& os, const Descriptions& desc) +/*! @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++) { - desc.print (os); - return os; + 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; +} - //------------------------------------------------------------------------ - /*! @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) +//------------------------------------------------------------------------ +/*! 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) { - return desc.parse (ac, av, result, files); + 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 +//------------------------------------------------------------------------ +} // namespace CommandLine +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp index 9fe27d85aa..18fa1c9b44 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.cpp @@ -11,7 +11,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h index 3b376ae642..ecfb82fcb7 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fdebug.h @@ -11,7 +11,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp index a061556b92..239afb5617 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.cpp @@ -10,7 +10,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h index 4165a7b400..080c05599c 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -125,6 +125,9 @@ class FObject : public IDependent // static helper functions static inline bool classIDsEqual (FClassID ci1, FClassID ci2); ///< compares (evaluates) 2 class IDs static inline FObject* unknownToObject (FUnknown* unknown); ///< pointer conversion from FUnknown to FObject + /** convert from FUnknown to FObject */ + template + static inline IPtr fromUnknown (FUnknown* unknown); /** Special UID that is used to cast an FUnknown pointer to a FObject */ static const FUID iid; @@ -140,7 +143,24 @@ class FObject : public IDependent //------------------------------------------------------------------------ -// conversion from FUnknown to FObject +// conversion from FUnknown to FObject subclass +//------------------------------------------------------------------------ +template +inline IPtr FObject::fromUnknown (FUnknown* unknown) +{ + if (unknown) + { + FObject* object = nullptr; + if (unknown->queryInterface (FObject::iid, (void**)&object) == kResultTrue && object) + { + if (object->isTypeOf (C::getFClassID (), true)) + return IPtr (static_cast (object), false); + object->release (); + } + } + return {}; +} + //------------------------------------------------------------------------ inline FObject* FObject::unknownToObject (FUnknown* unknown) { @@ -149,7 +169,10 @@ inline FObject* FObject::unknownToObject (FUnknown* unknown) { unknown->queryInterface (FObject::iid, (void**)&object); if (object) - object->release (); // queryInterface has added ref + { + if (object->release () == 0) + object = nullptr; + } } return object; } @@ -168,7 +191,7 @@ inline C* FCast (const FObject* object) { if (object && object->isTypeOf (C::getFClassID (), true)) return (C*) object; - return 0; + return nullptr; } //----------------------------------------------------------------------- @@ -182,19 +205,48 @@ inline C* FCast (FUnknown* unknown) } //----------------------------------------------------------------------- -/** FUCast - casting from FUnknown to Interface */ +/** ICast - casting from FObject to FUnknown Interface */ +//----------------------------------------------------------------------- +template +inline IPtr ICast (FObject* object) +{ + return FUnknownPtr (object ? object->unknownCast () : nullptr); +} + +//----------------------------------------------------------------------- +/** ICast - casting from FUnknown to another FUnknown Interface */ +//----------------------------------------------------------------------- +template +inline IPtr ICast (FUnknown* object) +{ + return FUnknownPtr (object); +} + +//------------------------------------------------------------------------ +template +inline C* FCastIsA (const FObject* object) +{ + if (object && object->isA (C::getFClassID ())) + return (C*)object; + return nullptr; +} + +#ifndef SMTG_HIDE_DEPRECATED_INLINE_FUNCTIONS +//----------------------------------------------------------------------- +/** \deprecated FUCast - casting from FUnknown to Interface */ //----------------------------------------------------------------------- template -inline C* FUCast (FObject* object) +SMTG_DEPRECATED_MSG("use ICast<>") inline C* FUCast (FObject* object) { return FUnknownPtr (object ? object->unknownCast () : nullptr); } template -inline C* FUCast (FUnknown* object) +SMTG_DEPRECATED_MSG("use ICast<>") inline C* FUCast (FUnknown* object) { return FUnknownPtr (object); } +#endif // SMTG_HIDE_DEPRECATED_FUNCTIONS //------------------------------------------------------------------------ /** @name Convenience methods that call release or delete respectively diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp index 524956b9ef..3a1a2a5aad 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -607,8 +607,10 @@ TSize FStreamer::readString8 (char8* ptr, TSize size) if (i > 0 && ptr[i - 1] == '\r') i--; } + if (i >= size) + i = size - 1; ptr[i] = 0; - + return i; } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h index 8b97bb6cd1..dbec4054bc 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstreamer.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp index 907baa7338..77024c248e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -2245,7 +2245,8 @@ bool String::toMultiByte (uint32 destCodePage) //----------------------------------------------------------------------------- void String::fromUTF8 (const char8* utf8String) { - resize (0, false); + if (buffer8 != utf8String) + resize (0, false); _toWideString (utf8String, static_cast (strlen (utf8String)), kCP_Utf8); } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h index 7fc758aa77..b8676d6d86 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/fstring.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp index f4ac80cc57..e722d45ed7 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -299,10 +299,7 @@ tresult PLUGIN_API UpdateHandler::removeDependent (FUnknown* u, IDependent* depe listIsEmpty = true; break; } - else - { - iterList = list.erase (iterList); - } + iterList = list.erase (iterList); } else { diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h index e85a9bbcc3..084105e5f1 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/source/updatehandler.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h index 2ef35ba8d8..14ffee4158 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/include/flock.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -178,6 +178,7 @@ class FConditionalGuard FLock* lock; ///< guarded lock }; -} // Thread -} // Base -} // Steinberg +//------------------------------------------------------------------------ +} // namespace Thread +} // namespace Base +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp index e7c154bad7..ac9d7d5729 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/base/thread/source/flock.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -140,7 +140,7 @@ bool FLock::trylock () #endif } -} // Thread -} // Base -} // Steinberg - +//------------------------------------------------------------------------ +} // namespace Thread +} // namespace Base +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt index 6daa072e68..f5df1de438 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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 diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/coreiids.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/coreiids.cpp index d5935044d4..95d59aed49 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/coreiids.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/coreiids.cpp @@ -37,4 +37,4 @@ DEF_CLASS_IID (IBStream) DEF_CLASS_IID (ISizeableStream) //------------------------------------------------------------------------ -} // Steinberg +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h index 7b4a78d27a..fea5e8d629 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fplatform.h @@ -322,8 +322,12 @@ // Deprecation setting //----------------------------------------------------------------------------- #ifndef SMTG_DEPRECATED_ATTRIBUTE +#if SMTG_CPP17 +#define SMTG_DEPRECATED_ATTRIBUTE(msg) [[deprecated(msg)]] +#else #define SMTG_DEPRECATED_ATTRIBUTE(msg) #endif +#endif #define SMTG_DEPRECATED_MSG(msg) SMTG_DEPRECATED_ATTRIBUTE(msg) //----------------------------------------------------------------------------- diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h index fea4522c56..a365b69594 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/fstrdefs.h @@ -246,7 +246,7 @@ inline SMTG_CONSTEXPR14 void str8ToStr16 (char16* dst, const char8* src, int32 n int32 i = 0; for (;;) { - if (i == n) + if (i == (n - 1)) { dst[i] = 0; return; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h index 133dbba38d..e1bf9388cb 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h @@ -117,7 +117,7 @@ namespace Steinberg typedef int32 UCoord; static const UCoord kMaxCoord = ((UCoord)0x7FFFFFFF); static const UCoord kMinCoord = ((UCoord)-0x7FFFFFFF); -} // namespace Steinberg +} // namespace Steinberg //---------------------------------------------------------------------------- diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h index 99dd037303..ca64ae8f62 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/smartpointer.h @@ -381,4 +381,6 @@ Used toUsed (T* obj) { return Detail::Adopt::toOwnerType (obj); } //------------------------------------------------------------------------ } // SKI #endif -} // Steinberg + +//------------------------------------------------------------------------ +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugview.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugview.h index 797650198d..b4a00efd25 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugview.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/gui/iplugview.h @@ -253,7 +253,11 @@ DECLARE_CLASS_IID (ITimerHandler, 0x10BDD94F, 0x41424774, 0x821FAD8F, 0xECA72CA9 - [released: 3.6.8] On Linux the host has to provide this interface to the plug-in as there's no global event run loop -defined as on other platforms. +defined as on other platforms. + +This can be done by IPlugFrame and the context which is passed to the plug-in as an argument +in the method IPlugFactory3::setHostContext. This way the plug-in can get a runloop even if +it does not have an editor. A plug-in can register an event handler for a file descriptor. The host has to call the event handler when the file descriptor is marked readable. diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h index 82d550e327..03e76b4640 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstaudioprocessor.h @@ -48,15 +48,20 @@ namespace PlugType //------------------------------------------------------------------------ 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 kFxBass = "Fx|Bass"; ///< Tools dedicated to Bass Guitar +SMTG_CONSTEXPR const CString kFxChannelStrip = "Fx|Channel Strip"; ///< Tools dedicated to Channel Strip 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 kFxDrums = "Fx|Drums"; ///< Tools dedicated to Drums... 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 kFxGuitar = "Fx|Guitar"; ///< Tools dedicated to Guitar 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 kFxMicrophone = "Fx|Microphone"; ///< Tools dedicated to Microphone 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... @@ -65,7 +70,7 @@ SMTG_CONSTEXPR const CString kFxReverb = "Fx|Reverb"; ///< Reverberation, Ro 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 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 diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstdataexchange.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstdataexchange.h new file mode 100644 index 0000000000..9919c17759 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstdataexchange.h @@ -0,0 +1,221 @@ +//------------------------------------------------------------------------ +// Project : VST SDK +// +// Category : Interfaces +// Filename : pluginterfaces/vst/ivstdataexchange.h +// Created by : Steinberg, 06/2022 +// Description : VST Data Exchange Interface +// +//----------------------------------------------------------------------------- +// 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/base/funknown.h" + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpush.h" +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +namespace Steinberg { +namespace Vst { + +//------------------------------------------------------------------------ +class IAudioProcessor; + +//------------------------------------------------------------------------ +typedef uint32 DataExchangeQueueID; +typedef uint32 DataExchangeBlockID; +typedef uint32 DataExchangeUserContextID; + +//------------------------------------------------------------------------ +static SMTG_CONSTEXPR DataExchangeQueueID InvalidDataExchangeQueueID = kMaxInt32; +static SMTG_CONSTEXPR DataExchangeBlockID InvalidDataExchangeBlockID = kMaxInt32; + +//------------------------------------------------------------------------ +struct DataExchangeBlock +{ + /** pointer to the memory buffer */ + void* data; + /** size of the memory buffer */ + uint32 size; + /** block identifier */ + DataExchangeBlockID blockID; +}; + +//------------------------------------------------------------------------ +/** Host Data Exchange handler interface: Vst::IDataExchangeHandler +\ingroup vstHost vst379 +- [host imp] +- [context interface] +- [released: 3.7.9] +- [optional] + +The IDataExchangeHandler implements a direct and thread-safe connection from the realtime +audio context of the audio processor to the non-realtime audio context of the edit controller. +This should be used when the edit controller needs continuous data from the audio process for +visualization or other use-cases. To circumvent the bottleneck on the main thread it is possible +to configure the connection in a way that the calls to the edit controller will happen on a +background thread. + +Opening a queue: +The main operation for a plug-in is to open a queue via the handler before the plug-in is activated +(but it must be connected to the edit controller via the IConnectionPoint when the plug-in is using +the recommended separation of edit controller and audio processor). The best place to do this is in +the IAudioProcessor::setupProcessing method as this is also the place where the plug-in knows the +sample rate and maximum block size which the plug-in may need to calculate the queue block size. +When a queue is opened the edit controller gets a notification about it and the controller can +decide if it wishes to receive the data on the main thread or the background thread. + +Sending data: +In the IAudioProcessor::process call the plug-in can now lock a block from the handler, fill it and +when done free the block via the handler which then sends the block to the edit controller. The edit +controller then receives the block either on the main thread or on a background thread depending on +the setup of the queue. +The host guarantees that all blocks are send before the plug-in is deactivated. + +Closing a queue: +The audio processor must close an opened queue and this has to be done after the processor was +deactivated and before it is disconnected from the edit controller (see IConnectionPoint). + +What to do when the queue is full and no block can be locked? +The plug-in needs to be prepared for this situation as constraints in the overall system may cause +the queue to get full. If you need to get this information to the controller you can declare a +hidden parameter which you set to a special value and send this parameter change in your audio +process method. +*/ +class IDataExchangeHandler : public FUnknown +{ +public: + /** open a new queue + * + * only allowed to be called from the main thread when the component is not active but + * initialized and connected (see IConnectionPoint) + * + * @param processor the processor who wants to open the queue + * @param blockSize size of one block + * @param numBlocks number of blocks in the queue + * @param alignment data alignment, if zero will use the platform default alignment if any + * @param userContextID an identifier internal to the processor + * @param outID on return the ID of the queue + * @return kResultTrue on success + */ + virtual tresult PLUGIN_API openQueue (IAudioProcessor* processor, uint32 blockSize, + uint32 numBlocks, uint32 alignment, + DataExchangeUserContextID userContextID, + DataExchangeQueueID* outID) = 0; + /** close a queue + * + * closes and frees all memory of a previously opened queue + * if there are locked blocks in the queue, they are freed and made invalid + * + * only allowed to be called from the main thread when the component is not active but + * initialized and connected + * + * @param queueID the ID of the queue to close + * @return kResultTrue on success + */ + virtual tresult PLUGIN_API closeQueue (DataExchangeQueueID queueID) = 0; + + /** lock a block if available + * + * only allowed to be called from within the IAudioProcessor::process call + * + * @param queueID the ID of the queue + * @param block on return will contain the data pointer and size of the block + * @return kResultTrue if a free block was found and kOutOfMemory if all blocks are locked + */ + virtual tresult PLUGIN_API lockBlock (DataExchangeQueueID queueId, + DataExchangeBlock* block) = 0; + + /** free a previously locked block + * + * only allowed to be called from within the IAudioProcessor::process call + * + * @param queueID the ID of the queue + * @param blockID the ID of the block + * @param sendToController if true the block data will be send to the IEditController otherwise + * it will be discarded + * @return kResultTrue on success + */ + virtual tresult PLUGIN_API freeBlock (DataExchangeQueueID queueId, DataExchangeBlockID blockID, + TBool sendToController) = 0; + +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (IDataExchangeHandler, 0x36D551BD, 0x6FF54F08, 0xB48E830D, 0x8BD5A03B) + +//------------------------------------------------------------------------ +/** Data Exchange Receiver interface: Vst::IDataExchangeReceiver +\ingroup vstPlug vst379 +- [plug imp] +- [released: 3.7.9 +- [optional] + +The receiver interface is required to receive data from the realtime audio process via the +IDataExchangeHandler. + +\see \ref IDataExchangeHandler +*/ +class IDataExchangeReceiver : public FUnknown +{ +public: + /** queue opened notification + * + * called on the main thread when the processor has opened a queue + * + * @param userContextID the user context ID of the queue + * @param blockSize the size of one block of the queue + * @param dispatchedOnBackgroundThread if true on output the blocks are dispatched on a + * background thread [defaults to false in which case the + * blocks are dispatched on the main thread] + */ + virtual void PLUGIN_API queueOpened (DataExchangeUserContextID userContextID, uint32 blockSize, + TBool& dispatchOnBackgroundThread) = 0; + /** queue closed notification + * + * called on the main thread when the processor has closed a queue + * + * @param userContextID the user context ID of the queue + */ + virtual void PLUGIN_API queueClosed (DataExchangeUserContextID userContextID) = 0; + + /** one or more blocks were received + * + * called either on the main thread or a background thread depending on the + * dispatchOnBackgroundThread value in the queueOpened call. + * + * the data of the blocks are only valid inside this call and the blocks only become available + * to the queue afterwards. + * + * @param userContextID the user context ID of the queue + * @param numBlocks number of blocks + * @param blocks the blocks + * @param onBackgroundThread true if the call is done on a background thread + */ + virtual void PLUGIN_API onDataExchangeBlocksReceived (DataExchangeUserContextID userContextID, + uint32 numBlocks, + DataExchangeBlock* blocks, + TBool onBackgroundThread) = 0; + +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (IDataExchangeReceiver, 0x45A759DC, 0x84FA4907, 0xABCB6175, 0x2FC786B6) + +//------------------------------------------------------------------------ +} // namespace Vst +} // namespace Steinberg + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpop.h" +//------------------------------------------------------------------------ diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h index d7c8925c13..48128fbe90 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivsteditcontroller.h @@ -86,7 +86,7 @@ const CString kEditor = "editor"; enum RestartFlags { /** The Component should be reloaded - * The host has to unload completely the plug-in (controller/processor) and reload it. + * The host has to unload completely the plug-in (controller/processor) and reload it. * [SDK 3.0.0] */ kReloadComponent = 1 << 0, @@ -105,7 +105,7 @@ enum RestartFlags /** Latency has changed * The plug informs the host that its latency has changed, getLatencySamples should return the new latency after setActive (true) was called * The host has to deactivate and reactivate the plug-in, then afterwards the host could ask for the current latency (getLatencySamples) - * see IAudioProcessor::getLatencySamples + * See IAudioProcessor::getLatencySamples * [SDK 3.0.0] */ kLatencyChanged = 1 << 3, @@ -121,39 +121,53 @@ enum RestartFlags * and reread program changes parameters (stepCount and associated unitID) * [SDK 3.0.1] */ kMidiCCAssignmentChanged = 1 << 5, - + /** Note Expression has changed (info, count, PhysicalUIMapping, ...) * Either the note expression type info, the count of note expressions or the physical UI mapping has changed. * The host invalidates all caches of note expression infos and asks the edit controller for the current ones. * See INoteExpressionController, NoteExpressionTypeInfo and INoteExpressionPhysicalUIMapping * [SDK 3.5.0] */ kNoteExpressionChanged = 1 << 6, - + /** Input / Output bus titles have changed * The host invalidates all caches of bus titles and asks the edit controller for the current titles. * [SDK 3.5.0] */ kIoTitlesChanged = 1 << 7, - + /** Prefetch support has changed * The plug-in informs the host that its PrefetchSupport has changed - * The host has to deactivate the plug-in, calls IPrefetchableSupport::getPrefetchableSupport and reactivate the plug-in - * see IPrefetchableSupport + * The host has to deactivate the plug-in, calls IPrefetchableSupport::getPrefetchableSupport + * and reactivate the plug-in. + * See IPrefetchableSupport * [SDK 3.6.1] */ - kPrefetchableSupportChanged = 1 << 8, + kPrefetchableSupportChanged = 1 << 8, /** RoutingInfo has changed - * The plug-in informs the host that its internal routing (relation of an event-input-channel to an audio-output-bus) has changed - * The host ask the plug-in for the new routing with IComponent::getRoutingInfo, \ref vst3Routing - * see IComponent + * The plug-in informs the host that its internal routing (relation of an event-input-channel to + * an audio-output-bus) has changed. The host asks the plug-in for the new routing with + * IComponent::getRoutingInfo, \ref vst3Routing + * See IComponent * [SDK 3.6.6] */ 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. + * 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 + kKeyswitchChanged = 1 << 10, + + /** Mapping of ParamID has changed + * The Plug-in informs the host that its parameters ID has changed. This has to be called by the + * edit controller in the method setComponentState or setState (during projects loading) when the + * plug-in detects that the given state was associated to an older version of the plug-in, or to a + * plug-in to replace (for ex. migrating VST2 => VST3), with a different set of parameter IDs, then + * the host could remap any used parameters like automation by asking the IRemapParamID interface + * (which extends IEditController). + * See IRemapParamID + * [SDK 3.7.11] */ + kParamIDMappingChanged = 1 << 11 }; //------------------------------------------------------------------------ @@ -613,6 +627,27 @@ class IEditControllerHostEditing : public FUnknown DECLARE_CLASS_IID (IEditControllerHostEditing, 0xC1271208, 0x70594098, 0xB9DD34B3, 0x6BB0195E) +//------------------------------------------------------------------------ +/** Extended plug-in interface IComponentHandler for an edit controller +\ingroup vstIHost vst379 +- [host imp] +- [extends IComponentHandler] +- [released: 3.7.9] +- [optional] +*/ +//------------------------------------------------------------------------ +class IComponentHandlerSystemTime : public FUnknown +{ +public: +//------------------------------------------------------------------------ + /** get the current systemTime (the same as the one used in ProcessContext::systemTime). */ + virtual tresult PLUGIN_API getSystemTime (int64& systemTime) = 0; +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (IComponentHandlerSystemTime, 0xF9E53056, 0xD1554CD5, 0xB7695E1B, 0x7B0F7745) + //------------------------------------------------------------------------ } // namespace Vst } // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstremapparamid.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstremapparamid.h new file mode 100644 index 0000000000..bf655d4e31 --- /dev/null +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/ivstremapparamid.h @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------ +// Project : VST SDK +// +// Category : Interfaces +// Filename : pluginterfaces/vst/ivstremapparamid.h +// Created by : Steinberg, 02/2024 +// Description : VST Edit Controller 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 "pluginterfaces/base/funknown.h" +#include "pluginterfaces/vst/vsttypes.h" + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpush.h" +//------------------------------------------------------------------------ + +//------------------------------------------------------------------------ +namespace Steinberg { +namespace Vst { + +//------------------------------------------------------------------------ +/** Extended IEditController interface for a component. +\ingroup vstIPlug vst3711 +- [plug imp] +- [extends IEditController] +- [released: 3.7.11] +- [optional] + +When replacing one plug-in with another, the host can ask the new plug-in for remapping paramIDs to +new ones. + +\n +\see Moduleinfo +\see \ref IPluginCompatibility +\see IEditController +*/ +class IRemapParamID : public FUnknown +{ +public: +//------------------------------------------------------------------------ + /** Retrieve the appropriate paramID for a specific plug-in UID and paramID (or index for VST 2 + * plug-ins). + * The retrieved paramID should match the one it replaces, maintaining the same + * behavior during automation playback. Called in UI-Thread context. + * @param[in] pluginToReplaceUID - TUID of plug-in (processor) that will be replaced + * @param[in] oldParamID - paramID (or index for VST 2 plug-ins) to be replaced + * @param[out] newParamID - contains the associated paramID to be used + * Return kResultTrue means that a compatible parameter is available + * Return kResultFalse means that NO compatible parameter is available + */ + virtual tresult PLUGIN_API getCompatibleParamID (const TUID pluginToReplaceUID /*in*/, + ParamID oldParamID /*in*/, + ParamID& newParamID /*out*/) = 0; +//------------------------------------------------------------------------ + static const FUID iid; +}; + +DECLARE_CLASS_IID (IRemapParamID, 0x2B88021E, 0x6286B646, 0xB49DF76A, 0x5663061C) + +//------------------------------------------------------------------------ +} // namespace Vst +} // namespace Steinberg + +//------------------------------------------------------------------------ +#include "pluginterfaces/base/falignpop.h" +//------------------------------------------------------------------------ diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h index 0d21684fc1..ad70211d1a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vstspeaker.h @@ -103,6 +103,9 @@ const Speaker kSpeakerBsr = (Speaker)1 << 34; ///< Bottom Side Right (Bsr) const Speaker kSpeakerBrl = (Speaker)1 << 35; ///< Bottom Rear Left (Brl) const Speaker kSpeakerBrc = (Speaker)1 << 36; ///< Bottom Rear Center (Brc) const Speaker kSpeakerBrr = (Speaker)1 << 37; ///< Bottom Rear Right (Brr) + +const Speaker kSpeakerLw = (Speaker)1 << 59; ///< Left Wide (Lw) +const Speaker kSpeakerRw = (Speaker)1 << 60; ///< Right Wide (Rw) //------------------------------------------------------------------------ /** @}*/ @@ -118,6 +121,7 @@ namespace SpeakerArr const SpeakerArrangement kEmpty = 0; ///< empty arrangement const SpeakerArrangement kMono = kSpeakerM; ///< M const SpeakerArrangement kStereo = kSpeakerL | kSpeakerR; ///< L R +const SpeakerArrangement kStereoWide = kSpeakerLw | kSpeakerRw; ///< Lw Rw const SpeakerArrangement kStereoSurround = kSpeakerLs | kSpeakerRs; ///< Ls Rs const SpeakerArrangement kStereoCenter = kSpeakerLc | kSpeakerRc; ///< Lc Rc const SpeakerArrangement kStereoSide = kSpeakerSl | kSpeakerSr; ///< Sl Sr @@ -306,6 +310,22 @@ const SpeakerArrangement k90_6 = kSpeakerL | kSpeakerR | kSpeakerC | /** L R C Lfe Ls Rs Lc Rc Sl Sr Tfl Tfr Trl Trr Tsl Tsr */ // 9.1.6 const SpeakerArrangement k91_6 = k90_6 | kSpeakerLfe; +/** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Lw Rw */ // 9.0.4 (Dolby) +const SpeakerArrangement k90_4_W = kSpeakerL | kSpeakerR | kSpeakerC | + kSpeakerLs | kSpeakerRs | kSpeakerLw | kSpeakerRw | kSpeakerSl | kSpeakerSr | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr; + +/** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr Lw Rw */ // 9.1.4 (Dolby) +const SpeakerArrangement k91_4_W = k90_4_W | kSpeakerLfe; + +/** L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr Lw Rw */ // 9.0.6 (Dolby) +const SpeakerArrangement k90_6_W = kSpeakerL | kSpeakerR | kSpeakerC | + kSpeakerLs | kSpeakerRs | kSpeakerLw | kSpeakerRw | kSpeakerSl | kSpeakerSr | + kSpeakerTfl | kSpeakerTfr | kSpeakerTrl | kSpeakerTrr | kSpeakerTsl | kSpeakerTsr; + +/** L R C Lfe Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr Lw Rw */ // 9.1.6 (Dolby) +const SpeakerArrangement k91_6_W = k90_6_W | kSpeakerLfe; + /** 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; @@ -424,6 +444,7 @@ const SpeakerArrangement k50_4_4 = kSpeakerL | kSpeakerR | kSpeakerC | kSpeakerL const CString kStringEmpty = ""; const CString kStringMono = "Mono"; const CString kStringStereo = "Stereo"; +const CString kStringStereoWide = "Stereo (Lw Rw)"; const CString kStringStereoR = "Stereo (Ls Rs)"; const CString kStringStereoC = "Stereo (Lc Rc)"; const CString kStringStereoSide = "Stereo (Sl Sr)"; @@ -487,10 +508,14 @@ const CString kString70_4 = "7.0.4"; const CString kString71_4 = "7.1.4"; const CString kString70_6 = "7.0.6"; const CString kString71_6 = "7.1.6"; -const CString kString90_4 = "9.0.4"; -const CString kString91_4 = "9.1.4"; -const CString kString90_6 = "9.0.6"; -const CString kString91_6 = "9.1.6"; +const CString kString90_4 = "9.0.4 ITU"; +const CString kString91_4 = "9.1.4 ITU"; +const CString kString90_6 = "9.0.6 ITU"; +const CString kString91_6 = "9.1.6 ITU"; +const CString kString90_4_W = "9.0.4"; +const CString kString91_4_W = "9.1.4"; +const CString kString90_6_W = "9.0.6"; +const CString kString91_6_W = "9.1.6"; const CString kString50_5 = "10.0 Auro-3D"; const CString kString51_5 = "10.1 Auro-3D"; const CString kString50_6 = "11.0 Auro-3D"; @@ -514,13 +539,13 @@ 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"; +const CString kStringAmbi1stOrder = "1OA"; +const CString kStringAmbi2cdOrder = "2OA"; +const CString kStringAmbi3rdOrder = "3OA"; +const CString kStringAmbi4thOrder = "4OA"; +const CString kStringAmbi5thOrder = "5OA"; +const CString kStringAmbi6thOrder = "6OA"; +const CString kStringAmbi7thOrder = "7OA"; /*@}*/ //------------------------------------------------------------------------ @@ -529,6 +554,7 @@ const CString kStringAmbi7thOrder = "7th Order Ambisonics"; /*@{*/ const CString kStringMonoS = "M"; const CString kStringStereoS = "L R"; +const CString kStringStereoWideS = "Lw Rw"; const CString kStringStereoRS = "Ls Rs"; const CString kStringStereoCS = "Lc Rc"; const CString kStringStereoSS = "Sl Sr"; @@ -589,6 +615,10 @@ 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 kString90_4_WS = "L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Lw Rw"; +const CString kString91_4_WS = "L R C LFE Ls Rs Sl Sr Tfl Tfr Trl Trr Lw Rw"; +const CString kString90_6_WS = "L R C Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr Lw Rw"; +const CString kString91_6_WS = "L R C LFE Ls Rs Sl Sr Tfl Tfr Trl Trr Tsl Tsr Lw Rw"; 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"; @@ -730,7 +760,8 @@ inline bool hasMiddleSpeakers (const SpeakerArrangement& arr) if (arr & kSpeakerL || arr & kSpeakerR || arr & kSpeakerC || arr & kSpeakerLs || arr & kSpeakerRs || arr & kSpeakerLc || arr & kSpeakerRc || arr & kSpeakerCs || arr & kSpeakerSl || arr & kSpeakerSr || arr & kSpeakerM || arr & kSpeakerPl || - arr & kSpeakerPr || arr & kSpeakerLcs || arr & kSpeakerRcs) + arr & kSpeakerPr || arr & kSpeakerLcs || arr & kSpeakerRcs || arr & kSpeakerLw || + arr & kSpeakerRw) return true; return false; } @@ -802,6 +833,8 @@ inline SpeakerArrangement getSpeakerArrangementFromString (CString arrStr) return kStereo; if (!strcmp8 (arrStr, kStringStereoR)) return kStereoSurround; + if (!strcmp8 (arrStr, kStringStereoWide)) + return kStereoWide; if (!strcmp8 (arrStr, kStringStereoC)) return kStereoCenter; if (!strcmp8 (arrStr, kStringStereoSide)) @@ -926,6 +959,14 @@ inline SpeakerArrangement getSpeakerArrangementFromString (CString arrStr) return k90_6; if (!strcmp8 (arrStr, kString91_6)) return k91_6; + if (!strcmp8 (arrStr, kString90_4_W)) + return k90_4_W; + if (!strcmp8 (arrStr, kString91_4_W)) + return k91_4_W; + if (!strcmp8 (arrStr, kString90_6_W)) + return k90_6_W; + if (!strcmp8 (arrStr, kString91_6_W)) + return k91_6_W; if (!strcmp8 (arrStr, kString50_5)) return k50_5; if (!strcmp8 (arrStr, kString51_5)) @@ -998,6 +1039,7 @@ inline CString getSpeakerArrangementString (SpeakerArrangement arr, bool withSpe //--- Stereo pairs--- case kStereo: return withSpeakersName ? kStringStereoS : kStringStereo; case kStereoSurround: return withSpeakersName ? kStringStereoRS : kStringStereoR; + case kStereoWide: return withSpeakersName ? kStringStereoWideS : kStringStereoWide; case kStereoCenter: return withSpeakersName ? kStringStereoCS : kStringStereoC; case kStereoSide: return withSpeakersName ? kStringStereoSS : kStringStereoSide; case kStereoCLfe: return withSpeakersName ? kStringStereoCLfeS: kStringStereoCLfe; @@ -1066,6 +1108,10 @@ inline CString getSpeakerArrangementString (SpeakerArrangement arr, bool withSpe case k91_4: return withSpeakersName ? kString91_4S : kString91_4; case k90_6: return withSpeakersName ? kString90_6S : kString90_6; case k91_6: return withSpeakersName ? kString91_6S : kString91_6; + case k90_4_W: return withSpeakersName ? kString90_4_WS : kString90_4_W; + case k91_4_W: return withSpeakersName ? kString91_4_WS : kString91_4_W; + case k90_6_W: return withSpeakersName ? kString90_6_WS : kString90_6_W; + case k91_6_W: return withSpeakersName ? kString91_6_WS : kString91_6_W; case k130: return withSpeakersName ? kString130S : kString130; case k131: return withSpeakersName ? kString131S : kString131; @@ -1257,6 +1303,10 @@ inline CString getSpeakerShortName (const SpeakerArrangement& arr, int32 index) if (speaker == kSpeakerBrr) return "Brr"; + if (speaker == kSpeakerLw) + return "Lw"; + if (speaker == kSpeakerRw) + return "Rw"; return ""; } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h index 081177fa68..243f02aa72 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h @@ -24,17 +24,20 @@ namespace Vst { //------------------------------------------------------------------------ /** VST 3 SDK Version */ #ifndef kVstVersionString -#define kVstVersionString "VST 3.7.8" ///< SDK version for PClassInfo2 +#define kVstVersionString "VST 3.7.11" ///< SDK version for PClassInfo2 #endif #define kVstVersionMajor 3 #define kVstVersionMinor 7 -#define kVstVersionSub 8 +#define kVstVersionSub 11 #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_11_VERSION 0x03070B +#define VST_3_7_10_VERSION 0x03070A +#define VST_3_7_9_VERSION 0x030709 #define VST_3_7_8_VERSION 0x030708 #define VST_3_7_7_VERSION 0x030707 #define VST_3_7_6_VERSION 0x030706 @@ -77,8 +80,11 @@ typedef int32 BusDirection; ///< bus direction (in/out) typedef int32 BusType; ///< bus type (main/aux) typedef int32 IoMode; ///< I/O mode (see \ref vst3IoMode) typedef int32 UnitID; ///< unit identifier -typedef double ParamValue; ///< parameter value type -typedef uint32 ParamID; ///< parameter identifier + +typedef double ParamValue; ///< parameter value type: normalized value => [0.0, 1.0] +typedef uint32 ParamID; ///< parameter identifier: value in range [0, 0x7FFFFFFF]. + /// The range [0x80000000, 0xFFFFFFFF], is reserved for host application. + typedef int32 ProgramListID; ///< program list identifier typedef int16 CtrlNumber; ///< MIDI controller number (see \ref ControllerNumbers for allowed values) @@ -88,8 +94,9 @@ typedef int64 TSamples; ///< time expressed in audio samples typedef uint32 ColorSpec; ///< color defining by 4 component ARGB value (Alpha/Red/Green/Blue) //------------------------------------------------------------------------ -static const ParamID kNoParamId = 0xffffffff; ///< default for uninitialized parameter ID -// static const ParamID kNoParamId = std::numeric_limits::max (); +static const ParamID kNoParamId = 0xFFFFFFFF; ///< default for uninitialized parameter ID +static const ParamID kMinParamId = 0; ///< value min for a parameter ID +static const ParamID kMaxParamId = 0x7FFFFFFF; ///< value max for a parameter ID //------------------------------------------------------------------------ // Audio Types @@ -117,6 +124,10 @@ static SMTG_CONSTEXPR const uint32 SDKVersion = // Versions History which allows to write such code: // if constexpr (SDKVersion >= SDKVersion_3_6_5) { ... } +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_11 = VST_3_7_11_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_10 = VST_3_7_10_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_9 = VST_3_7_9_VERSION; +static SMTG_CONSTEXPR const uint32 SDKVersion_3_7_8 = VST_3_7_8_VERSION; 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; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt index f9c531e745..ec797c8bd3 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/LICENSE.txt @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md index e7c8a93748..b06fef1ac7 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/README.md @@ -7,7 +7,6 @@ Here are located: - **AAX** Wrapper - **AU** Wrapper - **AUv3** Wrapper -- **VST 2** Wrapper - InterAppAudio ## License & Usage guidelines diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp index 2d568ae831..b18b92fcd5 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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,16 +35,17 @@ // 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 "base/source/fcommandline.h" +#include "pluginterfaces/base/fplatform.h" +#include "pluginterfaces/vst/vsttypes.h" #include #include #include @@ -358,7 +359,7 @@ int run (int argc, char* argv[]) auto outputFile = valueMap[optOutputPath]; #endif auto ostream = new std::ofstream (outputFile); - + if (ostream->is_open ()) outputStream = ostream; else @@ -388,10 +389,6 @@ int run (int argc, char* argv[]) //------------------------------------------------------------------------ #if SMTG_OS_WINDOWS -//------------------------------------------------------------------------ -#include -#include - //------------------------------------------------------------------------ using Utf8String = std::string; @@ -402,7 +399,7 @@ Utf8Args toUtf8Args (int argc, wchar_t* wargv[]) Utf8Args utf8Args; for (int i = 0; i < argc; i++) { - auto str = reinterpret_cast(wargv[i]); + auto str = reinterpret_cast (wargv[i]); utf8Args.push_back (VST3::StringConvert::convert (str)); } @@ -431,9 +428,14 @@ int wmain (int argc, wchar_t* wargv[]) 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 + +//------------------------------------------------------------------------ +#endif // SMTG_OS_WINDOWS diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp index 5b6c245e00..91bd01478b 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h index 489ace5fff..b942f0b196 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp index 0b42b5eefb..24c18869ff 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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,6 @@ CPluginView::CPluginView (const ViewRect* _rect) //------------------------------------------------------------------------ CPluginView::~CPluginView () { - // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall) setFrame (nullptr); } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h index ce131b94cb..6799fb594e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/pluginview.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -112,4 +112,5 @@ class CPluginView : public FObject, public IPlugView IPtr plugFrame; }; -} // namespace +//------------------------------------------------------------------------ +} // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp index 5f6045770a..f1f0216ed4 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.cpp @@ -36,8 +36,13 @@ //----------------------------------------------------------------------------- #include "readfile.h" -#include "public.sdk/source/vst/utility/stringconvert.h" + #include "pluginterfaces/base/fplatform.h" + +#if SMTG_OS_WINDOWS +#include "public.sdk/source/vst/utility/stringconvert.h" +#endif + #include #include diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h index fdc7105eac..8fe2ab925e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/readfile.h @@ -51,5 +51,4 @@ Returns entire file content at the given path std::string readFile (const std::string& path); //------------------------------------------------------------------------ - } // namespace Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp index e04987e16e..266c08c3b3 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h index 4a254cac16..bd51f30c26 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/hostclasses.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp index 9ce5b57522..88d910f6ff 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h index 36b3afad2e..adeb1c2876 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp index 404054c828..96b87979ac 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_linux.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm index 49a7155543..8532906728 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_mac.mm @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -180,7 +180,12 @@ bool load (const std::string& path, std::string& errorDescription) override { std::string wd (workDir); wd += "/"; - return loadInternal (wd + path, errorDescription); + if (loadInternal (wd + path, errorDescription)) + { + name = path; + return true; + } + return false; } } return loadInternal (path, errorDescription); diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp index 77990fdcca..ae1d03a7da 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/module_win32.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp index adabdb9028..3e9f8f85ab 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h index a88cbf6815..ef769bb21b 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/hosting/pluginterfacesupport.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h index 979c2f8527..79687789a9 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/jsoncxx.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h index 81b93f74be..1a0001a39d 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfo.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp index 8f12829c7d..cd554e411e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h index f28716ae2a..2fad32fa18 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfocreator.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp index 0d09d2bb0c..eb738822a5 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.cpp @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h index 9b426da3c9..54d5705e25 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/moduleinfoparser.h @@ -9,7 +9,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h index 7ea6a3c373..1f2244a61e 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/optional.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -92,7 +92,7 @@ struct Optional T&& value () noexcept { checkValid (); - return move (_value); + return std::move (_value); } const T& value () const noexcept diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp index 6bc7f3aa7c..75cf08c0a7 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h index d2d4678a74..b3bc1ac65a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -130,7 +130,7 @@ inline const Steinberg::Vst::TChar* toTChar (const std::u16string& str) //------------------------------------------------------------------------ /** - * convert an number to an UTF-16 string + * convert a number to an UTF-16 string * * @param value number * diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h index 2f8ed8b335..56674afa29 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -172,10 +172,7 @@ inline UID& UID::operator= (const UID& uid) noexcept //------------------------------------------------------------------------ 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]; + memcpy (_data, reinterpret_cast(uid), 16); return *this; } @@ -281,12 +278,7 @@ inline Optional UID::fromString (const StringT& str, bool comFormat) noexce 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]; - + memcpy (result._data, reinterpret_cast(_uid), 16); return result; } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp index 8f6ff44fc8..70722fa8d5 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h index f1e7ad4b06..4820e7701f 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp index 57e03d0815..6e999b2e23 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h index a1009d4871..e5942690fa 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp index c82ac39cde..d2e5ffb1d9 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h index e71b857be9..4b149bd0f2 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponentbase.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp index 4342c7b21c..be32db509d 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h index 9fcb0e6922..446914b7d9 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vsteditcontroller.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp index c5ad8b08fd..d61803776f 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstinitiids.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -41,6 +41,7 @@ #include "pluginterfaces/vst/ivstautomationstate.h" #include "pluginterfaces/vst/ivstchannelcontextinfo.h" #include "pluginterfaces/vst/ivstcontextmenu.h" +#include "pluginterfaces/vst/ivstdataexchange.h" #include "pluginterfaces/vst/ivsteditcontroller.h" #include "pluginterfaces/vst/ivstevents.h" #include "pluginterfaces/vst/ivsthostapplication.h" @@ -53,6 +54,7 @@ #include "pluginterfaces/vst/ivstpluginterfacesupport.h" #include "pluginterfaces/vst/ivstplugview.h" #include "pluginterfaces/vst/ivstprefetchablesupport.h" +#include "pluginterfaces/vst/ivstremapparamid.h" #include "pluginterfaces/vst/ivstrepresentation.h" #include "pluginterfaces/vst/ivsttestplugprovider.h" #include "pluginterfaces/vst/ivstunits.h" @@ -138,8 +140,15 @@ DEF_CLASS_IID (Vst::IProcessContextRequirements) DEF_CLASS_IID (Vst::IProgress) DEF_CLASS_IID (Vst::ITestPlugProvider2) - //----VST 3.7.5--------------------------------- DEF_CLASS_IID (IPluginCompatibility) +//----VST 3.7.9--------------------------------- +DEF_CLASS_IID (Vst::IComponentHandlerSystemTime) +DEF_CLASS_IID (Vst::IDataExchangeHandler) +DEF_CLASS_IID (Vst::IDataExchangeReceiver) + +//----VST 3.7.11--------------------------------- +DEF_CLASS_IID (Vst::IRemapParamID) + } // Steinberg diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp index dd0835167d..213a73e8b6 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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: @@ -228,6 +228,8 @@ ParamValue RangeParameter::toNormalized (ParamValue plainValue) const { if (info.stepCount > 1) return ToNormalized (plainValue - getMin (), info.stepCount); + + SMTG_ASSERT (getMax () - getMin () != 0); return (plainValue - getMin ()) / (getMax () - getMin ()); } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h index 88742e20ce..42d3e92f42 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstparameters.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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,7 +98,7 @@ class Parameter : public FObject OBJ_METHODS (Parameter, FObject) //------------------------------------------------------------------------ protected: - ParameterInfo info {0}; + ParameterInfo info {}; ParamValue valueNormalized {0.}; int32 precision {4}; }; diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp index 3a47c175c1..4d1fb35c12 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.cpp @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h index 2a9f83fce5..47d23f1e96 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstpresetfile.h @@ -8,7 +8,7 @@ // //----------------------------------------------------------------------------- // LICENSE -// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved +// (c) 2024, 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/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AU_Shared.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AU_Shared.h index 61518c99b7..447da4d9c0 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AU_Shared.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AU_Shared.h @@ -366,21 +366,18 @@ struct AudioUnitHelpers static Array getAUChannelInfo (const AudioProcessor& processor) { + #if JucePlugin_IsMidiEffect + // A MIDI effect requires an output bus in order to determine the sample rate. + // No audio will be written to the output bus, so it can have any number of channels. + // No input bus is required. + return { AUChannelInfo { 0, -1 } }; + #endif + Array channelInfo; auto hasMainInputBus = (AudioUnitHelpers::getBusCountForWrapper (processor, true) > 0); auto hasMainOutputBus = (AudioUnitHelpers::getBusCountForWrapper (processor, false) > 0); - if ((! hasMainInputBus) && (! hasMainOutputBus)) - { - // midi effect plug-in: no audio - AUChannelInfo info; - info.inChannels = 0; - info.outChannels = 0; - - return { &info, 1 }; - } - auto layout = processor.getBusesLayout(); // The 'standard' layout with the most channels defined is AudioChannelSet::create9point1point6(). diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index f498eb72b8..6a81fd0887 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -349,19 +349,82 @@ bool isValid() const noexcept }; #endif - template - static Optional tryGetProperty (AudioUnit inUnit, - AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement) + template + static std::optional tryGetProperty (AudioUnit inUnit, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) { - Value data; - auto size = (UInt32) sizeof (Value); + PropertyType property{}; + auto size = (UInt32) sizeof (property); - if (AudioUnitGetProperty (inUnit, inID, inScope, inElement, &data, &size) == noErr) - return data; + if (AudioUnitGetProperty (inUnit, inID, inScope, inElement, &property, &size) != noErr) + return {}; - return {}; + // This may lead to a memory corruption as the plugin has written more data than was provided! + jassert (size <= sizeof (PropertyType)); + + return property; + } + + template + class PropertyData + { + public: + explicit PropertyData (MemoryBlock&& inData) : data (std::move (inData)) {} + + Type& get() { return *static_cast< Type*> (data.getData()); } + const Type& get() const { return *static_cast (data.getData()); } + UInt32 size() const { return (UInt32) data.getSize(); } + + private: + MemoryBlock data; + }; + + template + static std::optional> tryGetPropertyData (AudioUnit inUnit, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement) + { + UInt32 size{}; + + if (AudioUnitGetPropertyInfo (inUnit, inID, inScope, inElement, &size, nullptr) != noErr) + return {}; + + constexpr auto minimumSize = sizeof (Type); + size = jmax ((UInt32) minimumSize, size); + + MemoryBlock data; + data.setSize (size, true); + + if (AudioUnitGetProperty (inUnit, inID, inScope, inElement, data.getData(), &size) != noErr) + return {}; + + // This may lead to a memory corruption as the plugin has written more data than was provided! + jassert (size <= data.getSize()); + + return PropertyData { std::move (data) }; + } + + template + static bool trySetProperty (AudioUnit inUnit, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const Type& newValue) + { + return AudioUnitSetProperty (inUnit, inID, inScope, inElement, &newValue, sizeof (Type)); + } + + template + static bool trySetProperty (AudioUnit inUnit, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement, + const PropertyData& newValue) + { + return AudioUnitSetProperty (inUnit, inID, inScope, inElement, newValue.get(), newValue.size()); } static UInt32 getElementCount (AudioUnit comp, AudioUnitScope scope) noexcept @@ -392,10 +455,10 @@ void setUpMapping (AudioUnit comp, bool isInput) { std::vector busMap; - if (const auto layout = tryGetProperty (comp, kAudioUnitProperty_AudioChannelLayout, scope, busIndex)) + if (const auto layout = tryGetPropertyData (comp, kAudioUnitProperty_AudioChannelLayout, scope, busIndex)) { - const auto juceChannelOrder = CoreAudioLayouts::fromCoreAudio (*layout); - const auto auChannelOrder = CoreAudioLayouts::getCoreAudioLayoutChannels (*layout); + const auto juceChannelOrder = CoreAudioLayouts::fromCoreAudio (layout->get()); + const auto auChannelOrder = CoreAudioLayouts::getCoreAudioLayoutChannels (layout->get()); for (auto juceChannelIndex = 0; juceChannelIndex < juceChannelOrder.size(); ++juceChannelIndex) busMap.push_back ((size_t) auChannelOrder.indexOf (juceChannelOrder.getTypeOfChannel (juceChannelIndex))); @@ -1002,99 +1065,77 @@ bool syncBusLayouts (const BusesLayout& layouts, bool isInitialized, bool& layou { layoutHasChanged = false; - for (int dir = 0; dir < 2; ++dir) + for (const auto scope : { kAudioUnitScope_Input, kAudioUnitScope_Output }) { - const bool isInput = (dir == 0); - const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - const int n = getBusCount (isInput); + const auto isInput = scope == kAudioUnitScope_Input; + const auto busCount = (UInt32) getBusCount (isInput); - if (getElementCount (scope) != n && isBusCountWritable (isInput)) + if (AudioUnitFormatHelpers::getElementCount (audioUnit, scope) != busCount && isBusCountWritable (isInput)) { - auto newCount = static_cast (n); layoutHasChanged = true; - [[maybe_unused]] auto err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ElementCount, scope, 0, &newCount, sizeof (newCount)); - jassert (err == noErr); + if (! AudioUnitFormatHelpers::trySetProperty (audioUnit, kAudioUnitProperty_ElementCount, scope, 0, busCount)) + jassertfalse; } - for (int i = 0; i < n; ++i) + for (UInt32 busIndex = 0; busIndex < busCount; ++busIndex) { - Float64 sampleRate; - UInt32 sampleRateSize = sizeof (sampleRate); + const auto& set = layouts.getChannelSet (isInput, (int) busIndex); + const auto currentStream = AudioUnitFormatHelpers::tryGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, busIndex); - AudioUnitGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, static_cast (i), &sampleRate, &sampleRateSize); + if (! currentStream.has_value()) + return false; - const AudioChannelSet& set = layouts.getChannelSet (isInput, i); - const int requestedNumChannels = set.size(); + const auto actualNumChannels = static_cast (currentStream->mChannelsPerFrame); + const auto requestedNumChannels = set.size(); + if (actualNumChannels != requestedNumChannels) { - AudioStreamBasicDescription stream; - UInt32 dataSize = sizeof (stream); - auto err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (i), &stream, &dataSize); - - if (err != noErr || dataSize < sizeof (stream)) + const auto sampleRate = AudioUnitFormatHelpers::tryGetProperty (audioUnit, kAudioUnitProperty_SampleRate, scope, busIndex); + jassert (sampleRate.has_value()); + + layoutHasChanged = true; + AudioStreamBasicDescription newStream{}; + newStream.mSampleRate = *sampleRate; + newStream.mFormatID = kAudioFormatLinearPCM; + newStream.mFormatFlags = (int) kAudioFormatFlagsNativeFloatPacked | (int) kAudioFormatFlagIsNonInterleaved | (int) kAudioFormatFlagsNativeEndian; + newStream.mFramesPerPacket = 1; + newStream.mBytesPerPacket = 4; + newStream.mBytesPerFrame = 4; + newStream.mBitsPerChannel = 32; + newStream.mChannelsPerFrame = static_cast (requestedNumChannels); + + if (AudioUnitFormatHelpers::trySetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, busIndex, newStream)) return false; - - const int actualNumChannels = static_cast (stream.mChannelsPerFrame); - - if (actualNumChannels != requestedNumChannels) - { - layoutHasChanged = true; - zerostruct (stream); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct) - stream.mSampleRate = sampleRate; - stream.mFormatID = kAudioFormatLinearPCM; - stream.mFormatFlags = (int) kAudioFormatFlagsNativeFloatPacked | (int) kAudioFormatFlagIsNonInterleaved | (int) kAudioFormatFlagsNativeEndian; - stream.mFramesPerPacket = 1; - stream.mBytesPerPacket = 4; - stream.mBytesPerFrame = 4; - stream.mBitsPerChannel = 32; - stream.mChannelsPerFrame = static_cast (requestedNumChannels); - - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (i), &stream, sizeof (stream)); - if (err != noErr) return false; - } } - if (! set.isDiscreteLayout()) + if (isInitialized && ! set.isDiscreteLayout()) { - const AudioChannelLayoutTag requestedTag = CoreAudioLayouts::toCoreAudio (set); - - AudioChannelLayout layout; - const UInt32 minDataSize = sizeof (layout) - sizeof (AudioChannelDescription); - UInt32 dataSize = minDataSize; - - AudioChannelLayoutTag actualTag = kAudioChannelLayoutTag_Unknown; - auto err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, &dataSize); - bool supportsLayouts = (err == noErr && dataSize >= minDataSize); - - if (supportsLayouts) + if (const auto layout = AudioUnitFormatHelpers::tryGetPropertyData (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, busIndex)) { - const UInt32 expectedSize = - minDataSize + (sizeof (AudioChannelDescription) * layout.mNumberChannelDescriptions); - - HeapBlock layoutBuffer; - layoutBuffer.malloc (1, expectedSize); - dataSize = expectedSize; - - err = AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, - static_cast (i), layoutBuffer.get(), &dataSize); + // This is likely a fault with the plugin. Not enough data has been allocated + // to support the AudioChannelLayout being described + jassert (layout->get().mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions + || layout->size() >= offsetof (AudioChannelLayout, mChannelDescriptions) + layout->get().mNumberChannelDescriptions * sizeof (AudioChannelDescription)); - if (err != noErr || dataSize < expectedSize) - return false; - - // try to convert the layout into a tag - actualTag = CoreAudioLayouts::toCoreAudio (CoreAudioLayouts::fromCoreAudio (layout)); + const auto requestedTag = CoreAudioLayouts::toCoreAudio (set); + const auto actualTag = CoreAudioLayouts::toCoreAudio (CoreAudioLayouts::fromCoreAudio (layout->get())); if (actualTag != requestedTag) { - zerostruct (layout); - layout.mChannelLayoutTag = requestedTag; + AudioChannelLayout newLayout{}; + newLayout.mChannelLayoutTag = requestedTag; + + // We'll likely need to fill more data in the newLayout for these tags. + // Please notify the JUCE team if you hit this assertion and provide clear + // instructions regarding the plugin being loaded and any other relevant + // details required to hit this assertion. Preferably if you can recreate + // the assertion using the AudioPluginHost that would be extremely helpful. - err = AudioUnitSetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (i), &layout, minDataSize); + jassert (requestedTag != kAudioChannelLayoutTag_UseChannelBitmap + && requestedTag != kAudioChannelLayoutTag_UseChannelDescriptions); - // only bail out if the plug-in claims to support layouts - // See AudioUnit headers on kAudioUnitProperty_AudioChannelLayout - if (err != noErr && supportsLayouts && isInitialized) + if (AudioUnitFormatHelpers::trySetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, busIndex, newLayout)) return false; } } @@ -2382,12 +2423,6 @@ bool isBusCountWritable (bool isInput) const noexcept return (err == noErr && writable != 0 && countSize == sizeof (UInt32)); } - //============================================================================== - int getElementCount (AudioUnitScope scope) const noexcept - { - return static_cast (AudioUnitFormatHelpers::getElementCount (audioUnit, scope)); - } - //============================================================================== void getBusProperties (bool isInput, UInt32 busIdx, String& busName, AudioChannelSet& currentLayout) const { @@ -2407,13 +2442,8 @@ static void getBusProperties (AudioUnit comp, bool isInput, UInt32 busIdx, Strin if (busNameCF.object != nullptr) busName = nsStringToJuce ((NSString*) busNameCF.object); - { - AudioChannelLayout auLayout; - propertySize = sizeof (auLayout); - - if (AudioUnitGetProperty (comp, kAudioUnitProperty_AudioChannelLayout, scope, busIdx, &auLayout, &propertySize) == noErr) - currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout); - } + if (const auto auLayout = AudioUnitFormatHelpers::tryGetPropertyData (comp, kAudioUnitProperty_AudioChannelLayout, scope, busIdx)) + currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout->get()); if (currentLayout.isDisabled()) { @@ -2443,27 +2473,22 @@ void updateSupportedLayouts() { const bool isInput = (dir == 0); const AudioUnitScope scope = isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output; - auto n = getElementCount (scope); + const auto n = AudioUnitFormatHelpers::getElementCount (audioUnit, scope); - for (int busIdx = 0; busIdx < n; ++busIdx) + for (UInt32 busIdx = 0; busIdx < n; ++busIdx) { Array supported; AudioChannelSet currentLayout; - { - AudioChannelLayout auLayout; - UInt32 propertySize = sizeof (auLayout); - - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, static_cast (busIdx), &auLayout, &propertySize) == noErr) - currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout); - } + if (const auto auLayout = AudioUnitFormatHelpers::tryGetPropertyData (audioUnit, kAudioUnitProperty_AudioChannelLayout, scope, busIdx)) + currentLayout = CoreAudioLayouts::fromCoreAudio (auLayout->get()); if (currentLayout.isDisabled()) { AudioStreamBasicDescription descr; UInt32 propertySize = sizeof (descr); - if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, static_cast (busIdx), &descr, &propertySize) == noErr) + if (AudioUnitGetProperty (audioUnit, kAudioUnitProperty_StreamFormat, scope, busIdx, &descr, &propertySize) == noErr) currentLayout = AudioChannelSet::canonicalChannelSet (static_cast (descr.mChannelsPerFrame)); } @@ -2472,7 +2497,7 @@ void updateSupportedLayouts() UInt32 propertySize = 0; Boolean writable; - if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_SupportedChannelLayoutTags, scope, static_cast (busIdx), &propertySize, &writable) == noErr + if (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_SupportedChannelLayoutTags, scope, busIdx, &propertySize, &writable) == noErr && propertySize > 0) { const size_t numElements = propertySize / sizeof (AudioChannelLayoutTag); diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h index a5c137494a..86a05a9a8a 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -269,6 +269,8 @@ static std::optional getSpeakerType (const AudioChannel case AudioChannelSet::bottomRearLeft: return Steinberg::Vst::kSpeakerBrl; case AudioChannelSet::bottomRearCentre: return Steinberg::Vst::kSpeakerBrc; case AudioChannelSet::bottomRearRight: return Steinberg::Vst::kSpeakerBrr; + case AudioChannelSet::wideLeft: return Steinberg::Vst::kSpeakerLw; + case AudioChannelSet::wideRight: return Steinberg::Vst::kSpeakerRw; case AudioChannelSet::discreteChannel0: return Steinberg::Vst::kSpeakerM; @@ -311,8 +313,6 @@ static std::optional getSpeakerType (const AudioChannel case AudioChannelSet::ambisonicACN61: case AudioChannelSet::ambisonicACN62: case AudioChannelSet::ambisonicACN63: - case AudioChannelSet::wideLeft: - case AudioChannelSet::wideRight: case AudioChannelSet::unknown: break; } @@ -383,6 +383,8 @@ static std::optional getChannelType (Steinberg::Vs case Steinberg::Vst::kSpeakerBrl: return AudioChannelSet::bottomRearLeft; case Steinberg::Vst::kSpeakerBrc: return AudioChannelSet::bottomRearCentre; case Steinberg::Vst::kSpeakerBrr: return AudioChannelSet::bottomRearRight; + case Steinberg::Vst::kSpeakerLw: return AudioChannelSet::wideLeft; + case Steinberg::Vst::kSpeakerRw: return AudioChannelSet::wideRight; } return {}; @@ -433,11 +435,15 @@ namespace detail { k71_6, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, { 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 } }, + { k90_4_W, { X::left, X::right, X::centre, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::wideLeft, X::wideRight } }, + { k91_4_W, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::wideLeft, X::wideRight } }, + { k90_6_W, { 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, X::wideLeft, X::wideRight } }, + { k91_6_W, { X::left, X::right, X::centre, X::LFE, X::leftSurroundRear, X::rightSurroundRear, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight, X::wideLeft, X::wideRight } }, + + { k90_4, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } }, + { k91_4, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight } }, + { k90_6, { X::left, X::right, X::centre, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, + { k91_6, { X::left, X::right, X::centre, X::LFE, X::leftSurround, X::rightSurround, X::leftCentre, X::rightCentre, X::leftSurroundSide, X::rightSurroundSide, X::topFrontLeft, X::topFrontRight, X::topRearLeft, X::topRearRight, X::topSideLeft, X::topSideRight } }, }; #if JUCE_DEBUG diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 6aef613fc1..56eaf4b8ee 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -2290,14 +2290,9 @@ class VST3PluginInstance final : public AudioPluginInstance //============================================================================== struct VST3Parameter final : public Parameter { - VST3Parameter (VST3PluginInstance& parent, - Steinberg::int32 vstParameterIndex, - Steinberg::Vst::ParamID parameterID, - bool parameterIsAutomatable) + VST3Parameter (VST3PluginInstance& parent, Steinberg::int32 vstParameterIndex) : pluginInstance (parent), - vstParamIndex (vstParameterIndex), - paramID (parameterID), - automatable (parameterIsAutomatable) + vstParamIndex (vstParameterIndex) { } @@ -2332,7 +2327,7 @@ class VST3PluginInstance final : public AudioPluginInstance { Vst::String128 result; - if (pluginInstance.editController->getParamStringByValue (paramID, value, result) == kResultOk) + if (pluginInstance.editController->getParamStringByValue (cachedInfo.id, value, result) == kResultOk) return toString (result).substring (0, maximumLength); } @@ -2347,7 +2342,7 @@ class VST3PluginInstance final : public AudioPluginInstance { Vst::ParamValue result; - if (pluginInstance.editController->getParamValueByString (paramID, toString (text), result) == kResultOk) + if (pluginInstance.editController->getParamValueByString (cachedInfo.id, toString (text), result) == kResultOk) return (float) result; } @@ -2356,32 +2351,34 @@ class VST3PluginInstance final : public AudioPluginInstance float getDefaultValue() const override { - return (float) getParameterInfo().defaultNormalizedValue; + return (float) cachedInfo.defaultNormalizedValue; } String getName (int /*maximumStringLength*/) const override { - return toString (getParameterInfo().title); + return toString (cachedInfo.title); } String getLabel() const override { - return toString (getParameterInfo().units); + return toString (cachedInfo.units); } bool isAutomatable() const override { - return automatable; + return (cachedInfo.flags & Vst::ParameterInfo::kCanAutomate) != 0; } bool isDiscrete() const override { - return discrete; + return getNumSteps() != AudioProcessor::getDefaultNumParameterSteps(); } int getNumSteps() const override { - return numSteps; + const auto stepCount = cachedInfo.stepCount; + return stepCount == 0 ? AudioProcessor::getDefaultNumParameterSteps() + : stepCount + 1; } StringArray getAllValueStrings() const override @@ -2391,28 +2388,31 @@ class VST3PluginInstance final : public AudioPluginInstance String getParameterID() const override { - return String (paramID); + return String (cachedInfo.id); } - Steinberg::Vst::ParamID getParamID() const noexcept { return paramID; } + Steinberg::Vst::ParamID getParamID() const noexcept { return cachedInfo.id; } + + void updateCachedInfo() + { + cachedInfo = fetchParameterInfo(); + } - private: Vst::ParameterInfo getParameterInfo() const { + return cachedInfo; + } + + private: + Vst::ParameterInfo fetchParameterInfo() const + { + JUCE_ASSERT_MESSAGE_THREAD return pluginInstance.getParameterInfoForIndex (vstParamIndex); } VST3PluginInstance& pluginInstance; const Steinberg::int32 vstParamIndex; - const Steinberg::Vst::ParamID paramID; - const bool automatable; - const int numSteps = [&] - { - auto stepCount = getParameterInfo().stepCount; - return stepCount == 0 ? AudioProcessor::getDefaultNumParameterSteps() - : stepCount + 1; - }(); - const bool discrete = getNumSteps() != AudioProcessor::getDefaultNumParameterSteps(); + Vst::ParameterInfo cachedInfo = fetchParameterInfo(); }; //============================================================================== @@ -3203,6 +3203,13 @@ class VST3PluginInstance final : public AudioPluginInstance { } + void updateParameterInfo() + { + for (auto& pair : idToParamMap) + if (auto* param = pair.second) + param->updateCachedInfo(); + } + private: void deactivate() { @@ -3361,11 +3368,8 @@ class VST3PluginInstance final : public AudioPluginInstance for (int i = 0; i < editController->getParameterCount(); ++i) { - auto paramInfo = getParameterInfoForIndex (i); - auto* param = new VST3Parameter (*this, - i, - paramInfo.id, - (paramInfo.flags & Vst::ParameterInfo::kCanAutomate) != 0); + auto* param = new VST3Parameter (*this, i); + const auto paramInfo = param->getParameterInfo(); if ((paramInfo.flags & Vst::ParameterInfo::kIsBypass) != 0) bypassParam = param; @@ -3796,6 +3800,9 @@ void VST3HostContext::restartComponentOnMessageThread (int32 flags) if (hasFlag (flags, Vst::kParamValuesChanged)) plugin->resetParameters(); + if (hasFlag (flags, Vst::kParamTitlesChanged)) + plugin->updateParameterInfo(); + plugin->updateHostDisplay (AudioProcessorListener::ChangeDetails().withProgramChanged (true) .withParameterInfoChanged (true)); } diff --git a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp index afb3fd2e80..1006b6e3f1 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp @@ -57,9 +57,9 @@ class VST3PluginFormatTests final : public UnitTest expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right } - beginTest ("ChannelMapping for a 9.1.6 bus remaps the channels appropriately"); + beginTest ("ChannelMapping for a k91_6 bus remaps the channels appropriately"); { - ChannelMapping map (AudioChannelSet::create9point1point6()); + ChannelMapping map (AudioChannelSet::create9point1point6ITU()); expect (map.size() == 16); // VST3 order is: @@ -80,6 +80,64 @@ class VST3PluginFormatTests final : public UnitTest // Tsl // Tsr // JUCE order is: + // left + // right + // centre + // LFE + // leftSurround + // rightSurround + // leftCentre + // rightCentre + // leftSurroundSide + // rightSurroundSide + // topFrontLeft + // topRearRight + // topRearLeft + // topRearRight + // topSideLeft + // topSideRight + + expect (map.getJuceChannelForVst3Channel (0) == 0); // L -> left + expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right + expect (map.getJuceChannelForVst3Channel (2) == 2); // C -> centre + expect (map.getJuceChannelForVst3Channel (3) == 3); // Lfe -> LFE + expect (map.getJuceChannelForVst3Channel (4) == 4); // Ls -> leftSurround + expect (map.getJuceChannelForVst3Channel (5) == 5); // Rs -> rightSurround + expect (map.getJuceChannelForVst3Channel (6) == 6); // Lc -> leftCentre + expect (map.getJuceChannelForVst3Channel (7) == 7); // Rc -> rightCentre + expect (map.getJuceChannelForVst3Channel (8) == 8); // Sl -> leftSurroundSide + expect (map.getJuceChannelForVst3Channel (9) == 9); // Sr -> rightSurroundSide + expect (map.getJuceChannelForVst3Channel (10) == 10); // Tfl -> topFrontLeft + expect (map.getJuceChannelForVst3Channel (11) == 11); // Tfr -> topFrontRight + expect (map.getJuceChannelForVst3Channel (12) == 12); // Trl -> topRearLeft + expect (map.getJuceChannelForVst3Channel (13) == 13); // Trr -> topRearRight + expect (map.getJuceChannelForVst3Channel (14) == 14); // Tsl -> topSideLeft + expect (map.getJuceChannelForVst3Channel (15) == 15); // Tsr -> topSideRight + } + + beginTest ("ChannelMapping for a k91_6_W bus remaps the channels appropriately"); + { + ChannelMapping map (AudioChannelSet::create9point1point6()); + expect (map.size() == 16); + + // VST3 order is: + // L + // R + // C + // Lfe + // Ls + // Rs + // Sl + // Sr + // Tfl + // Tfr + // Trl + // Trr + // Tsl + // Tsr + // Lw + // Rw + // JUCE order is: // Left // Right // Centre @@ -97,22 +155,22 @@ class VST3PluginFormatTests final : public UnitTest // Top Side Left // Top Side Right - expect (map.getJuceChannelForVst3Channel (0) == 12); // L -> wideLeft - expect (map.getJuceChannelForVst3Channel (1) == 13); // R -> wideRight + expect (map.getJuceChannelForVst3Channel (0) == 0); // L -> left + expect (map.getJuceChannelForVst3Channel (1) == 1); // R -> right expect (map.getJuceChannelForVst3Channel (2) == 2); // C -> centre expect (map.getJuceChannelForVst3Channel (3) == 3); // Lfe -> LFE expect (map.getJuceChannelForVst3Channel (4) == 10); // Ls -> leftSurroundRear expect (map.getJuceChannelForVst3Channel (5) == 11); // Rs -> rightSurroundRear - expect (map.getJuceChannelForVst3Channel (6) == 0); // Lc -> left - expect (map.getJuceChannelForVst3Channel (7) == 1); // Rc -> right - expect (map.getJuceChannelForVst3Channel (8) == 4); // Sl -> leftSurroundSide - expect (map.getJuceChannelForVst3Channel (9) == 5); // Sl -> leftSurroundSide - expect (map.getJuceChannelForVst3Channel (10) == 6); // Tfl -> topFrontLeft - expect (map.getJuceChannelForVst3Channel (11) == 7); // Tfr -> topFrontRight - expect (map.getJuceChannelForVst3Channel (12) == 8); // Trl -> topRearLeft - expect (map.getJuceChannelForVst3Channel (13) == 9); // Trr -> topRearRight - expect (map.getJuceChannelForVst3Channel (14) == 14); // Tsl -> topSideLeft - expect (map.getJuceChannelForVst3Channel (15) == 15); // Tsr -> topSideRight + expect (map.getJuceChannelForVst3Channel (6) == 4); // Sl -> leftSurroundSide + expect (map.getJuceChannelForVst3Channel (7) == 5); // Sr -> rightSurroundSide + expect (map.getJuceChannelForVst3Channel (8) == 6); // Tfl -> topFrontLeft + expect (map.getJuceChannelForVst3Channel (9) == 7); // Tfr -> topFrontRight + expect (map.getJuceChannelForVst3Channel (10) == 8); // Trl -> topRearLeft + expect (map.getJuceChannelForVst3Channel (11) == 9); // Trr -> topRearRight + expect (map.getJuceChannelForVst3Channel (12) == 14); // Tsl -> topSideLeft + expect (map.getJuceChannelForVst3Channel (13) == 15); // Tsr -> topSideRight + expect (map.getJuceChannelForVst3Channel (14) == 12); // Lw -> wideLeft + expect (map.getJuceChannelForVst3Channel (15) == 13); // Lw -> wideRight } const auto blockSize = 128; diff --git a/JuceLibraryCode/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp b/JuceLibraryCode/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp index c3c0a04e27..4f5931c840 100644 --- a/JuceLibraryCode/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp +++ b/JuceLibraryCode/modules/juce_audio_processors/utilities/juce_ParameterAttachments.cpp @@ -304,6 +304,7 @@ void WebSliderParameterAttachment::sendInitialUpdate() object->setProperty ("label", parameter.getLabel()); object->setProperty ("numSteps", parameter.getNumSteps()); object->setProperty ("interval", range.interval); + object->setProperty ("parameterIndex", parameter.getParameterIndex()); sliderState.emitEvent (object.get()); attachment.sendInitialUpdate(); } @@ -347,6 +348,7 @@ void WebToggleButtonParameterAttachment::sendInitialUpdate() DynamicObject::Ptr object { new DynamicObject }; object->setProperty (detail::WebSliderRelayEvents::Event::eventTypeKey, "propertiesChanged"); object->setProperty ("name", parameter.getName (100)); + object->setProperty ("parameterIndex", parameter.getParameterIndex()); relay.emitEvent (object.get()); attachment.sendInitialUpdate(); } @@ -395,6 +397,7 @@ void WebComboBoxParameterAttachment::sendInitialUpdate() DynamicObject::Ptr object { new DynamicObject }; object->setProperty (detail::WebSliderRelayEvents::Event::eventTypeKey, "propertiesChanged"); object->setProperty ("name", parameter.getName (100)); + object->setProperty ("parameterIndex", parameter.getParameterIndex()); if (auto* choiceParameter = dynamic_cast (¶meter)) object->setProperty ("choices", choiceParameter->choices); diff --git a/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h b/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h index a0cfe3bc5f..6f690f0813 100644 --- a/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h +++ b/JuceLibraryCode/modules/juce_core/containers/juce_ListenerList.h @@ -73,10 +73,7 @@ namespace juce guaranteed that no more listeners will be called. By default a ListenerList is not thread safe. If thread-safety is required, - you can provide a thread-safe Array type as the second type parameter e.g. - @code - using ThreadSafeList = ListenerList>; - @endcode + use the ThreadSafeListenerList type. When calling listeners the iteration can be escaped early by using a "BailOutChecker". A BailOutChecker is a type that has a public member function @@ -87,8 +84,8 @@ namespace juce @tags{Core} */ -template > +template > class ListenerList { public: @@ -111,6 +108,8 @@ class ListenerList */ void add (ListenerClass* listenerToAdd) { + initialiseIfNeeded(); + if (listenerToAdd != nullptr) listeners->addIfNotAlreadyThere (listenerToAdd); else @@ -127,6 +126,9 @@ class ListenerList { jassert (listenerToRemove != nullptr); // Listeners can't be null pointers! + if (! initialised()) + return; + const ScopedLockType lock (listeners->getLock()); if (const auto index = listeners->removeFirstMatchingValue (listenerToRemove); index >= 0) @@ -154,10 +156,10 @@ class ListenerList } /** Returns the number of registered listeners. */ - int size() const noexcept { return listeners->size(); } + int size() const noexcept { return ! initialised() ? 0 : listeners->size(); } /** Returns true if no listeners are registered, false otherwise. */ - bool isEmpty() const noexcept { return listeners->isEmpty(); } + bool isEmpty() const noexcept { return ! initialised() || listeners->isEmpty(); } /** Clears the list. @@ -166,7 +168,10 @@ class ListenerList */ void clear() { - const ScopedLockType lock (listeners->getLock()); + if (! initialised()) + return; + + const ScopedLockType lock { listeners->getLock() }; listeners->clear(); @@ -175,7 +180,11 @@ class ListenerList } /** Returns true if the specified listener has been added to the list. */ - bool contains (ListenerClass* listener) const noexcept { return listeners->contains (listener); } + bool contains (ListenerClass* listener) const noexcept + { + return initialised() + && listeners->contains (listener); + } /** Returns the raw array of listeners. @@ -186,7 +195,11 @@ class ListenerList @see add, remove, clear, contains */ - const ArrayType& getListeners() const noexcept { return *listeners; } + const ArrayType& getListeners() const noexcept + { + const_cast (this)->initialiseIfNeeded(); + return *listeners; + } //============================================================================== /** Calls an invokable object for each listener in the list. */ @@ -234,6 +247,9 @@ class ListenerList const BailOutCheckerType& bailOutChecker, Callback&& callback) { + if (! initialised()) + return; + const auto localListeners = listeners; const ScopedLockType lock { localListeners->getLock() }; @@ -339,7 +355,7 @@ class ListenerList //============================================================================== using SharedListeners = std::shared_ptr; - const SharedListeners listeners = std::make_shared(); + SharedListeners listeners; struct Iterator { @@ -349,10 +365,49 @@ class ListenerList using SafeIterators = std::vector; using SharedIterators = std::shared_ptr; - const SharedIterators iterators = std::make_shared(); + SharedIterators iterators; + + enum class State + { + uninitialised, + initialising, + initialised + }; + + std::atomic state { State::uninitialised }; + + inline bool initialised() const noexcept { return state == State::initialised; } + + inline void initialiseIfNeeded() noexcept + { + if (initialised()) + return; + + auto expected = State::uninitialised; + + if (state.compare_exchange_strong (expected, State::initialising)) + { + listeners = std::make_shared(); + iterators = std::make_shared(); + state = State::initialised; + return; + } + + while (! initialised()) + std::this_thread::yield(); + } //============================================================================== JUCE_DECLARE_NON_COPYABLE (ListenerList) }; +//============================================================================== +/** + A thread safe version of the ListenerList class. + + @see ListenerList +*/ +template +using ThreadSafeListenerList = ListenerList>; + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp index f58e9dda7c..a4adf159a3 100644 --- a/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp +++ b/JuceLibraryCode/modules/juce_core/javascript/juce_Javascript.cpp @@ -35,7 +35,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-with-dtor", "-Wunused-but-set-variable", "-Wdeprecated", - "-Wunused-function") + "-Wunused-function", + "-Wpedantic") JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011 6246 6255 6262 6297 6308 6323 6340 6385 6386 28182) #include #include @@ -228,6 +229,10 @@ static qjs::JSValue juceToQuickJs (var variant, qjs::JSContext* ctx) } //============================================================================== +// Any type that references the QuickJS types inside the anonymous namespace added by us requires +// this with GCC. Suppressing this warning is fine, since these classes are only visible and used +// in a single translation unit. +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsubobject-linkage") class detail::QuickJSWrapper { public: @@ -268,6 +273,7 @@ class detail::QuickJSWrapper choc::javascript::Context context = choc::javascript::createQuickJSContext(); std::function interruptHandler; }; +JUCE_END_IGNORE_WARNINGS_GCC_LIKE using SetterFn = qjs::JSValue (*) (qjs::JSContext* ctx, qjs::JSValueConst thisVal, @@ -644,6 +650,7 @@ static uint32_t toUint32 (int64 value) } //============================================================================== +JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wsubobject-linkage") struct JSFunctionArguments { explicit JSFunctionArguments (qjs::JSContext* contextIn) : context (contextIn) @@ -822,6 +829,7 @@ class JSObject::Impl const detail::QuickJSWrapper* engine = nullptr; ValuePtr valuePtr; }; +JUCE_END_IGNORE_WARNINGS_GCC_LIKE JSObject::JSObject (const detail::QuickJSWrapper* engine) : impl (new Impl (engine)) diff --git a/JuceLibraryCode/modules/juce_core/juce_core_CompilationTime.cpp b/JuceLibraryCode/modules/juce_core/juce_core_CompilationTime.cpp new file mode 100644 index 0000000000..d372d71cd2 --- /dev/null +++ b/JuceLibraryCode/modules/juce_core/juce_core_CompilationTime.cpp @@ -0,0 +1,41 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +const char* juce_compilationDate = __DATE__; +const char* juce_compilationTime = __TIME__; + +} diff --git a/JuceLibraryCode/modules/juce_core/misc/juce_OptionsHelpers.h b/JuceLibraryCode/modules/juce_core/misc/juce_OptionsHelpers.h index 6e7fd9c8ce..0dff5cfa00 100644 --- a/JuceLibraryCode/modules/juce_core/misc/juce_OptionsHelpers.h +++ b/JuceLibraryCode/modules/juce_core/misc/juce_OptionsHelpers.h @@ -32,6 +32,10 @@ ============================================================================== */ +/** A base class for building Options. + + @tags{Core} +*/ template class OptionsBuilder { diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h index cc272e62c4..f74f9ccee6 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_Thread.h @@ -602,7 +602,7 @@ class JUCE_API Thread uint32 affinityMask = 0; bool deleteOnThreadEnd = false; std::atomic shouldExit { false }; - ListenerList> listeners; + ThreadSafeListenerList listeners; #if JUCE_ANDROID || JUCE_LINUX || JUCE_BSD std::atomic priority; diff --git a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h index cd20c90f0c..c8ae06fddf 100644 --- a/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h +++ b/JuceLibraryCode/modules/juce_core/threads/juce_ThreadPool.h @@ -147,7 +147,7 @@ class JUCE_API ThreadPoolJob String jobName; ThreadPool* pool = nullptr; std::atomic shouldStop { false }, isActive { false }, shouldBeDeleted { false }; - ListenerList> listeners; + ThreadSafeListenerList listeners; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob) }; diff --git a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp b/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp index 2b625e8250..dcb84bbad9 100644 --- a/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp +++ b/JuceLibraryCode/modules/juce_core/time/juce_Time.cpp @@ -602,14 +602,18 @@ static int getMonthNumberForCompileDate (const String& m) return 0; } +// Implemented in juce_core_CompilationTime.cpp +extern const char* juce_compilationDate; +extern const char* juce_compilationTime; + Time Time::getCompilationDate() { StringArray dateTokens, timeTokens; - dateTokens.addTokens (__DATE__, true); + dateTokens.addTokens (juce_compilationDate, true); dateTokens.removeEmptyStrings (true); - timeTokens.addTokens (__TIME__, ":", StringRef()); + timeTokens.addTokens (juce_compilationTime, ":", StringRef()); return Time (dateTokens[2].getIntValue(), getMonthNumberForCompileDate (dateTokens[0]), diff --git a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp index cfe4702f63..a7fbe47c4d 100644 --- a/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp +++ b/JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp @@ -76,23 +76,21 @@ class ValueTree::SharedObject final : public ReferenceCountedObject template void callListeners (ValueTree::Listener* listenerToExclude, Function fn) const { - auto numListeners = valueTreesWithListeners.size(); + if (valueTreesWithListeners.size() == 0) + return; - if (numListeners == 1) + if (valueTreesWithListeners.size() == 1) { valueTreesWithListeners.getUnchecked (0)->listeners.callExcluding (listenerToExclude, fn); + return; } - else if (numListeners > 0) - { - auto listenersCopy = valueTreesWithListeners; - for (int i = 0; i < numListeners; ++i) - { - auto* v = listenersCopy.getUnchecked (i); + const auto listenersCopy = valueTreesWithListeners; - if (i == 0 || valueTreesWithListeners.contains (v)) - v->listeners.callExcluding (listenerToExclude, fn); - } + for (auto [i, v] : enumerate (listenersCopy, int{})) + { + if (valueTreesWithListeners[i] == v || valueTreesWithListeners.contains (v)) + v->listeners.callExcluding (listenerToExclude, fn); } } diff --git a/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp index 47b09ada6a..2942cfeffd 100644 --- a/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp +++ b/JuceLibraryCode/modules/juce_events/timers/juce_Timer.cpp @@ -65,7 +65,7 @@ class ShutdownDetector : private DeletedAtShutdown } private: - using ListenerListType = ListenerList>; + using ListenerListType = ThreadSafeListenerList; // By having a static ListenerList it can outlive the ShutdownDetector instance preventing // issues for objects trying to remove themselves after the instance has been deleted diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Font.cpp b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Font.cpp index c234333c56..49d5af97a2 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Font.cpp +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Font.cpp @@ -275,12 +275,7 @@ class Font::SharedFontInternal : public ReferenceCountedObject jassert (getReferenceCount() == 1); typeface = newTypeface; - if (newTypeface != nullptr) - { - options = options.withTypeface (typeface) - .withName (typeface->getName()) - .withStyle (typeface->getStyle()); - } + options = options.withTypeface (typeface); } void setTypefaceName (String x) @@ -477,8 +472,8 @@ void Font::setTypefaceName (const String& faceName) jassert (faceName.isNotEmpty()); dupeInternalIfShared(); - font->setTypefaceName (faceName); font->setTypeface (nullptr); + font->setTypefaceName (faceName); } } @@ -487,8 +482,8 @@ void Font::setTypefaceStyle (const String& typefaceStyle) if (typefaceStyle != font->getTypefaceStyle()) { dupeInternalIfShared(); - font->setTypefaceStyle (typefaceStyle); font->setTypeface (nullptr); + font->setTypefaceStyle (typefaceStyle); } } @@ -763,22 +758,22 @@ int Font::getStringWidth (const String& text) const float Font::getStringWidthFloat (const String& text) const { - const auto w = getTypefacePtr()->getStringWidth (font->getMetricsKind(), text, getHeight(), getHorizontalScale()); - return w + (font->getHeight() * font->getHorizontalScale() * font->getKerning() * (float) text.length()); + const auto w = getTypefacePtr()->getStringWidth (getMetricsKind(), text, getHeight(), getHorizontalScale()); + return w + (getHeight() * getHorizontalScale() * getExtraKerningFactor() * (float) text.length()); } void Font::getGlyphPositions (const String& text, Array& glyphs, Array& xOffsets) const { - getTypefacePtr()->getGlyphPositions (font->getMetricsKind(), text, glyphs, xOffsets, getHeight(), getHorizontalScale()); + getTypefacePtr()->getGlyphPositions (getMetricsKind(), text, glyphs, xOffsets, getHeight(), getHorizontalScale()); if (auto num = xOffsets.size()) { - auto scale = font->getHeight() * font->getHorizontalScale(); + auto scale = getHeight() * getHorizontalScale(); auto* x = xOffsets.getRawDataPointer(); - if (! approximatelyEqual (font->getKerning(), 0.0f)) + if (! approximatelyEqual (getExtraKerningFactor(), 0.0f)) for (int i = 0; i < num; ++i) - x[i] += ((float) i * font->getKerning() * scale); + x[i] += ((float) i * getExtraKerningFactor() * scale); } } @@ -935,4 +930,104 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font) return Native::getDefaultPlatformTypefaceForFont (font); } +//============================================================================== +//============================================================================== +#if JUCE_UNIT_TESTS + +class FontTests : public UnitTest +{ +public: + FontTests() : UnitTest ("Font", UnitTestCategories::graphics) {} + + void runTest() override + { + const Span data { FontBinaryData::Karla_Regular_Typo_On_Offsets_Off }; + const auto face = Typeface::createSystemTypefaceFor (data.data(), data.size()); + + beginTest ("Old constructor from Typeface"); + { + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996) + Font f { face }; + JUCE_END_IGNORE_WARNINGS_MSVC + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == face->getStyle()); + expect (f.getTypefacePtr() == face); + + f.setTypefaceStyle ("Italic"); + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == "Italic"); + expect (f.getTypefacePtr() != face); + } + + beginTest ("FontOptions constructor from Typeface"); + { + const FontOptions opt { face }; + expect (opt.getName() == face->getName()); + expect (opt.getStyle() == face->getStyle()); + expect (opt.getTypeface() == face); + + Font f { opt }; + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == face->getStyle()); + expect (f.getTypefacePtr() == face); + + f.setTypefaceStyle ("Italic"); + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == "Italic"); + expect (f.getTypefacePtr() != face); + } + + beginTest ("FontOptions constructor from Typeface with style and name set"); + { + const auto opt = FontOptions { face }.withName ("placeholder").withStyle ("Italic"); + expect (opt.getName() == face->getName()); + expect (opt.getStyle() == face->getStyle()); + expect (opt.getTypeface() == face); + + Font f { opt }; + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == face->getStyle()); + expect (f.getTypefacePtr() == face); + + f.setTypefaceStyle ("Italic"); + + expect (f.getTypefaceName() == face->getName()); + expect (f.getTypefaceStyle() == "Italic"); + expect (f.getTypefacePtr() != face); + } + + auto a = FontOptions().withName ("placeholder").withStyle ("Italic"); + + beginTest ("Setting Typeface on FontOptions replaces previous name/style"); + { + auto b = a.withTypeface (face); + + expect (b.getName() == face->getName()); + expect (b.getStyle() == face->getStyle()); + } + + beginTest ("Setting a name or style on a FontOptions holding a typeface has no effect"); + { + auto b = a.withTypeface (face).withName ("name").withStyle ("style"); + expect (b.getName() == face->getName()); + expect (b.getStyle() == face->getStyle()); + + auto c = b.withTypeface (nullptr).withName ("name").withStyle ("style"); + expect (c.getName() == "name"); + expect (c.getStyle() == "style"); + } + } +}; + +static FontTests fontTests; + +#endif + } // namespace juce diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_FontOptions.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_FontOptions.h index 5d50d97f9b..0f48606bfd 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_FontOptions.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_FontOptions.h @@ -90,18 +90,44 @@ class JUCE_API FontOptions final If the options include a non-null Typeface::Ptr, this will be ignored. Otherwise, a suitable typeface will be located based on the typeface name and style strings. */ - [[nodiscard]] FontOptions withName (String x) const { return withMember (*this, &FontOptions::name, x); } + [[nodiscard]] FontOptions withName (String x) const + { + if (typeface == nullptr) + return withMember (*this, &FontOptions::name, x); + + // This field will be ignored if the typeface pointer is non-null. + // If you want to set a custom name, first set the typeface pointer to null. + jassertfalse; + return *this; + } /** Returns a copy of these options with a new typeface style. If the options include a non-null Typeface::Ptr, this will be ignored. Otherwise, a suitable typeface will be located based on the typeface name and style strings. */ - [[nodiscard]] FontOptions withStyle (String x) const { return withMember (*this, &FontOptions::style, x); } + [[nodiscard]] FontOptions withStyle (String x) const + { + if (typeface == nullptr) + return withMember (*this, &FontOptions::style, x); + + // This field will be ignored if the typeface pointer is non-null. + // If you want to set a custom style, first set the typeface pointer to null. + jassertfalse; + return *this; + } /** Returns a copy of these options with a new typeface. If the typeface is non-null, it takes precedence over the name and style strings. */ - [[nodiscard]] FontOptions withTypeface (Typeface::Ptr x) const { return withMember (*this, &FontOptions::typeface, x); } + [[nodiscard]] FontOptions withTypeface (Typeface::Ptr x) const + { + // If the typeface is non-null, then the name and style fields will be ignored. + jassert (x == nullptr || name.isEmpty()); + jassert (x == nullptr || style.isEmpty()); + + auto result = (x != nullptr ? withName (x->getName()).withStyle (x->getStyle()) : *this); + return withMember (std::move (result), &FontOptions::typeface, x); + } /** Returns a copy of these options with a new set of preferred fallback family names. */ [[nodiscard]] FontOptions withFallbacks (std::vector x) const { return withMember (*this, &FontOptions::fallbacks, std::move (x)); } diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h index a010a51c27..0f23461622 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_FunctionPointerDestructor.h @@ -32,6 +32,8 @@ ============================================================================== */ +#ifndef DOXYGEN + namespace juce { @@ -47,3 +49,5 @@ struct FunctionPointerDestructor }; } // namespace juce + +#endif diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_JustifiedText.cpp b/JuceLibraryCode/modules/juce_graphics/fonts/juce_JustifiedText.cpp index 1020642be9..e755d33e1c 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_JustifiedText.cpp +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_JustifiedText.cpp @@ -371,7 +371,6 @@ JustifiedText::JustifiedText (const SimpleShapedText& t, const ShapedTextOptions || effectiveLength <= *options.getMaxWidth() + maxWidthTolerance) return; - // TODO(ati) This should be (! isLtr) once we have a mechanism to determine the base writing direction const auto cutoffAtFront = lastLineAlignment.value.getX() < 0.0f - maxWidthTolerance; const auto getLastLineVisibleRange = [&] (float ellipsisLength) diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_LruCache.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_LruCache.h index a585959c44..9c394ae337 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_LruCache.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_LruCache.h @@ -32,6 +32,8 @@ ============================================================================== */ +#ifndef DOXYGEN + namespace juce { @@ -82,3 +84,5 @@ class LruCache }; } // namespace juce + +#endif diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_SimpleShapedText.cpp b/JuceLibraryCode/modules/juce_graphics/fonts/juce_SimpleShapedText.cpp index e15ce4ec36..173b1c9319 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_SimpleShapedText.cpp +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_SimpleShapedText.cpp @@ -288,7 +288,6 @@ SimpleShapedText::SimpleShapedText (const String* data, shape (string, options); } -// TODO(ati) This can probably be removed. Or we can do shaping using raw UTF8 pointers. struct Utf8Lookup { Utf8Lookup (const String& s) @@ -349,27 +348,8 @@ static std::vector lowLevelShape (const String& string, hb_buffer_set_direction (buffer.get(), direction == TextDirection::ltr ? HB_DIRECTION_LTR : HB_DIRECTION_RTL); - // TODO(ati) I lifted this from the Skia source comments. Unfortunately the bug tracker isn't - // externally available. - // - // Documentation for HB_BUFFER_FLAG_BOT/EOT at 763e5466c0a03a7c27020e1e2598e488612529a7. - // Currently BOT forces a dotted circle when first codepoint is a mark; EOT has no effect. - // Avoid adding dotted circle, re-evaluate if BOT/EOT change. See https://skbug.com/9618. - // hb_buffer_set_flags(buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT); - // const auto flags = HB_BUFFER_FLAG_DEFAULT - // | (byteRange.getStart() == 0 ? HB_BUFFER_FLAG_BOT : 0) - // | (byteRange.getEnd() == string.getNumBytesAsUTF8() ? HB_BUFFER_FLAG_EOT : 0); - // - // hb_buffer_set_flags (buffer.get(), (hb_buffer_flags_t) flags); - Utf8Lookup utf8Lookup { string }; - // TODO(ati) Test this first. I wonder if visual linebreaks are forced by the SKIA technique, - // where they add the buffer contents in three separate calls to hb_buffer_add* and add - // precontext, text-to-shape and postcontext. - // - // I am afraid they just assume that it is safe to break at run boundaries, which doesn't quite - // hit all our imagined use-cases. const auto preContextByteRange = utf8Lookup.getByteRange (Range { 0, range.getStart() }); hb_buffer_add_utf8 (buffer.get(), @@ -381,9 +361,9 @@ static std::vector lowLevelShape (const String& string, // Adding the converted portion of the text with hb_buffer_add_utf32() or especially with // hb_buffer_add() gives us control over cluster numbers. hb_buffer_add_utf32() will increment // cluster numbers by unicode codepoints (as opposed to UTF8 bytes) starting from 0. - auto utf32Ptr = string.toUTF32() + (int) range.getStart(); + auto utf32Span = Span { string.toUTF32().getAddress() + (size_t) range.getStart(), + (size_t) range.getLength() }; - // TODO(ati) This should be configurable in case someone wants to implement a "display whitespace" functionality // We're using a word joiner (zero width non-breaking space) followed by a non-breaking space // for visual representation. This is so that it's not possible to break the glyph representing // the line breaking glyph on its own. @@ -391,11 +371,12 @@ static std::vector lowLevelShape (const String& string, const auto numLineEndsToReplace = [&] { - const auto chunkLength = (int) range.getLength(); + constexpr auto lf = 0x0a; + constexpr auto cr = 0x0d; - if (chunkLength >= 1 && utf32Ptr[chunkLength - 1] == 0xa) + if (! utf32Span.empty() && (utf32Span.back() == lf || utf32Span.back() == cr)) { - if (chunkLength >= 2 && utf32Ptr[chunkLength - 2] == 0xd) + if (utf32Span.size() >= 2 && utf32Span[utf32Span.size() - 2] == cr) return 2; return 1; @@ -405,14 +386,14 @@ static std::vector lowLevelShape (const String& string, }(); hb_buffer_add_utf32 (buffer.get(), - (uint32_t*) utf32Ptr.getAddress(), + (uint32_t*) utf32Span.data(), (int) range.getLength() - numLineEndsToReplace, (unsigned int) 0, (int) range.getLength() - numLineEndsToReplace); for (int i = 0; i < numLineEndsToReplace; ++i) { - // TODO(ati) The following gets cluster values right, but this does not follow clearly from harfbuzz documentation. + // The following gets cluster values right, but this does not follow clearly from harfbuzz documentation. // Add at least a regression test checking the correctness of cluster values. hb_buffer_add (buffer.get(), static_cast (*(crLf + (2 - numLineEndsToReplace) + i)), @@ -467,7 +448,8 @@ static std::vector lowLevelShape (const String& string, }); // It this is hit, the typeface can't display one or more characters. - // This normally shouldn't happen if font fallback is enabled. + // This normally shouldn't happen if font fallback is enabled, unless the String contains + // control characters that JUCE doesn't know how to handle appropriately. jassert (unknownGlyph == infos.end()); [[maybe_unused]] const auto trackingAmount = (! HB_DIRECTION_IS_VERTICAL (direction) && ! trackingIsDefault) @@ -527,7 +509,6 @@ struct SubSpanLookup template static auto makeSubSpanLookup (Span s) { return SubSpanLookup { s }; } -// TODO(ati) Fix Unicode::WordBreakIterator struct CanBreakBeforeIterator { explicit CanBreakBeforeIterator (Span s) @@ -613,7 +594,6 @@ struct IntegralCanBreakBeforeIterator CanBreakBeforeIterator it; Range restrictedTo { std::numeric_limits::min(), std::numeric_limits::max() }; - // TODO(ati) Move this out of here into append(). We want to signal that the entire range can be consumed without breaking. bool rangeEndReturned = false; }; diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h index ff3f2d26b3..c62580f614 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h @@ -37,6 +37,8 @@ namespace juce /** A single path-based layer of a colour glyph. Contains the glyph shape and the colour in which the shape should be painted. + + @tags{Graphics} */ struct ColourLayer { @@ -45,6 +47,8 @@ struct ColourLayer }; /** A bitmap representing (part of) a glyph, most commonly used to represent colour emoji glyphs. + + @tags{Graphics} */ struct ImageLayer { @@ -53,6 +57,8 @@ struct ImageLayer }; /** A single layer that makes up part of a glyph image. + + @tags{Graphics} */ struct GlyphLayer { @@ -85,6 +91,8 @@ enum class TypefaceMetricsKind }; /** Font metrics using JUCE conventions. + + @tags{Graphics} */ struct TypefaceMetrics { @@ -280,6 +288,7 @@ class JUCE_API Typeface : public ReferenceCountedObject const auto isMonochrome = typeface->getColourGlyphFormats() == 0; const auto isSvg = (typeface->getColourGlyphFormats() & Typeface::colourGlyphFormatSvg) != 0; const auto isSimpleColour = (typeface->getColourGlyphFormats() & (Typeface::colourGlyphFormatBitmap | Typeface::colourGlyphFormatCOLRv0)) != 0; + @endcode */ int getColourGlyphFormats() const; diff --git a/JuceLibraryCode/modules/juce_graphics/fonts/juce_TypefaceFileCache.h b/JuceLibraryCode/modules/juce_graphics/fonts/juce_TypefaceFileCache.h index ff0e380607..0569a1e705 100644 --- a/JuceLibraryCode/modules/juce_graphics/fonts/juce_TypefaceFileCache.h +++ b/JuceLibraryCode/modules/juce_graphics/fonts/juce_TypefaceFileCache.h @@ -32,6 +32,8 @@ ============================================================================== */ +#ifndef DOXYGEN + namespace juce { @@ -68,3 +70,5 @@ class TypefaceFileCache : public DeletedAtShutdown JUCE_IMPLEMENT_SINGLETON (TypefaceFileCache) } // namespace juce + +#endif diff --git a/JuceLibraryCode/modules/juce_graphics/juce_graphics_Harfbuzz.cpp b/JuceLibraryCode/modules/juce_graphics/juce_graphics_Harfbuzz.cpp index b67e1034ea..1aa6b402e8 100644 --- a/JuceLibraryCode/modules/juce_graphics/juce_graphics_Harfbuzz.cpp +++ b/JuceLibraryCode/modules/juce_graphics/juce_graphics_Harfbuzz.cpp @@ -53,6 +53,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations", "-Wexpansion-to-defined", "-Wunsafe-loop-optimizations") +#define HAVE_ATEXIT 1 + #if JUCE_LINUX || JUCE_BSD #ifndef JUCE_USE_FREETYPE #define JUCE_USE_FREETYPE 1 diff --git a/JuceLibraryCode/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp b/JuceLibraryCode/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp index 1cca51401f..656372570d 100644 --- a/JuceLibraryCode/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp +++ b/JuceLibraryCode/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp @@ -55,89 +55,68 @@ class PushedLayers void push (ComSmartPtr context, const D2D1_LAYER_PARAMETERS& layerParameters) { // Clipping and transparency are all handled by pushing Direct2D - // layers.The SavedState creates an internal stack of Layer objects to + // layers. The SavedState creates an internal stack of Layer objects to // keep track of how many layers need to be popped. Pass nullptr for // the PushLayer layer parameter to allow Direct2D to manage the layers // (Windows 8 or later) - #if JUCE_DEBUG - // Check if this should be an axis-aligned clip layer (per the D2D debug layer) - // - // D2D DEBUG INFO - PERF - A layer is being used with a NULL opacity mask, 1.0 opacity, and an axis aligned rectangular geometric mask.The Push / Pop Clip API should achieve the same results with higher performance. - auto checkAxisAlignedClipLayer = [&]() + #if JUCE_DEBUG + + // Check if this should be an axis-aligned clip layer (per the D2D + // debug layer) + const auto isGeometryAxisAlignedRectangle = [&] { + auto* geometry = layerParameters.geometricMask; + + if (geometry == nullptr) + return false; + struct Sink : public ComBaseClassHelper { - D2D1_POINT_2F lastPoint {}; + D2D1_POINT_2F lastPoint{}; bool axisAlignedLines = true; UINT32 lineCount = 0; - STDMETHOD_ (void, SetFillMode) - (D2D1_FILL_MODE) override { return; } - STDMETHOD_ (void, SetSegmentFlags) - (D2D1_PATH_SEGMENT) override { return; } - STDMETHOD_ (void, BeginFigure) - (D2D1_POINT_2F p, D2D1_FIGURE_BEGIN) override - { - lastPoint = p; - return; - } - STDMETHOD_ (void, AddLines) - (const D2D1_POINT_2F* points, UINT32 count) override + STDMETHOD (Close)() override { return S_OK; } + STDMETHOD_ (void, SetFillMode) (D2D1_FILL_MODE) override {} + STDMETHOD_ (void, SetSegmentFlags) (D2D1_PATH_SEGMENT) override {} + STDMETHOD_ (void, EndFigure) (D2D1_FIGURE_END) override {} + + STDMETHOD_ (void, BeginFigure) (D2D1_POINT_2F p, D2D1_FIGURE_BEGIN) override { lastPoint = p; } + + STDMETHOD_ (void, AddLines) (const D2D1_POINT_2F* points, UINT32 count) override { for (UINT32 i = 0; i < count; ++i) { auto p = points[i]; - axisAlignedLines &= approximatelyEqual (p.x, lastPoint.x) || approximatelyEqual (p.y, lastPoint.y); - + axisAlignedLines &= (approximatelyEqual (p.x, lastPoint.x) || approximatelyEqual (p.y, lastPoint.y)); lastPoint = p; } lineCount += count; - - return; } - STDMETHOD_ (void, AddBeziers) - (const D2D1_BEZIER_SEGMENT*, UINT32) override + + STDMETHOD_ (void, AddBeziers) (const D2D1_BEZIER_SEGMENT*, UINT32) override { axisAlignedLines = false; - return; } - STDMETHOD_ (void, EndFigure) - (D2D1_FIGURE_END) override - { - return; - } - STDMETHOD (Close) - () override { return S_OK; } - } sink; - - if (layerParameters.opacity != 1.0f) - return false; - - if (layerParameters.opacityBrush) - return false; - - if (! layerParameters.geometricMask) - return false; - - if (layerParameters.maskTransform.m12 != 0.0f || layerParameters.maskTransform.m21 != 0.0f) - return false; + }; - layerParameters.geometricMask->Simplify (D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, - D2D1::Matrix3x2F::Identity(), - 1.0f, - &sink); + Sink sink; + geometry->Simplify (D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + layerParameters.maskTransform, + 1.0f, + &sink); - // - // Check for 3 lines; BeginFigure counts as 1 line - // + // Check for 3 lines; the BeginFigure counts as 1 line return sink.axisAlignedLines && sink.lineCount == 3; - }; + }(); - // jassert (! checkAxisAlignedClipLayer()); - #endif + // jassert (layerParameters.opacity != 1.0f + // || layerParameters.opacityBrush + // || ! isGeometryAxisAlignedRectangle); + #endif context->PushLayer (layerParameters, nullptr); pushedLayers.emplace_back (popLayerFlag); @@ -1312,21 +1291,16 @@ void Direct2DGraphicsContext::fillRectList (const RectangleList& list) void Direct2DGraphicsContext::drawRect (const Rectangle& r, float lineThickness) { - // ID2D1DeviceContext::DrawRectangle centers the stroke around the edges of the specified rectangle, but - // the software renderer contains the stroke within the rectangle - // To match the software renderer, reduce the rectangle by half the stroke width - if (r.getWidth() * 0.5f < lineThickness || r.getHeight() * 0.5f < lineThickness) - return; - auto draw = [&] (Rectangle rect, ComSmartPtr deviceContext, ComSmartPtr brush) { + // ID2D1DeviceContext::DrawRectangle centers the stroke around the edges of the specified rectangle, but + // the software renderer contains the stroke within the rectangle + // To match the software renderer, reduce the rectangle by half the stroke width if (brush != nullptr) - deviceContext->DrawRectangle (D2DUtilities::toRECT_F (rect), brush, lineThickness); + deviceContext->DrawRectangle (D2DUtilities::toRECT_F (rect.reduced (lineThickness * 0.5f)), brush, lineThickness); }; - auto reducedR = r.reduced (lineThickness * 0.5f); - - getPimpl()->paintPrimitive (reducedR, draw); + getPimpl()->paintPrimitive (r, draw); } void Direct2DGraphicsContext::fillPath (const Path& p, const AffineTransform& transform) diff --git a/JuceLibraryCode/modules/juce_gui_basics/desktop/juce_Desktop.cpp b/JuceLibraryCode/modules/juce_gui_basics/desktop/juce_Desktop.cpp index 214b0add89..7e2dbed55e 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/desktop/juce_Desktop.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/desktop/juce_Desktop.cpp @@ -376,7 +376,7 @@ bool Desktop::isHeadless() const noexcept bool Desktop::supportsBorderlessNonClientResize() const { - #if JUCE_WINDOWS || JUCE_MAC + #if JUCE_MAC return true; #else return false; diff --git a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp index e75fecf310..89890a1092 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.cpp @@ -88,7 +88,6 @@ #include #include #include - #include #if JUCE_ETW_TRACELOGGING #include @@ -117,7 +116,6 @@ #pragma comment(lib, "vfw32.lib") #pragma comment(lib, "imm32.lib") #pragma comment(lib, "comctl32.lib") - #pragma comment(lib, "dwmapi.lib") #if JUCE_OPENGL #pragma comment(lib, "OpenGL32.Lib") diff --git a/JuceLibraryCode/modules/juce_gui_basics/native/juce_Windowing_windows.cpp b/JuceLibraryCode/modules/juce_gui_basics/native/juce_Windowing_windows.cpp index 4c2f05ca07..ad00e032af 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/native/juce_Windowing_windows.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/native/juce_Windowing_windows.cpp @@ -1460,6 +1460,7 @@ struct RenderContext virtual bool getResizing() const = 0; virtual void handleNcCalcSize (WPARAM wParam, LPARAM lParam) = 0; virtual void handleShowWindow() = 0; + virtual std::optional getNcHitTestResult() = 0; /* Gets a snapshot of whatever the render context is currently showing. */ virtual Image createSnapshot() = 0; @@ -1579,56 +1580,17 @@ class HWNDComponentPeer final : public ComponentPeer handlePaintMessage(); } - std::optional> getCustomBorderSize() const + void updateBorderSize() { - if (hasTitleBar() || (styleFlags & windowAppearsOnTaskbar) == 0) - return {}; - - ScopedThreadDPIAwarenessSetter setter { hwnd }; - // Apply standard padding to the left, right, and bottom of the client area. - // The system will use this for the resizable border area. - // No padding at the top, though, because we want to paint our own title there. - const auto dpi = GetDpiForWindow (hwnd); - const auto frameX = GetSystemMetricsForDpi (SM_CXFRAME, dpi); - const auto frameY = GetSystemMetricsForDpi (SM_CYFRAME, dpi); - const auto padding = GetSystemMetricsForDpi (SM_CXPADDEDBORDER, dpi); - - // On Windows 11, the non-client area drawing will obscure the top pixel of the client - // area. Adding a bit of extra padding ensures that the entirety of the client area remains - // visible. - // Unfortunately, earlier Windows versions seem to display the full title bar if the top - // padding is not zero, so we have to use a different padding value there. - const auto topPadding = SystemStats::getOperatingSystemType() == SystemStats::Windows11 - ? (int) dpi / USER_DEFAULT_SCREEN_DPI - : 0; - - return BorderSize { isFullScreen() ? frameY + padding : topPadding, - frameX + padding, - frameY + padding, - frameX + padding }; - } - - BorderSize findPhysicalBorderSize() const - { - if (const auto custom = getCustomBorderSize()) - return *custom; - - ScopedThreadDPIAwarenessSetter setter { hwnd }; - - WINDOWINFO info{}; + WINDOWINFO info; info.cbSize = sizeof (info); - if (! GetWindowInfo (hwnd, &info)) - return {}; - - return { roundToInt ((info.rcClient.top - info.rcWindow.top)), - roundToInt ((info.rcClient.left - info.rcWindow.left)), - roundToInt ((info.rcWindow.bottom - info.rcClient.bottom)), - roundToInt ((info.rcWindow.right - info.rcClient.right)) }; - } + if (GetWindowInfo (hwnd, &info)) + windowBorder = BorderSize (roundToInt ((info.rcClient.top - info.rcWindow.top) / scaleFactor), + roundToInt ((info.rcClient.left - info.rcWindow.left) / scaleFactor), + roundToInt ((info.rcWindow.bottom - info.rcClient.bottom) / scaleFactor), + roundToInt ((info.rcWindow.right - info.rcClient.right) / scaleFactor)); - void updateBorderSize() - { if (renderContext != nullptr) renderContext->updateBorderSize(); } @@ -1653,20 +1615,7 @@ class HWNDComponentPeer final : public ComponentPeer fullScreen = isNowFullScreen; - const auto borderSize = findPhysicalBorderSize(); - auto newBounds = borderSize.addedTo ([&] - { - ScopedThreadDPIAwarenessSetter setter { hwnd }; - - if (! isPerMonitorDPIAwareWindow (hwnd)) - return bounds; - - if (inDpiChange) - return convertLogicalScreenRectangleToPhysical (bounds, hwnd); - - return convertLogicalScreenRectangleToPhysical (bounds, hwnd) - .withPosition (Desktop::getInstance().getDisplays().logicalToPhysical (bounds.getTopLeft())); - }()); + auto newBounds = windowBorder.addedTo (bounds); if (isNotOpaque()) { @@ -1677,29 +1626,17 @@ class HWNDComponentPeer final : public ComponentPeer } } - const auto oldBounds = [this] - { - ScopedThreadDPIAwarenessSetter setter { hwnd }; - RECT result; - GetWindowRect (hwnd, &result); - return D2DUtilities::toRectangle (result); - }(); + auto oldBounds = getBounds(); const bool hasMoved = (oldBounds.getPosition() != bounds.getPosition()); const bool hasResized = (oldBounds.getWidth() != bounds.getWidth() || oldBounds.getHeight() != bounds.getHeight()); - DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED; + DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER; if (! hasMoved) flags |= SWP_NOMOVE; if (! hasResized) flags |= SWP_NOSIZE; - SetWindowPos (hwnd, - nullptr, - newBounds.getX(), - newBounds.getY(), - newBounds.getWidth(), - newBounds.getHeight(), - flags); + setWindowPos (hwnd, newBounds, flags, ! inDpiChange); if (hasResized && isValidPeer (this)) { @@ -1710,20 +1647,28 @@ class HWNDComponentPeer final : public ComponentPeer Rectangle getBounds() const override { - if (parentToAddTo == nullptr) - return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd); + auto bounds = [this] + { + if (parentToAddTo == nullptr) + return convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd); - auto localBounds = D2DUtilities::toRectangle (getWindowClientRect (hwnd)); + auto localBounds = D2DUtilities::toRectangle (getWindowClientRect (hwnd)); - if (isPerMonitorDPIAwareWindow (hwnd)) - return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt(); + if (isPerMonitorDPIAwareWindow (hwnd)) + return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt(); - return localBounds; + return localBounds; + }(); + + return windowBorder.subtractedFrom (bounds); } Point getScreenPosition() const { - return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd).getPosition(); + auto r = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd); + + return { r.getX() + windowBorder.getLeft(), + r.getY() + windowBorder.getTop() }; } Point localToGlobal (Point relativePosition) override { return relativePosition + getScreenPosition().toFloat(); } @@ -1793,14 +1738,18 @@ class HWNDComponentPeer final : public ComponentPeer { auto boundsCopy = lastNonFullscreenBounds; - ShowWindow (hwnd, SW_SHOWNORMAL); + if (hasTitleBar()) + ShowWindow (hwnd, SW_SHOWNORMAL); if (! boundsCopy.isEmpty()) setBounds (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, boundsCopy), false); } else { - ShowWindow (hwnd, SW_SHOWMAXIMIZED); + if (hasTitleBar()) + ShowWindow (hwnd, SW_SHOWMAXIMIZED); + else + SendMessageW (hwnd, WM_SETTINGCHANGE, 0, 0); } if (deletionChecker != nullptr) @@ -1816,6 +1765,9 @@ class HWNDComponentPeer final : public ComponentPeer bool isFullScreen() const override { + if (! hasTitleBar()) + return fullScreen; + WINDOWPLACEMENT wp; wp.length = sizeof (wp); GetWindowPlacement (hwnd, &wp); @@ -1838,12 +1790,12 @@ class HWNDComponentPeer final : public ComponentPeer OptionalBorderSize getFrameSizeIfPresent() const override { - return ComponentPeer::OptionalBorderSize { getFrameSize() }; + return ComponentPeer::OptionalBorderSize { windowBorder }; } BorderSize getFrameSize() const override { - return findPhysicalBorderSize().multipliedBy (1.0 / scaleFactor); + return windowBorder; } bool setAlwaysOnTop (bool alwaysOnTop) override @@ -2289,6 +2241,7 @@ class HWNDComponentPeer final : public ComponentPeer ULONGLONG lastMagnifySize = 0; bool fullScreen = false, isDragging = false, isMouseOver = false, hasCreatedCaret = false, constrainerIsResizing = false; + BorderSize windowBorder; IconConverters::IconPtr currentWindowIcon; FileDropTarget* dropTarget = nullptr; UWPUIViewSettings uwpViewSettings; @@ -2449,37 +2402,33 @@ class HWNDComponentPeer final : public ComponentPeer { type |= WS_OVERLAPPED; - if ((styleFlags & windowHasCloseButton) == 0) + if ((styleFlags & windowHasCloseButton) != 0) { - // annoyingly, windows won't let you have a min/max button without a close button - jassert ((styleFlags & (windowHasMinimiseButton | windowHasMaximiseButton)) == 0); + type |= WS_SYSMENU; } else { - type |= WS_SYSMENU; + // annoyingly, windows won't let you have a min/max button without a close button + jassert ((styleFlags & (windowHasMinimiseButton | windowHasMaximiseButton)) == 0); } + + if ((styleFlags & windowIsResizable) != 0) + type |= WS_THICKFRAME; } else if (parentToAddTo != nullptr) { type |= WS_CHILD; } - - if (parentToAddTo == nullptr) + else { - if ((styleFlags & windowAppearsOnTaskbar) != 0) - { - exstyle |= WS_EX_APPWINDOW; - } - else - { - exstyle |= WS_EX_TOOLWINDOW; - type |= WS_POPUP; // Note that popup windows don't get rounded corners by default - } - - if ((styleFlags & windowIsResizable) != 0) - type |= WS_THICKFRAME; + type |= WS_POPUP | WS_SYSMENU; } + if ((styleFlags & windowAppearsOnTaskbar) == 0) + exstyle |= WS_EX_TOOLWINDOW; + else + exstyle |= WS_EX_APPWINDOW; + // Don't set WS_EX_TRANSPARENT here; setting that flag hides OpenGL child windows // behind the Direct2D composition tree. if ((styleFlags & windowHasMinimiseButton) != 0) type |= WS_MINIMIZEBOX; @@ -2490,14 +2439,6 @@ class HWNDComponentPeer final : public ComponentPeer L"", type, 0, 0, 0, 0, parentToAddTo, nullptr, (HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr); - // if (! hasTitleBar() && parentToAddTo == nullptr) - // { - // // Disable rounded corners on Windows 11 for custom windows with no titlebar, - // // because window borders look weird when they get rounded away. - // const auto pref = DWMWCP_DONOTROUND; - // DwmSetWindowAttribute (hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &pref, sizeof (pref)); - // } - #if JUCE_DEBUG // The DPI-awareness context of this window and JUCE's hidden message window are different. // You normally want these to match otherwise timer events and async messages will happen @@ -2612,10 +2553,8 @@ class HWNDComponentPeer final : public ComponentPeer void updateShadower() { - if (! component.isCurrentlyModal() - && (styleFlags & windowHasDropShadow) != 0 - && (styleFlags & windowIsTemporary) != 0 - && (! hasTitleBar() || SystemStats::getOperatingSystemType() < SystemStats::WinVista)) + if (! component.isCurrentlyModal() && (styleFlags & windowHasDropShadow) != 0 + && ((! hasTitleBar()) || SystemStats::getOperatingSystemType() < SystemStats::WinVista)) { shadower = component.getLookAndFeel().createDropShadowerForComponent (component); @@ -2697,13 +2636,7 @@ class HWNDComponentPeer final : public ComponentPeer return false; } - enum class WindowArea - { - nonclient, - client, - }; - - void doMouseMove (Point position, bool isMouseDownEvent, WindowArea area) + void doMouseMove (Point position, bool isMouseDownEvent) { ModifierKeys modsToSend (ModifierKeys::currentModifiers); @@ -2737,8 +2670,7 @@ class HWNDComponentPeer final : public ComponentPeer if (! TrackMouseEvent (&tme)) jassertfalse; - if (area == WindowArea::client) - Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); + Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); } else if (! isDragging) { @@ -2761,7 +2693,7 @@ class HWNDComponentPeer final : public ComponentPeer } } - void doMouseDown (Point position, const WPARAM wParam, WindowArea area) + void doMouseDown (Point position, const WPARAM wParam) { // this will be handled by WM_TOUCH if (isTouchEvent() || areOtherTouchSourcesActive()) @@ -2770,7 +2702,7 @@ class HWNDComponentPeer final : public ComponentPeer if (GetCapture() != hwnd) SetCapture (hwnd); - doMouseMove (position, true, area); + doMouseMove (position, true); if (isValidPeer (this)) { @@ -3326,51 +3258,32 @@ class HWNDComponentPeer final : public ComponentPeer bool isConstrainedNativeWindow() const { return constrainer != nullptr - && (styleFlags & windowIsResizable) != 0 + && (styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable) && ! isKioskMode(); } Rectangle getCurrentScaledBounds() const { - const auto windowBorder = findPhysicalBorderSize().multipliedBy (1.0 / scaleFactor); - const auto unscaled = windowBorder.addedTo (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBounds())); - return detail::ScalingHelpers::unscaledScreenPosToScaled (component, unscaled); + return detail::ScalingHelpers::unscaledScreenPosToScaled (component, windowBorder.addedTo (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBounds()))); } LRESULT handleSizeConstraining (RECT& r, const WPARAM wParam) { if (isConstrainedNativeWindow()) { - const auto movingTop = wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT; - const auto movingLeft = wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT; - const auto movingBottom = wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT; - const auto movingRight = wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT; + const auto logicalBounds = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (r).toFloat(), hwnd); + auto pos = detail::ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds).toNearestInt(); - const auto snap = [&] (auto original, auto constrained) - { - const auto snappedX = movingLeft ? constrained.withRightX (original.getRight()) : constrained.withX (original.getX()); - const auto snappedY = movingTop ? snappedX .withBottomY (original.getBottom()) : snappedX .withY (original.getY()); - return snappedY; - }; - - const auto physicalBounds = D2DUtilities::toRectangle (r); - const auto logicalBounds = convertPhysicalScreenRectangleToLogical (physicalBounds.toFloat(), hwnd); - const auto posFloat = detail::ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds); - auto pos = posFloat.toNearestInt(); - - constrainer->checkBounds (pos, - getCurrentScaledBounds(), - Desktop::getInstance().getDisplays().getTotalBounds (true), - movingTop, - movingLeft, - movingBottom, - movingRight); + const auto original = getCurrentScaledBounds(); - const auto snappedLogicalPos = snap (posFloat, pos.toFloat()); - const auto newPhysicalRect = convertLogicalScreenRectangleToPhysical (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, snappedLogicalPos).toNearestInt(), hwnd); - const auto snappedPhysicalPos = snap (physicalBounds, newPhysicalRect); + constrainer->checkBounds (pos, original, + Desktop::getInstance().getDisplays().getTotalBounds (true), + wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT, + wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT, + wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT, + wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT); - r = D2DUtilities::toRECT (snappedPhysicalPos); + r = D2DUtilities::toRECT (convertLogicalScreenRectangleToPhysical (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, pos.toFloat()).toNearestInt(), hwnd)); } updateBorderSize(); @@ -3555,29 +3468,29 @@ class HWNDComponentPeer final : public ComponentPeer void handleLeftClickInNCArea (WPARAM wParam) { - if (sendInputAttemptWhenModalMessage()) - return; - - switch (wParam) - { - case HTBOTTOM: - case HTBOTTOMLEFT: - case HTBOTTOMRIGHT: - case HTGROWBOX: - case HTLEFT: - case HTRIGHT: - case HTTOP: - case HTTOPLEFT: - case HTTOPRIGHT: - if (isConstrainedNativeWindow()) + if (! sendInputAttemptWhenModalMessage()) + { + switch (wParam) { - constrainerIsResizing = true; - constrainer->resizeStart(); - } - return; + case HTBOTTOM: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + case HTGROWBOX: + case HTLEFT: + case HTRIGHT: + case HTTOP: + case HTTOPLEFT: + case HTTOPRIGHT: + if (isConstrainedNativeWindow()) + { + constrainerIsResizing = true; + constrainer->resizeStart(); + } + break; - default: - break; + default: + break; + } } } @@ -3655,12 +3568,6 @@ class HWNDComponentPeer final : public ComponentPeer return { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; } - Point getLocalPointFromScreenLParam (LPARAM lParam) - { - const auto globalPos = D2DUtilities::toPoint (getPOINTFromLParam (lParam)); - return globalToLocal (convertPhysicalScreenPointToLogical (globalPos, hwnd).toFloat()); - } - Point getPointFromLocalLParam (LPARAM lParam) noexcept { auto p = D2DUtilities::toPoint (getPOINTFromLParam (lParam)); @@ -3670,9 +3577,8 @@ class HWNDComponentPeer final : public ComponentPeer // LPARAM is relative to this window's top-left but may be on a different monitor so we need to calculate the // physical screen position and then convert this to local logical coordinates auto r = getWindowScreenRect (hwnd); - const auto windowBorder = findPhysicalBorderSize(); - return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (D2DUtilities::toPoint ({ r.left + p.x + windowBorder.getLeft(), - r.top + p.y + windowBorder.getTop() })).toFloat()); + return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (D2DUtilities::toPoint ({ r.left + p.x + roundToInt (windowBorder.getLeft() * scaleFactor), + r.top + p.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat()); } return p.toFloat(); @@ -3689,41 +3595,14 @@ class HWNDComponentPeer final : public ComponentPeer { //============================================================================== case WM_NCHITTEST: - { if ((styleFlags & windowIgnoresMouseClicks) != 0) return HTTRANSPARENT; - if (! hasTitleBar() && parentToAddTo == nullptr) - { - if ((styleFlags & windowIsResizable) != 0) - if (const auto result = DefWindowProc (h, message, wParam, lParam); HTSIZEFIRST <= result && result <= HTSIZELAST) - return result; - - const auto kind = component.findControlAtPoint (getLocalPointFromScreenLParam (lParam).toFloat()); - - using Kind = Component::WindowControlKind; - switch (kind) - { - case Kind::client: return HTCLIENT; - case Kind::caption: return HTCAPTION; - case Kind::minimise: return HTMINBUTTON; - case Kind::maximise: return HTMAXBUTTON; - case Kind::close: return HTCLOSE; - case Kind::sizeTop: return HTTOP; - case Kind::sizeLeft: return HTLEFT; - case Kind::sizeRight: return HTRIGHT; - case Kind::sizeBottom: return HTBOTTOM; - case Kind::sizeTopLeft: return HTTOPLEFT; - case Kind::sizeTopRight: return HTTOPRIGHT; - case Kind::sizeBottomLeft: return HTBOTTOMLEFT; - case Kind::sizeBottomRight: return HTBOTTOMRIGHT; - } - - return HTNOWHERE; - } + if (renderContext != nullptr) + if (auto result = renderContext->getNcHitTestResult()) + return *result; break; - } //============================================================================== case WM_PAINT: @@ -3731,11 +3610,12 @@ class HWNDComponentPeer final : public ComponentPeer return 0; case WM_NCPAINT: - // this must be done, even with native titlebars, or there are rendering artifacts. - handlePaintMessage(); - // Even if we're *not* using a native titlebar (i.e. extending into the nonclient area) - // the system needs to handle the NCPAINT to draw rounded corners and shadows. - break; + handlePaintMessage(); // this must be done, even with native titlebars, or there are rendering artifacts. + + if (hasTitleBar()) + break; // let the DefWindowProc handle drawing the frame. + + return 0; case WM_ERASEBKGND: if (hasTitleBar()) @@ -3744,27 +3624,10 @@ class HWNDComponentPeer final : public ComponentPeer return 1; case WM_NCCALCSIZE: - { if (renderContext != nullptr) renderContext->handleNcCalcSize (wParam, lParam); - if (! wParam) - break; - - const auto custom = getCustomBorderSize(); - - if (! custom.has_value()) - break; - - auto& rect = *reinterpret_cast (lParam)->rgrc; - - rect.top += custom->getTop(); - rect.bottom -= custom->getBottom(); - rect.left += custom->getLeft(); - rect.right -= custom->getRight(); - - return 0; - } + break; //============================================================================== case WM_POINTERUPDATE: @@ -3783,21 +3646,14 @@ class HWNDComponentPeer final : public ComponentPeer break; //============================================================================== - case WM_NCMOUSEMOVE: - case WM_MOUSEMOVE: - doMouseMove (message == WM_MOUSEMOVE ? getPointFromLocalLParam (lParam) : getLocalPointFromScreenLParam (lParam), - false, - message == WM_MOUSEMOVE ? WindowArea::client : WindowArea::nonclient); - return 0; + case WM_MOUSEMOVE: doMouseMove (getPointFromLocalLParam (lParam), false); return 0; case WM_POINTERLEAVE: case WM_MOUSELEAVE: doMouseExit(); return 0; case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - doMouseDown (getPointFromLocalLParam (lParam), wParam, WindowArea::client); - return 0; + case WM_RBUTTONDOWN: doMouseDown (getPointFromLocalLParam (lParam), wParam); return 0; case WM_LBUTTONUP: case WM_MBUTTONUP: @@ -3811,6 +3667,13 @@ class HWNDComponentPeer final : public ComponentPeer case WM_CAPTURECHANGED: doCaptureChanged(); return 0; + case WM_NCPOINTERUPDATE: + case WM_NCMOUSEMOVE: + if (hasTitleBar()) + break; + + return 0; + case WM_TOUCH: if (getTouchInputInfo != nullptr) return doTouchEvent ((int) wParam, (HTOUCHINPUT) lParam); @@ -4015,8 +3878,12 @@ class HWNDComponentPeer final : public ComponentPeer if (sendInputAttemptWhenModalMessage()) return 0; - PostMessage (h, WM_CLOSE, 0, 0); - return 0; + if (hasTitleBar()) + { + PostMessage (h, WM_CLOSE, 0, 0); + return 0; + } + break; case SC_KEYMENU: #if ! JUCE_WINDOWS_ALT_KEY_TRIGGERS_MENU @@ -4031,24 +3898,27 @@ class HWNDComponentPeer final : public ComponentPeer // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very obscure // situations that can arise if a modal loop is started from an alt-key keypress). - if (h == GetCapture()) + if (hasTitleBar() && h == GetCapture()) ReleaseCapture(); break; case SC_MAXIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + if (! sendInputAttemptWhenModalMessage()) + setFullScreen (true); - setFullScreen (true); return 0; case SC_MINIMIZE: if (sendInputAttemptWhenModalMessage()) return 0; - setMinimised (true); - return 0; + if (! hasTitleBar()) + { + setMinimised (true); + return 0; + } + break; case SC_RESTORE: if (sendInputAttemptWhenModalMessage()) @@ -4077,38 +3947,14 @@ class HWNDComponentPeer final : public ComponentPeer break; case WM_NCPOINTERDOWN: - handleLeftClickInNCArea (HIWORD (wParam)); - break; - case WM_NCLBUTTONDOWN: handleLeftClickInNCArea (wParam); - - if (wParam == HTCLOSE || wParam == HTMAXBUTTON || wParam == HTMINBUTTON) - return 0; - - break; - - case WM_NCLBUTTONUP: - switch (wParam) - { - case HTCLOSE: - PostMessage (h, WM_CLOSE, 0, 0); - return 0; - - case HTMAXBUTTON: - setFullScreen (! isFullScreen()); - return 0; - - case HTMINBUTTON: - setMinimised (true); - return 0; - } break; case WM_NCRBUTTONDOWN: case WM_NCMBUTTONDOWN: sendInputAttemptWhenModalMessage(); - return 0; + break; case WM_IME_SETCONTEXT: imeHandler.handleSetContext (h, wParam == TRUE); @@ -4144,7 +3990,7 @@ class HWNDComponentPeer final : public ComponentPeer break; } - return DefWindowProc (h, message, wParam, lParam); + return DefWindowProcW (h, message, wParam, lParam); } bool sendInputAttemptWhenModalMessage() @@ -4626,6 +4472,15 @@ class GDIContext : public RenderContext void setResizing (bool x) override { resizing = x; } bool getResizing() const override { return resizing; } + + std::optional getNcHitTestResult() override + { + if (! peer.hasTitleBar()) + return HTCLIENT; + + return {}; + } + void handleNcCalcSize (WPARAM, LPARAM) override {} void handleShowWindow() override {} @@ -4882,6 +4737,8 @@ class D2DContext : public RenderContext handleDirect2DPaint(); } + std::optional getNcHitTestResult() override { return {}; } + void setResizing (bool x) override { direct2DContext->setResizing (x); diff --git a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.cpp b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.cpp index 2e35d3f5b5..46ea8da0b9 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.cpp @@ -225,7 +225,10 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis // Need to do this comparison because the Value will use equalsWithSameType to compare // the new and old values, so will generate unwanted change events if the type changes. // Cast to double before comparing, to prevent comparing as another type (e.g. String). - if (! approximatelyEqual (static_cast (currentValue.getValue()), newValue)) + // We also want to avoid sending a notification if both new and old values are NaN. + const auto asDouble = static_cast (currentValue.getValue()); + + if (! (approximatelyEqual (asDouble, newValue) || (std::isnan (asDouble) && std::isnan (newValue)))) currentValue = newValue; updateText(); diff --git a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.h b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.h index e57f3b190c..61d847d1f0 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.h +++ b/JuceLibraryCode/modules/juce_gui_basics/widgets/juce_Slider.h @@ -42,6 +42,8 @@ namespace juce @see Slider::addListener, Slider::removeListener, WebSliderRelay::addListener, WebSliderRelay::removeListener + + @tags{GUI} */ template class JUCE_API SliderListener diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp index b692d88a05..02de2150ef 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp @@ -314,7 +314,7 @@ auto DocumentWindow::findControlAtPoint (Point pt) const -> WindowControl constexpr auto topResizerSize = 4; const auto topResizerArea = getLocalBounds().withHeight (topResizerSize).toFloat(); - if (topResizerArea.contains (pt) && isResizable()) + if (topResizerArea.contains (pt)) { if (pt.x <= topResizerArea.getX() + topResizerSize) return WindowControlKind::sizeTopLeft; @@ -325,6 +325,10 @@ auto DocumentWindow::findControlAtPoint (Point pt) const -> WindowControl return WindowControlKind::sizeTop; } + for (const auto& c : getChildren()) + if (c->contains (c->getLocalPoint (this, pt))) + return WindowControlKind::client; + return WindowControlKind::caption; } diff --git a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp index 13bfbe328b..2fe7e0632d 100644 --- a/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp +++ b/JuceLibraryCode/modules/juce_gui_basics/windows/juce_ResizableWindow.cpp @@ -326,13 +326,12 @@ void ResizableWindow::setConstrainer (ComponentBoundsConstrainer* newConstrainer { constrainer = newConstrainer; - bool useBottomRightCornerResizer = resizableCorner != nullptr; - bool shouldBeResizable = useBottomRightCornerResizer || resizableBorder != nullptr; + const bool useBottomRightCornerResizer = resizableCorner != nullptr; resizableCorner.reset(); resizableBorder.reset(); - setResizable (shouldBeResizable, useBottomRightCornerResizer); + setResizable (isResizable(), useBottomRightCornerResizer); updatePeerConstrainer(); } } diff --git a/JuceLibraryCode/modules/juce_gui_extra/juce_gui_extra.h b/JuceLibraryCode/modules/juce_gui_extra/juce_gui_extra.h index 636bc299c1..ab89328ca2 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/juce_gui_extra.h +++ b/JuceLibraryCode/modules/juce_gui_extra/juce_gui_extra.h @@ -158,3 +158,4 @@ #include "misc/juce_AnimatedAppComponent.h" #include "detail/juce_WebControlRelayEvents.h" #include "misc/juce_WebControlRelays.h" +#include "misc/juce_WebControlParameterIndexReceiver.h" diff --git a/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebBrowserComponent.h b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebBrowserComponent.h index 4794a8ad02..9330f76cd2 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebBrowserComponent.h +++ b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebBrowserComponent.h @@ -212,6 +212,43 @@ class JUCE_API WebBrowserComponent : public Component Colour backgroundColour; }; + /** Options specific to the WkWebView backend used on Apple systems. These options will be + ignored on non-Apple platforms. + */ + class AppleWkWebView + { + public: + /** Specifies whether the WebView is allowed to access siblings of files specified with + the file:// URL scheme. + + Allowing this is a potential security vulnerability if you don't have full control + over the file that you are opening. + */ + [[nodiscard]] AppleWkWebView withAllowAccessToEnclosingDirectory (bool x) const + { + return withMember (*this, &AppleWkWebView::allowAccessToEnclosingDirectory, x); + } + + /** If this options is specified, the underlying WebView will return NO from its + acceptsFirstMouse method. + + This disables the click-through behaviour, meaning that clicking a previously + unfocused application window only makes the window focused, but will not pass on the + click to whichever control inside the WebView is under the mouse. + */ + [[nodiscard]] AppleWkWebView withDisabledAcceptsFirstMouse() const + { + return withMember (*this, &AppleWkWebView::acceptsFirstMouse, false); + } + + auto getAllowAccessToEnclosingDirectory() const { return allowAccessToEnclosingDirectory; } + auto getAcceptsFirstMouse() const { return acceptsFirstMouse; } + + private: + bool allowAccessToEnclosingDirectory = false; + bool acceptsFirstMouse = true; + }; + /** Specifies options that apply to the Windows implementation when the WebView2 feature is enabled. @@ -222,6 +259,13 @@ class JUCE_API WebBrowserComponent : public Component return withMember (*this, &Options::winWebView2, winWebView2Options); } + /** Specifies options that influence the WebBrowserComponent's behaviour on Apple systems. + */ + [[nodiscard]] Options withAppleWkWebViewOptions (const AppleWkWebView& appleWkWebViewOptions) const + { + return withMember (*this, &Options::appleWkWebView, appleWkWebViewOptions); + } + /** Enables native integration features for the code running inside the WebBrowserComponent. This injects data and function objects under `window.__JUCE__.backend` through which @@ -342,6 +386,7 @@ class JUCE_API WebBrowserComponent : public Component auto keepsPageLoadedWhenBrowserIsHidden() const noexcept { return keepPageLoadedWhenBrowserIsHidden; } auto getUserAgent() const { return userAgent; } auto getWinWebView2BackendOptions() const { return winWebView2; } + auto getAppleWkWebViewOptions() const { return appleWkWebView; } auto getNativeIntegrationsEnabled() const { return enableNativeIntegration; } const auto& getNativeFunctions() const { return nativeFunctions; } const auto& getEventListeners() const { return eventListeners; } @@ -357,6 +402,7 @@ class JUCE_API WebBrowserComponent : public Component bool enableNativeIntegration = false; String userAgent; WinWebView2 winWebView2; + AppleWkWebView appleWkWebView; std::map nativeFunctions; std::vector> eventListeners; StringArray userScripts; @@ -436,8 +482,10 @@ class JUCE_API WebBrowserComponent : public Component class EvaluationResult { public: + /** A simple error type class. */ struct Error { + /** Error type. */ enum class Type { /** Error occurring for a reason unknown to us. */ diff --git a/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlParameterIndexReceiver.h b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlParameterIndexReceiver.h new file mode 100644 index 0000000000..76dbe8d49a --- /dev/null +++ b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlParameterIndexReceiver.h @@ -0,0 +1,76 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +#if JUCE_WEB_BROWSER || DOXYGEN + +/** This is a helper class for implementing AudioProcessorEditor::getControlParameterIndex with GUIs + using a WebBrowserComponent. + + Create an instance of this class and attach it to the WebBrowserComponent by using + WebBrowserComponent::Options::withOptionsFrom. + + In your frontend code you can use the ControlParameterIndexUpdater class, that emits + controlParameterIndexChanged events based on the mouse movement, and control parameter index + annotations attached to DOM elements. + + @tags{GUI} +*/ +class JUCE_API WebControlParameterIndexReceiver : public OptionsBuilder +{ +public: + /* Returns the control parameter index last reported by the WebBrowserComponent GUI to be + active. + */ + int getControlParameterIndex() const { return controlParameterIndex; } + + //============================================================================== + WebBrowserComponent::Options buildOptions (const WebBrowserComponent::Options& initialOptions) override + { + return initialOptions.withEventListener ("__juce__controlParameterIndexChanged", + [this] (auto newIndex) + { + controlParameterIndex = (int) newIndex; + }); + } + +private: + int controlParameterIndex = -1; +}; + +#endif + +} diff --git a/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlRelays.h b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlRelays.h index 1c08668299..a756eae97b 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlRelays.h +++ b/JuceLibraryCode/modules/juce_gui_extra/misc/juce_WebControlRelays.h @@ -59,6 +59,8 @@ namespace juce @endcode @see WebSliderParameterAttachment + + @tags{GUI} */ class JUCE_API WebSliderRelay : public OptionsBuilder { @@ -129,6 +131,8 @@ class JUCE_API WebSliderRelay : public OptionsBuilder { @@ -197,6 +201,8 @@ class JUCE_API WebToggleButtonRelay : public OptionsBuilder { diff --git a/JuceLibraryCode/modules/juce_gui_extra/native/javascript/index.js b/JuceLibraryCode/modules/juce_gui_extra/native/javascript/index.js index 302383db69..7bdd152fd1 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/native/javascript/index.js +++ b/JuceLibraryCode/modules/juce_gui_extra/native/javascript/index.js @@ -141,6 +141,7 @@ class SliderState { label: "", numSteps: 100, interval: 0, + parameterIndex: -1, }; this.valueChangedEvent = new ListenerList(); this.propertiesChangedEvent = new ListenerList(); @@ -252,6 +253,7 @@ class ToggleState { this.value = false; this.properties = { name: "", + parameterIndex: -1, }; this.valueChangedEvent = new ListenerList(); this.propertiesChangedEvent = new ListenerList(); @@ -326,6 +328,7 @@ class ComboBoxState { this.value = 0.0; this.properties = { name: "", + parameterIndex: -1, choices: [], }; this.valueChangedEvent = new ListenerList(); @@ -412,10 +415,78 @@ function getBackendResourceAddress(path) { return path; } +/** + * This helper class is intended to aid the implementation of + * AudioProcessorEditor::getControlParameterIndex() for editors using a WebView interface. + * + * Create an instance of this class and call its handleMouseMove() method in each mousemove event. + * + * This class can be used to continuously report the controlParameterIndexAnnotation attribute's + * value related to the DOM element that is currently under the mouse pointer. + * + * This value is defined at all times as follows + * * the annotation attribute's value for the DOM element directly under the mouse, if it has it, + * * the annotation attribute's value for the first parent element, that has it, + * * -1 otherwise. + * + * Whenever there is a change in this value, an event is emitted to the frontend with the new value. + * You can use a ControlParameterIndexReceiver object on the backend to listen to these events. + * + * @param {String} controlParameterIndexAnnotation + */ +class ControlParameterIndexUpdater { + constructor(controlParameterIndexAnnotation) { + this.controlParameterIndexAnnotation = controlParameterIndexAnnotation; + this.lastElement = null; + this.lastControlParameterIndex = null; + } + + handleMouseMove(event) { + const currentElement = document.elementFromPoint( + event.clientX, + event.clientY + ); + + if (currentElement === this.lastElement) return; + this.lastElement = currentElement; + + let controlParameterIndex = -1; + + if (currentElement !== null) + controlParameterIndex = this.#getControlParameterIndex(currentElement); + + if (controlParameterIndex === this.lastControlParameterIndex) return; + this.lastControlParameterIndex = controlParameterIndex; + + window.__JUCE__.backend.emitEvent( + "__juce__controlParameterIndexChanged", + controlParameterIndex + ); + } + + //============================================================================== + #getControlParameterIndex(element) { + const isValidNonRootElement = (e) => { + return e !== null && e !== document.documentElement; + }; + + while (isValidNonRootElement(element)) { + if (element.hasAttribute(this.controlParameterIndexAnnotation)) { + return element.getAttribute(this.controlParameterIndexAnnotation); + } + + element = element.parentElement; + } + + return -1; + } +} + export { getNativeFunction, getSliderState, getToggleState, getComboBoxState, getBackendResourceAddress, + ControlParameterIndexUpdater, }; diff --git a/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp b/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp index 2f6d290085..d1ccc3f566 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp +++ b/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_linux.cpp @@ -373,14 +373,37 @@ class WebKitSymbols final : public DeletedAtShutdown makeSymbolBinding (juce_g_free, "g_free")); } + struct WebKitAndDependencyLibraryNames + { + const char* webkitLib; + const char* jsLib; + const char* soupLib; + }; + + bool openWebKitAndDependencyLibraries (const WebKitAndDependencyLibraryNames& names) + { + if (webkitLib.open (names.webkitLib) && jsLib.open (names.jsLib) && soupLib.open (names.soupLib)) + return true; + + for (auto* l : { &webkitLib, &jsLib, &soupLib }) + l->close(); + + return false; + } + //============================================================================== + DynamicLibrary webkitLib, jsLib, soupLib; + DynamicLibrary gtkLib { "libgtk-3.so" }, - webkitLib { "libwebkit2gtk-4.0.so" }, - jsLib { "libjavascriptcoregtk-4.0.so" }, - soupLib { "libsoup-2.4.so" }, glib { "libglib-2.0.so" }; - const bool webKitIsAvailable = loadWebkitSymbols() + const bool webKitIsAvailable = ( openWebKitAndDependencyLibraries ({ "libwebkit2gtk-4.1.so", + "libjavascriptcoregtk-4.1.so", + "libsoup-3.0.so" }) + || openWebKitAndDependencyLibraries ({ "libwebkit2gtk-4.0.so", + "libjavascriptcoregtk-4.0.so", + "libsoup-2.4.so" })) + && loadWebkitSymbols() && loadGtkSymbols() && loadJsLibSymbols() && loadSoupLibSymbols() diff --git a/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm b/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm index 65aaadd30d..0958542473 100644 --- a/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm +++ b/JuceLibraryCode/modules/juce_gui_extra/native/juce_WebBrowserComponent_mac.mm @@ -202,7 +202,7 @@ static var fromObject (id object) { using Base = ObjCClass; - WebViewKeyEquivalentResponder() + explicit WebViewKeyEquivalentResponder (bool acceptsFirstMouse) : Base ("WebViewKeyEquivalentResponder_") { this->template addIvar (lastFocusChangeMemberName); @@ -283,6 +283,9 @@ static var fromObject (id object) return result; }); + if (acceptsFirstMouse) + this->addMethod (@selector (acceptsFirstMouse:), [] (id, SEL, NSEvent*) { return YES; }); + this->registerClass(); } }; @@ -680,7 +683,7 @@ static void displayError (WebBrowserComponent* owner, NSError* error) public: WebViewImpl (WebBrowserComponent::Impl& implIn, const String& userAgent) : browser (implIn.owner) { - static WebViewKeyEquivalentResponder webviewClass; + static WebViewKeyEquivalentResponder webviewClass { false }; webView.reset ([webviewClass.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) frameName: nsEmptyString() @@ -818,7 +821,9 @@ class API_AVAILABLE (macos (10.11)) WebBrowserComponent::Impl::Platform::WKWebVi delegateConnector (implIn.owner, [this] (const auto& m) { owner.handleNativeEvent (m); }, [this] (const auto& r) { return owner.handleResourceRequest (r); }, - browserOptions) + browserOptions), + allowAccessToEnclosingDirectory (browserOptions.getAppleWkWebViewOptions() + .getAllowAccessToEnclosingDirectory()) { ObjCObjectHandle config { [WKWebViewConfiguration new] }; id preferences = [config.get() preferences]; @@ -861,7 +866,19 @@ class API_AVAILABLE (macos (10.11)) WebBrowserComponent::Impl::Platform::WKWebVi #endif #if JUCE_MAC - static WebViewKeyEquivalentResponder webviewClass; + auto& webviewClass = [&]() -> auto& + { + if (browserOptions.getAppleWkWebViewOptions().getAcceptsFirstMouse()) + { + static WebViewKeyEquivalentResponder juceWebviewClass { true }; + return juceWebviewClass; + } + else + { + static WebViewKeyEquivalentResponder juceWebviewClass { false }; + return juceWebviewClass; + } + }(); webView.reset ([webviewClass.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) configuration: config.get()]); @@ -987,8 +1004,23 @@ void goToURL (const String& url, { auto file = URL (url).getLocalFile(); - if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]) - [webView.get() loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: nsUrl]; + NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())]; + + auto* accessPath = [&] + { + if (! allowAccessToEnclosingDirectory) + return nsUrl; + + auto* parentUrl = [NSURL fileURLWithPath: juceStringToNS (file.getParentDirectory().getFullPathName())]; + + if (parentUrl == nullptr) + return nsUrl; + + return parentUrl; + }(); + + if (nsUrl != nullptr) + [webView.get() loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: accessPath]; } else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData)) { @@ -1061,6 +1093,7 @@ void evaluateJavascript (const String& script, WebBrowserComponent::EvaluationCa private: WebBrowserComponent::Impl& owner; DelegateConnector delegateConnector; + bool allowAccessToEnclosingDirectory = false; LastFocusChange lastFocusChange; ObjCObjectHandle webView; ObjCObjectHandle webViewDelegate;