26#if JUCE_PLUGINHOST_VST
29#undef PRAGMA_ALIGN_SUPPORTED
32#if ! JUCE_MINGW && ! JUCE_MSVC
36JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wzero-as-null-pointer-constant")
37JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
39#define VST_FORCE_DEPRECATED 0
40#define JUCE_VSTINTERFACE_H_INCLUDED 1
51#include <pluginterfaces/vst2.x/aeffect.h>
52#include <pluginterfaces/vst2.x/aeffectx.h>
55#include "juce_VSTCommon.h"
57JUCE_END_IGNORE_WARNINGS_GCC_LIKE
58JUCE_END_IGNORE_WARNINGS_MSVC
60JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
61JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4355)
63#include "juce_VSTMidiEventList.h"
67 #define WM_APPCOMMAND 0x0319
70 static void _fpreset() {}
71 static void _clearfp() {}
74#ifndef JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
75 #define JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
78#ifndef JUCE_VST_WRAPPER_INVOKE_MAIN
79#define JUCE_VST_WRAPPER_INVOKE_MAIN effect = module->moduleMain ((Vst2::audioMasterCallback) &audioMaster);
82#ifndef JUCE_VST_FALLBACK_HOST_NAME
83 #define JUCE_VST_FALLBACK_HOST_NAME "Juce VST Host"
93 const int fxbVersionNum = 1;
118 fxProgram programs[1];
150 static bool compareMagic (
int32 magic,
const char* name)
noexcept
159 static float fxbSwapFloat (
const float x)
noexcept
161 #ifdef JUCE_LITTLE_ENDIAN
162 union {
uint32 asInt;
float asFloat; } n;
175 static double getVSTHostTimeNanoseconds() noexcept
178 return timeGetTime() * 1000000.0;
179 #elif JUCE_LINUX || JUCE_BSD || JUCE_IOS || JUCE_ANDROID
182 return (
double) micro.tv_usec * 1000.0;
185 Microseconds (µ);
186 return micro.lo * 1000.0;
190 static int shellUIDToCreate = 0;
191 static int insideVSTCallback = 0;
193 struct IdleCallRecursionPreventer
195 IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
201 ~IdleCallRecursionPreventer()
207 const bool isMessageThread;
212 static bool makeFSRefFromPath (FSRef* destFSRef,
const String& path)
214 return FSPathMakeRef (
reinterpret_cast<const UInt8*
> (path.toRawUTF8()), destFSRef,
nullptr) == noErr;
220typedef Vst2::AEffect* (VSTCALLBACK *MainCall) (Vst2::audioMasterCallback);
226 #define VST_LOGGING 1
230 #define JUCE_VST_LOG(a) Logger::writeToLog(a);
232 #define JUCE_VST_LOG(a)
236#if JUCE_LINUX || JUCE_BSD
240 using EventProcPtr = void (*)(XEvent*);
242 Window getChildWindow (Window windowToCheck)
244 Window rootWindow, parentWindow;
245 Window* childWindows;
246 unsigned int numChildren = 0;
248 X11Symbols::getInstance()->xQueryTree (XWindowSystem::getInstance()->getDisplay(),
249 windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
252 return childWindows [0];
266 if (xml.
hasTagName (
"VSTParametersStructure"))
267 return new VSTXMLInfo (xml);
269 if (
const auto* x = xml.
getChildByName (
"VSTParametersStructure"))
270 return new VSTXMLInfo (*x);
282 Group* parent =
nullptr;
285 struct Param final :
public Base
295 struct Group final :
public Base
314 high = str.fromLastOccurrenceOf (
",",
false,
false).getFloatValue();
317 bool contains (
float f)
const noexcept
319 return (inclusiveLow ? (f >= low) : (f > low))
320 && (inclusiveHigh ? (f <= high) : (f < high));
326 bool inclusiveLow =
false;
327 bool inclusiveHigh =
false;
348 const Param* getParamForID (
const int paramID,
const Group*
const grp)
const
350 for (
auto item : (grp != nullptr ? grp->paramTree : paramTree))
352 if (
auto param =
dynamic_cast<const Param*
> (item))
353 if (param->paramID == paramID)
356 if (
auto group =
dynamic_cast<const Group*
> (item))
357 if (
auto res = getParamForID (paramID, group))
364 const ValueType* getValueType (
const juce::String& name)
const
366 for (
auto v : valueTypes)
377 ValueType switchValueType;
382 switchValueType.entries.add (
new Entry ({
TRANS (
"Off"), Range (
"[0, 0.5[") }));
383 switchValueType.entries.add (
new Entry ({
TRANS (
"On"), Range (
"[0.5, 1]") }));
385 for (
auto* item : xml.getChildIterator())
387 if (item->hasTagName (
"Param")) parseParam (*item,
nullptr,
nullptr);
388 else if (item->hasTagName (
"ValueType")) parseValueType (*item);
389 else if (item->hasTagName (
"Template")) parseTemplate (*item);
390 else if (item->hasTagName (
"Group")) parseGroup (*item,
nullptr);
394 void parseParam (
const juce::XmlElement& item, Group* group, Template* temp)
396 auto param =
new Param();
410 param->shortNames.trim();
411 param->shortNames.removeEmptyStrings();
413 if (group !=
nullptr)
415 group->paramTree.add (param);
416 param->parent = group;
418 else if (temp !=
nullptr)
420 temp->params.add (param);
424 paramTree.
add (param);
430 auto vt =
new ValueType();
439 for (
auto* entryXml : item.getChildWithTagNameIterator (
"Entry"))
441 auto entry =
new Entry();
442 entry->name = entryXml->getStringAttribute (
"name");
444 if (entryXml->hasAttribute (
"value"))
446 entry->range.set (entryXml->getStringAttribute (
"value"));
450 entry->range.low = (
float) curEntry / (
float) numEntries;
451 entry->range.high = (
float) (curEntry + 1) / (
float) numEntries;
453 entry->range.inclusiveLow =
true;
454 entry->range.inclusiveHigh = (curEntry == numEntries - 1);
457 vt->entries.add (entry);
464 auto temp =
new Template();
465 templates.
add (temp);
468 for (
auto* param : item.getChildIterator())
469 parseParam (*param, nullptr, temp);
474 auto group =
new Group();
478 parentGroup->paramTree.add (group);
479 group->parent = parentGroup;
483 paramTree.
add (group);
494 for (
auto temp : templates)
498 for (
int i = 0; i < temp->params.size(); ++i)
500 auto param =
new Param();
501 group->paramTree.add (param);
503 param->parent = group;
504 param->paramID = evaluate (temp->params[i]->expr, variables);
505 param->defaultValue = temp->params[i]->defaultValue;
506 param->label = temp->params[i]->label;
507 param->name = temp->params[i]->name;
508 param->numberOfStates = temp->params[i]->numberOfStates;
509 param->shortNames = temp->params[i]->shortNames;
510 param->type = temp->params[i]->type;
517 for (
auto* subItem : item.getChildIterator())
519 if (subItem->hasTagName (
"Param")) parseParam (*subItem, group,
nullptr);
520 else if (subItem->hasTagName (
"Group")) parseGroup (*subItem, group);
530 for (
auto& v : variables)
532 if (v.contains (
"="))
534 names.
add (v.upToFirstOccurrenceOf (
"=",
false,
false));
535 vals.
add (v.fromFirstOccurrenceOf (
"=",
false,
false).getIntValue());
539 for (
int i = 0; i < names.
size(); ++i)
561 for (
const auto& s : tokens)
585struct ModuleHandle final :
public ReferenceCountedObject
588 MainCall moduleMain, customMain = {};
592 using Ptr = ReferenceCountedObjectPtr<ModuleHandle>;
594 static Array<ModuleHandle*>& getActiveModules()
596 static Array<ModuleHandle*> activeModules;
597 return activeModules;
601 static Ptr findOrCreateModule (
const File& file)
603 for (
auto* module : getActiveModules())
604 if (module->file == file)
607 const IdleCallRecursionPreventer icrp;
608 shellUIDToCreate = 0;
611 JUCE_VST_LOG (
"Attempting to load VST: " + file.getFullPathName());
613 Ptr m =
new ModuleHandle (file,
nullptr);
625 ModuleHandle (
const File& f, MainCall customMainCall)
626 : file (f), moduleMain (customMainCall)
628 getActiveModules().add (
this);
630 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_IOS || JUCE_ANDROID
631 fullParentDirectoryPathName = f.getParentDirectory().getFullPathName();
634 makeFSRefFromPath (&ref, f.getParentDirectory().getFullPathName());
635 FSGetCatalogInfo (&ref, kFSCatInfoNone,
nullptr,
nullptr, &parentDirFSSpec,
nullptr);
641 getActiveModules().removeFirstMatchingValue (
this);
647 String fullParentDirectoryPathName;
650 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
651 DynamicLibrary
module;
655 if (moduleMain !=
nullptr)
658 pluginName = file.getFileNameWithoutExtension();
660 module.open (file.getFullPathName());
662 moduleMain = (MainCall) module.getFunction (
"VSTPluginMain");
664 if (moduleMain ==
nullptr)
665 moduleMain = (MainCall) module.getFunction (
"main");
667 JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
669 if (moduleMain !=
nullptr)
671 vstXml =
parseXML (file.withFileExtension (
"vstxml"));
674 if (vstXml ==
nullptr)
675 vstXml =
parseXML (getDLLResource (file,
"VSTXML", 1));
679 return moduleMain !=
nullptr;
689 void closeEffect (Vst2::AEffect* eff)
691 eff->dispatcher (eff, Vst2::effClose, 0, 0,
nullptr, 0);
695 static String getDLLResource (
const File& dllFile,
const String& type,
int resID)
697 DynamicLibrary dll (dllFile.getFullPathName());
698 auto dllModule = (HMODULE) dll.getNativeHandle();
700 if (dllModule != INVALID_HANDLE_VALUE)
702 if (
auto res = FindResource (dllModule, MAKEINTRESOURCE (resID), type.toWideCharPointer()))
704 if (
auto hGlob = LoadResource (dllModule, res))
706 auto*
data =
static_cast<const char*
> (LockResource (hGlob));
707 return String::fromUTF8 (data, (
int) SizeofResource (dllModule, res));
716 Handle resHandle = {};
717 CFUniquePtr<CFBundleRef> bundleRef;
720 CFBundleRefNum resFileId = {};
721 FSSpec parentDirFSSpec;
726 if (moduleMain !=
nullptr)
731 if (file.hasFileExtension (
".vst"))
733 auto* utf8 = file.getFullPathName().toRawUTF8();
735 if (
auto url = CFUniquePtr<CFURLRef> (CFURLCreateFromFileSystemRepresentation (
nullptr, (
const UInt8*) utf8,
736 (CFIndex) strlen (utf8), file.isDirectory())))
738 bundleRef.reset (CFBundleCreate (kCFAllocatorDefault, url.get()));
740 if (bundleRef !=
nullptr)
742 if (CFBundleLoadExecutable (bundleRef.get()))
744 moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef.get(), CFSTR (
"main_macho"));
746 if (moduleMain ==
nullptr)
747 moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef.get(), CFSTR (
"VSTPluginMain"));
749 JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
751 if (moduleMain !=
nullptr)
753 if (CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef.get(), CFSTR (
"CFBundleName")))
755 if (CFGetTypeID (name) == CFStringGetTypeID())
759 if (CFStringGetCString ((CFStringRef) name, buffer,
sizeof (buffer), CFStringGetSystemEncoding()))
764 if (pluginName.isEmpty())
765 pluginName = file.getFileNameWithoutExtension();
768 resFileId = CFBundleOpenBundleResourceMap (bundleRef.get());
773 auto vstXmlFiles = file
775 .getChildFile (
"Contents")
776 .getChildFile (
"Resources")
778 .findChildFiles (File::findFiles,
false,
"*.vstxml");
780 if (! vstXmlFiles.isEmpty())
781 vstXml =
parseXML (vstXmlFiles.getReference (0));
787 CFBundleUnloadExecutable (bundleRef.get());
799 if (bundleRef !=
nullptr)
802 CFBundleCloseBundleResourceMap (bundleRef.get(), resFileId);
805 if (CFGetRetainCount (bundleRef.get()) == 1)
806 CFBundleUnloadExecutable (bundleRef.get());
808 if (CFGetRetainCount (bundleRef.get()) > 0)
813 void closeEffect (Vst2::AEffect* eff)
815 eff->dispatcher (eff, Vst2::effClose, 0, 0,
nullptr, 0);
824static const int defaultVSTSampleRateValue = 44100;
825static const int defaultVSTBlockSizeValue = 512;
827JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
829class TempChannelPointers
832 template <
typename T>
833 auto getArrayOfModifiableWritePointers (AudioBuffer<T>& buffer)
835 auto& pointers = getPointers (Tag<T>{});
837 jassert (buffer.getNumChannels() <=
static_cast<int> (pointers.capacity()));
838 pointers.resize (
jmax (pointers.size(), (
size_t) buffer.getNumChannels()));
840 std::copy (buffer.getArrayOfWritePointers(),
841 buffer.getArrayOfWritePointers() + buffer.getNumChannels(),
844 return pointers.data();
848 template <
typename>
struct Tag {};
850 auto& getPointers (Tag<float>) {
return floatPointers; }
851 auto& getPointers (Tag<double>) {
return doublePointers; }
858struct VSTPluginInstance final :
public AudioPluginInstance,
862 struct VSTParameter final :
public Parameter
864 VSTParameter (VSTPluginInstance& parent,
865 const String& paramName,
866 const Array<String>& shortParamNames,
867 float paramDefaultValue,
868 const String& paramLabel,
869 bool paramIsAutomatable,
870 bool paramIsDiscrete,
873 const StringArray& paramValueStrings,
874 const VSTXMLInfo::ValueType* paramValueType)
875 : pluginInstance (parent),
877 shortNames (shortParamNames),
878 defaultValue (paramDefaultValue),
880 automatable (paramIsAutomatable),
881 discrete (paramIsDiscrete),
882 numSteps (numParamSteps),
883 isSwitch (isBoolSwitch),
884 vstValueStrings (paramValueStrings),
885 valueType (paramValueType)
889 float getValue()
const override
891 if (
auto* effect = pluginInstance.vstEffect)
895 return effect->getParameter (effect, getParameterIndex());
901 void setValue (
float newValue)
override
903 if (
auto* effect = pluginInstance.vstEffect)
907 if (! approximatelyEqual (effect->getParameter (effect, getParameterIndex()), newValue))
908 effect->setParameter (effect, getParameterIndex(), newValue);
912 String getText (
float value,
int maximumStringLength)
const override
914 if (valueType !=
nullptr)
916 for (
auto& v : valueType->entries)
917 if (v->range.contains (value))
921 return Parameter::getText (value, maximumStringLength);
924 float getValueForText (
const String& text)
const override
926 if (valueType !=
nullptr)
928 for (
auto& v : valueType->entries)
930 return (v->range.high + v->range.low) / 2.0f;
933 return Parameter::getValueForText (text);
936 String getCurrentValueAsText()
const override
938 if (valueType !=
nullptr || ! vstValueStrings.isEmpty())
939 return getText (getValue(), 1024);
941 return pluginInstance.getTextForOpcode (getParameterIndex(), Vst2::effGetParamDisplay);
944 float getDefaultValue()
const override
949 String getName (
int maximumStringLength)
const override
952 return pluginInstance.getTextForOpcode (getParameterIndex(),
953 Vst2::effGetParamName);
955 if (name.length() <= maximumStringLength)
958 if (! shortNames.isEmpty())
960 for (
auto& n : shortNames)
961 if (n.length() <= maximumStringLength)
964 return shortNames.getLast();
970 String getLabel()
const override
972 return label.isEmpty() ? pluginInstance.getTextForOpcode (getParameterIndex(),
973 Vst2::effGetParamLabel)
977 bool isAutomatable()
const override
982 bool isDiscrete()
const override
987 bool isBoolean()
const override
992 int getNumSteps()
const override
997 StringArray getAllValueStrings()
const override
999 return vstValueStrings;
1002 String getParameterID()
const override
1004 return String (getParameterIndex());
1007 VSTPluginInstance& pluginInstance;
1010 const Array<String> shortNames;
1011 const float defaultValue;
1013 const bool automatable, discrete;
1015 const bool isSwitch;
1016 const StringArray vstValueStrings;
1017 const VSTXMLInfo::ValueType*
const valueType;
1020 VSTPluginInstance (
const ModuleHandle::Ptr& mh,
const BusesProperties& ioConfig, Vst2::AEffect* effect,
1021 double sampleRateToUse,
int blockSizeToUse)
1022 : AudioPluginInstance (ioConfig),
1025 name (mh->pluginName),
1026 bypassParam (new VST2BypassParameter (*this))
1028 jassert (vstEffect !=
nullptr);
1030 if (
auto* xml = vstModule->vstXml.get())
1031 xmlInfo.reset (VSTXMLInfo::createFor (*xml));
1033 refreshParameterList();
1035 vstSupportsBypass = (pluginCanDo (
"bypass") > 0);
1036 setRateAndBufferSizeDetails (sampleRateToUse, blockSizeToUse);
1039 void refreshParameterList()
override
1041 AudioProcessorParameterGroup newParameterTree;
1043 for (
int i = 0; i < vstEffect->numParams; ++i)
1046 Array<String> shortParamNames;
1047 float defaultValue = 0;
1049 bool isAutomatable = dispatch (Vst2::effCanBeAutomated, i, 0,
nullptr, 0) != 0;
1050 bool isDiscrete =
false;
1051 int numSteps = AudioProcessor::getDefaultNumParameterSteps();
1052 bool isBoolSwitch =
false;
1053 StringArray parameterValueStrings;
1054 const VSTXMLInfo::ValueType* valueType =
nullptr;
1056 if (xmlInfo !=
nullptr)
1058 if (
auto* param = xmlInfo->getParamForID (i,
nullptr))
1060 paramName = param->name;
1062 for (
auto& n : param->shortNames)
1063 shortParamNames.add (n);
1065 struct LengthComparator
1069 return first.length() - second.length();
1073 LengthComparator comp;
1074 shortParamNames.sort (comp);
1076 defaultValue = param->defaultValue;
1077 label = param->label;
1079 if (param->type ==
"switch")
1081 isBoolSwitch =
true;
1083 valueType = &xmlInfo->switchValueType;
1087 valueType = xmlInfo->getValueType (param->type);
1090 if (param->numberOfStates >= 2)
1092 numSteps = param->numberOfStates;
1094 if (valueType !=
nullptr)
1096 for (
auto* entry : valueType->entries)
1097 parameterValueStrings.add (entry->name);
1099 parameterValueStrings.removeEmptyStrings();
1103 isDiscrete = (numSteps != AudioProcessor::getDefaultNumParameterSteps());
1108 label, isAutomatable, isDiscrete, numSteps,
1109 isBoolSwitch, parameterValueStrings, valueType));
1112 setHostedParameterTree (std::move (newParameterTree));
1115 ~VSTPluginInstance()
override
1117 if (vstEffect !=
nullptr && vstEffect->magic == 0x56737450 )
1118 callOnMessageThread ([
this] { cleanup(); });
1123 if (vstEffect !=
nullptr && vstEffect->magic == 0x56737450 )
1126 if (vstModule->resFileId != 0)
1127 UseResFile (vstModule->resFileId);
1131 jassert (getActiveEditor() ==
nullptr);
1135 vstModule->closeEffect (vstEffect);
1138 vstModule =
nullptr;
1139 vstEffect =
nullptr;
1142 static VSTPluginInstance* create (
const ModuleHandle::Ptr& newModule,
1143 double initialSampleRate,
1144 int initialBlockSize)
1146 if (
auto* newEffect = constructEffect (newModule))
1148 newEffect->resvd2 = 0;
1150 newEffect->dispatcher (newEffect, Vst2::effIdentify, 0, 0,
nullptr, 0);
1152 auto blockSize =
jmax (32, initialBlockSize);
1154 newEffect->dispatcher (newEffect, Vst2::effSetSampleRate, 0, 0,
nullptr,
static_cast<float> (initialSampleRate));
1155 newEffect->dispatcher (newEffect, Vst2::effSetBlockSize, 0, blockSize,
nullptr, 0);
1157 newEffect->dispatcher (newEffect, Vst2::effOpen, 0, 0,
nullptr, 0);
1158 BusesProperties ioConfig = queryBusIO (newEffect);
1160 return new VSTPluginInstance (newModule, ioConfig, newEffect, initialSampleRate, blockSize);
1167 void fillInPluginDescription (PluginDescription& desc)
const override
1172 char buffer[512] = { 0 };
1173 dispatch (Vst2::effGetEffectName, 0, 0, buffer, 0);
1175 desc.descriptiveName = String::createStringFromData (buffer, (
int)
sizeof (buffer)).trim();
1177 if (desc.descriptiveName.isEmpty())
1178 desc.descriptiveName = name;
1181 desc.fileOrIdentifier = vstModule->file.getFullPathName();
1182 desc.uniqueId = desc.deprecatedUid = getUID();
1183 desc.lastFileModTime = vstModule->file.getLastModificationTime();
1184 desc.lastInfoUpdateTime = Time::getCurrentTime();
1185 desc.pluginFormatName =
"VST";
1186 desc.category = getCategory();
1189 char buffer[512] = { 0 };
1190 dispatch (Vst2::effGetVendorString, 0, 0, buffer, 0);
1191 desc.manufacturerName = String::createStringFromData (buffer, (
int)
sizeof (buffer)).trim();
1194 desc.version = getVersion();
1195 desc.numInputChannels = getTotalNumInputChannels();
1196 desc.numOutputChannels = getTotalNumOutputChannels();
1197 desc.isInstrument = isSynthPlugin();
1200 bool initialiseEffect (
double initialSampleRate,
int initialBlockSize)
1202 if (vstEffect !=
nullptr)
1205 initialise (initialSampleRate, initialBlockSize);
1212 void initialise (
double initialSampleRate,
int initialBlockSize)
1214 if (initialised || vstEffect ==
nullptr)
1225 JUCE_VST_LOG (
"Initialising VST: " + vstModule->pluginName +
" (" + getVersion() +
")");
1228 setRateAndBufferSizeDetails (initialSampleRate, initialBlockSize);
1230 dispatch (Vst2::effIdentify, 0, 0,
nullptr, 0);
1232 if (getSampleRate() > 0)
1233 dispatch (Vst2::effSetSampleRate, 0, 0,
nullptr, (
float) getSampleRate());
1235 if (getBlockSize() > 0)
1236 dispatch (Vst2::effSetBlockSize, 0, jmax (32, getBlockSize()),
nullptr, 0);
1238 dispatch (Vst2::effOpen, 0, 0,
nullptr, 0);
1240 setRateAndBufferSizeDetails (getSampleRate(), getBlockSize());
1242 if (getNumPrograms() > 1)
1243 setCurrentProgram (0);
1245 dispatch (Vst2::effSetProgram, 0, 0,
nullptr, 0);
1247 for (
int i = vstEffect->numInputs; --i >= 0;) dispatch (Vst2::effConnectInput, i, 1,
nullptr, 0);
1248 for (
int i = vstEffect->numOutputs; --i >= 0;) dispatch (Vst2::effConnectOutput, i, 1,
nullptr, 0);
1250 if (getVstCategory() != Vst2::kPlugCategShell)
1251 updateStoredProgramNames();
1253 wantsMidiMessages = pluginCanDo (
"receiveVstMidiEvent") > 0 || isSynthPlugin();
1255 setLatencySamples (vstEffect->initialDelay);
1258 void getExtensions (ExtensionsVisitor& visitor)
const override
1260 struct Extensions final :
public ExtensionsVisitor::VSTClient
1262 explicit Extensions (
const VSTPluginInstance* instanceIn) : instance (instanceIn) {}
1264 AEffect* getAEffectPtr() const noexcept
override {
return reinterpret_cast<AEffect*
> (instance->vstEffect); }
1266 const VSTPluginInstance* instance =
nullptr;
1269 visitor.visitVSTClient (Extensions {
this });
1272 void* getPlatformSpecificData()
override {
return vstEffect; }
1274 const String getName()
const override
1276 if (vstEffect !=
nullptr)
1278 char buffer[512] = { 0 };
1280 if (dispatch (Vst2::effGetProductString, 0, 0, buffer, 0) != 0)
1282 String productName = String::createStringFromData (buffer, (
int)
sizeof (buffer));
1284 if (productName.isNotEmpty())
1294 int uid = vstEffect !=
nullptr ? vstEffect->uniqueID : 0;
1297 uid = vstModule->file.hashCode();
1302 double getTailLengthSeconds()
const override
1304 if (vstEffect ==
nullptr)
1307 if ((vstEffect->flags & Vst2::effFlagsNoSoundInStop) != 0)
1310 auto tailSize = dispatch (Vst2::effGetTailSize, 0, 0,
nullptr, 0);
1311 auto sampleRate = getSampleRate();
1320 if (tailSize >= 0 && sampleRate > 0)
1321 return static_cast<double> (tailSize) / sampleRate;
1326 bool acceptsMidi()
const override {
return wantsMidiMessages; }
1327 bool producesMidi()
const override {
return pluginCanDo (
"sendVstMidiEvent") > 0; }
1328 bool supportsMPE()
const override {
return pluginCanDo (
"MPE") > 0; }
1330 Vst2::VstPlugCategory getVstCategory() const noexcept {
return (Vst2::VstPlugCategory) dispatch (Vst2::effGetPlugCategory, 0, 0,
nullptr, 0); }
1332 bool isSynthPlugin()
const {
return (vstEffect !=
nullptr && (vstEffect->flags & Vst2::effFlagsIsSynth) != 0); }
1334 int pluginCanDo (
const char* text)
const {
return (
int) dispatch (Vst2::effCanDo, 0, 0, (
void*) text, 0); }
1337 void prepareToPlay (
double rate,
int samplesPerBlockExpected)
override
1339 auto numInputBuses = getBusCount (
true);
1340 auto numOutputBuses = getBusCount (
false);
1342 setRateAndBufferSizeDetails (rate, samplesPerBlockExpected);
1344 if (numInputBuses <= 1 && numOutputBuses <= 1)
1346 SpeakerMappings::VstSpeakerConfigurationHolder inArr (getChannelLayoutOfBus (
true, 0));
1347 SpeakerMappings::VstSpeakerConfigurationHolder outArr (getChannelLayoutOfBus (
false, 0));
1349 dispatch (Vst2::effSetSpeakerArrangement, 0, (pointer_sized_int) &inArr.get(), (
void*) &outArr.get(), 0.0f);
1352 vstHostTime.tempo = 120.0;
1353 vstHostTime.timeSigNumerator = 4;
1354 vstHostTime.timeSigDenominator = 4;
1355 vstHostTime.sampleRate = rate;
1356 vstHostTime.samplePos = 0;
1357 vstHostTime.flags = Vst2::kVstNanosValid
1358 | Vst2::kVstAutomationWriting
1359 | Vst2::kVstAutomationReading;
1361 initialise (rate, samplesPerBlockExpected);
1365 wantsMidiMessages = wantsMidiMessages || (pluginCanDo (
"receiveVstMidiEvent") > 0) || isSynthPlugin();
1367 if (wantsMidiMessages)
1368 midiEventsToSend.ensureSize (256);
1370 midiEventsToSend.freeEvents();
1372 incomingMidi.clear();
1374 dispatch (Vst2::effSetSampleRate, 0, 0,
nullptr, (
float) rate);
1375 dispatch (Vst2::effSetBlockSize, 0, jmax (16, samplesPerBlockExpected),
nullptr, 0);
1377 if (supportsDoublePrecisionProcessing())
1379 int32 vstPrecision = isUsingDoublePrecision() ? Vst2::kVstProcessPrecision64
1380 : Vst2::kVstProcessPrecision32;
1382 dispatch (Vst2::effSetProcessPrecision, 0, (pointer_sized_int) vstPrecision,
nullptr, 0);
1385 auto maxChannels =
jmax (1, jmax (vstEffect->numInputs, vstEffect->numOutputs));
1387 tmpBufferFloat .setSize (maxChannels, samplesPerBlockExpected);
1388 tmpBufferDouble.setSize (maxChannels, samplesPerBlockExpected);
1390 channelBufferFloat .calloc (
static_cast<size_t> (maxChannels));
1391 channelBufferDouble.calloc (
static_cast<size_t> (maxChannels));
1393 outOfPlaceBuffer.setSize (jmax (1, vstEffect->numOutputs), samplesPerBlockExpected);
1401 if (
auto* firstParam = getParameters()[0])
1403 auto old = firstParam->getValue();
1404 firstParam->setValue ((old < 0.5f) ? 1.0f : 0.0f);
1405 firstParam->setValue (old);
1409 dispatch (Vst2::effStartProcess, 0, 0,
nullptr, 0);
1411 setLatencySamples (vstEffect->initialDelay);
1415 void releaseResources()
override
1419 dispatch (Vst2::effStopProcess, 0, 0,
nullptr, 0);
1423 channelBufferFloat.free();
1424 tmpBufferFloat.setSize (0, 0);
1426 channelBufferDouble.free();
1427 tmpBufferDouble.setSize (0, 0);
1429 outOfPlaceBuffer.setSize (1, 1);
1430 incomingMidi.clear();
1432 midiEventsToSend.freeEvents();
1435 void reset()
override
1445 void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
override
1447 jassert (! isUsingDoublePrecision());
1448 processAudio (buffer, midiMessages, tmpBufferFloat, channelBufferFloat,
false);
1451 void processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages)
override
1453 jassert (isUsingDoublePrecision());
1454 processAudio (buffer, midiMessages, tmpBufferDouble, channelBufferDouble,
false);
1457 void processBlockBypassed (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
override
1459 jassert (! isUsingDoublePrecision());
1460 processAudio (buffer, midiMessages, tmpBufferFloat, channelBufferFloat,
true);
1463 void processBlockBypassed (AudioBuffer<double>& buffer, MidiBuffer& midiMessages)
override
1465 jassert (isUsingDoublePrecision());
1466 processAudio (buffer, midiMessages, tmpBufferDouble, channelBufferDouble,
true);
1470 bool supportsDoublePrecisionProcessing()
const override
1472 return ((vstEffect->flags & Vst2::effFlagsCanReplacing) != 0
1473 && (vstEffect->flags & Vst2::effFlagsCanDoubleReplacing) != 0);
1476 AudioProcessorParameter* getBypassParameter()
const override {
return vstSupportsBypass ? bypassParam.get() :
nullptr; }
1479 bool canAddBus (
bool)
const override {
return false; }
1480 bool canRemoveBus (
bool)
const override {
return false; }
1482 bool isBusesLayoutSupported (
const BusesLayout& layouts)
const override
1484 auto numInputBuses = getBusCount (
true);
1485 auto numOutputBuses = getBusCount (
false);
1488 if (numInputBuses > 1 || numOutputBuses > 1)
1489 return (layouts == getBusesLayout());
1491 return (layouts.getNumChannels (
true, 0) <= vstEffect->numInputs
1492 && layouts.getNumChannels (
false, 0) <= vstEffect->numOutputs);
1496 #if JUCE_IOS || JUCE_ANDROID
1497 bool hasEditor()
const override {
return false; }
1499 bool hasEditor()
const override {
return vstEffect !=
nullptr && (vstEffect->flags & Vst2::effFlagsHasEditor) != 0; }
1502 AudioProcessorEditor* createEditor()
override;
1505 const String getInputChannelName (
int index)
const override
1507 if (isValidChannel (index,
true))
1509 Vst2::VstPinProperties pinProps;
1510 if (dispatch (Vst2::effGetInputProperties, index, 0, &pinProps, 0.0f) != 0)
1511 return String (pinProps.label, sizeof (pinProps.label));
1517 bool isInputChannelStereoPair (
int index)
const override
1519 if (! isValidChannel (index,
true))
1522 Vst2::VstPinProperties pinProps;
1523 if (dispatch (Vst2::effGetInputProperties, index, 0, &pinProps, 0.0f) != 0)
1524 return (pinProps.flags & Vst2::kVstPinIsStereo) != 0;
1529 const String getOutputChannelName (
int index)
const override
1531 if (isValidChannel (index,
false))
1533 Vst2::VstPinProperties pinProps;
1534 if (dispatch (Vst2::effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0)
1535 return String (pinProps.label, sizeof (pinProps.label));
1541 bool isOutputChannelStereoPair (
int index)
const override
1543 if (! isValidChannel (index,
false))
1546 Vst2::VstPinProperties pinProps;
1547 if (dispatch (Vst2::effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0)
1548 return (pinProps.flags & Vst2::kVstPinIsStereo) != 0;
1553 bool isValidChannel (
int index,
bool isInput)
const noexcept
1556 : getTotalNumOutputChannels());
1560 int getNumPrograms()
override {
return vstEffect !=
nullptr ?
jmax (0, vstEffect->numPrograms) : 0; }
1563 int getCurrentProgram()
override {
return (
int) dispatch (Vst2::effGetProgram, 0, 0,
nullptr, 0); }
1565 void setCurrentProgram (
int newIndex)
override
1567 if (getNumPrograms() > 0 && newIndex != getCurrentProgram())
1568 dispatch (Vst2::effSetProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex),
nullptr, 0);
1571 const String getProgramName (
int index)
override
1575 if (index == getCurrentProgram())
1576 return getCurrentProgramName();
1578 if (vstEffect !=
nullptr)
1580 char nm[264] = { 0 };
1582 if (dispatch (Vst2::effGetProgramNameIndexed, jlimit (0, getNumPrograms() - 1, index), -1, nm, 0) != 0)
1583 return String::fromUTF8 (nm).trim();
1590 void changeProgramName (
int index,
const String& newName)
override
1592 if (index >= 0 && index == getCurrentProgram())
1594 if (getNumPrograms() > 0 && newName != getCurrentProgramName())
1595 dispatch (Vst2::effSetProgramName, 0, 0, (
void*) newName.substring (0, 24).toRawUTF8(), 0.0f);
1604 void getStateInformation (MemoryBlock& mb)
override { saveToFXBFile (mb,
true); }
1605 void getCurrentProgramStateInformation (MemoryBlock& mb)
override { saveToFXBFile (mb,
false); }
1607 void setStateInformation (
const void* data,
int size)
override { loadFromFXBFile (data, (
size_t) size); }
1608 void setCurrentProgramStateInformation (
const void* data,
int size)
override { loadFromFXBFile (data, (
size_t) size); }
1611 void timerCallback()
override
1613 if (dispatch (Vst2::effIdle, 0, 0,
nullptr, 0) == 0)
1617 void handleAsyncUpdate()
override
1619 updateHostDisplay (AudioProcessorListener::ChangeDetails().withProgramChanged (
true)
1620 .withParameterInfoChanged (
true));
1623 pointer_sized_int handleCallback (int32 opcode, int32 index, pointer_sized_int value,
void* ptr,
float opt)
1627 case Vst2::audioMasterAutomate:
1628 if (
auto* param = getParameters()[index])
1629 param->sendValueChangedMessageToListeners (opt);
1635 case Vst2::audioMasterProcessEvents: handleMidiFromPlugin ((
const Vst2::VstEvents*) ptr);
break;
1636 case Vst2::audioMasterGetTime:
return getVSTTime();
1637 case Vst2::audioMasterIdle: handleIdle();
break;
1638 case Vst2::audioMasterSizeWindow: setWindowSize (index, (
int) value);
return 1;
1639 case Vst2::audioMasterUpdateDisplay: triggerAsyncUpdate();
break;
1640 case Vst2::audioMasterIOChanged: setLatencySamples (vstEffect->initialDelay);
break;
1641 case Vst2::audioMasterNeedIdle: startTimer (50);
break;
1643 case Vst2::audioMasterGetSampleRate:
return (pointer_sized_int) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue);
1644 case Vst2::audioMasterGetBlockSize:
return (pointer_sized_int) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue);
1645 case Vst2::audioMasterWantMidi: wantsMidiMessages =
true;
break;
1646 case Vst2::audioMasterGetDirectory:
return getVstDirectory();
1648 case Vst2::audioMasterTempoAt:
return (pointer_sized_int) (extraFunctions !=
nullptr ? extraFunctions->getTempoAt ((int64) value) : 0);
1649 case Vst2::audioMasterGetAutomationState:
return (pointer_sized_int) (extraFunctions !=
nullptr ? extraFunctions->getAutomationState() : 0);
1651 case Vst2::audioMasterBeginEdit:
1652 if (
auto* param = getParameters()[index])
1653 param->beginChangeGesture();
1659 case Vst2::audioMasterEndEdit:
1660 if (
auto* param = getParameters()[index])
1661 param->endChangeGesture();
1667 case Vst2::audioMasterPinConnected:
return isValidChannel (index, value == 0) ? 0 : 1;
1668 case Vst2::audioMasterGetCurrentProcessLevel:
return isNonRealtime() ? 4 : 0;
1671 case Vst2::audioMasterSetTime:
1672 case Vst2::audioMasterGetParameterQuantization:
1673 case Vst2::audioMasterGetInputLatency:
1674 case Vst2::audioMasterGetOutputLatency:
1675 case Vst2::audioMasterGetPreviousPlug:
1676 case Vst2::audioMasterGetNextPlug:
1677 case Vst2::audioMasterWillReplaceOrAccumulate:
1678 case Vst2::audioMasterOfflineStart:
1679 case Vst2::audioMasterOfflineRead:
1680 case Vst2::audioMasterOfflineWrite:
1681 case Vst2::audioMasterOfflineGetCurrentPass:
1682 case Vst2::audioMasterOfflineGetCurrentMetaPass:
1683 case Vst2::audioMasterGetOutputSpeakerArrangement:
1684 case Vst2::audioMasterVendorSpecific:
1685 case Vst2::audioMasterSetIcon:
1686 case Vst2::audioMasterGetLanguage:
1687 case Vst2::audioMasterOpenWindow:
1688 case Vst2::audioMasterCloseWindow:
1692 return handleGeneralCallback (opcode, index, value, ptr, opt);
1699 static pointer_sized_int handleGeneralCallback (int32 opcode, int32 , pointer_sized_int ,
void* ptr,
float )
1703 case Vst2::audioMasterCanDo:
return handleCanDo ((
const char*) ptr);
1704 case Vst2::audioMasterVersion:
return 2400;
1705 case Vst2::audioMasterCurrentId:
return shellUIDToCreate;
1706 case Vst2::audioMasterGetNumAutomatableParameters:
return 0;
1707 case Vst2::audioMasterGetAutomationState:
return 1;
1708 case Vst2::audioMasterGetVendorVersion:
return 0x0101;
1710 case Vst2::audioMasterGetVendorString:
1711 case Vst2::audioMasterGetProductString:
return getHostName ((
char*) ptr);
1713 case Vst2::audioMasterGetSampleRate:
return (pointer_sized_int) defaultVSTSampleRateValue;
1714 case Vst2::audioMasterGetBlockSize:
return (pointer_sized_int) defaultVSTBlockSizeValue;
1715 case Vst2::audioMasterSetOutputSampleRate:
return 0;
1718 DBG (
"*** Unhandled VST Callback: " + String ((
int) opcode));
1726 pointer_sized_int dispatch (
int opcode,
int index, pointer_sized_int value,
void*
const ptr,
float opt)
const
1730 if (vstEffect !=
nullptr)
1733 const IdleCallRecursionPreventer icrp;
1738 auto oldResFile = CurResFile();
1740 if (vstModule->resFileId != 0)
1741 UseResFile (vstModule->resFileId);
1744 result = vstEffect->dispatcher (vstEffect, opcode, index, value, ptr, opt);
1747 auto newResFile = CurResFile();
1749 if (newResFile != oldResFile)
1751 vstModule->resFileId = newResFile;
1752 UseResFile (oldResFile);
1763 bool loadFromFXBFile (
const void*
const data,
const size_t dataSize)
1768 auto set = (
const fxSet*) data;
1770 if ((! compareMagic (set->chunkMagic,
"CcnK")) || fxbSwap (set->version) > fxbVersionNum)
1773 if (compareMagic (set->fxMagic,
"FxBk"))
1776 if (fxbSwap (set->numPrograms) >= 0)
1778 auto oldProg = getCurrentProgram();
1779 auto numParams = fxbSwap (((
const fxProgram*) (set->programs))->numParams);
1780 auto progLen = (
int)
sizeof (fxProgram) + (numParams - 1) * (
int)
sizeof (
float);
1782 for (
int i = 0; i < fxbSwap (set->numPrograms); ++i)
1788 if (getAddressDifference (prog, set) >= (
int) dataSize)
1791 if (fxbSwap (set->numPrograms) > 0)
1792 setCurrentProgram (i);
1794 if (! restoreProgramSettings (prog))
1799 if (fxbSwap (set->numPrograms) > 0)
1800 setCurrentProgram (oldProg);
1804 if (getAddressDifference (prog, set) >= (
int) dataSize)
1807 if (! restoreProgramSettings (prog))
1811 else if (compareMagic (set->fxMagic,
"FxCk"))
1814 auto prog = (
const fxProgram*) data;
1816 if (! compareMagic (prog->chunkMagic,
"CcnK"))
1819 changeProgramName (getCurrentProgram(), prog->prgName);
1821 for (
int i = 0; i < fxbSwap (prog->numParams); ++i)
1822 if (
auto* param = getParameters()[i])
1823 param->setValue (fxbSwapFloat (prog->params[i]));
1825 else if (compareMagic (set->fxMagic,
"FBCh"))
1828 auto cset = (
const fxChunkSet*) data;
1830 if ((
size_t) fxbSwap (cset->chunkSize) +
sizeof (fxChunkSet) - 8 > (
size_t) dataSize)
1833 setChunkData (cset->chunk, fxbSwap (cset->chunkSize),
false);
1835 else if (compareMagic (set->fxMagic,
"FPCh"))
1838 auto cset = (
const fxProgramSet*) data;
1840 if ((
size_t) fxbSwap (cset->chunkSize) +
sizeof (fxProgramSet) - 8 > (
size_t) dataSize)
1843 setChunkData (cset->chunk, fxbSwap (cset->chunkSize),
true);
1845 changeProgramName (getCurrentProgram(), cset->name);
1855 bool saveToFXBFile (MemoryBlock& dest,
bool isFXB,
int maxSizeMB = 128)
1857 auto numPrograms = getNumPrograms();
1858 auto numParams = getParameters().size();
1863 getChunkData (chunk, ! isFXB, maxSizeMB);
1867 auto totalLen =
sizeof (fxChunkSet) + chunk.getSize() - 8;
1868 dest.setSize (totalLen,
true);
1870 auto set = (fxChunkSet*) dest.getData();
1871 set->chunkMagic = fxbName (
"CcnK");
1873 set->fxMagic = fxbName (
"FBCh");
1874 set->version = fxbSwap (fxbVersionNum);
1875 set->fxID = fxbSwap (getUID());
1876 set->fxVersion = fxbSwap (getVersionNumber());
1877 set->numPrograms = fxbSwap (numPrograms);
1878 set->chunkSize = fxbSwap ((int32) chunk.getSize());
1880 chunk.copyTo (set->chunk, 0, chunk.getSize());
1884 auto totalLen =
sizeof (fxProgramSet) + chunk.getSize() - 8;
1885 dest.setSize (totalLen,
true);
1887 auto set = (fxProgramSet*) dest.getData();
1888 set->chunkMagic = fxbName (
"CcnK");
1890 set->fxMagic = fxbName (
"FPCh");
1891 set->version = fxbSwap (fxbVersionNum);
1892 set->fxID = fxbSwap (getUID());
1893 set->fxVersion = fxbSwap (getVersionNumber());
1894 set->numPrograms = fxbSwap (numPrograms);
1895 set->chunkSize = fxbSwap ((int32) chunk.getSize());
1897 getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1);
1898 chunk.copyTo (set->chunk, 0, chunk.getSize());
1905 auto progLen = (
int)
sizeof (fxProgram) + (numParams - 1) * (
int)
sizeof (
float);
1906 auto len = (
size_t) (progLen * jmax (1, numPrograms)) + (
sizeof (fxSet) -
sizeof (fxProgram));
1907 dest.setSize (len,
true);
1909 auto set = (fxSet*) dest.getData();
1910 set->chunkMagic = fxbName (
"CcnK");
1912 set->fxMagic = fxbName (
"FxBk");
1913 set->version = fxbSwap (fxbVersionNum);
1914 set->fxID = fxbSwap (getUID());
1915 set->fxVersion = fxbSwap (getVersionNumber());
1916 set->numPrograms = fxbSwap (numPrograms);
1918 MemoryBlock oldSettings;
1919 createTempParameterStore (oldSettings);
1921 auto oldProgram = getCurrentProgram();
1923 if (oldProgram >= 0)
1924 setParamsInProgramBlock (addBytesToPointer (set->programs, oldProgram * progLen));
1926 for (
int i = 0; i < numPrograms; ++i)
1928 if (i != oldProgram)
1930 setCurrentProgram (i);
1931 setParamsInProgramBlock (addBytesToPointer (set->programs, i * progLen));
1935 if (oldProgram >= 0)
1936 setCurrentProgram (oldProgram);
1938 restoreFromTempParameterStore (oldSettings);
1942 dest.setSize ((
size_t) ((numParams - 1) * (
int)
sizeof (
float)) +
sizeof (fxProgram),
true);
1943 setParamsInProgramBlock ((fxProgram*) dest.getData());
1950 bool usesChunks() const noexcept {
return vstEffect !=
nullptr && (vstEffect->flags & Vst2::effFlagsProgramChunks) != 0; }
1952 bool getChunkData (MemoryBlock& mb,
bool isPreset,
int maxSizeMB)
const
1956 void*
data =
nullptr;
1957 auto bytes = (
size_t) dispatch (Vst2::effGetChunk, isPreset ? 1 : 0, 0, &
data, 0.0f);
1959 if (data !=
nullptr && bytes <= (
size_t) maxSizeMB * 1024 * 1024)
1962 mb.copyFrom (data, 0, bytes);
1971 bool setChunkData (
const void* data,
const int size,
bool isPreset)
1973 if (size > 0 && usesChunks())
1975 dispatch (Vst2::effSetChunk, isPreset ? 1 : 0,
size, (void*)
data, 0.0f);
1978 updateStoredProgramNames();
1986 bool updateSizeFromEditor (
int w,
int h);
1988 Vst2::AEffect* vstEffect;
1989 ModuleHandle::Ptr vstModule;
1995 struct VST2BypassParameter final :
public Parameter
1997 VST2BypassParameter (VSTPluginInstance& effectToUse)
1998 : parent (effectToUse),
2005 void setValue (
float newValue)
override
2009 if (parent.vstSupportsBypass)
2010 parent.dispatch (Vst2::effSetBypass, 0, currentValue ? 1 : 0, nullptr, 0.0f);
2013 float getValueForText (
const String& text)
const override
2015 String lowercaseText (text.toLowerCase());
2017 for (
auto& testText : vstOnStrings)
2018 if (lowercaseText == testText)
2021 for (
auto& testText : vstOffStrings)
2022 if (lowercaseText == testText)
2025 return text.getIntValue() != 0 ? 1.0f : 0.0f;
2028 float getValue()
const override {
return currentValue; }
2029 float getDefaultValue()
const override {
return 0.0f; }
2030 String getName (
int )
const override {
return "Bypass"; }
2031 String getText (
float value,
int)
const override {
return (! approximatelyEqual (value, 0.0f) ?
TRANS (
"On") :
TRANS (
"Off")); }
2032 bool isAutomatable()
const override {
return true; }
2033 bool isDiscrete()
const override {
return true; }
2034 bool isBoolean()
const override {
return true; }
2035 int getNumSteps()
const override {
return 2; }
2036 StringArray getAllValueStrings()
const override {
return values; }
2037 String getLabel()
const override {
return {}; }
2038 String getParameterID()
const override {
return {}; }
2040 VSTPluginInstance& parent;
2041 bool currentValue =
false;
2042 StringArray vstOnStrings, vstOffStrings, values;
2047 CriticalSection
lock;
2049 bool initialised =
false;
2051 bool lastProcessBlockCallWasBypass =
false, vstSupportsBypass =
false;
2052 mutable StringArray programNames;
2053 AudioBuffer<float> outOfPlaceBuffer;
2054 TempChannelPointers tempChannelPointers[2];
2056 CriticalSection midiInLock;
2057 MidiBuffer incomingMidi;
2058 VSTMidiEventList midiEventsToSend;
2059 Vst2::VstTimeInfo vstHostTime;
2061 AudioBuffer<float> tmpBufferFloat;
2062 HeapBlock<float*> channelBufferFloat;
2064 AudioBuffer<double> tmpBufferDouble;
2065 HeapBlock<double*> channelBufferDouble;
2072 static const char* canDos[] = {
"supplyIdle",
2077 "receiveVstMidiEvent",
2083 if (strcmp (canDos[i], name) == 0)
2091 String hostName (JUCE_VST_FALLBACK_HOST_NAME);
2093 if (
auto* app = JUCEApplicationBase::getInstance())
2094 hostName = app->getApplicationName();
2096 hostName.copyToUTF8 (name, (
size_t) jmin (Vst2::kVstMaxVendorStrLen, Vst2::kVstMaxProductStrLen) - 1);
2102 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4311)
2104 return (pointer_sized_int) &vstHostTime;
2106 JUCE_END_IGNORE_WARNINGS_MSVC
2111 if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread())
2113 const IdleCallRecursionPreventer icrp;
2116 if (getActiveEditor() !=
nullptr)
2117 dispatch (Vst2::effEditIdle, 0, 0,
nullptr, 0);
2120 Timer::callPendingTimersSynchronously();
2121 handleUpdateNowIfNeeded();
2123 for (
int i = ComponentPeer::getNumPeers(); --i >= 0;)
2124 if (
auto* p = ComponentPeer::getPeer (i))
2125 p->performAnyPendingRepaintsNow();
2129 void setWindowSize (
int width,
int height)
2131 #if JUCE_LINUX || JUCE_BSD
2132 const MessageManagerLock mmLock;
2135 updateSizeFromEditor (width, height);
2139 static Vst2::AEffect* constructEffect (
const ModuleHandle::Ptr& module)
2141 Vst2::AEffect* effect =
nullptr;
2144 const IdleCallRecursionPreventer icrp;
2147 JUCE_VST_LOG (
"Creating VST instance: " + module->pluginName);
2150 if (module->resFileId != 0)
2151 UseResFile (module->resFileId);
2155 JUCE_VST_WRAPPER_INVOKE_MAIN
2158 if (effect !=
nullptr && effect->magic == 0x56737450 )
2160 jassert (effect->resvd2 == 0);
2161 jassert (effect->object !=
nullptr);
2176 static BusesProperties queryBusIO (Vst2::AEffect* effect)
2178 BusesProperties returnValue;
2180 if (effect->numInputs == 0 && effect->numOutputs == 0)
2189 if (! pluginHasDefaultChannelLayouts (effect))
2191 SpeakerMappings::VstSpeakerConfigurationHolder canonicalIn (AudioChannelSet::canonicalChannelSet (effect->numInputs));
2192 SpeakerMappings::VstSpeakerConfigurationHolder canonicalOut (AudioChannelSet::canonicalChannelSet (effect->numOutputs));
2194 effect->dispatcher (effect, Vst2::effSetSpeakerArrangement, 0,
2195 (pointer_sized_int) &canonicalIn.get(), (
void*) &canonicalOut.get(), 0.0f);
2198 const auto arrangement = getSpeakerArrangementWrapper (effect);
2200 for (
int dir = 0; dir < 2; ++dir)
2202 const bool isInput = (dir == 0);
2203 const int opcode = (isInput ? Vst2::effGetInputProperties : Vst2::effGetOutputProperties);
2204 const int maxChannels = (isInput ? effect->numInputs : effect->numOutputs);
2205 const auto* arr = (isInput ? arrangement.in : arrangement.out);
2206 bool busAdded =
false;
2208 Vst2::VstPinProperties pinProps;
2209 AudioChannelSet layout;
2211 for (
int ch = 0; ch < maxChannels; ch += layout.size())
2213 if (effect->dispatcher (effect, opcode, ch, 0, &pinProps, 0.0f) == 0)
2216 if ((pinProps.flags & Vst2::kVstPinUseSpeaker) != 0)
2218 layout = SpeakerMappings::vstArrangementTypeToChannelSet (pinProps.arrangementType, 0);
2220 if (layout.isDisabled())
2223 else if (arr ==
nullptr)
2225 layout = ((pinProps.flags & Vst2::kVstPinIsStereo) != 0 ? AudioChannelSet::stereo() : AudioChannelSet::mono());
2231 returnValue.addBus (isInput, pinProps.label, layout,
true);
2235 if (! busAdded && maxChannels > 0)
2237 String busName = (isInput ?
"Input" :
"Output");
2239 if (effect->dispatcher (effect, opcode, 0, 0, &pinProps, 0.0f) != 0)
2240 busName = pinProps.label;
2243 layout = SpeakerMappings::vstArrangementTypeToChannelSet (*arr);
2245 layout = AudioChannelSet::canonicalChannelSet (maxChannels);
2247 returnValue.addBus (isInput, busName, layout,
true);
2254 static bool pluginHasDefaultChannelLayouts (Vst2::AEffect* effect)
2256 if (getSpeakerArrangementWrapper (effect).isValid())
2259 for (
int dir = 0; dir < 2; ++dir)
2261 const bool isInput = (dir == 0);
2262 const int opcode = (isInput ? Vst2::effGetInputProperties : Vst2::effGetOutputProperties);
2263 const int maxChannels = (isInput ? effect->numInputs : effect->numOutputs);
2267 for (
int ch = 0; ch < maxChannels; ch += channels)
2269 Vst2::VstPinProperties pinProps;
2271 if (effect->dispatcher (effect, opcode, ch, 0, &pinProps, 0.0f) == 0)
2274 if ((pinProps.flags & Vst2::kVstPinUseSpeaker) != 0)
2277 channels = (pinProps.flags & Vst2::kVstPinIsStereo) != 0 ? 2 : 1;
2284 struct SpeakerArrangements
2286 const Vst2::VstSpeakerArrangement* in;
2287 const Vst2::VstSpeakerArrangement* out;
2289 bool isValid() const noexcept {
return in !=
nullptr && out !=
nullptr; }
2292 static SpeakerArrangements getSpeakerArrangementWrapper (Vst2::AEffect* effect)
2298 if (effect->numInputs == 0)
2299 return {
nullptr,
nullptr };
2301 SpeakerArrangements result {
nullptr,
nullptr };
2302 const auto dispatchResult = effect->dispatcher (effect,
2303 Vst2::effGetSpeakerArrangement,
2309 if (dispatchResult != 0)
2312 return {
nullptr,
nullptr };
2315 template <
typename Member,
typename Value>
2316 void setFromOptional (Member& target, Optional<Value> opt, int32_t flag)
2320 target =
static_cast<Member
> (*opt);
2321 vstHostTime.flags |= flag;
2325 vstHostTime.flags &= ~flag;
2330 template <
typename FloatType>
2331 void processAudio (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages,
2332 AudioBuffer<FloatType>& tmpBuffer,
2333 HeapBlock<FloatType*>& channelBuffer,
2334 bool processBlockBypassedCalled)
2336 if (vstSupportsBypass)
2338 updateBypass (processBlockBypassedCalled);
2340 else if (processBlockBypassedCalled)
2343 AudioProcessor::processBlockBypassed (buffer, midiMessages);
2347 auto numSamples = buffer.getNumSamples();
2348 auto numChannels = buffer.getNumChannels();
2352 if (
auto* currentPlayHead = getPlayHead())
2354 if (
const auto position = currentPlayHead->getPosition())
2356 if (
const auto samplePos = position->getTimeInSamples())
2357 vstHostTime.samplePos = (
double) *samplePos;
2361 if (
auto sig = position->getTimeSignature())
2363 vstHostTime.flags |= Vst2::kVstTimeSigValid;
2364 vstHostTime.timeSigNumerator = sig->numerator;
2365 vstHostTime.timeSigDenominator = sig->denominator;
2369 vstHostTime.flags &= ~Vst2::kVstTimeSigValid;
2372 setFromOptional (vstHostTime.ppqPos, position->getPpqPosition(), Vst2::kVstPpqPosValid);
2373 setFromOptional (vstHostTime.barStartPos, position->getPpqPositionOfLastBarStart(), Vst2::kVstBarsValid);
2374 setFromOptional (vstHostTime.nanoSeconds, position->getHostTimeNs(), Vst2::kVstNanosValid);
2375 setFromOptional (vstHostTime.tempo, position->getBpm(), Vst2::kVstTempoValid);
2377 int32 newTransportFlags = 0;
2378 if (position->getIsPlaying()) newTransportFlags |= Vst2::kVstTransportPlaying;
2379 if (position->getIsRecording()) newTransportFlags |= Vst2::kVstTransportRecording;
2381 if (newTransportFlags != (vstHostTime.flags & (Vst2::kVstTransportPlaying
2382 | Vst2::kVstTransportRecording)))
2383 vstHostTime.flags = (vstHostTime.flags & ~(Vst2::kVstTransportPlaying | Vst2::kVstTransportRecording)) | newTransportFlags | Vst2::kVstTransportChanged;
2385 vstHostTime.flags &= ~Vst2::kVstTransportChanged;
2387 const auto optionalFrameRate = [fr = position->getFrameRate()]() -> Optional<Vst2::VstInt32>
2389 if (! fr.hasValue())
2392 switch (fr->getBaseRate())
2394 case 24:
return fr->isPullDown() ? Vst2::kVstSmpte239fps : Vst2::kVstSmpte24fps;
2395 case 25:
return fr->isPullDown() ? Vst2::kVstSmpte249fps : Vst2::kVstSmpte25fps;
2396 case 30:
return fr->isPullDown() ? (fr->isDrop() ? Vst2::kVstSmpte2997dfps : Vst2::kVstSmpte2997fps)
2397 : (fr->isDrop() ? Vst2::kVstSmpte30dfps : Vst2::kVstSmpte30fps);
2398 case 60:
return fr->isPullDown() ? Vst2::kVstSmpte599fps : Vst2::kVstSmpte60fps;
2404 vstHostTime.flags |= optionalFrameRate ? Vst2::kVstSmpteValid : 0;
2405 vstHostTime.smpteFrameRate = optionalFrameRate.orFallback (Vst2::VstSmpteFrameRate{});
2406 const auto effectiveRate = position->getFrameRate().hasValue() ? position->getFrameRate()->getEffectiveRate() : 0.0;
2407 vstHostTime.smpteOffset = (int32) (position->getTimeInSeconds().orFallback (0.0) * 80.0 * effectiveRate + 0.5);
2409 if (
const auto loop = position->getLoopPoints())
2411 vstHostTime.flags |= Vst2::kVstCyclePosValid;
2412 vstHostTime.cycleStartPos = loop->ppqStart;
2413 vstHostTime.cycleEndPos = loop->ppqEnd;
2417 vstHostTime.flags &= ~Vst2::kVstCyclePosValid;
2420 if (position->getIsLooping())
2421 vstHostTime.flags |= Vst2::kVstTransportCycleActive;
2423 vstHostTime.flags &= ~Vst2::kVstTransportCycleActive;
2427 vstHostTime.nanoSeconds = getVSTHostTimeNanoseconds();
2429 if (wantsMidiMessages)
2431 midiEventsToSend.clear();
2432 midiEventsToSend.ensureSize (1);
2434 for (
const auto metadata : midiMessages)
2435 midiEventsToSend.addEvent (metadata.
data, metadata.numBytes,
2436 jlimit (0, numSamples - 1, metadata.samplePosition));
2438 vstEffect->dispatcher (vstEffect, Vst2::effProcessEvents, 0, 0, midiEventsToSend.events, 0);
2444 auto maxChannels =
jmax (vstEffect->numInputs, vstEffect->numOutputs);
2445 auto channels = channelBuffer.get();
2447 if (numChannels < maxChannels)
2449 if (numSamples > tmpBuffer.getNumSamples())
2450 tmpBuffer.setSize (tmpBuffer.getNumChannels(), numSamples);
2455 for (
int ch = 0; ch < maxChannels; ++ch)
2456 channels[ch] = (ch < numChannels ? buffer.getWritePointer (ch) : tmpBuffer.getWritePointer (ch));
2459 AudioBuffer<FloatType> processBuffer (channels, maxChannels, numSamples);
2461 invokeProcessFunction (processBuffer, numSamples);
2467 for (
int i = getTotalNumOutputChannels(); --i >= 0;)
2468 buffer.clear (i, 0, buffer.getNumSamples());
2475 midiMessages.swapWith (incomingMidi);
2476 incomingMidi.clear();
2481 inline void invokeProcessFunction (AudioBuffer<float>& buffer, int32 sampleFrames)
2483 if ((vstEffect->flags & Vst2::effFlagsCanReplacing) != 0)
2485 vstEffect->processReplacing (vstEffect, tempChannelPointers[0].getArrayOfModifiableWritePointers (buffer),
2486 tempChannelPointers[1].getArrayOfModifiableWritePointers (buffer), sampleFrames);
2490 outOfPlaceBuffer.setSize (vstEffect->numOutputs, sampleFrames);
2491 outOfPlaceBuffer.clear();
2493 vstEffect->process (vstEffect, tempChannelPointers[0].getArrayOfModifiableWritePointers (buffer),
2494 tempChannelPointers[1].getArrayOfModifiableWritePointers (outOfPlaceBuffer), sampleFrames);
2496 for (
int i = vstEffect->numOutputs; --i >= 0;)
2497 buffer.copyFrom (i, 0, outOfPlaceBuffer.getReadPointer (i), sampleFrames);
2501 inline void invokeProcessFunction (AudioBuffer<double>& buffer, int32 sampleFrames)
2503 vstEffect->processDoubleReplacing (vstEffect, tempChannelPointers[0].getArrayOfModifiableWritePointers (buffer),
2504 tempChannelPointers[1].getArrayOfModifiableWritePointers (buffer), sampleFrames);
2508 bool restoreProgramSettings (
const fxProgram*
const prog)
2510 if (compareMagic (prog->chunkMagic,
"CcnK")
2511 && compareMagic (prog->fxMagic,
"FxCk"))
2513 changeProgramName (getCurrentProgram(), prog->prgName);
2515 for (
int i = 0; i < fxbSwap (prog->numParams); ++i)
2516 if (
auto* param = getParameters()[i])
2517 param->setValue (fxbSwapFloat (prog->params[i]));
2525 String getTextForOpcode (
const int index,
const int opcode)
const
2527 if (vstEffect ==
nullptr)
2530 jassert (index >= 0 && index < vstEffect->numParams);
2531 char nm[256] = { 0 };
2532 dispatch (opcode, index, 0, nm, 0);
2533 return String::createStringFromData (nm, (
int)
sizeof (nm)).trim();
2536 String getCurrentProgramName()
2540 if (vstEffect !=
nullptr)
2543 char nm[256] = { 0 };
2544 dispatch (Vst2::effGetProgramName, 0, 0, nm, 0);
2545 progName = String::createStringFromData (nm, (
int)
sizeof (nm)).trim();
2548 const int index = getCurrentProgram();
2550 if (index >= 0 && programNames[index].isEmpty())
2552 while (programNames.size() < index)
2553 programNames.add (String());
2555 programNames.set (index, progName);
2562 void setParamsInProgramBlock (fxProgram* prog)
2564 auto numParams = getParameters().size();
2566 prog->chunkMagic = fxbName (
"CcnK");
2568 prog->fxMagic = fxbName (
"FxCk");
2569 prog->version = fxbSwap (fxbVersionNum);
2570 prog->fxID = fxbSwap (getUID());
2571 prog->fxVersion = fxbSwap (getVersionNumber());
2572 prog->numParams = fxbSwap (numParams);
2574 getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1);
2576 for (
int i = 0; i < numParams; ++i)
2577 if (
auto* param = getParameters()[i])
2578 prog->params[i] = fxbSwapFloat (param->getValue());
2581 void updateStoredProgramNames()
2583 if (vstEffect !=
nullptr && getNumPrograms() > 0)
2585 char nm[256] = { 0 };
2588 if (dispatch (Vst2::effGetProgramNameIndexed, 0, -1, nm, 0) == 0)
2590 auto oldProgram = getCurrentProgram();
2591 MemoryBlock oldSettings;
2592 createTempParameterStore (oldSettings);
2594 for (
int i = 0; i < getNumPrograms(); ++i)
2596 setCurrentProgram (i);
2597 getCurrentProgramName();
2600 setCurrentProgram (oldProgram);
2601 restoreFromTempParameterStore (oldSettings);
2606 void handleMidiFromPlugin (
const Vst2::VstEvents* events)
2608 if (events !=
nullptr)
2611 VSTMidiEventList::addEventsToMidiBuffer (events, incomingMidi);
2616 void createTempParameterStore (MemoryBlock& dest)
2618 auto numParameters = getParameters().size();
2619 dest.setSize (64 + 4 * (
size_t) numParameters);
2622 getCurrentProgramName().copyToUTF8 ((
char*) dest.getData(), 63);
2624 auto p = unalignedPointerCast<float*> (((
char*) dest.getData()) + 64);
2626 for (
int i = 0; i < numParameters; ++i)
2627 if (
auto* param = getParameters()[i])
2628 p[i] = param->getValue();
2631 void restoreFromTempParameterStore (
const MemoryBlock& m)
2633 changeProgramName (getCurrentProgram(), (
const char*) m.getData());
2635 auto p = unalignedPointerCast<float*> (((
char*) m.getData()) + 64);
2636 auto numParameters = getParameters().size();
2638 for (
int i = 0; i < numParameters; ++i)
2639 if (
auto* param = getParameters()[i])
2640 param->setValue (p[i]);
2646 return (pointer_sized_int) (
void*) &vstModule->parentDirFSSpec;
2648 return (pointer_sized_int) (
pointer_sized_uint) vstModule->fullParentDirectoryPathName.toRawUTF8();
2653 int getVersionNumber() const noexcept {
return vstEffect !=
nullptr ? vstEffect->version : 0; }
2655 String getVersion()
const
2657 auto v = (
unsigned int) dispatch (Vst2::effGetVendorVersion, 0, 0,
nullptr, 0);
2661 if (v == 0 || (
int) v == -1)
2662 v = (
unsigned int) getVersionNumber();
2669 unsigned int major = 0, minor = 0, bugfix = 0, build = 0;
2678 minor = (v % 1000) / 100;
2679 bugfix = (v % 100) / 10;
2682 else if (v < 0x10000)
2684 major = (v / 10000);
2685 minor = (v % 10000) / 1000;
2686 bugfix = (v % 1000) / 100;
2687 build = (v % 100) / 10;
2689 else if (v < 0x650000)
2691 major = (v >> 16) & 0xff;
2692 minor = (v >> 8) & 0xff;
2693 bugfix = (v >> 0) & 0xff;
2697 major = (v / 10000000);
2698 minor = (v % 10000000) / 100000;
2699 bugfix = (v % 100000) / 1000;
2703 s << (
int) major <<
'.' << (
int) minor <<
'.' << (
int) bugfix <<
'.' << (
int) build;
2709 const char* getCategory()
const
2711 switch (getVstCategory())
2713 case Vst2::kPlugCategEffect:
return "Effect";
2714 case Vst2::kPlugCategSynth:
return "Synth";
2715 case Vst2::kPlugCategAnalysis:
return "Analysis";
2716 case Vst2::kPlugCategMastering:
return "Mastering";
2717 case Vst2::kPlugCategSpacializer:
return "Spacial";
2718 case Vst2::kPlugCategRoomFx:
return "Reverb";
2719 case Vst2::kPlugSurroundFx:
return "Surround";
2720 case Vst2::kPlugCategRestoration:
return "Restoration";
2721 case Vst2::kPlugCategGenerator:
return "Tone generation";
2722 case Vst2::kPlugCategOfflineProcess:
return "Offline Process";
2723 case Vst2::kPlugCategShell:
return "Shell";
2724 case Vst2::kPlugCategUnknown:
return "Unknown";
2725 case Vst2::kPlugCategMaxCount:
2732 void setPower (
const bool on)
2734 dispatch (Vst2::effMainsChanged, 0, on ? 1 : 0, nullptr, 0);
2739 void updateBypass (
bool processBlockBypassedCalled)
2741 if (processBlockBypassedCalled)
2743 if (approximatelyEqual (bypassParam->getValue(), 0.0f) || ! lastProcessBlockCallWasBypass)
2744 bypassParam->setValue (1.0f);
2748 if (lastProcessBlockCallWasBypass)
2749 bypassParam->setValue (0.0f);
2752 lastProcessBlockCallWasBypass = processBlockBypassedCalled;
2759#if ! (JUCE_IOS || JUCE_ANDROID)
2760struct VSTPluginWindow;
2761static Array<VSTPluginWindow*> activeVSTWindows;
2764struct VSTPluginWindow final :
public AudioProcessorEditor,
2766 private ComponentMovementWatcher,
2771 VSTPluginWindow (VSTPluginInstance& plug)
2772 : AudioProcessorEditor (&plug),
2774 ComponentMovementWatcher (this),
2778 #if JUCE_LINUX || JUCE_BSD
2779 pluginWindow = None;
2782 ignoreUnused (recursiveResize, pluginRefusesToResize, alreadyInside);
2784 cocoaWrapper.reset (
new NSViewComponentWithParent (plugin));
2785 addAndMakeVisible (cocoaWrapper.get());
2788 activeVSTWindows.add (
this);
2790 Vst2::ERect* rect =
nullptr;
2791 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
2793 if (rect !=
nullptr)
2794 updateSizeFromEditor (rect->right - rect->left, rect->bottom - rect->top);
2796 updateSizeFromEditor (1, 1);
2802 addAndMakeVisible (embeddedComponent);
2806 ~VSTPluginWindow()
override
2808 activeVSTWindows.removeFirstMatchingValue (
this);
2810 closePluginWindow();
2813 cocoaWrapper.reset();
2816 plugin.editorBeingDeleted (
this);
2821 Rectangle<int> vstToComponentRect (Component& editor,
const Rectangle<int>& vr)
const
2823 return editor.getLocalArea (
nullptr, vr / (nativeScaleFactor * getDesktopScaleFactor()));
2826 Rectangle<int> componentToVstRect (Component& editor,
const Rectangle<int>& vr)
const
2828 if (
auto* tl = editor.getTopLevelComponent())
2829 return tl->getLocalArea (&editor, vr) * nativeScaleFactor * tl->getDesktopScaleFactor();
2834 bool updateSizeFromEditor (
int w,
int h)
2836 const auto correctedBounds = vstToComponentRect (*
this, { w, h });
2837 setSize (correctedBounds.getWidth(), correctedBounds.getHeight());
2840 if (cocoaWrapper !=
nullptr)
2841 cocoaWrapper->setSize (correctedBounds.getWidth(), correctedBounds.getHeight());
2848 void paint (Graphics& g)
override
2850 g.fillAll (Colours::black);
2853 void visibilityChanged()
override
2856 openPluginWindow ((NSView*) cocoaWrapper->getView());
2858 closePluginWindow();
2861 void childBoundsChanged (Component*)
override
2863 auto w = cocoaWrapper->getWidth();
2864 auto h = cocoaWrapper->getHeight();
2866 if (w != getWidth() || h != getHeight())
2870 void parentHierarchyChanged()
override { visibilityChanged(); }
2872 float getEffectiveScale()
const
2874 return nativeScaleFactor * userScaleFactor;
2877 void paint (Graphics& g)
override
2879 #if JUCE_LINUX || JUCE_BSD
2882 if (pluginWindow != 0)
2884 auto clip = componentToVstRect (*
this, g.getClipBounds().toNearestInt());
2886 X11Symbols::getInstance()->xClearArea (display, pluginWindow, clip.getX(), clip.getY(),
2887 static_cast<unsigned int> (clip.getWidth()),
2888 static_cast<unsigned int> (clip.getHeight()), True);
2894 g.fillAll (Colours::black);
2898 void componentMovedOrResized (
bool ,
bool )
override
2900 if (recursiveResize)
2903 if (getPeer() !=
nullptr)
2905 const ScopedValueSetter<bool> recursiveResizeSetter (recursiveResize,
true);
2908 embeddedComponent.setBounds (getLocalBounds());
2909 #elif JUCE_LINUX || JUCE_BSD
2910 const auto pos = componentToVstRect (*
this, getLocalBounds());
2912 if (pluginWindow != 0)
2914 auto* symbols = X11Symbols::getInstance();
2915 symbols->xMoveResizeWindow (display,
2919 (
unsigned int) pos.getWidth(),
2920 (
unsigned int) pos.getHeight());
2921 symbols->xMapRaised (display, pluginWindow);
2922 symbols->xFlush (display);
2928 using ComponentMovementWatcher::componentMovedOrResized;
2930 void componentVisibilityChanged()
override
2934 else if (! shouldAvoidDeletingWindow())
2935 closePluginWindow();
2937 setContentScaleFactor();
2939 #if JUCE_LINUX || JUCE_BSD
2940 MessageManager::callAsync ([safeThis = SafePointer<VSTPluginWindow> {
this }]
2942 if (safeThis !=
nullptr)
2943 safeThis->componentMovedOrResized (
true,
true);
2946 componentMovedOrResized (
true,
true);
2950 using ComponentMovementWatcher::componentVisibilityChanged;
2952 void componentPeerChanged()
override
2954 closePluginWindow();
2956 if (getPeer() !=
nullptr)
2959 componentMovedOrResized (
true,
true);
2963 void setContentScaleFactor()
2965 if (pluginRespondsToDPIChanges)
2966 dispatch (Vst2::effVendorSpecific,
2967 (
int) ByteOrder::bigEndianInt (
"PreS"),
2968 (
int) ByteOrder::bigEndianInt (
"AeCs"),
2969 nullptr, getEffectiveScale());
2973 void setScaleFactor (
float scale)
override
2975 userScaleFactor = scale;
2978 setContentScaleFactor();
2987 bool keyStateChanged (
bool)
override {
return pluginWantsKeys; }
2988 bool keyPressed (
const juce::KeyPress&)
override {
return pluginWantsKeys; }
2991 void timerCallback()
override
2996 if (--sizeCheckCount <= 0)
2998 sizeCheckCount = 10;
2999 checkPluginWindowSize();
3003 static bool reentrantGuard =
false;
3005 if (! reentrantGuard)
3007 reentrantGuard =
true;
3012 ScopedThreadDPIAwarenessSetter scope (getPluginHWND());
3014 plugin.dispatch (Vst2::effEditIdle, 0, 0,
nullptr, 0);
3016 reentrantGuard =
false;
3019 #if JUCE_LINUX || JUCE_BSD
3020 if (pluginWindow == 0)
3022 updatePluginWindowHandle();
3024 if (pluginWindow != 0)
3025 componentMovedOrResized (
true,
true);
3032 void mouseDown ([[maybe_unused]]
const MouseEvent& e)
override
3034 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD
3039 void broughtToFront()
override
3041 if (activeVSTWindows.removeFirstMatchingValue (
this) != -1)
3042 activeVSTWindows.add (
this);
3045 dispatch (Vst2::effEditTop, 0, 0,
nullptr, 0);
3053 bool shouldAvoidDeletingWindow()
const
3055 return plugin.getPluginDescription()
3056 .manufacturerName.containsIgnoreCase (
"Loud Technologies");
3061 bool shouldRepaintCarbonWindowWhenCreated()
3063 return ! plugin.getName().containsIgnoreCase (
"izotope");
3068 void openPluginWindow (
void* parentWindow)
3070 if (isOpen || parentWindow ==
nullptr)
3075 Vst2::ERect* rect =
nullptr;
3076 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
3077 dispatch (Vst2::effEditOpen, 0, 0, parentWindow, 0);
3080 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
3081 dispatch (Vst2::effGetProgram, 0, 0,
nullptr, 0);
3084 pluginWantsKeys = (dispatch (Vst2::effKeysRequired, 0, 0,
nullptr, 0) == 0);
3087 int w = 250, h = 150;
3089 if (rect !=
nullptr)
3091 w = rect->right - rect->left;
3092 h = rect->bottom - rect->top;
3094 if (w == 0 || h == 0)
3104 updateSizeFromEditor (w, h);
3110 void openPluginWindow()
3115 JUCE_VST_LOG (
"Opening VST UI: " + plugin.getName());
3118 pluginRespondsToDPIChanges = plugin.pluginCanDo (
"supportsViewDpiScaling") > 0;
3120 setContentScaleFactor();
3122 Vst2::ERect* rect =
nullptr;
3124 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
3127 auto* handle = embeddedComponent.getHWND();
3129 auto* handle = getWindowHandle();
3131 dispatch (Vst2::effEditOpen, 0, 0, handle, 0);
3132 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
3133 dispatch (Vst2::effGetProgram, 0, 0,
nullptr, 0);
3135 pluginWantsKeys = (dispatch (Vst2::effKeysRequired, 0, 0,
nullptr, 0) == 0);
3138 originalWndProc =
nullptr;
3139 auto* pluginHWND = getPluginHWND();
3141 if (pluginHWND ==
nullptr)
3148 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4244)
3150 if (! pluginWantsKeys)
3152 originalWndProc = (
void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
3153 SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc);
3156 JUCE_END_IGNORE_WARNINGS_MSVC
3161 ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
3162 GetWindowRect (pluginHWND, &r);
3165 auto w = (
int) (r.right - r.left);
3166 auto h = (
int) (r.bottom - r.top);
3168 if (rect !=
nullptr)
3170 auto rw = rect->right - rect->left;
3171 auto rh = rect->bottom - rect->top;
3173 if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && (! isWithin (w, rw, 2) || ! isWithin (h, rh, 2)))
3174 || ((w == 0 && rw > 0) || (h == 0 && rh > 0)))
3177 if (std::abs (rw - w) > 350 || std::abs (rh - h) > 350)
3179 ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
3181 SetWindowPos (pluginHWND,
nullptr,
3183 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
3185 GetWindowRect (pluginHWND, &r);
3187 w = r.right - r.left;
3188 h = r.bottom - r.top;
3190 pluginRefusesToResize = (w != rw) || (h != rh);
3197 #elif JUCE_LINUX || JUCE_BSD
3198 updatePluginWindowHandle();
3200 int w = 250, h = 150;
3202 if (rect !=
nullptr)
3204 w = rect->right - rect->left;
3205 h = rect->bottom - rect->top;
3207 if (w == 0 || h == 0)
3214 if (pluginWindow != 0)
3215 X11Symbols::getInstance()->xMapRaised (display, pluginWindow);
3222 updateSizeFromEditor (w, h);
3225 checkPluginWindowSize();
3234 void closePluginWindow()
3242 JUCE_VST_LOG (
"Closing VST UI: " + plugin.getName());
3244 dispatch (Vst2::effEditClose, 0, 0,
nullptr, 0);
3248 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4244)
3249 auto* pluginHWND = getPluginHWND();
3251 if (originalWndProc !=
nullptr && pluginHWND !=
nullptr && IsWindow (pluginHWND))
3252 SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
3253 JUCE_END_IGNORE_WARNINGS_MSVC
3255 originalWndProc =
nullptr;
3256 #elif JUCE_LINUX || JUCE_BSD
3263 pointer_sized_int dispatch (
const int opcode,
const int index,
const int value,
void*
const ptr,
float opt)
3265 return plugin.dispatch (opcode, index, value, ptr, opt);
3270 bool isWindowSizeCorrectForPlugin (
int w,
int h)
3272 if (pluginRefusesToResize)
3275 const auto converted = vstToComponentRect (*
this, { w, h });
3276 return (isWithin (converted.getWidth(), getWidth(), 5) && isWithin (converted.getHeight(), getHeight(), 5));
3281 Vst2::ERect* rect =
nullptr;
3282 dispatch (Vst2::effEditGetRect, 0, 0, &rect, 0);
3284 auto w = rect->right - rect->left;
3285 auto h = rect->bottom - rect->top;
3287 if (! isWindowSizeCorrectForPlugin (w, h))
3289 updateSizeFromEditor (w, h);
3290 embeddedComponent.updateHWNDBounds();
3295 void checkPluginWindowSize()
3297 if (! pluginRespondsToDPIChanges)
3302 static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam)
3304 for (
int i = activeVSTWindows.size(); --i >= 0;)
3306 Component::SafePointer<VSTPluginWindow> w (activeVSTWindows[i]);
3308 auto* pluginHWND = w->getPluginHWND();
3310 if (w !=
nullptr && pluginHWND == hW)
3312 if (message == WM_CHAR
3313 || message == WM_KEYDOWN
3314 || message == WM_SYSKEYDOWN
3315 || message == WM_KEYUP
3316 || message == WM_SYSKEYUP
3317 || message == WM_APPCOMMAND)
3319 SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(),
3320 message, wParam, lParam);
3324 return CallWindowProc ((WNDPROC) w->originalWndProc,
3326 message, wParam, lParam);
3330 return DefWindowProc (hW, message, wParam, lParam);
3334 #if JUCE_LINUX || JUCE_BSD
3335 void updatePluginWindowHandle()
3337 pluginWindow = getChildWindow ((Window) getWindowHandle());
3345 void resized()
override
3351 VSTPluginInstance& plugin;
3352 float userScaleFactor = 1.0f;
3353 bool isOpen =
false, recursiveResize =
false;
3354 bool pluginWantsKeys =
false, pluginRefusesToResize =
false, alreadyInside =
false;
3357 bool pluginRespondsToDPIChanges =
false;
3359 float nativeScaleFactor = 1.0f;
3361 struct ScaleNotifierCallback
3363 VSTPluginWindow& window;
3365 void operator() (
float platformScale)
const
3367 MessageManager::callAsync ([ref = Component::SafePointer<VSTPluginWindow> (&window), platformScale]
3369 if (
auto* r =
ref.getComponent())
3371 r->nativeScaleFactor = platformScale;
3372 r->setContentScaleFactor();
3376 r->embeddedComponent.updateHWNDBounds();
3378 r->componentMovedOrResized (true, true);
3384 NativeScaleFactorNotifier scaleNotifier {
this, ScaleNotifierCallback { *
this } };
3387 struct ViewComponent final :
public HWNDComponent
3392 inner.addToDesktop (0);
3394 if (
auto* peer = inner.getPeer())
3395 setHWND (peer->getNativeHandle());
3398 void paint (Graphics& g)
override { g.fillAll (Colours::black); }
3401 struct Inner final :
public Component
3403 Inner() { setOpaque (
true); }
3404 void paint (Graphics& g)
override { g.fillAll (Colours::black); }
3410 HWND getPluginHWND()
const
3412 return GetWindow ((HWND) embeddedComponent.getHWND(), GW_CHILD);
3415 ViewComponent embeddedComponent;
3416 void* originalWndProc = {};
3417 int sizeCheckCount = 0;
3418 #elif JUCE_LINUX || JUCE_BSD
3419 ::Display* display = XWindowSystem::getInstance()->getDisplay();
3420 Window pluginWindow = 0;
3423 static constexpr auto nativeScaleFactor = 1.0f;
3431JUCE_END_IGNORE_WARNINGS_MSVC
3434AudioProcessorEditor* VSTPluginInstance::createEditor()
3436 #if JUCE_IOS || JUCE_ANDROID
3439 return hasEditor() ?
new VSTPluginWindow (*
this)
3444bool VSTPluginInstance::updateSizeFromEditor ([[maybe_unused]]
int w, [[maybe_unused]]
int h)
3446 #if ! JUCE_IOS && ! JUCE_ANDROID
3447 if (
auto* editor =
dynamic_cast<VSTPluginWindow*
> (getActiveEditor()))
3448 return editor->updateSizeFromEditor (w, h);
3456static pointer_sized_int VSTCALLBACK audioMaster (Vst2::AEffect* effect, int32 opcode, int32 index, pointer_sized_int value,
void* ptr,
float opt)
3458 if (effect !=
nullptr)
3459 if (
auto* instance = (VSTPluginInstance*) (effect->resvd2))
3460 return instance->handleCallback (opcode, index, value, ptr, opt);
3462 return VSTPluginInstance::handleGeneralCallback (opcode, index, value, ptr, opt);
3466VSTPluginFormat::VSTPluginFormat() {}
3467VSTPluginFormat::~VSTPluginFormat() {}
3471 if (
auto p =
format.createInstanceFromDescription (desc, 44100.0, 512))
3473 if (
auto instance =
dynamic_cast<VSTPluginInstance*
> (p.release()))
3476 if (instance->vstModule->resFileId != 0)
3477 UseResFile (instance->vstModule->resFileId);
3480 instance->fillInPluginDescription (desc);
3490void VSTPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results,
3491 const String& fileOrIdentifier)
3493 if (! fileMightContainThisPluginType (fileOrIdentifier))
3496 PluginDescription desc;
3497 desc.fileOrIdentifier = fileOrIdentifier;
3498 desc.uniqueId = desc.deprecatedUid = 0;
3500 auto instance = createAndUpdateDesc (*
this, desc);
3502 if (instance ==
nullptr)
3505 if (instance->getVstCategory() != Vst2::kPlugCategShell)
3508 results.add (
new PluginDescription (desc));
3510 instance->dispatch (Vst2::effOpen, 0, 0,
nullptr, 0);
3517 char shellEffectName [256] = { 0 };
3518 auto uid = (
int) instance->dispatch (Vst2::effShellGetNextPlugin, 0, 0, shellEffectName, 0);
3523 desc.uniqueId = desc.deprecatedUid = uid;
3524 desc.name = shellEffectName;
3526 aboutToScanVSTShellPlugin (desc);
3530 if (shellInstance !=
nullptr)
3532 jassert (desc.deprecatedUid == uid);
3533 jassert (desc.uniqueId == uid);
3534 desc.hasSharedContainer =
true;
3535 desc.name = shellEffectName;
3537 if (! arrayContainsPlugin (results, desc))
3538 results.add (
new PluginDescription (desc));
3544void VSTPluginFormat::createPluginInstance (
const PluginDescription& desc,
3545 double sampleRate,
int blockSize,
3546 PluginCreationCallback callback)
3550 if (fileMightContainThisPluginType (desc.fileOrIdentifier))
3552 File file (desc.fileOrIdentifier);
3554 auto previousWorkingDirectory = File::getCurrentWorkingDirectory();
3555 file.getParentDirectory().setAsCurrentWorkingDirectory();
3557 if (
auto module = ModuleHandle::findOrCreateModule (file))
3559 shellUIDToCreate = desc.uniqueId != 0 ? desc.uniqueId : desc.deprecatedUid;
3561 result.
reset (VSTPluginInstance::create (module, sampleRate, blockSize));
3563 if (result !=
nullptr && ! result->initialiseEffect (sampleRate, blockSize))
3567 previousWorkingDirectory.setAsCurrentWorkingDirectory();
3572 if (result ==
nullptr)
3573 errorMsg =
TRANS (
"Unable to load XXX plug-in file").replace (
"XXX",
"VST-2");
3575 callback (std::move (result), errorMsg);
3578bool VSTPluginFormat::requiresUnblockedMessageThreadDuringCreation (
const PluginDescription&)
const
3583bool VSTPluginFormat::fileMightContainThisPluginType (
const String& fileOrIdentifier)
3585 auto f = File::createFileWithoutCheckingPath (fileOrIdentifier);
3587 #if JUCE_MAC || JUCE_IOS
3588 return f.isDirectory() && f.hasFileExtension (
".vst");
3590 return f.existsAsFile() && f.hasFileExtension (
".dll");
3591 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
3592 return f.existsAsFile() && f.hasFileExtension (
".so");
3596String VSTPluginFormat::getNameOfPluginFromIdentifier (
const String& fileOrIdentifier)
3598 return fileOrIdentifier;
3601bool VSTPluginFormat::pluginNeedsRescanning (
const PluginDescription& desc)
3603 return File (desc.fileOrIdentifier).getLastModificationTime() != desc.lastFileModTime;
3606bool VSTPluginFormat::doesPluginStillExist (
const PluginDescription& desc)
3608 return File (desc.fileOrIdentifier).exists();
3611StringArray VSTPluginFormat::searchPathsForPlugins (
const FileSearchPath& directoriesToSearch,
const bool recursive,
bool)
3613 StringArray results;
3615 for (
int j = 0; j < directoriesToSearch.getNumPaths(); ++j)
3616 recursiveFileSearch (results, directoriesToSearch [j], recursive);
3621void VSTPluginFormat::recursiveFileSearch (StringArray& results,
const File& dir,
const bool recursive)
3625 for (
const auto& iter : RangedDirectoryIterator (dir, false,
"*", File::findFilesAndDirectories))
3627 auto f = iter.getFile();
3628 bool isPlugin =
false;
3630 if (fileMightContainThisPluginType (f.getFullPathName()))
3633 results.add (f.getFullPathName());
3636 if (recursive && (! isPlugin) && f.isDirectory())
3637 recursiveFileSearch (results, f,
true);
3641FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch()
3644 return FileSearchPath (
"~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST");
3645 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
3646 return FileSearchPath (SystemStats::getEnvironmentVariable (
"VST_PATH",
3647 "/usr/lib/vst;/usr/local/lib/vst;~/.vst")
3648 .replace (
":",
";"));
3650 auto programFiles = File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName();
3652 FileSearchPath paths;
3653 paths.add (WindowsRegistry::getValue (
"HKEY_LOCAL_MACHINE\\Software\\VST\\VSTPluginsPath"));
3654 paths.addIfNotAlreadyThere (programFiles +
"\\Steinberg\\VstPlugins");
3655 paths.addIfNotAlreadyThere (programFiles +
"\\VstPlugins");
3656 paths.removeRedundantPaths();
3660 CFUniquePtr<CFURLRef> relativePluginDir (CFBundleCopyBuiltInPlugInsURL (CFBundleGetMainBundle()));
3661 CFUniquePtr<CFURLRef> pluginDir (CFURLCopyAbsoluteURL (relativePluginDir.get()));
3663 CFUniquePtr<CFStringRef> path (CFURLCopyFileSystemPath (pluginDir.get(), kCFURLPOSIXPathStyle));
3664 FileSearchPath retval (String (CFStringGetCStringPtr (path.get(), kCFStringEncodingUTF8)));
3669const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
3671 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3672 if (vst->vstModule !=
nullptr)
3673 return vst->vstModule->vstXml.get();
3678bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin,
const void* data,
size_t dataSize)
3680 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3681 return vst->loadFromFXBFile (data, dataSize);
3686bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest,
bool asFXB)
3688 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3689 return vst->saveToFXBFile (dest, asFXB);
3694bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result,
bool isPreset)
3696 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3697 return vst->getChunkData (result, isPreset, 128);
3702bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin,
const void* data,
int size,
bool isPreset)
3704 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3705 return vst->setChunkData (data, size, isPreset);
3710AudioPluginInstance* VSTPluginFormat::createCustomVSTFromMainCall (
void* entryPointFunction,
3711 double initialSampleRate,
int initialBufferSize)
3713 ModuleHandle::Ptr
module = new ModuleHandle (File(), (MainCall) entryPointFunction);
3719 if (result !=
nullptr)
3720 if (result->initialiseEffect (initialSampleRate, initialBufferSize))
3721 return result.release();
3727void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunctions* functions)
3731 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3735AudioPluginInstance* VSTPluginFormat::getPluginInstanceFromVstEffectInterface (
void* aEffect)
3737 if (
auto* vstAEffect =
reinterpret_cast<Vst2::AEffect*
> (aEffect))
3738 if (
auto* instanceVST =
reinterpret_cast<VSTPluginInstance*
> (vstAEffect->resvd2))
3739 return dynamic_cast<AudioPluginInstance*
> (instanceVST);
3744pointer_sized_int JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, pointer_sized_int value,
void* ptr,
float opt)
3746 if (
auto* vst =
dynamic_cast<VSTPluginInstance*
> (plugin))
3747 return vst->dispatch (opcode, index, value, ptr, opt);
3752void VSTPluginFormat::aboutToScanVSTShellPlugin (
const PluginDescription&) {}
3756JUCE_END_IGNORE_WARNINGS_GCC_LIKE
3757JUCE_END_IGNORE_WARNINGS_MSVC
Holds a resizable array of primitive or copy-by-value objects.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
static constexpr uint32 bigEndianInt(const void *bytes) noexcept
Turns 4 bytes into a big-endian integer.
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Turns 4 bytes into a little-endian integer.
static Type swapIfLittleEndian(Type value) noexcept
Swaps the byte order of a signed or unsigned integer if the CPU is little-endian.
static constexpr uint16 swap(uint16 value) noexcept
Swaps the upper and lower bytes of a 16-bit integer.
Represents a key press, including any modifier keys that are needed.
An array designed for holding objects.
ObjectClass * add(ObjectClass *newObject)
Appends a new object to the end of the array.
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it,...
A special array for holding a list of strings.
int size() const noexcept
Returns the number of strings in the array.
void trim()
Deletes any whitespace characters from the starts and ends of all the strings.
void add(String stringToAdd)
Appends a string at the end of the array.
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Breaks up a string into tokens and adds them to this array.
A simple class for holding temporary references to a string literal or String.
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
bool endsWithChar(juce_wchar character) const noexcept
Tests whether the string ends with a particular character.
float getFloatValue() const noexcept
Parses this string as a floating point number.
bool startsWithChar(juce_wchar character) const noexcept
Tests whether the string begins with a particular character.
String removeCharacters(StringRef charactersToRemove) const
Returns a version of this string with a set of characters removed.
String retainCharacters(StringRef charactersToRetain) const
Returns a version of this string that only retains a fixed set of characters.
int indexOfWholeWord(StringRef wordToLookFor) const noexcept
Finds an instance of another substring if it exists as a distinct word.
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Replaces all occurrences of a substring with another string.
String replaceSection(int startIndex, int numCharactersToReplace, StringRef stringToInsert) const
Replaces a sub-section of the string with another string.
int getIntValue() const noexcept
Reads the value of the string as a decimal number (up to 32 bits in size).
Used to build a tree of elements representing an XML document.
int getNumChildElements() const noexcept
Returns the number of sub-elements in this element.
XmlElement * getChildByName(StringRef tagNameToLookFor) const noexcept
Returns the first sub-element with a given tag-name.
double getDoubleAttribute(StringRef attributeName, double defaultReturnValue=0.0) const
Returns the value of a named attribute as floating-point.
bool hasAttribute(StringRef attributeName) const noexcept
Checks whether the element contains an attribute with a certain name.
bool hasTagName(StringRef possibleTagName) const noexcept
Tests whether this element has a particular tag name.
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
Returns the value of a named attribute as an integer.
const String & getStringAttribute(StringRef attributeName) const noexcept
Returns the value of a named attribute.
#define TRANS(stringLiteral)
Uses the LocalisedStrings class to translate the given string literal.
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
#define JUCE_ASSERT_MESSAGE_THREAD
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
CriticalSection::ScopedLockType ScopedLock
Automatically locks and unlocks a CriticalSection object.
int pointer_sized_int
A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
signed int int32
A platform-independent 32-bit signed integer type.
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
Attempts to parse some XML text, returning a new XmlElement if it was valid.
void ignoreUnused(Types &&...) noexcept
Handy function for avoiding unused variables warning.
unsigned int pointer_sized_uint
An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it...
Type * addBytesToPointer(Type *basePointer, IntegerType bytes) noexcept
A handy function which adds a number of bytes to any type of pointer and returns the result.
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.