From 9f31d6498a899dc3c4f8229bfd203737bc9901a1 Mon Sep 17 00:00:00 2001 From: tpoole Date: Mon, 22 Aug 2016 09:57:16 +0100 Subject: [PATCH] Use a bespoke VST2 interface --- .../Application/jucer_GlobalPreferences.cpp | 2 - .../Application/jucer_GlobalPreferences.h | 1 - .../projucer_CompileEngineClient.cpp | 1 - .../jucer_ProjectExport_CodeBlocks.h | 1 - .../Project Saving/jucer_ProjectExport_MSVC.h | 4 - .../Project Saving/jucer_ProjectExport_Make.h | 4 - .../jucer_ProjectExport_XCode.h | 1 - .../Project Saving/jucer_ProjectExporter.cpp | 21 +- .../Project Saving/jucer_ProjectExporter.h | 6 +- .../Projucer/Source/Utility/jucer_PresetIDs.h | 2 - .../Source/Utility/jucer_StoredSettings.cpp | 8 +- .../VST/juce_VST_Wrapper.cpp | 1574 ++++++++++------- .../format_types/juce_VSTInterface.h | 455 +++++ .../format_types/juce_VSTMidiEventList.h | 77 +- .../format_types/juce_VSTPluginFormat.cpp | 503 +++--- .../format_types/juce_VSTPluginFormat.h | 8 +- .../juce_audio_processors.h | 3 +- 17 files changed, 1660 insertions(+), 1011 deletions(-) create mode 100644 modules/juce_audio_processors/format_types/juce_VSTInterface.h diff --git a/extras/Projucer/Source/Application/jucer_GlobalPreferences.cpp b/extras/Projucer/Source/Application/jucer_GlobalPreferences.cpp index ad54227755..3d7fd0a5a8 100644 --- a/extras/Projucer/Source/Application/jucer_GlobalPreferences.cpp +++ b/extras/Projucer/Source/Application/jucer_GlobalPreferences.cpp @@ -34,7 +34,6 @@ PathSettingsTab::PathSettingsTab (DependencyPathOS os) StoredSettings& settings = getAppSettings(); - vst2PathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::vst2Path, os), "VST SDK", maxChars, false)); vst3PathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::vst3Path, os), "VST3 SDK", maxChars, false)); #if ! JUCE_LINUX @@ -70,7 +69,6 @@ void PathSettingsTab::textPropertyComponentChanged (TextPropertyComponent* textP Identifier PathSettingsTab::getKeyForPropertyComponent (TextPropertyComponent* component) const { - if (component == vst2PathComponent) return Ids::vst2Path; if (component == vst3PathComponent) return Ids::vst3Path; if (component == rtasPathComponent) return Ids::rtasPath; if (component == aaxPathComponent) return Ids::aaxPath; diff --git a/extras/Projucer/Source/Application/jucer_GlobalPreferences.h b/extras/Projucer/Source/Application/jucer_GlobalPreferences.h index c1720fac29..e9fcc14f22 100644 --- a/extras/Projucer/Source/Application/jucer_GlobalPreferences.h +++ b/extras/Projucer/Source/Application/jucer_GlobalPreferences.h @@ -64,7 +64,6 @@ private: OwnedArray pathComponents; - TextPropertyComponent* vst2PathComponent; TextPropertyComponent* vst3PathComponent; TextPropertyComponent* rtasPathComponent; TextPropertyComponent* aaxPathComponent; diff --git a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp index 388b96fea8..6b085b9f23 100644 --- a/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp +++ b/extras/Projucer/Source/LiveBuildEngine/projucer_CompileEngineClient.cpp @@ -481,7 +481,6 @@ private: if (project.getProjectType().isAudioPlugin()) { - paths.add (getAppSettings().getGlobalPath (Ids::vst2Path, TargetOS::getThisOS()).toString()); paths.add (getAppSettings().getGlobalPath (Ids::vst3Path, TargetOS::getThisOS()).toString()); } diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h index 241793d0c0..59a268ce6d 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_CodeBlocks.h @@ -433,7 +433,6 @@ private: DependencyPathOS pathOS = isLinux() ? TargetOS::linux : TargetOS::windows; - vst2Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vstFolder), Ids::vst2Path, pathOS))); vst3Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vst3Folder), Ids::vst3Path, pathOS))); if (! isLinux()) diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h index 3327a06a28..fdfb70573b 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_MSVC.h @@ -749,10 +749,6 @@ protected: void initialiseDependencyPathValues() { - vst2Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vstFolder), - Ids::vst2Path, - TargetOS::windows))); - vst3Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vst3Folder), Ids::vst3Path, TargetOS::windows))); diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h index e4f94e9e2e..7ed90c5cdc 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_Make.h @@ -473,10 +473,6 @@ private: void initialiseDependencyPathValues() { - vst2Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vstFolder), - Ids::vst2Path, - TargetOS::linux))); - vst3Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vst3Folder), Ids::vst3Path, TargetOS::linux))); diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h index 03ce09297f..77075906bb 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExport_XCode.h @@ -2706,7 +2706,6 @@ private: void initialiseDependencyPathValues() { - vst2Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vstFolder), Ids::vst2Path, TargetOS::osx))); vst3Path.referTo (Value (new DependencyPathValueSource (getSetting (Ids::vst3Folder), Ids::vst3Path, TargetOS::osx))); aaxPath. referTo (Value (new DependencyPathValueSource (getSetting (Ids::aaxFolder), Ids::aaxPath, TargetOS::osx))); rtasPath.referTo (Value (new DependencyPathValueSource (getSetting (Ids::rtasFolder), Ids::rtasPath, TargetOS::osx))); diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp index 2a948ed75b..7f5f7dd972 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.cpp @@ -242,15 +242,9 @@ void ProjectExporter::createPropertyEditors (PropertyListBuilder& props) void ProjectExporter::createDependencyPathProperties (PropertyListBuilder& props) { - if (project.shouldBuildVST().getValue() || project.isVSTPluginHost()) - { - props.add (new DependencyPathPropertyComponent (getVSTPathValue (false), "VST SDK Folder"), - "If you're building a VST plugin or host, this must be the folder containing the VST SDK. This can be an absolute path, or a path relative to the Projucer project file."); - } - if (supportsVST3() && (project.shouldBuildVST3().getValue() || project.isVST3PluginHost())) { - props.add (new DependencyPathPropertyComponent (getVSTPathValue (true), "VST3 SDK Folder"), + props.add (new DependencyPathPropertyComponent (getVST3PathValue(), "VST3 SDK Folder"), "If you're building a VST3 plugin or host, this must be the folder containing the VST3 SDK. This can be an absolute path, or a path relative to the Projucer project file."); } @@ -309,16 +303,13 @@ void ProjectExporter::addVSTPathsIfPluginOrHost() if (supportsVST() && project.shouldBuildVST().getValue()) makefileTargetSuffix = ".so"; - if (project.shouldBuildVST().getValue() || project.isVSTPluginHost()) - addVSTFolderToPath (false); - if (supportsVST3()) { if (project.shouldBuildVST3().getValue()) makefileTargetSuffix = ".so"; if (project.shouldBuildVST3().getValue() || project.isVST3PluginHost()) - addVSTFolderToPath (true); + addVST3FolderToPath(); } } @@ -333,12 +324,12 @@ void ProjectExporter::addCommonAudioPluginSettings() // Note: RTAS paths are platform-dependent, impl -> addPlatformSpecificSettingsForProjectType } -void ProjectExporter::addVSTFolderToPath (bool isVST3) +void ProjectExporter::addVST3FolderToPath() { - const String vstFolder (getVSTPathValue (isVST3).toString()); + const String vst3Folder (getVST3PathValue().toString()); - if (vstFolder.isNotEmpty()) - addToExtraSearchPaths (RelativePath (vstFolder, RelativePath::projectFolder), 0); + if (vst3Folder.isNotEmpty()) + addToExtraSearchPaths (RelativePath (vst3Folder, RelativePath::projectFolder), 0); } void ProjectExporter::addAAXFoldersToPath() diff --git a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h index 15c85d744d..e542495238 100644 --- a/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h +++ b/extras/Projucer/Source/Project Saving/jucer_ProjectExporter.h @@ -131,7 +131,7 @@ public: Value getUserNotes() { return getSetting (Ids::userNotes); } - Value getVSTPathValue (bool isVST3) const { return isVST3 ? vst3Path : vst2Path; } + Value getVST3PathValue() const { return vst3Path; } Value getRTASPathValue() const { return rtasPath; } Value getAAXPathValue() const { return aaxPath; } @@ -341,7 +341,7 @@ protected: const ProjectType& projectType; const String projectName; const File projectFolder; - Value vst2Path, vst3Path, rtasPath, aaxPath; // these must be initialised in the specific exporter c'tors! + Value vst3Path, rtasPath, aaxPath; // these must be initialised in the specific exporter c'tors! mutable Array itemGroups; void initItemGroups() const; @@ -406,7 +406,7 @@ private: void createIconProperties (PropertyListBuilder&); void addVSTPathsIfPluginOrHost(); void addCommonAudioPluginSettings(); - void addVSTFolderToPath (bool isVST3); + void addVST3FolderToPath(); void addAAXFoldersToPath(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectExporter) diff --git a/extras/Projucer/Source/Utility/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/jucer_PresetIDs.h index 0d60ce1127..145ace9e71 100644 --- a/extras/Projucer/Source/Utility/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/jucer_PresetIDs.h @@ -55,11 +55,9 @@ namespace Ids DECLARE_ID (intermediatesPath); DECLARE_ID (modulePaths); DECLARE_ID (searchpaths); - DECLARE_ID (vstFolder); DECLARE_ID (vst3Folder); DECLARE_ID (rtasFolder); DECLARE_ID (auFolder); - DECLARE_ID (vst2Path); DECLARE_ID (vst3Path); DECLARE_ID (rtasPath); DECLARE_ID (aaxPath); diff --git a/extras/Projucer/Source/Utility/jucer_StoredSettings.cpp b/extras/Projucer/Source/Utility/jucer_StoredSettings.cpp index 9228c67304..506038a3f6 100644 --- a/extras/Projucer/Source/Utility/jucer_StoredSettings.cpp +++ b/extras/Projucer/Source/Utility/jucer_StoredSettings.cpp @@ -236,7 +236,7 @@ Value StoredSettings::getGlobalPath (const Identifier& key, DependencyPathOS os) String StoredSettings::getFallbackPath (const Identifier& key, DependencyPathOS os) { - if (key == Ids::vst2Path || key == Ids::vst3Path) + if (key == Ids::vst3Path) return os == TargetOS::windows ? "c:\\SDKs\\VST3 SDK" : "~/SDKs/VST3 SDK"; @@ -275,11 +275,7 @@ bool StoredSettings::isGlobalPathValid (const Identifier& key, const String& pat { String fileToCheckFor; - if (key == Ids::vst2Path) - { - fileToCheckFor = "public.sdk/source/vst2.x/audioeffectx.h"; - } - else if (key == Ids::vst3Path) + if (key == Ids::vst3Path) { fileToCheckFor = "base/source/baseiids.cpp"; } diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index f266428271..e6a370beda 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -57,23 +57,7 @@ #pragma warning (disable : 4458) #endif -/* These files come with the Steinberg VST SDK - to get them, you'll need to - visit the Steinberg website and agree to whatever is currently required to - get them. The best version to get is the VST3 SDK, which also contains - the older VST2.4 files. - - Then, you'll need to make sure your include path contains your "VST SDK3" - directory (or whatever you've named it on your machine). The Projucer has - a special box for setting this path. -*/ -#include -#include -#include -#include - -#if ! VST_2_4_EXTENSIONS - #error "It looks like you're trying to include an out-of-date VSTSDK version - make sure you have at least version 2.4" -#endif +#include "../../juce_audio_processors/format_types/juce_VSTInterface.h" #ifndef JUCE_VST3_CAN_REPLACE_VST2 #define JUCE_VST3_CAN_REPLACE_VST2 1 @@ -229,8 +213,7 @@ static Array activePlugins; /** This is an AudioEffectX object that holds and wraps our AudioProcessor... */ -class JuceVSTWrapper : public AudioEffectX, - public AudioProcessorListener, +class JuceVSTWrapper : public AudioProcessorListener, public AudioPlayHead, private Timer, private AsyncUpdater @@ -256,10 +239,21 @@ private: juce::AudioBuffer processTempBuffer; }; + /** Use the same names as the VST SDK. */ + struct VstOpCodeArguments + { + int32 index; + pointer_sized_int value; + void* ptr; + float opt; + }; + public: //============================================================================== - JuceVSTWrapper (audioMasterCallback audioMasterCB, AudioProcessor* const af) - : AudioEffectX (audioMasterCB, jmax (1, af->getNumPrograms()), af->getNumParameters()), + JuceVSTWrapper (VstHostCallback cb, AudioProcessor* const af) + : hostCallback (cb), + sampleRate (44100.f), + blockSize (1024), filter (af), busUtils (*filter, true, 64), chunkMemoryTime (0), @@ -303,20 +297,33 @@ public: filter->setPlayHead (this); filter->addListener (this); - cEffect.flags |= effFlagsHasEditor; - cEffect.version = convertHexVersionToDecimal (JucePlugin_VersionCode); + memset (&vstEffect, 0, sizeof (vstEffect)); + vstEffect.interfaceIdentifier = juceVstInterfaceIdentifier; + vstEffect.dispatchFunction = dispatcherCB; + vstEffect.processAudioFunction = nullptr; + vstEffect.setParameterValueFunction = setParameterCB; + vstEffect.getParameterValueFunction = getParameterCB; + vstEffect.numPrograms = jmax (1, af->getNumPrograms()); + vstEffect.numParameters = af->getNumParameters(); + vstEffect.numInputChannels = maxNumInChannels; + vstEffect.numOutputChannels = maxNumOutChannels; + vstEffect.latency = filter->getLatencySamples(); + vstEffect.effectPointer = this; + vstEffect.plugInIdentifier = JucePlugin_VSTUniqueID; + vstEffect.plugInVersion = convertHexVersionToDecimal (JucePlugin_VersionCode); + vstEffect.processAudioInplaceFunction = processReplacingCB; + vstEffect.processDoubleAudioInplaceFunction = processDoubleReplacingCB; - setUniqueID ((int) (JucePlugin_VSTUniqueID)); + vstEffect.flags |= vstEffectFlagHasEditor; - setNumInputs (maxNumInChannels); - setNumOutputs (maxNumOutChannels); + vstEffect.flags |= vstEffectFlagInplaceAudio; + if (filter->supportsDoublePrecisionProcessing()) + vstEffect.flags |= vstEffectFlagInplaceDoubleAudio; - canProcessReplacing (true); - canDoubleReplacing (filter->supportsDoublePrecisionProcessing()); + if (JucePlugin_IsSynth != 0) + vstEffect.flags |= vstEffectFlagIsSynth; - isSynth ((JucePlugin_IsSynth) != 0); - setInitialDelay (filter->getLatencySamples()); - programsAreChunks (true); + vstEffect.flags |= vstEffectFlagDataInChunks; activePlugins.add (this); } @@ -357,138 +364,14 @@ public: #endif } } + } - void open() override - { - // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. - if (filter->hasEditor()) - cEffect.flags |= effFlagsHasEditor; - else - cEffect.flags &= ~effFlagsHasEditor; - } - - void close() override - { - // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. - stopTimer(); - - if (MessageManager::getInstance()->isThisTheMessageThread()) - deleteEditor (false); - } - - //============================================================================== - bool getEffectName (char* name) override - { - String (JucePlugin_Name).copyToUTF8 (name, 64 + 1); - return true; - } - - bool getVendorString (char* text) override - { - String (JucePlugin_Manufacturer).copyToUTF8 (text, 64 + 1); - return true; - } - - bool getProductString (char* text) override { return getEffectName (text); } - VstInt32 getVendorVersion() override { return convertHexVersionToDecimal (JucePlugin_VersionCode); } - VstPlugCategory getPlugCategory() override { return JucePlugin_VSTCategory; } - bool keysRequired() { return (JucePlugin_EditorRequiresKeyboardFocus) != 0; } - - VstInt32 canDo (char* text) override - { - if (strcmp (text, "receiveVstEvents") == 0 - || strcmp (text, "receiveVstMidiEvent") == 0 - || strcmp (text, "receiveVstMidiEvents") == 0) - { - #if JucePlugin_WantsMidiInput - return 1; - #else - return -1; - #endif - } - - if (strcmp (text, "sendVstEvents") == 0 - || strcmp (text, "sendVstMidiEvent") == 0 - || strcmp (text, "sendVstMidiEvents") == 0) - { - #if JucePlugin_ProducesMidiOutput - return 1; - #else - return -1; - #endif - } - - if (strcmp (text, "receiveVstTimeInfo") == 0 - || strcmp (text, "conformsToWindowRules") == 0 - || strcmp (text, "bypass") == 0) - { - return 1; - } - - // This tells Wavelab to use the UI thread to invoke open/close, - // like all other hosts do. - if (strcmp (text, "openCloseAnyThread") == 0) - return -1; - - if (strcmp (text, "MPE") == 0) - return filter->supportsMPE() ? 1 : 0; - - #if JUCE_MAC - if (strcmp (text, "hasCockosViewAsConfig") == 0) - { - useNSView = true; - return (VstInt32) 0xbeef0000; - } - #endif - - return 0; - } - - VstIntPtr vendorSpecific (VstInt32 lArg, VstIntPtr lArg2, void* ptrArg, float floatArg) override - { - ignoreUnused (lArg, lArg2, ptrArg, floatArg); - - #if JucePlugin_Build_VST3 && JUCE_VST3_CAN_REPLACE_VST2 - if ((lArg == 'stCA' || lArg == 'stCa') && lArg2 == 'FUID' && ptrArg != nullptr) - { - memcpy (ptrArg, getJuceVST3ComponentIID(), 16); - return 1; - } - #endif - - return 0; - } - - bool setBypass (bool b) override - { - isBypassed = b; - return true; - } - - VstInt32 getGetTailSize() override - { - if (filter != nullptr) - return (VstInt32) (filter->getTailLengthSeconds() * getSampleRate()); - - return 0; - } - - //============================================================================== - VstInt32 processEvents (VstEvents* events) override - { - #if JucePlugin_WantsMidiInput - VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); - return 1; - #else - ignoreUnused (events); - return 0; - #endif - } + VstEffectInterface* getVstEffectInterface() noexcept { return &vstEffect; } template void internalProcessReplacing (FloatType** inputs, FloatType** outputs, - VstInt32 numSamples, VstTempBuffers& tmpBuffers) + int32 numSamples, VstTempBuffers& tmpBuffers) { if (firstProcessCallback) { @@ -502,7 +385,7 @@ public: if (! isProcessing) resume(); - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + filter->setNonRealtime (isProcessLevelOffline()); #if JUCE_WINDOWS if (getHostType().isWavelab()) @@ -598,7 +481,7 @@ public: outgoingEvents.ensureSize (numEvents); outgoingEvents.clear(); - const juce::uint8* midiEventData; + const uint8* midiEventData; int midiEventSize, midiEventPosition; MidiBuffer::Iterator i (midiEvents); @@ -609,7 +492,9 @@ public: outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); } - sendVstEventsToHost (outgoingEvents.events); + // Send VST events to the host. + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodePreAudioProcessingEvents, 0, 0, outgoingEvents.events, 0); #elif JUCE_DEBUG /* This assertion is caused when you've added some events to the midiMessages array in your processBlock() method, which usually means @@ -632,55 +517,45 @@ public: } } - void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) override + void processReplacing (float** inputs, float** outputs, int32 sampleFrames) { jassert (! filter->isUsingDoublePrecision()); internalProcessReplacing (inputs, outputs, sampleFrames, floatTempBuffers); } - void processDoubleReplacing (double** inputs, double** outputs, VstInt32 sampleFrames) override + static void processReplacingCB (VstEffectInterface* vstInterface, float** inputs, float** outputs, int32 sampleFrames) + { + getWrapper (vstInterface)->processReplacing (inputs, outputs, sampleFrames); + } + + void processDoubleReplacing (double** inputs, double** outputs, int32 sampleFrames) { jassert (filter->isUsingDoublePrecision()); internalProcessReplacing (inputs, outputs, sampleFrames, doubleTempBuffers); } - //============================================================================== - VstInt32 startProcess() override { return 0; } - VstInt32 stopProcess() override { return 0; } - - //============================================================================== - bool setProcessPrecision (VstInt32 vstPrecision) override + static void processDoubleReplacingCB (VstEffectInterface* vstInterface, double** inputs, double** outputs, int32 sampleFrames) { - if (! isProcessing) - { - if (filter != nullptr) - { - filter->setProcessingPrecision (vstPrecision == kVstProcessPrecision64 && filter->supportsDoublePrecisionProcessing() - ? AudioProcessor::doublePrecision - : AudioProcessor::singlePrecision); - - return true; - } - } - - return false; + getWrapper (vstInterface)->processDoubleReplacing (inputs, outputs, sampleFrames); } - void resume() override + //============================================================================== + void resume() { if (filter != nullptr) { isProcessing = true; - floatTempBuffers .channels.calloc ((size_t) (cEffect.numInputs + cEffect.numOutputs)); - doubleTempBuffers.channels.calloc ((size_t) (cEffect.numInputs + cEffect.numOutputs)); + const size_t nInAndOutChannels = vstEffect.numInputChannels + vstEffect.numOutputChannels; + floatTempBuffers .channels.calloc (nInAndOutChannels); + doubleTempBuffers.channels.calloc (nInAndOutChannels); - const double currentRate = getSampleRate(); - const int currentBlockSize = getBlockSize(); + const double currentRate = sampleRate; + const int currentBlockSize = blockSize; firstProcessCallback = true; - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + filter->setNonRealtime (isProcessLevelOffline()); filter->setRateAndBufferSizeDetails (currentRate, currentBlockSize); deleteTempChannels(); @@ -690,9 +565,20 @@ public: midiEvents.ensureSize (2048); midiEvents.clear(); - setInitialDelay (filter->getLatencySamples()); + vstEffect.latency = filter->getLatencySamples(); - AudioEffectX::resume(); + /** If this plug-in is a synth or it can receive midi events we need to tell the + host that we want midi. In the SDK this method is marked as deprecated, but + some hosts rely on this behaviour. + */ + bool plugCanDoMidi = (hostCallback != nullptr && hostCallback (&vstEffect, hostOpcodeCanHostDo, 0, 0, + const_cast ("receiveVstMidiEvent"), 0)); + + if (vstEffect.flags & vstEffectFlagIsSynth || plugCanDoMidi) + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodePlugInWantsMidi, 0, 1, 0, 0); + } #if JucePlugin_ProducesMidiOutput outgoingEvents.ensureSize (512); @@ -700,12 +586,10 @@ public: } } - void suspend() override + void suspend() { if (filter != nullptr) { - AudioEffectX::suspend(); - filter->releaseResources(); outgoingEvents.freeEvents(); @@ -717,20 +601,31 @@ public: } } + //============================================================================== bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) override { - const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid | kVstTempoValid | kVstBarsValid | kVstCyclePosValid - | kVstTimeSigValid | kVstSmpteValid | kVstClockValid); + const VstTimingInformation* ti = nullptr; + + if (hostCallback != nullptr) + { + int32 flags = vstTimingInfoFlagMusicalPositionValid | vstTimingInfoFlagTempoValid + | vstTimingInfoFlagLastBarPositionValid | vstTimingInfoFlagLoopPositionValid + | vstTimingInfoFlagTimeSignatureValid | vstTimingInfoFlagSmpteValid + | vstTimingInfoFlagNearestClockValid; + + pointer_sized_int result = hostCallback (&vstEffect, hostOpcodeGetTimingInfo, 0, flags, 0, 0); + ti = reinterpret_cast (result); + } if (ti == nullptr || ti->sampleRate <= 0) return false; - info.bpm = (ti->flags & kVstTempoValid) != 0 ? ti->tempo : 0.0; + info.bpm = (ti->flags & vstTimingInfoFlagTempoValid) != 0 ? ti->tempoBPM : 0.0; - if ((ti->flags & kVstTimeSigValid) != 0) + if ((ti->flags & vstTimingInfoFlagTimeSignatureValid) != 0) { - info.timeSigNumerator = ti->timeSigNumerator; - info.timeSigDenominator = ti->timeSigDenominator; + info.timeSigNumerator = ti->timeSignatureNumerator; + info.timeSigDenominator = ti->timeSignatureDenominator; } else { @@ -738,34 +633,34 @@ public: info.timeSigDenominator = 4; } - info.timeInSamples = (int64) (ti->samplePos + 0.5); - info.timeInSeconds = ti->samplePos / ti->sampleRate; - info.ppqPosition = (ti->flags & kVstPpqPosValid) != 0 ? ti->ppqPos : 0.0; - info.ppqPositionOfLastBarStart = (ti->flags & kVstBarsValid) != 0 ? ti->barStartPos : 0.0; + info.timeInSamples = (int64) (ti->samplePosition + 0.5); + info.timeInSeconds = ti->samplePosition / ti->sampleRate; + info.ppqPosition = (ti->flags & vstTimingInfoFlagMusicalPositionValid) != 0 ? ti->musicalPosition : 0.0; + info.ppqPositionOfLastBarStart = (ti->flags & vstTimingInfoFlagLastBarPositionValid) != 0 ? ti->lastBarPosition : 0.0; - if ((ti->flags & kVstSmpteValid) != 0) + if ((ti->flags & vstTimingInfoFlagSmpteValid) != 0) { AudioPlayHead::FrameRateType rate = AudioPlayHead::fpsUnknown; double fps = 1.0; - switch (ti->smpteFrameRate) + switch (ti->smpteRate) { - case kVstSmpte24fps: rate = AudioPlayHead::fps24; fps = 24.0; break; - case kVstSmpte25fps: rate = AudioPlayHead::fps25; fps = 25.0; break; - case kVstSmpte2997fps: rate = AudioPlayHead::fps2997; fps = 29.97; break; - case kVstSmpte30fps: rate = AudioPlayHead::fps30; fps = 30.0; break; - case kVstSmpte2997dfps: rate = AudioPlayHead::fps2997drop; fps = 29.97; break; - case kVstSmpte30dfps: rate = AudioPlayHead::fps30drop; fps = 30.0; break; + case vstSmpteRateFps24: rate = AudioPlayHead::fps24; fps = 24.0; break; + case vstSmpteRateFps25: rate = AudioPlayHead::fps25; fps = 25.0; break; + case vstSmpteRateFps2997: rate = AudioPlayHead::fps2997; fps = 29.97; break; + case vstSmpteRateFps30: rate = AudioPlayHead::fps30; fps = 30.0; break; + case vstSmpteRateFps2997drop: rate = AudioPlayHead::fps2997drop; fps = 29.97; break; + case vstSmpteRateFps30drop: rate = AudioPlayHead::fps30drop; fps = 30.0; break; - case kVstSmpteFilm16mm: - case kVstSmpteFilm35mm: fps = 24.0; break; + case vstSmpteRate16mmFilm: + case vstSmpteRate35mmFilm: fps = 24.0; break; - case kVstSmpte239fps: fps = 23.976; break; - case kVstSmpte249fps: fps = 24.976; break; - case kVstSmpte599fps: fps = 59.94; break; - case kVstSmpte60fps: fps = 60; break; + case vstSmpteRateFps239: fps = 23.976; break; + case vstSmpteRateFps249: fps = 24.976; break; + case vstSmpteRateFps599: fps = 59.94; break; + case vstSmpteRateFps60: fps = 60; break; - default: jassertfalse; // unknown frame-rate.. + default: jassertfalse; // unknown frame-rate.. } info.frameRate = rate; @@ -777,14 +672,14 @@ public: info.editOriginTime = 0; } - info.isRecording = (ti->flags & kVstTransportRecording) != 0; - info.isPlaying = (ti->flags & (kVstTransportRecording | kVstTransportPlaying)) != 0; - info.isLooping = (ti->flags & kVstTransportCycleActive) != 0; + info.isRecording = (ti->flags & vstTimingInfoFlagCurrentlyRecording) != 0; + info.isPlaying = (ti->flags & (vstTimingInfoFlagCurrentlyRecording | vstTimingInfoFlagCurrentlyPlaying)) != 0; + info.isLooping = (ti->flags & vstTimingInfoFlagLoopActive) != 0; - if ((ti->flags & kVstCyclePosValid) != 0) + if ((ti->flags & vstTimingInfoFlagLoopPositionValid) != 0) { - info.ppqLoopStart = ti->cycleStartPos; - info.ppqLoopEnd = ti->cycleEndPos; + info.ppqLoopStart = ti->loopStartPosition; + info.ppqLoopEnd = ti->loopEndPosition; } else { @@ -796,42 +691,7 @@ public: } //============================================================================== - VstInt32 getProgram() override - { - return (filter != nullptr && filter->getNumPrograms() > 0 ? filter->getCurrentProgram() : 0); - } - - void setProgram (VstInt32 program) override - { - if (filter != nullptr && filter->getNumPrograms() > 0) - filter->setCurrentProgram (program); - } - - void setProgramName (char* name) override - { - if (filter != nullptr && filter->getNumPrograms() > 0) - filter->changeProgramName (filter->getCurrentProgram(), name); - } - - void getProgramName (char* name) override - { - if (filter != nullptr && filter->getNumPrograms() > 0) - filter->getProgramName (filter->getCurrentProgram()).copyToUTF8 (name, 24 + 1); - } - - bool getProgramNameIndexed (VstInt32 /*category*/, VstInt32 index, char* text) override - { - if (filter != nullptr && isPositiveAndBelow (index, filter->getNumPrograms())) - { - filter->getProgramName (index).copyToUTF8 (text, 24 + 1); - return true; - } - - return false; - } - - //============================================================================== - float getParameter (VstInt32 index) override + float getParameter (int32 index) const { if (filter == nullptr) return 0.0f; @@ -840,7 +700,12 @@ public: return filter->getParameter (index); } - void setParameter (VstInt32 index, float value) override + static float getParameterCB (VstEffectInterface* vstInterface, int32 index) + { + return getWrapper (vstInterface)->getParameter (index); + } + + void setParameter (int32 index, float value) { if (filter != nullptr) { @@ -849,203 +714,55 @@ public: } } - void getParameterDisplay (VstInt32 index, char* text) override + static void setParameterCB (VstEffectInterface* vstInterface, int32 index, float value) { - if (filter != nullptr) - { - jassert (isPositiveAndBelow (index, filter->getNumParameters())); - filter->getParameterText (index, 24).copyToUTF8 (text, 24 + 1); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - bool string2parameter (VstInt32 index, char* text) override - { - if (filter != nullptr) - { - jassert (isPositiveAndBelow (index, filter->getNumParameters())); - - if (AudioProcessorParameter* p = filter->getParameters()[index]) - { - filter->setParameter (index, p->getValueForText (String::fromUTF8 (text))); - return true; - } - } - - return false; - } - - void getParameterName (VstInt32 index, char* text) override - { - if (filter != nullptr) - { - jassert (isPositiveAndBelow (index, filter->getNumParameters())); - filter->getParameterName (index, 16).copyToUTF8 (text, 16 + 1); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - void getParameterLabel (VstInt32 index, char* text) override - { - if (filter != nullptr) - { - jassert (isPositiveAndBelow (index, filter->getNumParameters())); - filter->getParameterLabel (index).copyToUTF8 (text, 24 + 1); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } + getWrapper (vstInterface)->setParameter (index, value); } void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override { - if (audioMaster != nullptr) - audioMaster (&cEffect, audioMasterAutomate, index, 0, 0, newValue); + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodeParameterChanged, index, 0, 0, newValue); } - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override { beginEdit (index); } - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override { endEdit (index); } + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodeParameterChangeGestureBegin, index, 0, 0, 0); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override + { + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodeParameterChangeGestureEnd, index, 0, 0, 0); + } void audioProcessorChanged (AudioProcessor*) override { - setInitialDelay (filter->getLatencySamples()); - updateDisplay(); + vstEffect.latency = filter->getLatencySamples(); + + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodeUpdateView, 0, 0, 0, 0); + triggerAsyncUpdate(); } void handleAsyncUpdate() override { - ioChanged(); + if (hostCallback != nullptr) + hostCallback (&vstEffect, hostOpcodeIOModified, 0, 0, 0, 0); } - bool canParameterBeAutomated (VstInt32 index) override - { - return filter != nullptr && filter->isParameterAutomatable ((int) index); - } - - bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, - VstSpeakerArrangement* pluginOutput) override - { - const int numIns = busUtils.getBusCount (true); - const int numOuts = busUtils.getBusCount (false);; - - if (pluginInput != nullptr && numIns == 0) - return false; - - if (pluginOutput != nullptr && numOuts == 0) - return false; - - if (pluginInput != nullptr && pluginInput->type >= 0) - { - // inconsistent request? - if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput).size() != pluginInput->numChannels) - return false; - } - - if (pluginOutput != nullptr && pluginOutput->type >= 0) - { - // inconsistent request? - if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput).size() != pluginOutput->numChannels) - return false; - } - - if (numIns > 1 || numOuts > 1) - { - int newNumInChannels = (pluginInput != nullptr && pluginInput-> numChannels >= 0) ? pluginInput-> numChannels - : busUtils.findTotalNumChannels (true); - int newNumOutChannels = (pluginOutput != nullptr && pluginOutput->numChannels >= 0) ? pluginOutput->numChannels - : busUtils.findTotalNumChannels (false); - - newNumInChannels = jmin (newNumInChannels, maxNumInChannels); - newNumOutChannels = jmin (newNumOutChannels, maxNumOutChannels); - - if (! setBusArrangementFromTotalChannelNum (newNumInChannels, newNumOutChannels)) - return false; - } - else - { - PluginBusUtilities::ScopedBusRestorer busRestorer (busUtils); - AudioChannelSet inLayoutType; - - if (pluginInput != nullptr && pluginInput-> numChannels >= 0) - { - inLayoutType = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput); - if (busUtils.getChannelSet (true, 0) != inLayoutType) - if (! filter->setPreferredBusArrangement (true, 0, inLayoutType)) - return false; - } - - if (pluginOutput != nullptr && pluginOutput->numChannels >= 0) - { - AudioChannelSet newType = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput); - if (busUtils.getChannelSet (false, 0) != newType) - if (! filter->setPreferredBusArrangement (false, 0, newType)) - return false; - - // re-check the input - if ((! inLayoutType.isDisabled()) && busUtils.getChannelSet (true, 0) != inLayoutType) - return false; - - busRestorer.release(); - } - } - - filter->setRateAndBufferSizeDetails(0, 0); - return true; - } - - bool getSpeakerArrangement (VstSpeakerArrangement** pluginInput, VstSpeakerArrangement** pluginOutput) override - { - *pluginInput = 0; - *pluginOutput = 0; - - if (! AudioEffectX::allocateArrangement (pluginInput, busUtils.findTotalNumChannels (true))) - return false; - - if (! AudioEffectX::allocateArrangement (pluginOutput, busUtils.findTotalNumChannels (false))) - { - AudioEffectX::deallocateArrangement (pluginInput); - *pluginInput = 0; - return false; - } - - if (pluginHasSidechainsOrAuxs()) - { - int numIns = busUtils.findTotalNumChannels (true); - int numOuts = busUtils.findTotalNumChannels (false); - - AudioChannelSet layout = AudioChannelSet::canonicalChannelSet (numIns); - SpeakerMappings::channelSetToVstArrangement (layout, **pluginInput); - - layout = AudioChannelSet::canonicalChannelSet (numOuts); - SpeakerMappings::channelSetToVstArrangement (layout, **pluginOutput); - } - else - { - SpeakerMappings::channelSetToVstArrangement (busUtils.getChannelSet (true, 0), **pluginInput); - SpeakerMappings::channelSetToVstArrangement (busUtils.getChannelSet (false, 0), **pluginOutput); - } - - return true; - } - - bool getInputProperties (VstInt32 index, VstPinProperties* properties) override - { - return filter != nullptr - && getPinProperties (*properties, true, (int) index); - } - - bool getOutputProperties (VstInt32 index, VstPinProperties* properties) override - { - return filter != nullptr - && getPinProperties (*properties, false, (int) index); - } - - bool getPinProperties (VstPinProperties& properties, bool direction, int index) const + bool getPinProperties (VstPinInfo& properties, bool direction, int index) const { // fill with default - properties.flags = kVstPinUseSpeaker; - properties.label[0] = 0; - properties.shortLabel[0] = 0; - properties.arrangementType = kSpeakerArrEmpty; + properties.flags = vstPinInfoFlagValid; + properties.text[0] = 0; + properties.shortText[0] = 0; + properties.configurationType = vstSpeakerConfigTypeEmpty; // index refers to the absolute index when combining all channels of every bus - if (index >= (direction ? cEffect.numInputs : cEffect.numOutputs)) + if (index >= (direction ? vstEffect.numInputChannels : vstEffect.numOutputChannels)) return false; const int n = busUtils.getBusCount(direction); @@ -1072,17 +789,17 @@ public: String channelName = busInfo.name + String (" ") + abbvChannelName; - channelName.copyToUTF8 (properties.label, (size_t) (kVstMaxLabelLen + 1)); - channelName.copyToUTF8 (properties.shortLabel, (size_t) (kVstMaxShortLabelLen + 1)); + channelName.copyToUTF8 (properties.text, (size_t) (vstMaxParameterOrPinLabelLength + 1)); + channelName.copyToUTF8 (properties.shortText, (size_t) (vstMaxParameterOrPinShortLabelLength + 1)); - properties.flags = kVstPinUseSpeaker | kVstPinIsActive; - properties.arrangementType = SpeakerMappings::channelSetToVstArrangementType (busInfo.channels); + properties.flags = vstPinInfoFlagValid | vstPinInfoFlagIsActive; + properties.configurationType = SpeakerMappings::channelSetToVstArrangementType (busInfo.channels); - if (properties.arrangementType == kSpeakerArrEmpty) - properties.flags &= ~kVstPinIsActive; + if (properties.configurationType == vstSpeakerConfigTypeEmpty) + properties.flags &= vstPinInfoFlagIsActive; if (busInfo.channels.size() == 2) - properties.flags |= kVstPinIsStereo; + properties.flags |= vstPinInfoFlagIsStereo; return true; } @@ -1092,7 +809,7 @@ public: { struct Mapping { - VstInt32 vst2; + int32 vst2; ChannelType channels[13]; bool matches (const Array& chans) const noexcept @@ -1112,9 +829,9 @@ public: } }; - static AudioChannelSet vstArrangementTypeToChannelSet (const VstSpeakerArrangement& arr) + static AudioChannelSet vstArrangementTypeToChannelSet (const VstSpeakerConfiguration& arr) { - for (const Mapping* m = getMappings(); m->vst2 != kSpeakerArrEmpty; ++m) + for (const Mapping* m = getMappings(); m->vst2 != vstSpeakerConfigTypeEmpty; ++m) { if (m->vst2 == arr.type) { @@ -1127,33 +844,33 @@ public: } } - return AudioChannelSet::discreteChannels (arr.numChannels); + return AudioChannelSet::discreteChannels (arr.numberOfChannels); } - static VstInt32 channelSetToVstArrangementType (AudioChannelSet channels) + static int32 channelSetToVstArrangementType (AudioChannelSet channels) { Array chans (channels.getChannelTypes()); if (channels == AudioChannelSet::disabled()) - return kSpeakerArrEmpty; + return vstSpeakerConfigTypeEmpty; - for (const Mapping* m = getMappings(); m->vst2 != kSpeakerArrEmpty; ++m) + for (const Mapping* m = getMappings(); m->vst2 != vstSpeakerConfigTypeEmpty; ++m) if (m->matches (chans)) return m->vst2; - return kSpeakerArrUserDefined; + return vstSpeakerConfigTypeUser; } - static void channelSetToVstArrangement (const AudioChannelSet& channels, VstSpeakerArrangement& result) + static void channelSetToVstArrangement (const AudioChannelSet& channels, VstSpeakerConfiguration& result) { result.type = channelSetToVstArrangementType (channels); - result.numChannels = channels.size(); + result.numberOfChannels = channels.size(); - for (int i = 0; i < result.numChannels; ++i) + for (int i = 0; i < result.numberOfChannels; ++i) { - VstSpeakerProperties& speaker = result.speakers[i]; + VstIndividualSpeakerInfo& speaker = result.speakers[i]; - zeromem (&speaker, sizeof (VstSpeakerProperties)); + zeromem (&speaker, sizeof (VstIndividualSpeakerInfo)); speaker.type = getSpeakerType (channels.getTypeOfChannel (i)); } } @@ -1162,93 +879,93 @@ public: { static const Mapping mappings[] = { - { kSpeakerArrMono, { centre, unknown } }, - { kSpeakerArrStereo, { left, right, unknown } }, - { kSpeakerArrStereoSurround, { leftSurround, rightSurround, unknown } }, - { kSpeakerArrStereoCenter, { leftCentre, rightCentre, unknown } }, - { kSpeakerArrStereoSide, { leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArrStereoCLfe, { centre, subbass, unknown } }, - { kSpeakerArr30Cine, { left, right, centre, unknown } }, - { kSpeakerArr30Music, { left, right, surround, unknown } }, - { kSpeakerArr31Cine, { left, right, centre, subbass, unknown } }, - { kSpeakerArr31Music, { left, right, subbass, surround, unknown } }, - { kSpeakerArr40Cine, { left, right, centre, surround, unknown } }, - { kSpeakerArr40Music, { left, right, leftSurround, rightSurround, unknown } }, - { kSpeakerArr41Cine, { left, right, centre, subbass, surround, unknown } }, - { kSpeakerArr41Music, { left, right, subbass, leftSurround, rightSurround, unknown } }, - { kSpeakerArr50, { left, right, centre, leftSurround, rightSurround, unknown } }, - { kSpeakerArr51, { left, right, centre, subbass, leftSurround, rightSurround, unknown } }, - { kSpeakerArr60Cine, { left, right, centre, leftSurround, rightSurround, surround, unknown } }, - { kSpeakerArr60Music, { left, right, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr61Cine, { left, right, centre, subbass, leftSurround, rightSurround, surround, unknown } }, - { kSpeakerArr61Music, { left, right, subbass, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr70Cine, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, - { kSpeakerArr70Music, { left, right, centre, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr71Cine, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, - { kSpeakerArr71Music, { left, right, centre, subbass, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr80Cine, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, - { kSpeakerArr80Music, { left, right, centre, leftSurround, rightSurround, surround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr81Cine, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, - { kSpeakerArr81Music, { left, right, centre, subbass, leftSurround, rightSurround, surround, leftRearSurround, rightRearSurround, unknown } }, - { kSpeakerArr102, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontCentre, topFrontRight, topRearLeft, topRearRight, subbass2, unknown } }, - { kSpeakerArrEmpty, { unknown } } + { vstSpeakerConfigTypeMono, { centre, unknown } }, + { vstSpeakerConfigTypeLR, { left, right, unknown } }, + { vstSpeakerConfigTypeLsRs, { leftSurround, rightSurround, unknown } }, + { vstSpeakerConfigTypeLcRc, { leftCentre, rightCentre, unknown } }, + { vstSpeakerConfigTypeSlSr, { leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeCLfe, { centre, subbass, unknown } }, + { vstSpeakerConfigTypeLRC, { left, right, centre, unknown } }, + { vstSpeakerConfigTypeLRS, { left, right, surround, unknown } }, + { vstSpeakerConfigTypeLRCLfe, { left, right, centre, subbass, unknown } }, + { vstSpeakerConfigTypeLRLfeS, { left, right, subbass, surround, unknown } }, + { vstSpeakerConfigTypeLRCS, { left, right, centre, surround, unknown } }, + { vstSpeakerConfigTypeLRLsRs, { left, right, leftSurround, rightSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeS, { left, right, centre, subbass, surround, unknown } }, + { vstSpeakerConfigTypeLRLfeLsRs, { left, right, subbass, leftSurround, rightSurround, unknown } }, + { vstSpeakerConfigTypeLRCLsRs, { left, right, centre, leftSurround, rightSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRs, { left, right, centre, subbass, leftSurround, rightSurround, unknown } }, + { vstSpeakerConfigTypeLRCLsRsCs, { left, right, centre, leftSurround, rightSurround, surround, unknown } }, + { vstSpeakerConfigTypeLRLsRsSlSr, { left, right, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsCs, { left, right, centre, subbass, leftSurround, rightSurround, surround, unknown } }, + { vstSpeakerConfigTypeLRLfeLsRsSlSr, { left, right, subbass, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLsRsLcRc, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, + { vstSpeakerConfigTypeLRCLsRsSlSr, { left, right, centre, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsLcRc, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontRight, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsSlSr, { left, right, centre, subbass, leftSurround, rightSurround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLsRsLcRcCs, { left, right, centre, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, + { vstSpeakerConfigTypeLRCLsRsCsSlSr, { left, right, centre, leftSurround, rightSurround, surround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsLcRcCs, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontRight, surround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsCsSlSr, { left, right, centre, subbass, leftSurround, rightSurround, surround, leftRearSurround, rightRearSurround, unknown } }, + { vstSpeakerConfigTypeLRCLfeLsRsTflTfcTfrTrlTrrLfe2, { left, right, centre, subbass, leftSurround, rightSurround, topFrontLeft, topFrontCentre, topFrontRight, topRearLeft, topRearRight, subbass2, unknown } }, + { vstSpeakerConfigTypeEmpty, { unknown } } }; return mappings; } - static inline VstInt32 getSpeakerType (AudioChannelSet::ChannelType type) noexcept + static inline int32 getSpeakerType (AudioChannelSet::ChannelType type) noexcept { switch (type) { - case AudioChannelSet::left: return kSpeakerL; - case AudioChannelSet::right: return kSpeakerR; - case AudioChannelSet::centre: return kSpeakerC; - case AudioChannelSet::subbass: return kSpeakerLfe; - case AudioChannelSet::leftSurround: return kSpeakerLs; - case AudioChannelSet::rightSurround: return kSpeakerRs; - case AudioChannelSet::leftCentre: return kSpeakerLc; - case AudioChannelSet::rightCentre: return kSpeakerRc; - case AudioChannelSet::surround: return kSpeakerS; - case AudioChannelSet::leftRearSurround: return kSpeakerSl; - case AudioChannelSet::rightRearSurround: return kSpeakerSr; - case AudioChannelSet::topMiddle: return kSpeakerTm; - case AudioChannelSet::topFrontLeft: return kSpeakerTfl; - case AudioChannelSet::topFrontCentre: return kSpeakerTfc; - case AudioChannelSet::topFrontRight: return kSpeakerTfr; - case AudioChannelSet::topRearLeft: return kSpeakerTrl; - case AudioChannelSet::topRearCentre: return kSpeakerTrc; - case AudioChannelSet::topRearRight: return kSpeakerTrr; - case AudioChannelSet::subbass2: return kSpeakerLfe2; + case AudioChannelSet::left: return vstIndividualSpeakerTypeLeft; + case AudioChannelSet::right: return vstIndividualSpeakerTypeRight; + case AudioChannelSet::centre: return vstIndividualSpeakerTypeCentre; + case AudioChannelSet::subbass: return vstIndividualSpeakerTypeSubbass; + case AudioChannelSet::leftSurround: return vstIndividualSpeakerTypeLeftSurround; + case AudioChannelSet::rightSurround: return vstIndividualSpeakerTypeRightSurround; + case AudioChannelSet::leftCentre: return vstIndividualSpeakerTypeLeftCentre; + case AudioChannelSet::rightCentre: return vstIndividualSpeakerTypeRightCentre; + case AudioChannelSet::surround: return vstIndividualSpeakerTypeSurround; + case AudioChannelSet::leftRearSurround: return vstIndividualSpeakerTypeLeftRearSurround; + case AudioChannelSet::rightRearSurround: return vstIndividualSpeakerTypeRightRearSurround; + case AudioChannelSet::topMiddle: return vstIndividualSpeakerTypeTopMiddle; + case AudioChannelSet::topFrontLeft: return vstIndividualSpeakerTypeTopFrontLeft; + case AudioChannelSet::topFrontCentre: return vstIndividualSpeakerTypeTopFrontCentre; + case AudioChannelSet::topFrontRight: return vstIndividualSpeakerTypeTopFrontRight; + case AudioChannelSet::topRearLeft: return vstIndividualSpeakerTypeTopRearLeft; + case AudioChannelSet::topRearCentre: return vstIndividualSpeakerTypeTopRearCentre; + case AudioChannelSet::topRearRight: return vstIndividualSpeakerTypeTopRearRight; + case AudioChannelSet::subbass2: return vstIndividualSpeakerTypeSubbass2; default: break; } return 0; } - static inline AudioChannelSet::ChannelType getChannelType (VstInt32 type) noexcept + static inline AudioChannelSet::ChannelType getChannelType (int32 type) noexcept { switch (type) { - case kSpeakerL: return AudioChannelSet::left; - case kSpeakerR: return AudioChannelSet::right; - case kSpeakerC: return AudioChannelSet::centre; - case kSpeakerLfe: return AudioChannelSet::subbass; - case kSpeakerLs: return AudioChannelSet::leftSurround; - case kSpeakerRs: return AudioChannelSet::rightSurround; - case kSpeakerLc: return AudioChannelSet::leftCentre; - case kSpeakerRc: return AudioChannelSet::rightCentre; - case kSpeakerS: return AudioChannelSet::surround; - case kSpeakerSl: return AudioChannelSet::leftRearSurround; - case kSpeakerSr: return AudioChannelSet::rightRearSurround; - case kSpeakerTm: return AudioChannelSet::topMiddle; - case kSpeakerTfl: return AudioChannelSet::topFrontLeft; - case kSpeakerTfc: return AudioChannelSet::topFrontCentre; - case kSpeakerTfr: return AudioChannelSet::topFrontRight; - case kSpeakerTrl: return AudioChannelSet::topRearLeft; - case kSpeakerTrc: return AudioChannelSet::topRearCentre; - case kSpeakerTrr: return AudioChannelSet::topRearRight; - case kSpeakerLfe2: return AudioChannelSet::subbass2; + case vstIndividualSpeakerTypeLeft: return AudioChannelSet::left; + case vstIndividualSpeakerTypeRight: return AudioChannelSet::right; + case vstIndividualSpeakerTypeCentre: return AudioChannelSet::centre; + case vstIndividualSpeakerTypeSubbass: return AudioChannelSet::subbass; + case vstIndividualSpeakerTypeLeftSurround: return AudioChannelSet::leftSurround; + case vstIndividualSpeakerTypeRightSurround: return AudioChannelSet::rightSurround; + case vstIndividualSpeakerTypeLeftCentre: return AudioChannelSet::leftCentre; + case vstIndividualSpeakerTypeRightCentre: return AudioChannelSet::rightCentre; + case vstIndividualSpeakerTypeSurround: return AudioChannelSet::surround; + case vstIndividualSpeakerTypeLeftRearSurround: return AudioChannelSet::leftRearSurround; + case vstIndividualSpeakerTypeRightRearSurround: return AudioChannelSet::rightRearSurround; + case vstIndividualSpeakerTypeTopMiddle: return AudioChannelSet::topMiddle; + case vstIndividualSpeakerTypeTopFrontLeft: return AudioChannelSet::topFrontLeft; + case vstIndividualSpeakerTypeTopFrontCentre: return AudioChannelSet::topFrontCentre; + case vstIndividualSpeakerTypeTopFrontRight: return AudioChannelSet::topFrontRight; + case vstIndividualSpeakerTypeTopRearLeft: return AudioChannelSet::topRearLeft; + case vstIndividualSpeakerTypeTopRearCentre: return AudioChannelSet::topRearCentre; + case vstIndividualSpeakerTypeTopRearRight: return AudioChannelSet::topRearRight; + case vstIndividualSpeakerTypeSubbass2: return AudioChannelSet::subbass2; default: break; } @@ -1256,46 +973,6 @@ public: } }; - //============================================================================== - VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData) override - { - if (filter == nullptr) - return 0; - - chunkMemory.reset(); - if (onlyStoreCurrentProgramData) - filter->getCurrentProgramStateInformation (chunkMemory); - else - filter->getStateInformation (chunkMemory); - - *data = (void*) chunkMemory.getData(); - - // because the chunk is only needed temporarily by the host (or at least you'd - // hope so) we'll give it a while and then free it in the timer callback. - chunkMemoryTime = juce::Time::getApproximateMillisecondCounter(); - - return (VstInt32) chunkMemory.getSize(); - } - - VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData) override - { - if (filter != nullptr) - { - chunkMemory.reset(); - chunkMemoryTime = 0; - - if (byteSize > 0 && data != nullptr) - { - if (onlyRestoreCurrentProgramData) - filter->setCurrentProgramStateInformation (data, byteSize); - else - filter->setStateInformation (data, byteSize); - } - } - - return 0; - } - void timerCallback() override { if (shouldDeleteEditor) @@ -1318,25 +995,6 @@ public: #endif } - void doIdleCallback() - { - // (wavelab calls this on a separate thread and causes a deadlock).. - if (MessageManager::getInstance()->isThisTheMessageThread() - && ! recursionCheck) - { - ScopedValueSetter svs (recursionCheck, true, false); - - JUCE_AUTORELEASEPOOL - { - Timer::callPendingTimersSynchronously(); - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - if (ComponentPeer* p = ComponentPeer::getPeer(i)) - p->performAnyPendingRepaintsNow(); - } - } - } - void createEditorComp() { if (hasShutdown || filter == nullptr) @@ -1346,7 +1004,7 @@ public: { if (AudioProcessorEditor* const ed = filter->createEditorIfNeeded()) { - cEffect.flags |= effFlagsHasEditor; + vstEffect.flags |= vstEffectFlagHasEditor; ed->setOpaque (true); ed->setVisible (true); @@ -1354,7 +1012,7 @@ public: } else { - cEffect.flags &= ~effFlagsHasEditor; + vstEffect.flags &= ~vstEffectFlagHasEditor; } } @@ -1406,77 +1064,71 @@ public: } } - VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) override + pointer_sized_int dispatcher (int32 opCode, VstOpCodeArguments args) { if (hasShutdown) return 0; - if (opCode == effEditIdle) + switch (opCode) { - doIdleCallback(); - return 0; + case plugInOpcodeOpen: return handleOpen (args); + case plugInOpcodeClose: return handleClose (args); + case plugInOpcodeSetCurrentProgram: return handleSetCurrentProgram (args); + case plugInOpcodeGetCurrentProgram: return handleGetCurrentProgram (args); + case plugInOpcodeSetCurrentProgramName: return handleSetCurrentProgramName (args); + case plugInOpcodeGetCurrentProgramName: return handleGetCurrentProgramName (args); + case plugInOpcodeGetParameterLabel: return handleGetParameterLabel (args); + case plugInOpcodeGetParameterText: return handleGetParameterText (args); + case plugInOpcodeGetParameterName: return handleGetParameterName (args); + case plugInOpcodeSetSampleRate: return handleSetSampleRate (args); + case plugInOpcodeSetBlockSize: return handleSetBlockSize (args); + case plugInOpcodeResumeSuspend: return handleResumeSuspend (args); + case plugInOpcodeGetEditorBounds: return handleGetEditorBounds (args); + case plugInOpcodeOpenEditor: return handleOpenEditor (args); + case plugInOpcodeCloseEditor: return handleCloseEditor (args); + case plugInOpcodeEditorIdle: return handleEditorIdle (args); + case plugInOpcodeGetData: return handleGetData (args); + case plugInOpcodeSetData: return handleSetData (args); + case plugInOpcodePreAudioProcessingEvents: return handlePreAudioProcessingEvents (args); + case plugInOpcodeIsParameterAutomatable: return handleIsParameterAutomatable (args); + case plugInOpcodeParameterValueForText: return handleParameterValueForText (args); + case plugInOpcodeGetProgramName: return handleGetProgramName (args); + case plugInOpcodeGetInputPinProperties: return handleGetInputPinProperties (args); + case plugInOpcodeGetOutputPinProperties: return handleGetOutputPinProperties (args); + case plugInOpcodeGetPlugInCategory: return handleGetPlugInCategory (args); + case plugInOpcodeSetSpeakerConfiguration: return handleSetSpeakerConfiguration (args); + case plugInOpcodeSetBypass: return handleSetBypass (args); + case plugInOpcodeGetPlugInName: return handleGetPlugInName (args); + case plugInOpcodeGetManufacturerProductName: return handleGetPlugInName (args); + case plugInOpcodeGetManufacturerName: return handleGetManufacturerName (args); + case plugInOpcodeGetManufacturerVersion: return handleGetManufacturerVersion (args); + case plugInOpcodeManufacturerSpecific: return handleManufacturerSpecific (args); + case plugInOpcodeCanPlugInDo: return handleCanPlugInDo (args); + case plugInOpcodeGetTailSize: return handleGetTailSize (args); + case plugInOpcodeKeyboardFocusRequired: return handleKeyboardFocusRequired (args); + case plugInOpcodeGetVstInterfaceVersion: return handleGetVstInterfaceVersion (args); + case plugInOpcodeGetCurrentMidiProgram: return handleGetCurrentMidiProgram (args); + case plugInOpcodeGetSpeakerArrangement: return handleGetSpeakerConfiguration (args); + case plugInOpcodeSetNumberOfSamplesToProcess: return handleSetNumberOfSamplesToProcess (args); + case plugInOpcodeSetSampleFloatType: return handleSetSampleFloatType (args); + default: return 0; } - else if (opCode == effEditOpen) + } + + static pointer_sized_int dispatcherCB (VstEffectInterface* vstInterface, int32 opCode, int32 index, + pointer_sized_int value, void* ptr, float opt) + { + JuceVSTWrapper* wrapper = getWrapper (vstInterface); + VstOpCodeArguments args = { index, value, ptr, opt }; + + if (opCode == plugInOpcodeClose) { - checkWhetherMessageThreadIsCorrect(); - const MessageManagerLock mmLock; - jassert (! recursionCheck); - - startTimer (1000 / 4); // performs misc housekeeping chores - - deleteEditor (true); - createEditorComp(); - - if (editorComp != nullptr) - { - editorComp->setOpaque (true); - editorComp->setVisible (false); - - #if JUCE_WINDOWS - editorComp->addToDesktop (0, ptr); - hostWindow = (HWND) ptr; - #elif JUCE_LINUX - editorComp->addToDesktop (0, ptr); - hostWindow = (Window) ptr; - Window editorWnd = (Window) editorComp->getWindowHandle(); - XReparentWindow (display, editorWnd, hostWindow, 0, 0); - #else - hostWindow = attachComponentToWindowRefVST (editorComp, ptr, useNSView); - #endif - editorComp->setVisible (true); - - return 1; - } - } - else if (opCode == effEditClose) - { - checkWhetherMessageThreadIsCorrect(); - const MessageManagerLock mmLock; - deleteEditor (true); - return 0; - } - else if (opCode == effEditGetRect) - { - checkWhetherMessageThreadIsCorrect(); - const MessageManagerLock mmLock; - createEditorComp(); - - if (editorComp != nullptr) - { - editorSize.left = 0; - editorSize.top = 0; - editorSize.right = (VstInt16) editorComp->getWidth(); - editorSize.bottom = (VstInt16) editorComp->getHeight(); - - *((ERect**) ptr) = &editorSize; - - return (VstIntPtr) (pointer_sized_int) &editorSize; - } - - return 0; + wrapper->dispatcher (opCode, args); + delete wrapper; + return 1; } - return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); + return wrapper->dispatcher (opCode, args); } void resizeHostWindow (int newWidth, int newHeight) @@ -1485,11 +1137,14 @@ public: { bool sizeWasSuccessful = false; - if (canHostDo (const_cast ("sizeWindow"))) + if (hostCallback != nullptr) { - isInSizeWindow = true; - sizeWasSuccessful = sizeWindow (newWidth, newHeight); - isInSizeWindow = false; + if (hostCallback (&vstEffect, hostOpcodeCanHostDo, 0, 0, const_cast ("sizeWindow"), 0)) + { + isInSizeWindow = true; + sizeWasSuccessful = (hostCallback (&vstEffect, hostOpcodeWindowSize, newWidth, newHeight, 0, 0) != 0); + isInSizeWindow = false; + } } if (! sizeWasSuccessful) @@ -1670,12 +1325,16 @@ public: //============================================================================== private: + VstHostCallback hostCallback; + float sampleRate; + int32 blockSize; + VstEffectInterface vstEffect; AudioProcessor* filter; PluginBusUtilities busUtils; juce::MemoryBlock chunkMemory; juce::uint32 chunkMemoryTime; ScopedPointer editorComp; - ERect editorSize; + VstEditorBounds editorBounds; MidiBuffer midiEvents; VSTMidiEventList outgoingEvents; bool isProcessing, isBypassed, hasShutdown, isInSizeWindow, firstProcessCallback; @@ -1692,12 +1351,19 @@ private: HWND hostWindow; #endif - static inline VstInt32 convertHexVersionToDecimal (const unsigned int hexVersion) + static JuceVSTWrapper* getWrapper (VstEffectInterface* vstInterface) noexcept { return static_cast (vstInterface->effectPointer); } + + bool isProcessLevelOffline() + { + return hostCallback != nullptr && (int32) hostCallback (&vstEffect, hostOpcodeGetCurrentAudioProcessingLevel, 0, 0, 0, 0) == 4; + } + + static inline int32 convertHexVersionToDecimal (const unsigned int hexVersion) { #if JUCE_VST_RETURN_HEX_VERSION_NUMBER_DIRECTLY - return (VstInt32) hexVersion; + return (int32) hexVersion; #else - return (VstInt32) (((hexVersion >> 24) & 0xff) * 1000 + return (int32) (((hexVersion >> 24) & 0xff) * 1000 + ((hexVersion >> 16) & 0xff) * 100 + ((hexVersion >> 8) & 0xff) * 10 + (hexVersion & 0xff)); @@ -1741,8 +1407,8 @@ private: if (filter != nullptr) { - int numChannels = cEffect.numInputs + cEffect.numOutputs; - tmpBuffers.tempChannels.insertMultiple (0, nullptr, numChannels); + const int nInputAndOutputChannels = vstEffect.numInputChannels + vstEffect.numOutputChannels; + tmpBuffers.tempChannels.insertMultiple (0, nullptr, nInputAndOutputChannels); } } @@ -1931,8 +1597,28 @@ private: return false; } + void allocateSpeakerArrangement (VstSpeakerConfiguration** arrangement, int32 nChannels) + { + if (*arrangement) + delete [] (char*) *arrangement; + + // The last member of a full VstSpeakerConfiguration struct is an array of 8 + // VstIndividualSpeakerInfo. Here we only allocate space for channels we will + // actually use. + const int allocationSizeToSubtract = (8 - nChannels) * sizeof (VstIndividualSpeakerInfo); + const int allocationSize = sizeof (VstSpeakerConfiguration) - allocationSizeToSubtract; + char* newAllocation = new char[allocationSize]; + memset (newAllocation, 0, allocationSize); + + *arrangement = (VstSpeakerConfiguration*) newAllocation; + (*arrangement)->numberOfChannels = nChannels; + } + //============================================================================== - bool pluginHasSidechainsOrAuxs() const { return (busUtils.getBusCount (true) > 1 || busUtils.getBusCount (false) > 1); } + bool pluginHasSidechainsOrAuxs() const + { + return (busUtils.getBusCount (true) > 1 || busUtils.getBusCount (false) > 1); + } static int sumOfConfig (const int config[], int num) noexcept { @@ -1942,14 +1628,554 @@ private: return retval; } + + //============================================================================== + /** Host to plug-in calls. */ + + pointer_sized_int handleOpen (VstOpCodeArguments) + { + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. + if (filter->hasEditor()) + vstEffect.flags |= vstEffectFlagHasEditor; + else + vstEffect.flags &= ~vstEffectFlagHasEditor; + + return 0; + } + + pointer_sized_int handleClose (VstOpCodeArguments) + { + // Note: most hosts call this on the UI thread, but wavelab doesn't, so be careful in here. + stopTimer(); + + if (MessageManager::getInstance()->isThisTheMessageThread()) + deleteEditor (false); + + return 0; + } + + pointer_sized_int handleSetCurrentProgram (VstOpCodeArguments args) + { + if (filter != nullptr && isPositiveAndBelow((int) args.value, filter->getNumPrograms())) + filter->setCurrentProgram ((int) args.value); + + return 0; + } + + pointer_sized_int handleGetCurrentProgram (VstOpCodeArguments) + { + return (filter != nullptr && filter->getNumPrograms() > 0 ? filter->getCurrentProgram() : 0); + } + + pointer_sized_int handleSetCurrentProgramName (VstOpCodeArguments args) + { + if (filter != nullptr && filter->getNumPrograms() > 0) + filter->changeProgramName (filter->getCurrentProgram(), (char*) args.ptr); + + return 0; + } + + pointer_sized_int handleGetCurrentProgramName (VstOpCodeArguments args) + { + if (filter != nullptr && filter->getNumPrograms() > 0) + filter->getProgramName (filter->getCurrentProgram()).copyToUTF8 ((char*) args.ptr, 24 + 1); + + return 0; + } + + pointer_sized_int handleGetParameterLabel (VstOpCodeArguments args) + { + if (filter != nullptr) + { + jassert (isPositiveAndBelow (args.index, filter->getNumParameters())); + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + filter->getParameterLabel (args.index).copyToUTF8 ((char*) args.ptr, 24 + 1); + } + + return 0; + } + + pointer_sized_int handleGetParameterText (VstOpCodeArguments args) + { + if (filter != nullptr) + { + jassert (isPositiveAndBelow (args.index, filter->getNumParameters())); + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + filter->getParameterText (args.index, 24).copyToUTF8 ((char*) args.ptr, 24 + 1); + } + + return 0; + } + + pointer_sized_int handleGetParameterName (VstOpCodeArguments args) + { + if (filter != nullptr) + { + jassert (isPositiveAndBelow (args.index, filter->getNumParameters())); + // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + filter->getParameterName (args.index, 16).copyToUTF8 ((char*) args.ptr, 16 + 1); + } + + return 0; + } + + pointer_sized_int handleSetSampleRate (VstOpCodeArguments args) + { + sampleRate = args.opt; + return 0; + } + + pointer_sized_int handleSetBlockSize (VstOpCodeArguments args) + { + blockSize = (int32) args.value; + return 0; + } + + pointer_sized_int handleResumeSuspend (VstOpCodeArguments args) + { + if (args.value) + resume(); + else + suspend(); + + return 0; + } + + pointer_sized_int handleGetEditorBounds (VstOpCodeArguments args) + { + checkWhetherMessageThreadIsCorrect(); + const MessageManagerLock mmLock; + createEditorComp(); + + if (editorComp != nullptr) + { + editorBounds.upper = 0; + editorBounds.leftmost = 0; + editorBounds.lower = (int16) editorComp->getHeight(); + editorBounds.rightmost = (int16) editorComp->getWidth(); + + *((VstEditorBounds**) args.ptr) = &editorBounds; + + return (pointer_sized_int) (pointer_sized_int) &editorBounds; + } + + return 0; + } + + pointer_sized_int handleOpenEditor (VstOpCodeArguments args) + { + checkWhetherMessageThreadIsCorrect(); + const MessageManagerLock mmLock; + jassert (! recursionCheck); + + startTimer (1000 / 4); // performs misc housekeeping chores + + deleteEditor (true); + createEditorComp(); + + if (editorComp != nullptr) + { + editorComp->setOpaque (true); + editorComp->setVisible (false); + + #if JUCE_WINDOWS + editorComp->addToDesktop (0, args.ptr); + hostWindow = (HWND) args.ptr; + #elif JUCE_LINUX + editorComp->addToDesktop (0, args.ptr); + hostWindow = (Window) args.ptr; + Window editorWnd = (Window) editorComp->getWindowHandle(); + XReparentWindow (display, editorWnd, hostWindow, 0, 0); + #else + hostWindow = attachComponentToWindowRefVST (editorComp, args.ptr, useNSView); + #endif + editorComp->setVisible (true); + + return 1; + } + return 0; + } + + pointer_sized_int handleCloseEditor (VstOpCodeArguments) + { + checkWhetherMessageThreadIsCorrect(); + const MessageManagerLock mmLock; + deleteEditor (true); + return 0; + } + + pointer_sized_int handleEditorIdle (VstOpCodeArguments) + { + // (wavelab calls this on a separate thread and causes a deadlock).. + if (MessageManager::getInstance()->isThisTheMessageThread() && ! recursionCheck) + { + ScopedValueSetter svs (recursionCheck, true, false); + JUCE_AUTORELEASEPOOL + { + Timer::callPendingTimersSynchronously(); + + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + if (ComponentPeer* p = ComponentPeer::getPeer(i)) + p->performAnyPendingRepaintsNow(); + } + } + + return 0; + } + + pointer_sized_int handleGetData (VstOpCodeArguments args) + { + void** data = (void**) args.ptr; + bool onlyStoreCurrentProgramData = (args.index != 0); + + if (filter == nullptr) + return 0; + + chunkMemory.reset(); + if (onlyStoreCurrentProgramData) + filter->getCurrentProgramStateInformation (chunkMemory); + else + filter->getStateInformation (chunkMemory); + + *data = (void*) chunkMemory.getData(); + + // because the chunk is only needed temporarily by the host (or at least you'd + // hope so) we'll give it a while and then free it in the timer callback. + chunkMemoryTime = juce::Time::getApproximateMillisecondCounter(); + + return (int32) chunkMemory.getSize(); + } + + pointer_sized_int handleSetData (VstOpCodeArguments args) + { + void* data = args.ptr; + int32 byteSize = (int32) args.value; + bool onlyRestoreCurrentProgramData = (args.index != 0); + + if (filter != nullptr) + { + chunkMemory.reset(); + chunkMemoryTime = 0; + + if (byteSize > 0 && data != nullptr) + { + if (onlyRestoreCurrentProgramData) + filter->setCurrentProgramStateInformation (data, byteSize); + else + filter->setStateInformation (data, byteSize); + } + } + + return 0; + } + + pointer_sized_int handlePreAudioProcessingEvents (VstOpCodeArguments args) + { + #if JucePlugin_WantsMidiInput + VSTMidiEventList::addEventsToMidiBuffer ((VstEventBlock*) args.ptr, midiEvents); + return 1; + #else + ignoreUnused (args); + return 0; + #endif + } + + pointer_sized_int handleIsParameterAutomatable (VstOpCodeArguments args) + { + return (filter != nullptr && filter->isParameterAutomatable (args.index)) ? 1 : 0; + } + + pointer_sized_int handleParameterValueForText (VstOpCodeArguments args) + { + if (filter != nullptr) + { + jassert (isPositiveAndBelow (args.index, filter->getNumParameters())); + + if (AudioProcessorParameter* p = filter->getParameters()[args.index]) + { + filter->setParameter (args.index, p->getValueForText (String::fromUTF8 ((char*) args.ptr))); + return 1; + } + } + + return 0; + } + + pointer_sized_int handleGetProgramName (VstOpCodeArguments args) + { + if (filter != nullptr && isPositiveAndBelow (args.index, filter->getNumPrograms())) + { + filter->getProgramName (args.index).copyToUTF8 ((char*) args.ptr, 24 + 1); + return 1; + } + + return 0; + } + + pointer_sized_int handleGetInputPinProperties (VstOpCodeArguments args) + { + return (filter != nullptr && getPinProperties (*(VstPinInfo*) args.ptr, true, args.index)) ? 1 : 0; + } + + pointer_sized_int handleGetOutputPinProperties (VstOpCodeArguments args) + { + return (filter != nullptr && getPinProperties (*(VstPinInfo*) args.ptr, false, args.index)) ? 1 : 0; + } + + pointer_sized_int handleGetPlugInCategory (VstOpCodeArguments) + { + return JucePlugin_VSTCategory; + } + + pointer_sized_int handleSetSpeakerConfiguration (VstOpCodeArguments args) + { + VstSpeakerConfiguration* pluginInput = reinterpret_cast (args.value); + VstSpeakerConfiguration* pluginOutput = (VstSpeakerConfiguration*) args.ptr; + + const int numIns = busUtils.getBusCount (true); + const int numOuts = busUtils.getBusCount (false);; + + if (pluginInput != nullptr && numIns == 0) + return 0; + + if (pluginOutput != nullptr && numOuts == 0) + return 0; + + if (pluginInput != nullptr && pluginInput->type >= 0) + { + // inconsistent request? + if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput).size() != pluginInput->numberOfChannels) + return 0; + } + + if (pluginOutput != nullptr && pluginOutput->type >= 0) + { + // inconsistent request? + if (SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput).size() != pluginOutput->numberOfChannels) + return 0; + } + + if (numIns > 1 || numOuts > 1) + { + int newNumInChannels = (pluginInput != nullptr && pluginInput-> numberOfChannels >= 0) + ? pluginInput-> numberOfChannels + : busUtils.findTotalNumChannels (true); + int newNumOutChannels = (pluginOutput != nullptr && pluginOutput->numberOfChannels >= 0) + ? pluginOutput->numberOfChannels + : busUtils.findTotalNumChannels (false); + + newNumInChannels = jmin (newNumInChannels, maxNumInChannels); + newNumOutChannels = jmin (newNumOutChannels, maxNumOutChannels); + + if (! setBusArrangementFromTotalChannelNum (newNumInChannels, newNumOutChannels)) + return 0; + } + else + { + PluginBusUtilities::ScopedBusRestorer busRestorer (busUtils); + AudioChannelSet inLayoutType; + + if (pluginInput != nullptr && pluginInput-> numberOfChannels >= 0) + { + inLayoutType = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginInput); + if (busUtils.getChannelSet (true, 0) != inLayoutType) + if (! filter->setPreferredBusArrangement (true, 0, inLayoutType)) + return 0; + } + + if (pluginOutput != nullptr && pluginOutput->numberOfChannels >= 0) + { + AudioChannelSet newType = SpeakerMappings::vstArrangementTypeToChannelSet (*pluginOutput); + + if (busUtils.getChannelSet (false, 0) != newType) + if (! filter->setPreferredBusArrangement (false, 0, newType)) + return 0; + + // re-check the input + if ((! inLayoutType.isDisabled()) && busUtils.getChannelSet (true, 0) != inLayoutType) + return 0; + + busRestorer.release(); + } + } + + filter->setRateAndBufferSizeDetails(0, 0); + return 1; + } + + pointer_sized_int handleSetBypass (VstOpCodeArguments args) + { + isBypassed = (args.value != 0); + return 1; + } + + pointer_sized_int handleGetPlugInName (VstOpCodeArguments args) + { + String (JucePlugin_Name).copyToUTF8 ((char*) args.ptr, 64 + 1); + return 1; + } + + pointer_sized_int handleGetManufacturerName (VstOpCodeArguments args) + { + String (JucePlugin_Manufacturer).copyToUTF8 ((char*) args.ptr, 64 + 1); + return 1; + } + + pointer_sized_int handleGetManufacturerVersion (VstOpCodeArguments) + { + return convertHexVersionToDecimal (JucePlugin_VersionCode); + } + + pointer_sized_int handleManufacturerSpecific (VstOpCodeArguments args) + { + #if JucePlugin_Build_VST3 && JUCE_VST3_CAN_REPLACE_VST2 + if ((args.index == 'stCA' || args.index == 'stCa') && args.value == 'FUID' && args.ptr != nullptr) + { + memcpy (args.ptr, getJuceVST3ComponentIID(), 16); + return 1; + } + #else + ignoreUnused (args); + #endif + return 0; + } + + pointer_sized_int handleCanPlugInDo (VstOpCodeArguments args) + { + char* text = (char*) args.ptr; + if (strcmp (text, "receiveVstEvents") == 0 + || strcmp (text, "receiveVstMidiEvent") == 0 + || strcmp (text, "receiveVstMidiEvents") == 0) + { + #if JucePlugin_WantsMidiInput + return 1; + #else + return -1; + #endif + } + + if (strcmp (text, "sendVstEvents") == 0 + || strcmp (text, "sendVstMidiEvent") == 0 + || strcmp (text, "sendVstMidiEvents") == 0) + { + #if JucePlugin_ProducesMidiOutput + return 1; + #else + return -1; + #endif + } + + if (strcmp (text, "receiveVstTimeInfo") == 0 + || strcmp (text, "conformsToWindowRules") == 0 + || strcmp (text, "bypass") == 0) + { + return 1; + } + + // This tells Wavelab to use the UI thread to invoke open/close, + // like all other hosts do. + if (strcmp (text, "openCloseAnyThread") == 0) + return -1; + + if (strcmp (text, "MPE") == 0) + return filter->supportsMPE() ? 1 : 0; + + #if JUCE_MAC + if (strcmp (text, "hasCockosViewAsConfig") == 0) + { + useNSView = true; + return (int32) 0xbeef0000; + } + #endif + + return 0; + } + + pointer_sized_int handleGetTailSize (VstOpCodeArguments) + { + if (filter != nullptr) + return (pointer_sized_int) (filter->getTailLengthSeconds() * sampleRate); + + return 0; + } + + pointer_sized_int handleKeyboardFocusRequired (VstOpCodeArguments) + { + return (JucePlugin_EditorRequiresKeyboardFocus != 0) ? 1 : 0; + } + + pointer_sized_int handleGetVstInterfaceVersion (VstOpCodeArguments) + { + return juceVstInterfaceVersion; + } + + pointer_sized_int handleGetCurrentMidiProgram (VstOpCodeArguments) + { + return -1; + } + + pointer_sized_int handleGetSpeakerConfiguration (VstOpCodeArguments args) + { + VstSpeakerConfiguration** pluginInput = reinterpret_cast (args.value); + VstSpeakerConfiguration** pluginOutput = (VstSpeakerConfiguration**) args.ptr; + *pluginInput = nullptr; + *pluginOutput = nullptr; + + allocateSpeakerArrangement (pluginInput, busUtils.findTotalNumChannels (true)); + allocateSpeakerArrangement (pluginOutput, busUtils.findTotalNumChannels (false)); + + if (pluginHasSidechainsOrAuxs()) + { + int numIns = busUtils.findTotalNumChannels (true); + int numOuts = busUtils.findTotalNumChannels (false); + + AudioChannelSet layout = AudioChannelSet::canonicalChannelSet (numIns); + SpeakerMappings::channelSetToVstArrangement (layout, **pluginInput); + + layout = AudioChannelSet::canonicalChannelSet (numOuts); + SpeakerMappings::channelSetToVstArrangement (layout, **pluginOutput); + } + else + { + SpeakerMappings::channelSetToVstArrangement (busUtils.getChannelSet (true, 0), **pluginInput); + SpeakerMappings::channelSetToVstArrangement (busUtils.getChannelSet (false, 0), **pluginOutput); + } + + return 1; + } + + pointer_sized_int handleSetNumberOfSamplesToProcess (VstOpCodeArguments args) + { + return args.value; + } + + pointer_sized_int handleSetSampleFloatType (VstOpCodeArguments args) + { + if (! isProcessing) + { + if (filter != nullptr) + { + filter->setProcessingPrecision (args.value == vstProcessingSampleTypeDouble + && filter->supportsDoublePrecisionProcessing() + ? AudioProcessor::doublePrecision + : AudioProcessor::singlePrecision); + + return 1; + } + } + + return 0; + } + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVSTWrapper) }; + //============================================================================== namespace { - AEffect* pluginEntryPoint (audioMasterCallback audioMaster) + VstEffectInterface* pluginEntryPoint (VstHostCallback audioMaster) { JUCE_AUTORELEASEPOOL { @@ -1957,7 +2183,7 @@ namespace try { - if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0) + if (audioMaster (0, hostOpcodeVstVersion, 0, 0, 0, 0) != 0) { #if JUCE_LINUX MessageManagerLock mmLock; @@ -1965,7 +2191,7 @@ namespace AudioProcessor* const filter = createPluginFilterOfType (AudioProcessor::wrapperType_VST); JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter); - return wrapper->getAeffect(); + return wrapper->getVstEffectInterface(); } } catch (...) @@ -1984,8 +2210,8 @@ namespace // Mac startup code.. #if JUCE_MAC - JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster) + JUCE_EXPORTED_FUNCTION VstEffectInterface* VSTPluginMain (VstHostCallback audioMaster); + JUCE_EXPORTED_FUNCTION VstEffectInterface* VSTPluginMain (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; @@ -1993,8 +2219,8 @@ namespace return pluginEntryPoint (audioMaster); } - JUCE_EXPORTED_FUNCTION AEffect* main_macho (audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION AEffect* main_macho (audioMasterCallback audioMaster) + JUCE_EXPORTED_FUNCTION VstEffectInterface* main_macho (VstHostCallback audioMaster); + JUCE_EXPORTED_FUNCTION VstEffectInterface* main_macho (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; @@ -2006,8 +2232,8 @@ namespace // Linux startup code.. #elif JUCE_LINUX - JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster); - JUCE_EXPORTED_FUNCTION AEffect* VSTPluginMain (audioMasterCallback audioMaster) + JUCE_EXPORTED_FUNCTION VstEffectInterface* VSTPluginMain (VstHostCallback audioMaster); + JUCE_EXPORTED_FUNCTION VstEffectInterface* VSTPluginMain (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; @@ -2015,8 +2241,8 @@ namespace return pluginEntryPoint (audioMaster); } - JUCE_EXPORTED_FUNCTION AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main"); - JUCE_EXPORTED_FUNCTION AEffect* main_plugin (audioMasterCallback audioMaster) + JUCE_EXPORTED_FUNCTION VstEffectInterface* main_plugin (VstHostCallback audioMaster) asm ("main"); + JUCE_EXPORTED_FUNCTION VstEffectInterface* main_plugin (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; @@ -2031,7 +2257,7 @@ namespace // Win32 startup code.. #else - extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster) + extern "C" __declspec (dllexport) VstEffectInterface* VSTPluginMain (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; @@ -2039,7 +2265,7 @@ namespace } #ifndef JUCE_64BIT // (can't compile this on win64, but it's not needed anyway with VST2.4) - extern "C" __declspec (dllexport) int main (audioMasterCallback audioMaster) + extern "C" __declspec (dllexport) int main (VstHostCallback audioMaster) { PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_VST; diff --git a/modules/juce_audio_processors/format_types/juce_VSTInterface.h b/modules/juce_audio_processors/format_types/juce_VSTInterface.h new file mode 100644 index 0000000000..b673004044 --- /dev/null +++ b/modules/juce_audio_processors/format_types/juce_VSTInterface.h @@ -0,0 +1,455 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2016 - ROLI Ltd. + + Permission is granted to use this software under the terms of either: + a) the GPL v2 (or any later version) + b) the Affero GPL v3 + + Details of these licenses can be found at: www.gnu.org/licenses + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ----------------------------------------------------------------------------- + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.juce.com for more information. + + ============================================================================== +*/ + +#ifndef JUCE_VSTINTERFACE_H_INCLUDED +#define JUCE_VSTINTERFACE_H_INCLUDED + +#include "../../juce_core/juce_core.h" + +using namespace juce; + +#if JUCE_MSVC + #define VSTINTERFACECALL __cdecl + #pragma pack(push) + #pragma pack(8) +#elif JUCE_MAC || JUCE_IOS + #define VSTINTERFACECALL + #if JUCE_64BIT + #pragma options align=power + #else + #pragma options align=mac68k + #endif +#else + #define VSTINTERFACECALL + #pragma pack(push, 8) +#endif + +const int32 juceVstInterfaceVersion = 2400; +const int32 juceVstInterfaceIdentifier = 0x56737450; // The "magic" identifier in the SDK is 'VstP'. + +//============================================================================== +struct VstEffectInterface +{ + int32 interfaceIdentifier; + pointer_sized_int (VSTINTERFACECALL* dispatchFunction) (VstEffectInterface*, int32 op, int32 index, pointer_sized_int value, void* ptr, float opt); + void (VSTINTERFACECALL* processAudioFunction) (VstEffectInterface*, float** inputs, float** outputs, int32 numSamples); + void (VSTINTERFACECALL* setParameterValueFunction) (VstEffectInterface*, int32 parameterIndex, float value); + float (VSTINTERFACECALL* getParameterValueFunction) (VstEffectInterface*, int32 parameterIndex); + int32 numPrograms; + int32 numParameters; + int32 numInputChannels; + int32 numOutputChannels; + int32 flags; + pointer_sized_int hostSpace1; + pointer_sized_int hostSpace2; + int32 latency; + int32 deprecated1; + int32 deprecated2; + float deprecated3; + void* effectPointer; + void* userPointer; + int32 plugInIdentifier; + int32 plugInVersion; + void (VSTINTERFACECALL* processAudioInplaceFunction) (VstEffectInterface*, float** inputs, float** outputs, int32 numSamples); + void (VSTINTERFACECALL* processDoubleAudioInplaceFunction) (VstEffectInterface*, double** inputs, double** outputs, int32 numSamples); + char emptySpace[56]; +}; + +typedef pointer_sized_int (VSTINTERFACECALL* VstHostCallback) (VstEffectInterface*, int32 op, int32 index, pointer_sized_int value, void* ptr, float opt); + +enum VstEffectInterfaceFlags +{ + vstEffectFlagHasEditor = 1, + vstEffectFlagInplaceAudio = 16, + vstEffectFlagDataInChunks = 32, + vstEffectFlagIsSynth = 256, + vstEffectFlagInplaceDoubleAudio = 4096 +}; + +//============================================================================== +enum VstHostToPlugInOpcodes +{ + plugInOpcodeOpen, + plugInOpcodeClose, + plugInOpcodeSetCurrentProgram, + plugInOpcodeGetCurrentProgram, + plugInOpcodeSetCurrentProgramName, + plugInOpcodeGetCurrentProgramName, + plugInOpcodeGetParameterLabel, + plugInOpcodeGetParameterText, + plugInOpcodeGetParameterName, + plugInOpcodeSetSampleRate = plugInOpcodeGetParameterName + 2, + plugInOpcodeSetBlockSize, + plugInOpcodeResumeSuspend, + plugInOpcodeGetEditorBounds, + plugInOpcodeOpenEditor, + plugInOpcodeCloseEditor, + plugInOpcodeEditorIdle = plugInOpcodeCloseEditor + 4, + plugInOpcodeeffEditorTop, + plugInOpcodeIdentify = plugInOpcodeeffEditorTop + 2, + plugInOpcodeGetData, + plugInOpcodeSetData, + plugInOpcodePreAudioProcessingEvents, + plugInOpcodeIsParameterAutomatable, + plugInOpcodeParameterValueForText, + plugInOpcodeGetProgramName = plugInOpcodeParameterValueForText + 2, + plugInOpcodeConnectInput = plugInOpcodeGetProgramName + 2, + plugInOpcodeConnectOutput, + plugInOpcodeGetInputPinProperties, + plugInOpcodeGetOutputPinProperties, + plugInOpcodeGetPlugInCategory, + plugInOpcodeSetSpeakerConfiguration = plugInOpcodeGetPlugInCategory + 7, + plugInOpcodeSetBypass = plugInOpcodeSetSpeakerConfiguration + 2, + plugInOpcodeGetPlugInName, + plugInOpcodeGetManufacturerName = plugInOpcodeGetPlugInName + 2, + plugInOpcodeGetManufacturerProductName, + plugInOpcodeGetManufacturerVersion, + plugInOpcodeManufacturerSpecific, + plugInOpcodeCanPlugInDo, + plugInOpcodeGetTailSize, + plugInOpcodeIdle, + plugInOpcodeKeyboardFocusRequired = plugInOpcodeIdle + 4, + plugInOpcodeGetVstInterfaceVersion, + plugInOpcodeGetCurrentMidiProgram = plugInOpcodeGetVstInterfaceVersion + 5, + plugInOpcodeGetSpeakerArrangement = plugInOpcodeGetCurrentMidiProgram + 6, + plugInOpcodeNextPlugInUniqueID, + plugInOpcodeStartProcess, + plugInOpcodeStopProcess, + plugInOpcodeSetNumberOfSamplesToProcess, + plugInOpcodeSetSampleFloatType = plugInOpcodeSetNumberOfSamplesToProcess + 4, + plugInOpcodeMaximum = plugInOpcodeSetSampleFloatType +}; + + +enum VstPlugInToHostOpcodes +{ + hostOpcodeParameterChanged, + hostOpcodeVstVersion, + hostOpcodeCurrentId, + hostOpcodeIdle, + hostOpcodePinConnected, + hostOpcodePlugInWantsMidi = hostOpcodePinConnected + 2, + hostOpcodeGetTimingInfo, + hostOpcodePreAudioProcessingEvents, + hostOpcodeSetTime, + hostOpcodeTempoAt, + hostOpcodeGetNumberOfAutomatableParameters, + hostOpcodeGetParameterInterval, + hostOpcodeIOModified, + hostOpcodeNeedsIdle, + hostOpcodeWindowSize, + hostOpcodeGetSampleRate, + hostOpcodeGetBlockSize, + hostOpcodeGetInputLatency, + hostOpcodeGetOutputLatency, + hostOpcodeGetPreviousPlugIn, + hostOpcodeGetNextPlugIn, + hostOpcodeWillReplace, + hostOpcodeGetCurrentAudioProcessingLevel, + hostOpcodeGetAutomationState, + hostOpcodeOfflineStart, + hostOpcodeOfflineReadSource, + hostOpcodeOfflineWrite, + hostOpcodeOfflineGetCurrentPass, + hostOpcodeOfflineGetCurrentMetaPass, + hostOpcodeSetOutputSampleRate, + hostOpcodeGetOutputSpeakerConfiguration, + hostOpcodeGetManufacturerName, + hostOpcodeGetProductName, + hostOpcodeGetManufacturerVersion, + hostOpcodeManufacturerSpecific, + hostOpcodeSetIcon, + hostOpcodeCanHostDo, + hostOpcodeGetLanguage, + hostOpcodeOpenEditorWindow, + hostOpcodeCloseEditorWindow, + hostOpcodeGetDirectory, + hostOpcodeUpdateView, + hostOpcodeParameterChangeGestureBegin, + hostOpcodeParameterChangeGestureEnd, +}; + +//============================================================================== +enum VstProcessingSampleType +{ + vstProcessingSampleTypeFloat, + vstProcessingSampleTypeDouble +}; + +//============================================================================== +// These names must be identical to the Steinberg SDK so JUCE users can set +// exactly what they want. +enum VstPlugInCategory +{ + kPlugCategUnknown, + kPlugCategEffect, + kPlugCategSynth, + kPlugCategAnalysis, + kPlugCategMastering, + kPlugCategSpacializer, + kPlugCategRoomFx, + kPlugSurroundFx, + kPlugCategRestoration, + kPlugCategOfflineProcess, + kPlugCategShell, + kPlugCategGenerator +}; + +//============================================================================== +struct VstEditorBounds +{ + int16 upper; + int16 leftmost; + int16 lower; + int16 rightmost; +}; + +//============================================================================== +enum VstMaxStringLengths +{ + vstMaxNameLength = 64, + vstMaxParameterOrPinLabelLength = 64, + vstMaxParameterOrPinShortLabelLength = 8, + vstMaxCategoryLength = 24, + vstMaxManufacturerStringLength = 64, + vstMaxPlugInNameStringLength = 64 +}; + +//============================================================================== +struct VstPinInfo +{ + char text[vstMaxParameterOrPinLabelLength]; + int32 flags; + int32 configurationType; + char shortText[vstMaxParameterOrPinShortLabelLength]; + char unused[48]; +}; + +enum VstPinInfoFlags +{ + vstPinInfoFlagIsActive = 1, + vstPinInfoFlagIsStereo = 2, + vstPinInfoFlagValid = 4 +}; + +//============================================================================== +struct VstEvent +{ + int32 type; + int32 size; + int32 sampleOffset; + int32 flags; + char content[16]; +}; + +enum VstEventTypes +{ + vstMidiEventType = 1, + vstSysExEventType = 6 +}; + +struct VstEventBlock +{ + int32 numberOfEvents; + pointer_sized_int future; + VstEvent* events[2]; +}; + +struct VstMidiEvent +{ + int32 type; + int32 size; + int32 sampleOffset; + int32 flags; + int32 noteSampleLength; + int32 noteSampleOffset; + char midiData[4]; + char tuning; + char noteVelocityOff; + char future1; + char future2; +}; + +enum VstMidiEventFlags +{ + vstMidiEventIsRealtime = 1 +}; + +struct VstSysExEvent +{ + int32 type; + int32 size; + int32 offsetSamples; + int32 flags; + int32 sysExDumpSize; + pointer_sized_int future1; + char* sysExDump; + pointer_sized_int future2; +}; + +//============================================================================== +struct VstTimingInformation +{ + double samplePosition; + double sampleRate; + double systemTimeNanoseconds; + double musicalPosition; + double tempoBPM; + double lastBarPosition; + double loopStartPosition; + double loopEndPosition; + int32 timeSignatureNumerator; + int32 timeSignatureDenominator; + int32 smpteOffset; + int32 smpteRate; + int32 samplesToNearestClock; + int32 flags; +}; + +enum VstTimingInformationFlags +{ + vstTimingInfoFlagTransportChanged = 1, + vstTimingInfoFlagCurrentlyPlaying = 2, + vstTimingInfoFlagLoopActive = 4, + vstTimingInfoFlagCurrentlyRecording = 8, + vstTimingInfoFlagAutomationWriteModeActive = 64, + vstTimingInfoFlagAutomationReadModeActive = 128, + vstTimingInfoFlagNanosecondsValid = 256, + vstTimingInfoFlagMusicalPositionValid = 512, + vstTimingInfoFlagTempoValid = 1024, + vstTimingInfoFlagLastBarPositionValid = 2056, + vstTimingInfoFlagLoopPositionValid = 4096, + vstTimingInfoFlagTimeSignatureValid = 8192, + vstTimingInfoFlagSmpteValid = 16384, + vstTimingInfoFlagNearestClockValid = 32768 +}; + +//============================================================================== +enum VstSmpteRates +{ + vstSmpteRateFps24, + vstSmpteRateFps25, + vstSmpteRateFps2997, + vstSmpteRateFps30, + vstSmpteRateFps2997drop, + vstSmpteRateFps30drop, + + vstSmpteRate16mmFilm, + vstSmpteRate35mmFilm, + + vstSmpteRateFps239 = vstSmpteRate35mmFilm + 3, + vstSmpteRateFps249 , + vstSmpteRateFps599, + vstSmpteRateFps60 +}; + +//============================================================================== +struct VstIndividualSpeakerInfo +{ + float azimuthalAngle; + float elevationAngle; + float radius; + float reserved; + char label[vstMaxNameLength]; + int32 type; + char unused[28]; +}; + +enum VstIndividualSpeakerType +{ + vstIndividualSpeakerTypeUndefined = 0x7fffffff, + vstIndividualSpeakerTypeMono = 0, + vstIndividualSpeakerTypeLeft, + vstIndividualSpeakerTypeRight, + vstIndividualSpeakerTypeCentre, + vstIndividualSpeakerTypeSubbass, + vstIndividualSpeakerTypeLeftSurround, + vstIndividualSpeakerTypeRightSurround, + vstIndividualSpeakerTypeLeftCentre, + vstIndividualSpeakerTypeRightCentre, + vstIndividualSpeakerTypeSurround, + vstIndividualSpeakerTypeCentreSurround = vstIndividualSpeakerTypeSurround, + vstIndividualSpeakerTypeLeftRearSurround, + vstIndividualSpeakerTypeRightRearSurround, + vstIndividualSpeakerTypeTopMiddle, + vstIndividualSpeakerTypeTopFrontLeft, + vstIndividualSpeakerTypeTopFrontCentre, + vstIndividualSpeakerTypeTopFrontRight, + vstIndividualSpeakerTypeTopRearLeft, + vstIndividualSpeakerTypeTopRearCentre, + vstIndividualSpeakerTypeTopRearRight, + vstIndividualSpeakerTypeSubbass2 +}; + +struct VstSpeakerConfiguration +{ + int32 type; + int32 numberOfChannels; + VstIndividualSpeakerInfo speakers[8]; +}; + +enum VstSpeakerConfigurationType +{ + vstSpeakerConfigTypeUser = -2, + vstSpeakerConfigTypeEmpty = -1, + vstSpeakerConfigTypeMono = 0, + vstSpeakerConfigTypeLR, + vstSpeakerConfigTypeLsRs, + vstSpeakerConfigTypeLcRc, + vstSpeakerConfigTypeSlSr, + vstSpeakerConfigTypeCLfe, + vstSpeakerConfigTypeLRC, + vstSpeakerConfigTypeLRS, + vstSpeakerConfigTypeLRCLfe, + vstSpeakerConfigTypeLRLfeS, + vstSpeakerConfigTypeLRCS, + vstSpeakerConfigTypeLRLsRs, + vstSpeakerConfigTypeLRCLfeS, + vstSpeakerConfigTypeLRLfeLsRs, + vstSpeakerConfigTypeLRCLsRs, + vstSpeakerConfigTypeLRCLfeLsRs, + vstSpeakerConfigTypeLRCLsRsCs, + vstSpeakerConfigTypeLRLsRsSlSr, + vstSpeakerConfigTypeLRCLfeLsRsCs, + vstSpeakerConfigTypeLRLfeLsRsSlSr, + vstSpeakerConfigTypeLRCLsRsLcRc, + vstSpeakerConfigTypeLRCLsRsSlSr, + vstSpeakerConfigTypeLRCLfeLsRsLcRc, + vstSpeakerConfigTypeLRCLfeLsRsSlSr, + vstSpeakerConfigTypeLRCLsRsLcRcCs, + vstSpeakerConfigTypeLRCLsRsCsSlSr, + vstSpeakerConfigTypeLRCLfeLsRsLcRcCs, + vstSpeakerConfigTypeLRCLfeLsRsCsSlSr, + vstSpeakerConfigTypeLRCLfeLsRsTflTfcTfrTrlTrrLfe2 +}; + +#if JUCE_MSVC + #pragma pack(pop) +#elif JUCE_MAC || JUCE_IOS + #pragma options align=reset +#else + #pragma pack(pop) +#endif + +#endif // JUCE_VSTINTERFACE_H_INCLUDED diff --git a/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h b/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h index 6117481b75..2d486a59b6 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h +++ b/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h @@ -22,7 +22,8 @@ ============================================================================== */ -#ifdef __aeffect__ // NB: this must come first, *before* the header-guard. +// NB: this must come first, *before* the header-guard. +#ifdef JUCE_VSTINTERFACE_H_INCLUDED #ifndef JUCE_VSTMIDIEVENTLIST_H_INCLUDED #define JUCE_VSTMIDIEVENTLIST_H_INCLUDED @@ -53,7 +54,7 @@ public: numEventsUsed = 0; if (events != nullptr) - events->numEvents = 0; + events->numberOfEvents = 0; } void addEvent (const void* const midiData, const int numBytes, const int frameOffset) @@ -61,65 +62,65 @@ public: ensureSize (numEventsUsed + 1); VstMidiEvent* const e = (VstMidiEvent*) (events->events [numEventsUsed]); - events->numEvents = ++numEventsUsed; + events->numberOfEvents = ++numEventsUsed; if (numBytes <= 4) { - if (e->type == kVstSysExType) + if (e->type == vstSysExEventType) { - delete[] (((VstMidiSysexEvent*) e)->sysexDump); - e->type = kVstMidiType; - e->byteSize = sizeof (VstMidiEvent); - e->noteLength = 0; - e->noteOffset = 0; - e->detune = 0; - e->noteOffVelocity = 0; + delete[] (((VstSysExEvent*) e)->sysExDump); + e->type = vstMidiEventType; + e->size = sizeof (VstMidiEvent); + e->noteSampleLength = 0; + e->noteSampleOffset = 0; + e->tuning = 0; + e->noteVelocityOff = 0; } - e->deltaFrames = frameOffset; + e->sampleOffset = frameOffset; memcpy (e->midiData, midiData, (size_t) numBytes); } else { - VstMidiSysexEvent* const se = (VstMidiSysexEvent*) e; + VstSysExEvent* const se = (VstSysExEvent*) e; - if (se->type == kVstSysExType) - delete[] se->sysexDump; + if (se->type == vstSysExEventType) + delete[] se->sysExDump; - se->sysexDump = new char [(size_t) numBytes]; - memcpy (se->sysexDump, midiData, (size_t) numBytes); + se->sysExDump = new char [(size_t) numBytes]; + memcpy (se->sysExDump, midiData, (size_t) numBytes); - se->type = kVstSysExType; - se->byteSize = sizeof (VstMidiSysexEvent); - se->deltaFrames = frameOffset; + se->type = vstSysExEventType; + se->size = sizeof (VstSysExEvent); + se->offsetSamples = frameOffset; se->flags = 0; - se->dumpBytes = numBytes; - se->resvd1 = 0; - se->resvd2 = 0; + se->sysExDumpSize = numBytes; + se->future1 = 0; + se->future2 = 0; } } //============================================================================== // Handy method to pull the events out of an event buffer supplied by the host // or plugin. - static void addEventsToMidiBuffer (const VstEvents* events, MidiBuffer& dest) + static void addEventsToMidiBuffer (const VstEventBlock* events, MidiBuffer& dest) { - for (int i = 0; i < events->numEvents; ++i) + for (int i = 0; i < events->numberOfEvents; ++i) { const VstEvent* const e = events->events[i]; if (e != nullptr) { - if (e->type == kVstMidiType) + if (e->type == vstMidiEventType) { dest.addEvent ((const juce::uint8*) ((const VstMidiEvent*) e)->midiData, - 4, e->deltaFrames); + 4, e->sampleOffset); } - else if (e->type == kVstSysExType) + else if (e->type == vstSysExEventType) { - dest.addEvent ((const juce::uint8*) ((const VstMidiSysexEvent*) e)->sysexDump, - (int) ((const VstMidiSysexEvent*) e)->dumpBytes, - e->deltaFrames); + dest.addEvent ((const juce::uint8*) ((const VstSysExEvent*) e)->sysExDump, + (int) ((const VstSysExEvent*) e)->sysExDumpSize, + e->sampleOffset); } } } @@ -160,24 +161,24 @@ public: } //============================================================================== - HeapBlock events; + HeapBlock events; private: int numEventsUsed, numEventsAllocated; static VstEvent* allocateVSTEvent() { - VstEvent* const e = (VstEvent*) std::calloc (1, sizeof (VstMidiEvent) > sizeof (VstMidiSysexEvent) ? sizeof (VstMidiEvent) - : sizeof (VstMidiSysexEvent)); - e->type = kVstMidiType; - e->byteSize = sizeof (VstMidiEvent); + VstEvent* const e = (VstEvent*) std::calloc (1, sizeof (VstMidiEvent) > sizeof (VstSysExEvent) ? sizeof (VstMidiEvent) + : sizeof (VstSysExEvent)); + e->type = vstMidiEventType; + e->size = sizeof (VstMidiEvent); return e; } static void freeVSTEvent (VstEvent* e) { - if (e->type == kVstSysExType) - delete[] (((VstMidiSysexEvent*) e)->sysexDump); + if (e->type == vstSysExEventType) + delete[] (((VstSysExEvent*) e)->sysExDump); std::free (e); } diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index 37bd1c15e7..28cb3d0e7c 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -31,7 +31,6 @@ //============================================================================== #undef PRAGMA_ALIGN_SUPPORTED -#define VST_FORCE_DEPRECATED 0 #if JUCE_MSVC #pragma warning (push) @@ -40,13 +39,10 @@ #define __cdecl #endif -/* Obviously you're going to need the Steinberg vstsdk2.4 folder in - your include path if you want to add VST support. - - If you're not interested in VSTs, you can disable them by setting the - JUCE_PLUGINHOST_VST flag to 0. -*/ -#include "pluginterfaces/vst2.x/aeffectx.h" +namespace +{ +#include "juce_VSTInterface.h" +} #if JUCE_MSVC #pragma warning (pop) @@ -83,67 +79,67 @@ namespace struct fxProgram { - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCk' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numParams; + int32 chunkMagic; // 'CcnK' + int32 byteSize; // of this chunk, excl. magic + byteSize + int32 fxMagic; // 'FxCk' + int32 version; + int32 fxID; // fx unique id + int32 fxVersion; + int32 numParams; char prgName[28]; float params[1]; // variable no. of parameters }; struct fxSet { - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxBk' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; + int32 chunkMagic; // 'CcnK' + int32 byteSize; // of this chunk, excl. magic + byteSize + int32 fxMagic; // 'FxBk' + int32 version; + int32 fxID; // fx unique id + int32 fxVersion; + int32 numPrograms; char future[128]; fxProgram programs[1]; // variable no. of programs }; struct fxChunkSet { - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; + int32 chunkMagic; // 'CcnK' + int32 byteSize; // of this chunk, excl. magic + byteSize + int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + int32 version; + int32 fxID; // fx unique id + int32 fxVersion; + int32 numPrograms; char future[128]; - VstInt32 chunkSize; + int32 chunkSize; char chunk[8]; // variable }; struct fxProgramSet { - VstInt32 chunkMagic; // 'CcnK' - VstInt32 byteSize; // of this chunk, excl. magic + byteSize - VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' - VstInt32 version; - VstInt32 fxID; // fx unique id - VstInt32 fxVersion; - VstInt32 numPrograms; + int32 chunkMagic; // 'CcnK' + int32 byteSize; // of this chunk, excl. magic + byteSize + int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh' + int32 version; + int32 fxID; // fx unique id + int32 fxVersion; + int32 numPrograms; char name[28]; - VstInt32 chunkSize; + int32 chunkSize; char chunk[8]; // variable }; // Compares a magic value in either endianness. - static bool compareMagic (VstInt32 magic, const char* name) noexcept + static bool compareMagic (int32 magic, const char* name) noexcept { - return magic == (VstInt32) ByteOrder::littleEndianInt (name) - || magic == (VstInt32) ByteOrder::bigEndianInt (name); + return magic == (int32) ByteOrder::littleEndianInt (name) + || magic == (int32) ByteOrder::bigEndianInt (name); } - static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::littleEndianInt (name); } - static VstInt32 fxbSwap (const VstInt32 x) noexcept { return (VstInt32) ByteOrder::swapIfLittleEndian ((uint32) x); } + static int32 fxbName (const char* name) noexcept { return (int32) ByteOrder::littleEndianInt (name); } + static int32 fxbSwap (const int32 x) noexcept { return (int32) ByteOrder::swapIfLittleEndian ((uint32) x); } static float fxbSwapFloat (const float x) noexcept { @@ -206,8 +202,8 @@ namespace } //============================================================================== -typedef AEffect* (VSTCALLBACK *MainCall) (audioMasterCallback); -static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt); +typedef VstEffectInterface* (VSTINTERFACECALL *MainCall) (VstHostCallback); +static pointer_sized_int VSTINTERFACECALL audioMaster (VstEffectInterface* effect, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt); //============================================================================== // Change this to disable logging of various VST activities @@ -437,9 +433,9 @@ public: module.close(); } - void closeEffect (AEffect* eff) + void closeEffect (VstEffectInterface* eff) { - eff->dispatcher (eff, effClose, 0, 0, 0, 0); + eff->dispatchFunction (eff, plugInOpcodeClose, 0, 0, 0, 0); } #if JUCE_WINDOWS @@ -564,9 +560,9 @@ public: } } - void closeEffect (AEffect* eff) + void closeEffect (VstEffectInterface* eff) { - eff->dispatcher (eff, effClose, 0, 0, 0, 0); + eff->dispatchFunction (eff, plugInOpcodeClose, 0, 0, 0, 0); } #endif @@ -615,12 +611,12 @@ public: JUCE_VST_WRAPPER_INVOKE_MAIN } - if (effect != nullptr && effect->magic == kEffectMagic) + if (effect != nullptr && effect->interfaceIdentifier == juceVstInterfaceIdentifier) { - jassert (effect->resvd2 == 0); - jassert (effect->object != 0); + jassert (effect->hostSpace2 == 0); + jassert (effect->effectPointer != 0); - _fpreset(); // some dodgy plugs fuck around with this + _fpreset(); // some dodgy plugs mess around with this } else { @@ -636,7 +632,7 @@ public: const ScopedLock sl (lock); stopTimer(); - if (effect != nullptr && effect->magic == kEffectMagic) + if (effect != nullptr && effect->interfaceIdentifier == juceVstInterfaceIdentifier) { #if JUCE_MAC if (module->resFileId != 0) @@ -661,7 +657,7 @@ public: { char buffer[512] = { 0 }; - dispatch (effGetEffectName, 0, 0, buffer, 0); + dispatch (plugInOpcodeGetPlugInName, 0, 0, buffer, 0); desc.descriptiveName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim(); @@ -678,21 +674,21 @@ public: { char buffer[512] = { 0 }; - dispatch (effGetVendorString, 0, 0, buffer, 0); + dispatch (plugInOpcodeGetManufacturerName, 0, 0, buffer, 0); desc.manufacturerName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim(); } desc.version = getVersion(); desc.numInputChannels = getTotalNumInputChannels(); desc.numOutputChannels = getTotalNumOutputChannels(); - desc.isInstrument = (effect != nullptr && (effect->flags & effFlagsIsSynth) != 0); + desc.isInstrument = (effect != nullptr && (effect->flags & vstEffectFlagIsSynth) != 0); } bool initialiseEffect (double initialSampleRate, int initialBlockSize) { if (effect != nullptr) { - effect->resvd2 = (VstIntPtr) (pointer_sized_int) this; + effect->hostSpace2 = (pointer_sized_int) (pointer_sized_int) this; initialise (initialSampleRate, initialBlockSize); return true; } @@ -716,29 +712,29 @@ public: JUCE_VST_LOG ("Initialising VST: " + module->pluginName + " (" + getVersion() + ")"); initialised = true; - setPlayConfigDetails (effect->numInputs, effect->numOutputs, + setPlayConfigDetails (effect->numInputChannels, effect->numOutputChannels, initialSampleRate, initialBlockSize); - dispatch (effIdentify, 0, 0, 0, 0); + dispatch (plugInOpcodeIdentify, 0, 0, 0, 0); if (getSampleRate() > 0) - dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate()); + dispatch (plugInOpcodeSetSampleRate, 0, 0, 0, (float) getSampleRate()); if (getBlockSize() > 0) - dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); + dispatch (plugInOpcodeSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0); - dispatch (effOpen, 0, 0, 0, 0); + dispatch (plugInOpcodeOpen, 0, 0, 0, 0); - setPlayConfigDetails (effect->numInputs, effect->numOutputs, + setPlayConfigDetails (effect->numInputChannels, effect->numOutputChannels, getSampleRate(), getBlockSize()); if (getNumPrograms() > 1) setCurrentProgram (0); else - dispatch (effSetProgram, 0, 0, 0, 0); + dispatch (plugInOpcodeSetCurrentProgram, 0, 0, 0, 0); - for (int i = effect->numInputs; --i >= 0;) dispatch (effConnectInput, i, 1, 0, 0); - for (int i = effect->numOutputs; --i >= 0;) dispatch (effConnectOutput, i, 1, 0, 0); + for (int i = effect->numInputChannels; --i >= 0;) dispatch (plugInOpcodeConnectInput, i, 1, 0, 0); + for (int i = effect->numOutputChannels; --i >= 0;) dispatch (plugInOpcodeConnectOutput, i, 1, 0, 0); if (getVstCategory() != kPlugCategShell) // (workaround for Waves 5 plugins which crash during this call) updateStoredProgramNames(); @@ -749,7 +745,7 @@ public: usesCocoaNSView = ((unsigned int) pluginCanDo ("hasCockosViewAsConfig") & 0xffff0000ul) == 0xbeef0000ul; #endif - setLatencySamples (effect->initialDelay); + setLatencySamples (effect->latency); } void* getPlatformSpecificData() override { return effect; } @@ -760,7 +756,7 @@ public: { char buffer[512] = { 0 }; - if (dispatch (effGetProductString, 0, 0, buffer, 0) != 0) + if (dispatch (plugInOpcodeGetManufacturerProductName, 0, 0, buffer, 0) != 0) { String productName = String::createStringFromData (buffer, (int) sizeof (buffer)); @@ -774,7 +770,7 @@ public: int getUID() const { - int uid = effect != nullptr ? effect->uniqueID : 0; + int uid = effect != nullptr ? effect->plugInIdentifier : 0; if (uid == 0) uid = module->file.hashCode(); @@ -792,7 +788,7 @@ public: if (sampleRate <= 0) return 0.0; - VstIntPtr samples = dispatch (effGetTailSize, 0, 0, 0, 0); + pointer_sized_int samples = dispatch (plugInOpcodeGetTailSize, 0, 0, 0, 0); return samples / sampleRate; } @@ -800,21 +796,23 @@ public: bool producesMidi() const override { return pluginCanDo ("sendVstMidiEvent") > 0; } bool supportsMPE() const override { return pluginCanDo ("MPE") > 0; } - VstPlugCategory getVstCategory() const noexcept { return (VstPlugCategory) dispatch (effGetPlugCategory, 0, 0, 0, 0); } + VstPlugInCategory getVstCategory() const noexcept { return (VstPlugInCategory) dispatch (plugInOpcodeGetPlugInCategory, 0, 0, 0, 0); } - int pluginCanDo (const char* text) const { return (int) dispatch (effCanDo, 0, 0, (void*) text, 0); } + int pluginCanDo (const char* text) const { return (int) dispatch (plugInOpcodeCanPlugInDo, 0, 0, (void*) text, 0); } //============================================================================== void prepareToPlay (double rate, int samplesPerBlockExpected) override { - setPlayConfigDetails (effect->numInputs, effect->numOutputs, rate, samplesPerBlockExpected); + setPlayConfigDetails (effect->numInputChannels, effect->numOutputChannels, rate, samplesPerBlockExpected); - vstHostTime.tempo = 120.0; - vstHostTime.timeSigNumerator = 4; - vstHostTime.timeSigDenominator = 4; + vstHostTime.tempoBPM = 120.0; + vstHostTime.timeSignatureNumerator = 4; + vstHostTime.timeSignatureDenominator = 4; vstHostTime.sampleRate = rate; - vstHostTime.samplePos = 0; - vstHostTime.flags = kVstNanosValid | kVstAutomationWriting | kVstAutomationReading; + vstHostTime.samplePosition = 0; + vstHostTime.flags = vstTimingInfoFlagNanosecondsValid + | vstTimingInfoFlagAutomationWriteModeActive + | vstTimingInfoFlagAutomationReadModeActive; initialise (rate, samplesPerBlockExpected); @@ -829,22 +827,22 @@ public: incomingMidi.clear(); - dispatch (effSetSampleRate, 0, 0, 0, (float) rate); - dispatch (effSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); + dispatch (plugInOpcodeSetSampleRate, 0, 0, 0, (float) rate); + dispatch (plugInOpcodeSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0); if (supportsDoublePrecisionProcessing()) { - VstInt32 vstPrecision = isUsingDoublePrecision() ? kVstProcessPrecision64 - : kVstProcessPrecision32; + int32 vstPrecision = isUsingDoublePrecision() ? vstProcessingSampleTypeDouble + : vstProcessingSampleTypeFloat; // if you get an assertion here then your plug-in claims it supports double precision // but returns an error when we try to change the precision - VstIntPtr err = dispatch (effSetProcessPrecision, 0, (VstIntPtr) vstPrecision, 0, 0); + pointer_sized_int err = dispatch (plugInOpcodeSetSampleFloatType, 0, (pointer_sized_int) vstPrecision, 0, 0); jassert (err > 0); ignoreUnused (err); } - tempBuffer.setSize (jmax (1, effect->numOutputs), samplesPerBlockExpected); + tempBuffer.setSize (jmax (1, effect->numInputChannels), samplesPerBlockExpected); if (! isPowerOn) setPower (true); @@ -857,9 +855,9 @@ public: setParameter (0, old); } - dispatch (effStartProcess, 0, 0, 0, 0); + dispatch (plugInOpcodeStartProcess, 0, 0, 0, 0); - setLatencySamples (effect->initialDelay); + setLatencySamples (effect->latency); } } @@ -867,7 +865,7 @@ public: { if (initialised) { - dispatch (effStopProcess, 0, 0, 0, 0); + dispatch (plugInOpcodeStopProcess, 0, 0, 0, 0); setPower (false); } @@ -900,15 +898,15 @@ public: bool supportsDoublePrecisionProcessing() const override { - return ((effect->flags & effFlagsCanReplacing) != 0 - && (effect->flags & effFlagsCanDoubleReplacing) != 0); + return ((effect->flags & vstEffectFlagInplaceAudio) != 0 + && (effect->flags & vstEffectFlagInplaceDoubleAudio) != 0); } //============================================================================== #if JUCE_IOS bool hasEditor() const override { return false; } #else - bool hasEditor() const override { return effect != nullptr && (effect->flags & effFlagsHasEditor) != 0; } + bool hasEditor() const override { return effect != nullptr && (effect->flags & vstEffectFlagHasEditor) != 0; } #endif AudioProcessorEditor* createEditor() override; @@ -918,9 +916,9 @@ public: { if (isValidChannel (index, true)) { - VstPinProperties pinProps; - if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.label, sizeof (pinProps.label)); + VstPinInfo pinProps; + if (dispatch (plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0) + return String (pinProps.text, sizeof (pinProps.text)); } return String(); @@ -931,9 +929,9 @@ public: if (! isValidChannel (index, true)) return false; - VstPinProperties pinProps; - if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & kVstPinIsStereo) != 0; + VstPinInfo pinProps; + if (dispatch (plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0) + return (pinProps.flags & vstPinInfoFlagIsStereo) != 0; return true; } @@ -942,9 +940,9 @@ public: { if (isValidChannel (index, false)) { - VstPinProperties pinProps; - if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) - return String (pinProps.label, sizeof (pinProps.label)); + VstPinInfo pinProps; + if (dispatch (plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0) + return String (pinProps.text, sizeof (pinProps.text)); } return String(); @@ -955,9 +953,9 @@ public: if (! isValidChannel (index, false)) return false; - VstPinProperties pinProps; - if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0) - return (pinProps.flags & kVstPinIsStereo) != 0; + VstPinInfo pinProps; + if (dispatch (plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0) + return (pinProps.flags & vstPinInfoFlagIsStereo) != 0; return true; } @@ -969,14 +967,14 @@ public: } //============================================================================== - int getNumParameters() override { return effect != nullptr ? effect->numParams : 0; } + int getNumParameters() override { return effect != nullptr ? effect->numParameters : 0; } float getParameter (int index) override { - if (effect != nullptr && isPositiveAndBelow (index, (int) effect->numParams)) + if (effect != nullptr && isPositiveAndBelow (index, (int) effect->numParameters)) { const ScopedLock sl (lock); - return effect->getParameter (effect, index); + return effect->getParameterValueFunction (effect, index); } return 0.0f; @@ -984,25 +982,25 @@ public: void setParameter (int index, float newValue) override { - if (effect != nullptr && isPositiveAndBelow (index, (int) effect->numParams)) + if (effect != nullptr && isPositiveAndBelow (index, (int) effect->numParameters)) { const ScopedLock sl (lock); - if (effect->getParameter (effect, index) != newValue) - effect->setParameter (effect, index, newValue); + if (effect->getParameterValueFunction (effect, index) != newValue) + effect->setParameterValueFunction (effect, index, newValue); } } - const String getParameterName (int index) override { return getTextForOpcode (index, effGetParamName); } - const String getParameterText (int index) override { return getTextForOpcode (index, effGetParamDisplay); } - String getParameterLabel (int index) const override { return getTextForOpcode (index, effGetParamLabel); } + const String getParameterName (int index) override { return getTextForOpcode (index, plugInOpcodeGetParameterName); } + const String getParameterText (int index) override { return getTextForOpcode (index, plugInOpcodeGetParameterText); } + String getParameterLabel (int index) const override { return getTextForOpcode (index, plugInOpcodeGetParameterLabel); } bool isParameterAutomatable (int index) const override { if (effect != nullptr) { - jassert (index >= 0 && index < effect->numParams); - return dispatch (effCanBeAutomated, index, 0, 0, 0) != 0; + jassert (index >= 0 && index < effect->numParameters); + return dispatch (plugInOpcodeIsParameterAutomatable, index, 0, 0, 0) != 0; } return false; @@ -1012,12 +1010,12 @@ public: int getNumPrograms() override { return effect != nullptr ? jmax (0, effect->numPrograms) : 0; } // NB: some plugs return negative numbers from this function. - int getCurrentProgram() override { return (int) dispatch (effGetProgram, 0, 0, 0, 0); } + int getCurrentProgram() override { return (int) dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); } void setCurrentProgram (int newIndex) override { if (getNumPrograms() > 0 && newIndex != getCurrentProgram()) - dispatch (effSetProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0); + dispatch (plugInOpcodeSetCurrentProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0); } const String getProgramName (int index) override @@ -1031,7 +1029,7 @@ public: { char nm[264] = { 0 }; - if (dispatch (effGetProgramNameIndexed, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0) + if (dispatch (plugInOpcodeGetProgramName, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0) return String::fromUTF8 (nm).trim(); } } @@ -1044,7 +1042,7 @@ public: if (index >= 0 && index == getCurrentProgram()) { if (getNumPrograms() > 0 && newName != getCurrentProgramName()) - dispatch (effSetProgramName, 0, 0, (void*) newName.substring (0, 24).toRawUTF8(), 0.0f); + dispatch (plugInOpcodeSetCurrentProgramName, 0, 0, (void*) newName.substring (0, 24).toRawUTF8(), 0.0f); } else { @@ -1062,7 +1060,7 @@ public: //============================================================================== void timerCallback() override { - if (dispatch (effIdle, 0, 0, 0, 0) == 0) + if (dispatch (plugInOpcodeIdle, 0, 0, 0, 0) == 0) stopTimer(); } @@ -1072,30 +1070,30 @@ public: updateHostDisplay(); } - VstIntPtr handleCallback (VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) + pointer_sized_int handleCallback (int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) { switch (opcode) { - case audioMasterAutomate: sendParamChangeMessageToListeners (index, opt); break; - case audioMasterProcessEvents: handleMidiFromPlugin ((const VstEvents*) ptr); break; + case hostOpcodeParameterChanged: sendParamChangeMessageToListeners (index, opt); break; + case hostOpcodePreAudioProcessingEvents: handleMidiFromPlugin ((const VstEventBlock*) ptr); break; #if JUCE_MSVC #pragma warning (push) #pragma warning (disable: 4311) #endif - case audioMasterGetTime: return (VstIntPtr) &vstHostTime; + case hostOpcodeGetTimingInfo: return (pointer_sized_int) &vstHostTime; #if JUCE_MSVC #pragma warning (pop) #endif - case audioMasterIdle: + case hostOpcodeIdle: if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread()) { const IdleCallRecursionPreventer icrp; #if JUCE_MAC if (getActiveEditor() != nullptr) - dispatch (effEditIdle, 0, 0, 0, 0); + dispatch (plugInOpcodeEditorIdle, 0, 0, 0, 0); #endif Timer::callPendingTimersSynchronously(); @@ -1108,7 +1106,7 @@ public: } break; - case audioMasterSizeWindow: + case hostOpcodeWindowSize: if (AudioProcessorEditor* ed = getActiveEditor()) { #if JUCE_LINUX @@ -1119,53 +1117,54 @@ public: return 1; - case audioMasterUpdateDisplay: triggerAsyncUpdate(); break; - case audioMasterIOChanged: setLatencySamples (effect->initialDelay); break; - case audioMasterNeedIdle: startTimer (50); break; + case hostOpcodeUpdateView: triggerAsyncUpdate(); break; + case hostOpcodeIOModified: setLatencySamples (effect->latency); break; + case hostOpcodeNeedsIdle: startTimer (50); break; - case audioMasterGetSampleRate: return (VstIntPtr) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue); - case audioMasterGetBlockSize: return (VstIntPtr) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue); - case audioMasterWantMidi: wantsMidiMessages = true; break; - case audioMasterGetDirectory: return getVstDirectory(); + case hostOpcodeGetSampleRate: return (pointer_sized_int) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue); + case hostOpcodeGetBlockSize: return (pointer_sized_int) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue); + case hostOpcodePlugInWantsMidi: wantsMidiMessages = true; break; + case hostOpcodeGetDirectory: return getVstDirectory(); - case audioMasterTempoAt: + case hostOpcodeTempoAt: if (extraFunctions != nullptr) - return (VstIntPtr) extraFunctions->getTempoAt ((int64) value); + return (pointer_sized_int) extraFunctions->getTempoAt ((int64) value); break; - case audioMasterGetAutomationState: + case hostOpcodeGetAutomationState: if (extraFunctions != nullptr) - return (VstIntPtr) extraFunctions->getAutomationState(); + return (pointer_sized_int) extraFunctions->getAutomationState(); break; - case audioMasterPinConnected: + case hostOpcodePinConnected: return isValidChannel (index, value == 0) ? 0 : 1; // (yes, 0 = true) - case audioMasterGetCurrentProcessLevel: + case hostOpcodeGetCurrentAudioProcessingLevel: return isNonRealtime() ? 4 : 0; - // none of these are handled (yet).. - case audioMasterBeginEdit: - case audioMasterEndEdit: - case audioMasterSetTime: - case audioMasterGetParameterQuantization: - case audioMasterGetInputLatency: - case audioMasterGetOutputLatency: - case audioMasterGetPreviousPlug: - case audioMasterGetNextPlug: - case audioMasterWillReplaceOrAccumulate: - case audioMasterOfflineStart: - case audioMasterOfflineRead: - case audioMasterOfflineWrite: - case audioMasterOfflineGetCurrentPass: - case audioMasterOfflineGetCurrentMetaPass: - case audioMasterVendorSpecific: - case audioMasterSetIcon: - case audioMasterGetLanguage: - case audioMasterOpenWindow: - case audioMasterCloseWindow: + // none of these are handled (yet)... + case hostOpcodeSetTime: + case hostOpcodeGetParameterInterval: + case hostOpcodeGetInputLatency: + case hostOpcodeGetOutputLatency: + case hostOpcodeGetPreviousPlugIn: + case hostOpcodeGetNextPlugIn: + case hostOpcodeWillReplace: + case hostOpcodeOfflineStart: + case hostOpcodeOfflineReadSource: + case hostOpcodeOfflineWrite: + case hostOpcodeOfflineGetCurrentPass: + case hostOpcodeOfflineGetCurrentMetaPass: + case hostOpcodeGetOutputSpeakerConfiguration: + case hostOpcodeManufacturerSpecific: + case hostOpcodeSetIcon: + case hostOpcodeGetLanguage: + case hostOpcodeOpenEditorWindow: + case hostOpcodeCloseEditorWindow: + case hostOpcodeParameterChangeGestureBegin: + case hostOpcodeParameterChangeGestureEnd: break; default: @@ -1176,11 +1175,11 @@ public: } // handles non plugin-specific callbacks.. - static VstIntPtr handleGeneralCallback (VstInt32 opcode, VstInt32 /*index*/, VstIntPtr /*value*/, void *ptr, float /*opt*/) + static pointer_sized_int handleGeneralCallback (int32 opcode, int32 /*index*/, pointer_sized_int /*value*/, void *ptr, float /*opt*/) { switch (opcode) { - case audioMasterCanDo: + case hostOpcodeCanHostDo: { static const char* canDos[] = { "supplyIdle", "sendVstEvents", @@ -1199,27 +1198,27 @@ public: return 0; } - case audioMasterVersion: return 2400; - case audioMasterCurrentId: return shellUIDToCreate; - case audioMasterGetNumAutomatableParameters: return 0; - case audioMasterGetAutomationState: return 1; - case audioMasterGetVendorVersion: return 0x0101; + case hostOpcodeVstVersion: return 2400; + case hostOpcodeCurrentId: return shellUIDToCreate; + case hostOpcodeGetNumberOfAutomatableParameters: return 0; + case hostOpcodeGetAutomationState: return 1; + case hostOpcodeGetManufacturerVersion: return 0x0101; - case audioMasterGetVendorString: - case audioMasterGetProductString: + case hostOpcodeGetManufacturerName: + case hostOpcodeGetProductName: { String hostName ("Juce VST Host"); if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance()) hostName = app->getApplicationName(); - hostName.copyToUTF8 ((char*) ptr, (size_t) jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1); + hostName.copyToUTF8 ((char*) ptr, (size_t) jmin (vstMaxManufacturerStringLength, vstMaxPlugInNameStringLength) - 1); break; } - case audioMasterGetSampleRate: return (VstIntPtr) defaultVSTSampleRateValue; - case audioMasterGetBlockSize: return (VstIntPtr) defaultVSTBlockSizeValue; - case audioMasterSetOutputSampleRate: return 0; + case hostOpcodeGetSampleRate: return (pointer_sized_int) defaultVSTSampleRateValue; + case hostOpcodeGetBlockSize: return (pointer_sized_int) defaultVSTBlockSizeValue; + case hostOpcodeSetOutputSampleRate: return 0; default: DBG ("*** Unhandled VST Callback: " + String ((int) opcode)); @@ -1230,9 +1229,9 @@ public: } //============================================================================== - VstIntPtr dispatch (const int opcode, const int index, const VstIntPtr value, void* const ptr, float opt) const + pointer_sized_int dispatch (const int opcode, const int index, const pointer_sized_int value, void* const ptr, float opt) const { - VstIntPtr result = 0; + pointer_sized_int result = 0; if (effect != nullptr) { @@ -1248,7 +1247,7 @@ public: UseResFile (module->resFileId); #endif - result = effect->dispatcher (effect, opcode, index, value, ptr, opt); + result = effect->dispatchFunction (effect, opcode, index, value, ptr, opt); #if JUCE_MAC const ResFileRefNum newResFile = CurResFile(); @@ -1378,7 +1377,7 @@ public: set->fxID = fxbSwap (getUID()); set->fxVersion = fxbSwap (getVersionNumber()); set->numPrograms = fxbSwap (numPrograms); - set->chunkSize = fxbSwap ((VstInt32) chunk.getSize()); + set->chunkSize = fxbSwap ((int32) chunk.getSize()); chunk.copyTo (set->chunk, 0, chunk.getSize()); } @@ -1395,7 +1394,7 @@ public: set->fxID = fxbSwap (getUID()); set->fxVersion = fxbSwap (getVersionNumber()); set->numPrograms = fxbSwap (numPrograms); - set->chunkSize = fxbSwap ((VstInt32) chunk.getSize()); + set->chunkSize = fxbSwap ((int32) chunk.getSize()); getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1); chunk.copyTo (set->chunk, 0, chunk.getSize()); @@ -1450,14 +1449,14 @@ public: return true; } - bool usesChunks() const noexcept { return effect != nullptr && (effect->flags & effFlagsProgramChunks) != 0; } + bool usesChunks() const noexcept { return effect != nullptr && (effect->flags & vstEffectFlagDataInChunks) != 0; } bool getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const { if (usesChunks()) { void* data = nullptr; - const size_t bytes = (size_t) dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); + const size_t bytes = (size_t) dispatch (plugInOpcodeGetData, isPreset ? 1 : 0, 0, &data, 0.0f); if (data != nullptr && bytes <= (size_t) maxSizeMB * 1024 * 1024) { @@ -1475,7 +1474,7 @@ public: { if (size > 0 && usesChunks()) { - dispatch (effSetChunk, isPreset ? 1 : 0, size, (void*) data, 0.0f); + dispatch (plugInOpcodeSetData, isPreset ? 1 : 0, size, (void*) data, 0.0f); if (! isPreset) updateStoredProgramNames(); @@ -1486,7 +1485,7 @@ public: return false; } - AEffect* effect; + VstEffectInterface* effect; ModuleHandle::Ptr module; ScopedPointer extraFunctions; @@ -1501,7 +1500,7 @@ private: CriticalSection midiInLock; MidiBuffer incomingMidi; VSTMidiEventList midiEventsToSend; - VstTimeInfo vstHostTime; + VstTimingInformation vstHostTime; //============================================================================== template @@ -1518,22 +1517,26 @@ private: if (currentPlayHead->getCurrentPosition (position)) { - vstHostTime.samplePos = (double) position.timeInSamples; - vstHostTime.tempo = position.bpm; - vstHostTime.timeSigNumerator = position.timeSigNumerator; - vstHostTime.timeSigDenominator = position.timeSigDenominator; - vstHostTime.ppqPos = position.ppqPosition; - vstHostTime.barStartPos = position.ppqPositionOfLastBarStart; - vstHostTime.flags |= kVstTempoValid | kVstTimeSigValid | kVstPpqPosValid | kVstBarsValid; + vstHostTime.samplePosition = (double) position.timeInSamples; + vstHostTime.tempoBPM = position.bpm; + vstHostTime.timeSignatureNumerator = position.timeSigNumerator; + vstHostTime.timeSignatureDenominator = position.timeSigDenominator; + vstHostTime.musicalPosition = position.ppqPosition; + vstHostTime.lastBarPosition = position.ppqPositionOfLastBarStart; + vstHostTime.flags |= vstTimingInfoFlagTempoValid + | vstTimingInfoFlagTimeSignatureValid + | vstTimingInfoFlagMusicalPositionValid + | vstTimingInfoFlagLastBarPositionValid; - VstInt32 newTransportFlags = 0; - if (position.isPlaying) newTransportFlags |= kVstTransportPlaying; - if (position.isRecording) newTransportFlags |= kVstTransportRecording; + int32 newTransportFlags = 0; + if (position.isPlaying) newTransportFlags |= vstTimingInfoFlagCurrentlyPlaying; + if (position.isRecording) newTransportFlags |= vstTimingInfoFlagCurrentlyRecording; - if (newTransportFlags != (vstHostTime.flags & (kVstTransportPlaying | kVstTransportRecording))) - vstHostTime.flags = (vstHostTime.flags & ~(kVstTransportPlaying | kVstTransportRecording)) | newTransportFlags | kVstTransportChanged; + if (newTransportFlags != (vstHostTime.flags & (vstTimingInfoFlagCurrentlyPlaying + | vstTimingInfoFlagCurrentlyRecording))) + vstHostTime.flags = (vstHostTime.flags & ~(vstTimingInfoFlagCurrentlyPlaying | vstTimingInfoFlagCurrentlyRecording)) | newTransportFlags | vstTimingInfoFlagTransportChanged; else - vstHostTime.flags &= ~kVstTransportChanged; + vstHostTime.flags &= ~vstTimingInfoFlagTransportChanged; switch (position.frameRate) { @@ -1548,18 +1551,18 @@ private: if (position.isLooping) { - vstHostTime.cycleStartPos = position.ppqLoopStart; - vstHostTime.cycleEndPos = position.ppqLoopEnd; - vstHostTime.flags |= (kVstCyclePosValid | kVstTransportCycleActive); + vstHostTime.loopStartPosition = position.ppqLoopStart; + vstHostTime.loopEndPosition = position.ppqLoopEnd; + vstHostTime.flags |= (vstTimingInfoFlagLoopPositionValid | vstTimingInfoFlagLoopActive); } else { - vstHostTime.flags &= ~(kVstCyclePosValid | kVstTransportCycleActive); + vstHostTime.flags &= ~(vstTimingInfoFlagLoopPositionValid | vstTimingInfoFlagLoopActive); } } } - vstHostTime.nanoSeconds = getVSTHostTimeNanoseconds(); + vstHostTime.systemTimeNanoseconds = getVSTHostTimeNanoseconds(); if (wantsMidiMessages) { @@ -1576,7 +1579,7 @@ private: jlimit (0, numSamples - 1, samplePosition)); } - effect->dispatcher (effect, effProcessEvents, 0, 0, midiEventsToSend.events, 0); + effect->dispatchFunction (effect, plugInOpcodePreAudioProcessingEvents, 0, 0, midiEventsToSend.events, 0); } _clearfp(); @@ -1600,35 +1603,35 @@ private: } //============================================================================== - inline void invokeProcessFunction (AudioBuffer& buffer, VstInt32 sampleFrames) + inline void invokeProcessFunction (AudioBuffer& buffer, int32 sampleFrames) { - if ((effect->flags & effFlagsCanReplacing) != 0) + if ((effect->flags & vstEffectFlagInplaceAudio) != 0) { - effect->processReplacing (effect, buffer.getArrayOfWritePointers(), buffer.getArrayOfWritePointers(), sampleFrames); + effect->processAudioInplaceFunction (effect, buffer.getArrayOfWritePointers(), buffer.getArrayOfWritePointers(), sampleFrames); } else { - tempBuffer.setSize (effect->numOutputs, sampleFrames); + tempBuffer.setSize (effect->numOutputChannels, sampleFrames); tempBuffer.clear(); - effect->process (effect, buffer.getArrayOfWritePointers(), tempBuffer.getArrayOfWritePointers(), sampleFrames); + effect->processAudioFunction (effect, buffer.getArrayOfWritePointers(), tempBuffer.getArrayOfWritePointers(), sampleFrames); - for (int i = effect->numOutputs; --i >= 0;) + for (int i = effect->numOutputChannels; --i >= 0;) buffer.copyFrom (i, 0, tempBuffer.getReadPointer (i), sampleFrames); } } - inline void invokeProcessFunction (AudioBuffer& buffer, VstInt32 sampleFrames) + inline void invokeProcessFunction (AudioBuffer& buffer, int32 sampleFrames) { - effect->processDoubleReplacing (effect, buffer.getArrayOfWritePointers(), buffer.getArrayOfWritePointers(), sampleFrames); + effect->processDoubleAudioInplaceFunction (effect, buffer.getArrayOfWritePointers(), buffer.getArrayOfWritePointers(), sampleFrames); } //============================================================================== void setHostTimeFrameRate (long frameRateIndex, double frameRate, double currentTime) noexcept { - vstHostTime.flags |= kVstSmpteValid; - vstHostTime.smpteFrameRate = (VstInt32) frameRateIndex; - vstHostTime.smpteOffset = (VstInt32) (currentTime * 80.0 * frameRate + 0.5); + vstHostTime.flags |= vstTimingInfoFlagSmpteValid; + vstHostTime.smpteRate = (int32) frameRateIndex; + vstHostTime.smpteOffset = (int32) (currentTime * 80.0 * frameRate + 0.5); } bool restoreProgramSettings (const fxProgram* const prog) @@ -1647,12 +1650,12 @@ private: return false; } - String getTextForOpcode (const int index, const AEffectOpcodes opcode) const + String getTextForOpcode (const int index, const VstHostToPlugInOpcodes opcode) const { if (effect == nullptr) return String(); - jassert (index >= 0 && index < effect->numParams); + jassert (index >= 0 && index < effect->numParameters); char nm[256] = { 0 }; dispatch (opcode, index, 0, nm, 0); return String::createStringFromData (nm, (int) sizeof (nm)).trim(); @@ -1666,7 +1669,7 @@ private: { { char nm[256] = { 0 }; - dispatch (effGetProgramName, 0, 0, nm, 0); + dispatch (plugInOpcodeGetCurrentProgramName, 0, 0, nm, 0); progName = String::createStringFromData (nm, (int) sizeof (nm)).trim(); } @@ -1709,7 +1712,7 @@ private: char nm[256] = { 0 }; // only do this if the plugin can't use indexed names.. - if (dispatch (effGetProgramNameIndexed, 0, -1, nm, 0) == 0) + if (dispatch (plugInOpcodeGetProgramName, 0, -1, nm, 0) == 0) { const int oldProgram = getCurrentProgram(); MemoryBlock oldSettings; @@ -1727,7 +1730,7 @@ private: } } - void handleMidiFromPlugin (const VstEvents* const events) + void handleMidiFromPlugin (const VstEventBlock* const events) { if (events != nullptr) { @@ -1758,21 +1761,21 @@ private: setParameter (i, p[i]); } - VstIntPtr getVstDirectory() const + pointer_sized_int getVstDirectory() const { #if JUCE_MAC - return (VstIntPtr) (void*) &module->parentDirFSSpec; + return (pointer_sized_int) (void*) &module->parentDirFSSpec; #else - return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toRawUTF8(); + return (pointer_sized_int) (pointer_sized_uint) module->fullParentDirectoryPathName.toRawUTF8(); #endif } //============================================================================== - int getVersionNumber() const noexcept { return effect != nullptr ? effect->version : 0; } + int getVersionNumber() const noexcept { return effect != nullptr ? effect->plugInVersion : 0; } String getVersion() const { - unsigned int v = (unsigned int) dispatch (effGetVendorVersion, 0, 0, 0, 0); + unsigned int v = (unsigned int) dispatch (plugInOpcodeGetManufacturerVersion, 0, 0, 0, 0); String s; @@ -1833,7 +1836,7 @@ private: void setPower (const bool on) { - dispatch (effMainsChanged, 0, on ? 1 : 0, 0, 0); + dispatch (plugInOpcodeResumeSuspend, 0, on ? 1 : 0, 0, 0); isPowerOn = on; } @@ -2041,7 +2044,7 @@ public: if (! reentrantGuard) { reentrantGuard = true; - plugin.dispatch (effEditIdle, 0, 0, 0, 0); + plugin.dispatch (plugInOpcodeEditorIdle, 0, 0, 0, 0); reentrantGuard = false; } @@ -2085,7 +2088,7 @@ public: activeVSTWindows.add (this); #if JUCE_MAC - dispatch (effEditTop, 0, 0, 0, 0); + dispatch (plugInOpcodeeffEditorTop, 0, 0, 0, 0); #endif } @@ -2128,24 +2131,24 @@ private: isOpen = true; - ERect* rect = nullptr; - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effEditOpen, 0, 0, parentWindow, 0); + VstEditorBounds* rect = nullptr; + dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); + dispatch (plugInOpcodeOpenEditor, 0, 0, parentWindow, 0); // do this before and after like in the steinberg example - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code + dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); + dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); // also in steinberg code // Install keyboard hooks - pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0); + pluginWantsKeys = (dispatch (plugInOpcodeKeyboardFocusRequired, 0, 0, 0, 0) == 0); // double-check it's not too tiny int w = 250, h = 150; if (rect != nullptr) { - w = rect->right - rect->left; - h = rect->bottom - rect->top; + w = rect->rightmost - rect->leftmost; + h = rect->lower - rect->upper; if (w == 0 || h == 0) { @@ -2172,16 +2175,16 @@ private: JUCE_VST_LOG ("Opening VST UI: " + plugin.getName()); isOpen = true; - ERect* rect = nullptr; - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effEditOpen, 0, 0, getWindowHandle(), 0); + VstEditorBounds* rect = nullptr; + dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); + dispatch (plugInOpcodeOpenEditor, 0, 0, getWindowHandle(), 0); // do this before and after like in the steinberg example - dispatch (effEditGetRect, 0, 0, &rect, 0); - dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code + dispatch (plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); + dispatch (plugInOpcodeGetCurrentProgram, 0, 0, 0, 0); // also in steinberg code // Install keyboard hooks - pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0); + pluginWantsKeys = (dispatch (plugInOpcodeKeyboardFocusRequired, 0, 0, 0, 0) == 0); #if JUCE_WINDOWS originalWndProc = 0; @@ -2212,8 +2215,8 @@ private: if (rect != nullptr) { - const int rw = rect->right - rect->left; - const int rh = rect->bottom - rect->top; + const int rw = rect->rightmost - rect->leftmost; + const int rh = rect->lower - rect->upper; if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && rw != w && rh != h) || ((w == 0 && rw > 0) || (h == 0 && rh > 0))) @@ -2245,8 +2248,8 @@ private: if (rect != nullptr) { - w = rect->right - rect->left; - h = rect->bottom - rect->top; + w = rect->rightmost - rect->leftmost; + h = rect->lower - rect->upper; if (w == 0 || h == 0) { @@ -2285,7 +2288,7 @@ private: JUCE_VST_LOG ("Closing VST UI: " + plugin.getName()); isOpen = false; - dispatch (effEditClose, 0, 0, 0, 0); + dispatch (plugInOpcodeCloseEditor, 0, 0, 0, 0); stopTimer(); #if JUCE_WINDOWS @@ -2305,7 +2308,7 @@ private: } //============================================================================== - VstIntPtr dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) + pointer_sized_int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) { return plugin.dispatch (opcode, index, value, ptr, opt); } @@ -2600,10 +2603,10 @@ AudioProcessorEditor* VSTPluginInstance::createEditor() //============================================================================== // entry point for all callbacks from the plugin -static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) +static pointer_sized_int VSTINTERFACECALL audioMaster (VstEffectInterface* effect, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) { if (effect != nullptr) - if (VSTPluginInstance* instance = (VSTPluginInstance*) (effect->resvd2)) + if (VSTPluginInstance* instance = (VSTPluginInstance*) (effect->hostSpace2)) return instance->handleCallback (opcode, index, value, ptr, opt); return VSTPluginInstance::handleGeneralCallback (opcode, index, value, ptr, opt); @@ -2654,7 +2657,7 @@ void VSTPluginFormat::findAllTypesForFile (OwnedArray& result // Normal plugin... results.add (new PluginDescription (desc)); - instance->dispatch (effOpen, 0, 0, 0, 0); + instance->dispatch (plugInOpcodeOpen, 0, 0, 0, 0); } else { @@ -2662,7 +2665,7 @@ void VSTPluginFormat::findAllTypesForFile (OwnedArray& result for (;;) { char shellEffectName [256] = { 0 }; - const int uid = (int) instance->dispatch (effShellGetNextPlugin, 0, 0, shellEffectName, 0); + const int uid = (int) instance->dispatch (plugInOpcodeNextPlugInUniqueID, 0, 0, shellEffectName, 0); if (uid == 0) break; @@ -2888,7 +2891,7 @@ void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunct vst->extraFunctions = f; } -VSTPluginFormat::VstIntPtr JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt) +pointer_sized_int JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt) { if (VSTPluginInstance* vst = dynamic_cast (plugin)) return vst->dispatch (opcode, index, value, ptr, opt); diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h index 02f4a57f57..5bfa58c682 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.h @@ -82,14 +82,8 @@ public: static void setExtraFunctions (AudioPluginInstance* plugin, ExtraFunctions* functions); //============================================================================== - #if JUCE_64BIT - typedef int64 VstIntPtr; - #else - typedef int32 VstIntPtr; - #endif - /** This simply calls directly to the VST's AEffect::dispatcher() function. */ - static VstIntPtr JUCE_CALLTYPE dispatcher (AudioPluginInstance*, int32, int32, VstIntPtr, void*, float); + static pointer_sized_int JUCE_CALLTYPE dispatcher (AudioPluginInstance*, int32, int32, pointer_sized_int, void*, float); //============================================================================== String getName() const override { return "VST"; } diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index 3f332da8bf..bd62b9acf6 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -57,8 +57,7 @@ //============================================================================== /** Config: JUCE_PLUGINHOST_VST - Enables the VST audio plugin hosting classes. This requires the Steinberg VST SDK to be - installed on your machine. + Enables the VST audio plugin hosting classes. @see VSTPluginFormat, VST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU, JUCE_PLUGINHOST_VST3 */