LMMS
Loading...
Searching...
No Matches
juce_VSTPluginFormat.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26#if JUCE_PLUGINHOST_VST
27
28//==============================================================================
29#undef PRAGMA_ALIGN_SUPPORTED
30
31
32#if ! JUCE_MINGW && ! JUCE_MSVC
33 #define __cdecl
34#endif
35
36JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
38
39#define VST_FORCE_DEPRECATED 0
40
41namespace Vst2
42{
43#include "juce_VSTInterface.h"
44}
45
46#include "juce_VSTCommon.h"
47
50
51JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
53
54#include "juce_VSTMidiEventList.h"
55
56#if JUCE_MINGW
57 #ifndef WM_APPCOMMAND
58 #define WM_APPCOMMAND 0x0319
59 #endif
60#elif ! JUCE_WINDOWS
61 static void _fpreset() {}
62 static void _clearfp() {}
63#endif
64
65#ifndef JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
66 #define JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
67#endif
68
69#ifndef JUCE_VST_WRAPPER_INVOKE_MAIN
70 #define JUCE_VST_WRAPPER_INVOKE_MAIN effect = module->moduleMain (&audioMaster);
71#endif
72
73#ifndef JUCE_VST_FALLBACK_HOST_NAME
74 #define JUCE_VST_FALLBACK_HOST_NAME "Juce VST Host"
75#endif
76
77//==============================================================================
78namespace juce
79{
80
81//==============================================================================
82namespace
83{
84 const int fxbVersionNum = 1;
85
86 struct fxProgram
87 {
88 int32 chunkMagic; // 'CcnK'
89 int32 byteSize; // of this chunk, excl. magic + byteSize
90 int32 fxMagic; // 'FxCk'
92 int32 fxID; // fx unique id
93 int32 fxVersion;
94 int32 numParams;
95 char prgName[28];
96 float params[1]; // variable no. of parameters
97 };
98
99 struct fxSet
100 {
101 int32 chunkMagic; // 'CcnK'
102 int32 byteSize; // of this chunk, excl. magic + byteSize
103 int32 fxMagic; // 'FxBk'
105 int32 fxID; // fx unique id
106 int32 fxVersion;
107 int32 numPrograms;
108 char future[128];
109 fxProgram programs[1]; // variable no. of programs
110 };
111
112 struct fxChunkSet
113 {
114 int32 chunkMagic; // 'CcnK'
115 int32 byteSize; // of this chunk, excl. magic + byteSize
116 int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
118 int32 fxID; // fx unique id
119 int32 fxVersion;
120 int32 numPrograms;
121 char future[128];
122 int32 chunkSize;
123 char chunk[8]; // variable
124 };
125
126 struct fxProgramSet
127 {
128 int32 chunkMagic; // 'CcnK'
129 int32 byteSize; // of this chunk, excl. magic + byteSize
130 int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
132 int32 fxID; // fx unique id
133 int32 fxVersion;
134 int32 numPrograms;
135 char name[28];
136 int32 chunkSize;
137 char chunk[8]; // variable
138 };
139
140 // Compares a magic value in either endianness.
141 static bool compareMagic (int32 magic, const char* name) noexcept
142 {
143 return magic == (int32) ByteOrder::littleEndianInt (name)
144 || magic == (int32) ByteOrder::bigEndianInt (name);
145 }
146
147 static int32 fxbName (const char* name) noexcept { return (int32) ByteOrder::littleEndianInt (name); }
148 static int32 fxbSwap (int32 x) noexcept { return (int32) ByteOrder::swapIfLittleEndian ((uint32) x); }
149
150 static float fxbSwapFloat (const float x) noexcept
151 {
152 #ifdef JUCE_LITTLE_ENDIAN
153 union { uint32 asInt; float asFloat; } n;
154 n.asFloat = x;
155 n.asInt = ByteOrder::swap (n.asInt);
156 return n.asFloat;
157 #else
158 return x;
159 #endif
160 }
161}
162
163//==============================================================================
164namespace
165{
166 static double getVSTHostTimeNanoseconds() noexcept
167 {
168 #if JUCE_WINDOWS
169 return timeGetTime() * 1000000.0;
170 #elif JUCE_LINUX || JUCE_BSD || JUCE_IOS || JUCE_ANDROID
171 timeval micro;
172 gettimeofday (&micro, nullptr);
173 return (double) micro.tv_usec * 1000.0;
174 #elif JUCE_MAC
175 UnsignedWide micro;
176 Microseconds (&micro);
177 return micro.lo * 1000.0;
178 #endif
179 }
180
181 static int shellUIDToCreate = 0;
182 static int insideVSTCallback = 0;
183
184 struct IdleCallRecursionPreventer
185 {
186 IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
187 {
188 if (isMessageThread)
189 ++insideVSTCallback;
190 }
191
192 ~IdleCallRecursionPreventer()
193 {
194 if (isMessageThread)
195 --insideVSTCallback;
196 }
197
198 const bool isMessageThread;
199 JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer)
200 };
201
202 #if JUCE_MAC
203 static bool makeFSRefFromPath (FSRef* destFSRef, const String& path)
204 {
205 return FSPathMakeRef (reinterpret_cast<const UInt8*> (path.toRawUTF8()), destFSRef, nullptr) == noErr;
206 }
207 #endif
208}
209
210//==============================================================================
211typedef Vst2::VstEffectInterface* (VSTINTERFACECALL *MainCall) (Vst2::VstHostCallback);
212static pointer_sized_int VSTINTERFACECALL audioMaster (Vst2::VstEffectInterface*, int32, int32, pointer_sized_int, void*, float);
213
214//==============================================================================
215// Change this to disable logging of various VST activities
216#ifndef VST_LOGGING
217 #define VST_LOGGING 1
218#endif
219
220#if VST_LOGGING
221 #define JUCE_VST_LOG(a) Logger::writeToLog(a);
222#else
223 #define JUCE_VST_LOG(a)
224#endif
225
226//==============================================================================
227#if JUCE_LINUX || JUCE_BSD
228
229namespace
230{
231 using EventProcPtr = void (*)(XEvent*);
232
233 Window getChildWindow (Window windowToCheck)
234 {
235 Window rootWindow, parentWindow;
236 Window* childWindows;
237 unsigned int numChildren = 0;
238
239 X11Symbols::getInstance()->xQueryTree (XWindowSystem::getInstance()->getDisplay(),
240 windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
241
242 if (numChildren > 0)
243 return childWindows [0];
244
245 return 0;
246 }
247}
248
249#endif
250
251//==============================================================================
252class VSTXMLInfo
253{
254public:
255 static VSTXMLInfo* createFor (const juce::XmlElement& xml)
256 {
257 if (xml.hasTagName ("VSTParametersStructure"))
258 return new VSTXMLInfo (xml);
259
260 if (const auto* x = xml.getChildByName ("VSTParametersStructure"))
261 return new VSTXMLInfo (*x);
262
263 return nullptr;
264 }
265
266 struct Group;
267
268 struct Base
269 {
270 Base() noexcept {}
271 virtual ~Base() {}
272
273 Group* parent = nullptr;
274 };
275
276 struct Param : public Base
277 {
278 int paramID;
279 juce::String expr, name, label;
280 juce::StringArray shortNames;
281 juce::String type;
282 int numberOfStates;
283 float defaultValue;
284 };
285
286 struct Group : public Base
287 {
288 juce::String name;
289 juce::OwnedArray<Base> paramTree;
290 };
291
292 struct Range
293 {
294 Range() noexcept {}
295 Range (const juce::String& s) { set (s); }
296
297 void set (const juce::String& s)
298 {
299 inclusiveLow = s.startsWithChar ('[');
300 inclusiveHigh = s.endsWithChar (']');
301
302 auto str = s.removeCharacters ("[]");
303
304 low = str.upToFirstOccurrenceOf (",", false, false).getFloatValue();
305 high = str.fromLastOccurrenceOf (",", false, false).getFloatValue();
306 }
307
308 bool contains (float f) const noexcept
309 {
310 return (inclusiveLow ? (f >= low) : (f > low))
311 && (inclusiveHigh ? (f <= high) : (f < high));
312 }
313
314 float low = 0;
315 float high = 0;
316
317 bool inclusiveLow = false;
318 bool inclusiveHigh = false;
319 };
320
321 struct Entry
322 {
323 juce::String name;
324 Range range;
325 };
326
327 struct ValueType
328 {
329 juce::String name, label;
330 juce::OwnedArray<Entry> entries;
331 };
332
333 struct Template
334 {
335 juce::String name;
336 juce::OwnedArray<Param> params;
337 };
338
339 const Param* getParamForID (const int paramID, const Group* const grp) const
340 {
341 for (auto item : (grp != nullptr ? grp->paramTree : paramTree))
342 {
343 if (auto param = dynamic_cast<const Param*> (item))
344 if (param->paramID == paramID)
345 return param;
346
347 if (auto group = dynamic_cast<const Group*> (item))
348 if (auto res = getParamForID (paramID, group))
349 return res;
350 }
351
352 return nullptr;
353 }
354
355 const ValueType* getValueType (const juce::String& name) const
356 {
357 for (auto v : valueTypes)
358 if (v->name == name)
359 return v;
360
361 return nullptr;
362 }
363
364 juce::OwnedArray<Base> paramTree;
365 juce::OwnedArray<ValueType> valueTypes;
366 juce::OwnedArray<Template> templates;
367
368 ValueType switchValueType;
369
370private:
371 VSTXMLInfo (const juce::XmlElement& xml)
372 {
373 switchValueType.entries.add (new Entry({ TRANS("Off"), Range ("[0, 0.5[") }));
374 switchValueType.entries.add (new Entry({ TRANS("On"), Range ("[0.5, 1]") }));
375
376 for (auto* item : xml.getChildIterator())
377 {
378 if (item->hasTagName ("Param")) parseParam (*item, nullptr, nullptr);
379 else if (item->hasTagName ("ValueType")) parseValueType (*item);
380 else if (item->hasTagName ("Template")) parseTemplate (*item);
381 else if (item->hasTagName ("Group")) parseGroup (*item, nullptr);
382 }
383 }
384
385 void parseParam (const juce::XmlElement& item, Group* group, Template* temp)
386 {
387 auto param = new Param();
388
389 if (temp != nullptr)
390 param->expr = item.getStringAttribute ("id");
391 else
392 param->paramID = item.getIntAttribute ("id");
393
394 param->name = item.getStringAttribute ("name");
395 param->label = item.getStringAttribute ("label");
396 param->type = item.getStringAttribute ("type");
397 param->numberOfStates = item.getIntAttribute ("numberOfStates");
398 param->defaultValue = (float) item.getDoubleAttribute ("defaultValue");
399
400 param->shortNames.addTokens (item.getStringAttribute ("shortName"), ",", juce::StringRef());
401 param->shortNames.trim();
402 param->shortNames.removeEmptyStrings();
403
404 if (group != nullptr)
405 {
406 group->paramTree.add (param);
407 param->parent = group;
408 }
409 else if (temp != nullptr)
410 {
411 temp->params.add (param);
412 }
413 else
414 {
415 paramTree.add (param);
416 }
417 }
418
419 void parseValueType (const juce::XmlElement& item)
420 {
421 auto vt = new ValueType();
422 valueTypes.add (vt);
423
424 vt->name = item.getStringAttribute ("name");
425 vt->label = item.getStringAttribute ("label");
426
427 int curEntry = 0;
428 const int numEntries = item.getNumChildElements();
429
430 for (auto* entryXml : item.getChildWithTagNameIterator ("Entry"))
431 {
432 auto entry = new Entry();
433 entry->name = entryXml->getStringAttribute ("name");
434
435 if (entryXml->hasAttribute ("value"))
436 {
437 entry->range.set(entryXml->getStringAttribute ("value"));
438 }
439 else
440 {
441 entry->range.low = (float) curEntry / (float) numEntries;
442 entry->range.high = (float) (curEntry + 1) / (float) numEntries;
443
444 entry->range.inclusiveLow = true;
445 entry->range.inclusiveHigh = (curEntry == numEntries - 1);
446 }
447
448 vt->entries.add (entry);
449 ++curEntry;
450 }
451 }
452
453 void parseTemplate (const juce::XmlElement& item)
454 {
455 auto temp = new Template();
456 templates.add (temp);
457 temp->name = item.getStringAttribute ("name");
458
459 for (auto* param : item.getChildIterator())
460 parseParam (*param, nullptr, temp);
461 }
462
463 void parseGroup (const juce::XmlElement& item, Group* parentGroup)
464 {
465 auto group = new Group();
466
467 if (parentGroup)
468 {
469 parentGroup->paramTree.add (group);
470 group->parent = parentGroup;
471 }
472 else
473 {
474 paramTree.add (group);
475 }
476
477 group->name = item.getStringAttribute ("name");
478
479 if (item.hasAttribute ("template"))
480 {
481 juce::StringArray variables;
482 variables.addTokens (item.getStringAttribute ("values"), ";", juce::StringRef());
483 variables.trim();
484
485 for (auto temp : templates)
486 {
487 if (temp->name == item.getStringAttribute ("template"))
488 {
489 for (int i = 0; i < temp->params.size(); ++i)
490 {
491 auto param = new Param();
492 group->paramTree.add (param);
493
494 param->parent = group;
495 param->paramID = evaluate (temp->params[i]->expr, variables);
496 param->defaultValue = temp->params[i]->defaultValue;
497 param->label = temp->params[i]->label;
498 param->name = temp->params[i]->name;
499 param->numberOfStates = temp->params[i]->numberOfStates;
500 param->shortNames = temp->params[i]->shortNames;
501 param->type = temp->params[i]->type;
502 }
503 }
504 }
505 }
506 else
507 {
508 for (auto* subItem : item.getChildIterator())
509 {
510 if (subItem->hasTagName ("Param")) parseParam (*subItem, group, nullptr);
511 else if (subItem->hasTagName ("Group")) parseGroup (*subItem, group);
512 }
513 }
514 }
515
516 int evaluate (juce::String expr, const juce::StringArray& variables) const
517 {
518 juce::StringArray names;
519 juce::Array<int> vals;
520
521 for (auto& v : variables)
522 {
523 if (v.contains ("="))
524 {
525 names.add (v.upToFirstOccurrenceOf ("=", false, false));
526 vals.add (v.fromFirstOccurrenceOf ("=", false, false).getIntValue());
527 }
528 }
529
530 for (int i = 0; i < names.size(); ++i)
531 {
532 for (;;)
533 {
534 const int idx = expr.indexOfWholeWord (names[i]);
535 if (idx < 0)
536 break;
537
538 expr = expr.replaceSection (idx, names[i].length(), juce::String (vals[i]));
539 }
540 }
541
542 expr = expr.retainCharacters ("01234567890-+")
543 .replace ("+", " + ")
544 .replace ("-", " - ");
545
546 juce::StringArray tokens;
547 tokens.addTokens (expr, " ", juce::StringRef());
548
549 bool add = true;
550 int val = 0;
551
552 for (const auto& s : tokens)
553 {
554 if (s == "+")
555 {
556 add = true;
557 }
558 else if (s == "-")
559 {
560 add = false;
561 }
562 else
563 {
564 if (add)
565 val += s.getIntValue();
566 else
567 val -= s.getIntValue();
568 }
569 }
570
571 return val;
572 }
573};
574
575//==============================================================================
576struct ModuleHandle : public ReferenceCountedObject
577{
578 File file;
579 MainCall moduleMain, customMain = {};
580 String pluginName;
581 std::unique_ptr<XmlElement> vstXml;
582
583 using Ptr = ReferenceCountedObjectPtr<ModuleHandle>;
584
585 static Array<ModuleHandle*>& getActiveModules()
586 {
587 static Array<ModuleHandle*> activeModules;
588 return activeModules;
589 }
590
591 //==============================================================================
592 static Ptr findOrCreateModule (const File& file)
593 {
594 for (auto* module : getActiveModules())
595 if (module->file == file)
596 return module;
597
598 const IdleCallRecursionPreventer icrp;
599 shellUIDToCreate = 0;
600 _fpreset();
601
602 JUCE_VST_LOG ("Attempting to load VST: " + file.getFullPathName());
603
604 Ptr m = new ModuleHandle (file, nullptr);
605
606 if (m->open())
607 {
608 _fpreset();
609 return m;
610 }
611
612 return {};
613 }
614
615 //==============================================================================
616 ModuleHandle (const File& f, MainCall customMainCall)
617 : file (f), moduleMain (customMainCall)
618 {
619 getActiveModules().add (this);
620
621 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_IOS || JUCE_ANDROID
622 fullParentDirectoryPathName = f.getParentDirectory().getFullPathName();
623 #elif JUCE_MAC
624 FSRef ref;
625 makeFSRefFromPath (&ref, f.getParentDirectory().getFullPathName());
626 FSGetCatalogInfo (&ref, kFSCatInfoNone, nullptr, nullptr, &parentDirFSSpec, nullptr);
627 #endif
628 }
629
630 ~ModuleHandle()
631 {
632 getActiveModules().removeFirstMatchingValue (this);
633 close();
634 }
635
636 //==============================================================================
637 #if ! JUCE_MAC
638 String fullParentDirectoryPathName;
639 #endif
640
641 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
642 DynamicLibrary module;
643
644 bool open()
645 {
646 if (moduleMain != nullptr)
647 return true;
648
649 pluginName = file.getFileNameWithoutExtension();
650
651 module.open (file.getFullPathName());
652
653 moduleMain = (MainCall) module.getFunction ("VSTPluginMain");
654
655 if (moduleMain == nullptr)
656 moduleMain = (MainCall) module.getFunction ("main");
657
658 JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
659
660 if (moduleMain != nullptr)
661 {
662 vstXml = parseXML (file.withFileExtension ("vstxml"));
663
664 #if JUCE_WINDOWS
665 if (vstXml == nullptr)
666 vstXml = parseXML (getDLLResource (file, "VSTXML", 1));
667 #endif
668 }
669
670 return moduleMain != nullptr;
671 }
672
673 void close()
674 {
675 _fpreset(); // (doesn't do any harm)
676
677 module.close();
678 }
679
680 void closeEffect (Vst2::VstEffectInterface* eff)
681 {
682 eff->dispatchFunction (eff, Vst2::plugInOpcodeClose, 0, 0, nullptr, 0);
683 }
684
685 #if JUCE_WINDOWS
686 static String getDLLResource (const File& dllFile, const String& type, int resID)
687 {
688 DynamicLibrary dll (dllFile.getFullPathName());
689 auto dllModule = (HMODULE) dll.getNativeHandle();
690
691 if (dllModule != INVALID_HANDLE_VALUE)
692 {
693 if (auto res = FindResource (dllModule, MAKEINTRESOURCE (resID), type.toWideCharPointer()))
694 {
695 if (auto hGlob = LoadResource (dllModule, res))
696 {
697 auto* data = static_cast<const char*> (LockResource (hGlob));
698 return String::fromUTF8 (data, SizeofResource (dllModule, res));
699 }
700 }
701 }
702
703 return {};
704 }
705 #endif
706 #else
707 Handle resHandle = {};
708 CFUniquePtr<CFBundleRef> bundleRef;
709
710 #if JUCE_MAC
711 CFBundleRefNum resFileId = {};
712 FSSpec parentDirFSSpec;
713 #endif
714
715 bool open()
716 {
717 if (moduleMain != nullptr)
718 return true;
719
720 bool ok = false;
721
722 if (file.hasFileExtension (".vst"))
723 {
724 auto* utf8 = file.getFullPathName().toRawUTF8();
725
726 if (auto url = CFUniquePtr<CFURLRef> (CFURLCreateFromFileSystemRepresentation (nullptr, (const UInt8*) utf8,
727 (CFIndex) strlen (utf8), file.isDirectory())))
728 {
729 bundleRef.reset (CFBundleCreate (kCFAllocatorDefault, url.get()));
730
731 if (bundleRef != nullptr)
732 {
733 if (CFBundleLoadExecutable (bundleRef.get()))
734 {
735 moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef.get(), CFSTR("main_macho"));
736
737 if (moduleMain == nullptr)
738 moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef.get(), CFSTR("VSTPluginMain"));
739
740 JUCE_VST_WRAPPER_LOAD_CUSTOM_MAIN
741
742 if (moduleMain != nullptr)
743 {
744 if (CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef.get(), CFSTR("CFBundleName")))
745 {
746 if (CFGetTypeID (name) == CFStringGetTypeID())
747 {
748 char buffer[1024];
749
750 if (CFStringGetCString ((CFStringRef) name, buffer, sizeof (buffer), CFStringGetSystemEncoding()))
751 pluginName = buffer;
752 }
753 }
754
755 if (pluginName.isEmpty())
756 pluginName = file.getFileNameWithoutExtension();
757
758 #if JUCE_MAC
759 resFileId = CFBundleOpenBundleResourceMap (bundleRef.get());
760 #endif
761
762 ok = true;
763
764 auto vstXmlFiles = file
765 #if JUCE_MAC
766 .getChildFile ("Contents")
767 .getChildFile ("Resources")
768 #endif
769 .findChildFiles (File::findFiles, false, "*.vstxml");
770
771 if (! vstXmlFiles.isEmpty())
772 vstXml = parseXML (vstXmlFiles.getReference(0));
773 }
774 }
775
776 if (! ok)
777 {
778 CFBundleUnloadExecutable (bundleRef.get());
779 bundleRef = nullptr;
780 }
781 }
782 }
783 }
784
785 return ok;
786 }
787
788 void close()
789 {
790 if (bundleRef != nullptr)
791 {
792 #if JUCE_MAC
793 CFBundleCloseBundleResourceMap (bundleRef.get(), resFileId);
794 #endif
795
796 if (CFGetRetainCount (bundleRef.get()) == 1)
797 CFBundleUnloadExecutable (bundleRef.get());
798
799 if (CFGetRetainCount (bundleRef.get()) > 0)
800 bundleRef = nullptr;
801 }
802 }
803
804 void closeEffect (Vst2::VstEffectInterface* eff)
805 {
806 eff->dispatchFunction (eff, Vst2::plugInOpcodeClose, 0, 0, nullptr, 0);
807 }
808
809 #endif
810
811private:
813};
814
815static const int defaultVSTSampleRateValue = 44100;
816static const int defaultVSTBlockSizeValue = 512;
817
819
820//==============================================================================
821struct VSTPluginInstance final : public AudioPluginInstance,
822 private Timer,
823 private AsyncUpdater
824{
825 struct VSTParameter final : public Parameter
826 {
827 VSTParameter (VSTPluginInstance& parent,
828 const String& paramName,
829 const Array<String>& shortParamNames,
830 float paramDefaultValue,
831 const String& paramLabel,
832 bool paramIsAutomatable,
833 bool paramIsDiscrete,
834 int numParamSteps,
835 bool isBoolSwitch,
836 const StringArray& paramValueStrings,
837 const VSTXMLInfo::ValueType* paramValueType)
838 : pluginInstance (parent),
839 name (paramName),
840 shortNames (shortParamNames),
841 defaultValue (paramDefaultValue),
842 label (paramLabel),
843 automatable (paramIsAutomatable),
844 discrete (paramIsDiscrete),
845 numSteps (numParamSteps),
846 isSwitch (isBoolSwitch),
847 vstValueStrings (paramValueStrings),
848 valueType (paramValueType)
849 {
850 }
851
852 float getValue() const override
853 {
854 if (auto* effect = pluginInstance.vstEffect)
855 {
856 const ScopedLock sl (pluginInstance.lock);
857
858 return effect->getParameterValueFunction (effect, getParameterIndex());
859 }
860
861 return 0.0f;
862 }
863
864 void setValue (float newValue) override
865 {
866 if (auto* effect = pluginInstance.vstEffect)
867 {
868 const ScopedLock sl (pluginInstance.lock);
869
870 if (effect->getParameterValueFunction (effect, getParameterIndex()) != newValue)
871 effect->setParameterValueFunction (effect, getParameterIndex(), newValue);
872 }
873 }
874
875 String getText (float value, int maximumStringLength) const override
876 {
877 if (valueType != nullptr)
878 {
879 for (auto& v : valueType->entries)
880 if (v->range.contains (value))
881 return v->name;
882 }
883
884 return Parameter::getText (value, maximumStringLength);
885 }
886
887 float getValueForText (const String& text) const override
888 {
889 if (valueType != nullptr)
890 {
891 for (auto& v : valueType->entries)
892 if (v->name == text)
893 return (v->range.high + v->range.low) / 2.0f;
894 }
895
896 return Parameter::getValueForText (text);
897 }
898
899 String getCurrentValueAsText() const override
900 {
901 if (valueType != nullptr || ! vstValueStrings.isEmpty())
902 return getText (getValue(), 1024);
903
904 return pluginInstance.getTextForOpcode (getParameterIndex(), Vst2::plugInOpcodeGetParameterText);
905 }
906
907 float getDefaultValue() const override
908 {
909 return defaultValue;
910 }
911
912 String getName (int maximumStringLength) const override
913 {
914 if (name.isEmpty())
915 return pluginInstance.getTextForOpcode (getParameterIndex(),
917
918 if (name.length() <= maximumStringLength)
919 return name;
920
921 if (! shortNames.isEmpty())
922 {
923 for (auto& n : shortNames)
924 if (n.length() <= maximumStringLength)
925 return n;
926
927 return shortNames.getLast();
928 }
929
930 return name;
931 }
932
933 String getLabel() const override
934 {
935 return label.isEmpty() ? pluginInstance.getTextForOpcode (getParameterIndex(),
937 : label;
938 }
939
940 bool isAutomatable() const override
941 {
942 return automatable;
943 }
944
945 bool isDiscrete() const override
946 {
947 return discrete;
948 }
949
950 bool isBoolean() const override
951 {
952 return isSwitch;
953 }
954
955 int getNumSteps() const override
956 {
957 return numSteps;
958 }
959
960 StringArray getAllValueStrings() const override
961 {
962 return vstValueStrings;
963 }
964
965 String getParameterID() const override
966 {
967 return String (getParameterIndex());
968 }
969
970 VSTPluginInstance& pluginInstance;
971
972 const String name;
973 const Array<String> shortNames;
974 const float defaultValue;
975 const String label;
976 const bool automatable, discrete;
977 const int numSteps;
978 const bool isSwitch;
979 const StringArray vstValueStrings;
980 const VSTXMLInfo::ValueType* const valueType;
981 };
982
983 VSTPluginInstance (const ModuleHandle::Ptr& mh, const BusesProperties& ioConfig, Vst2::VstEffectInterface* effect,
984 double sampleRateToUse, int blockSizeToUse)
985 : AudioPluginInstance (ioConfig),
986 vstEffect (effect),
987 vstModule (mh),
988 name (mh->pluginName),
989 bypassParam (new VST2BypassParameter (*this))
990 {
991 jassert (vstEffect != nullptr);
992
993 if (auto* xml = vstModule->vstXml.get())
994 xmlInfo.reset (VSTXMLInfo::createFor (*xml));
995
996 refreshParameterList();
997
998 vstSupportsBypass = (pluginCanDo ("bypass") > 0);
999 setRateAndBufferSizeDetails (sampleRateToUse, blockSizeToUse);
1000 }
1001
1002 void refreshParameterList() override
1003 {
1004 AudioProcessorParameterGroup newParameterTree;
1005
1006 for (int i = 0; i < vstEffect->numParameters; ++i)
1007 {
1008 String paramName;
1009 Array<String> shortParamNames;
1010 float defaultValue = 0;
1011 String label;
1012 bool isAutomatable = dispatch (Vst2::plugInOpcodeIsParameterAutomatable, i, 0, nullptr, 0) != 0;
1013 bool isDiscrete = false;
1014 int numSteps = AudioProcessor::getDefaultNumParameterSteps();
1015 bool isBoolSwitch = false;
1016 StringArray parameterValueStrings;
1017 const VSTXMLInfo::ValueType* valueType = nullptr;
1018
1019 if (xmlInfo != nullptr)
1020 {
1021 if (auto* param = xmlInfo->getParamForID (i, nullptr))
1022 {
1023 paramName = param->name;
1024
1025 for (auto& n : param->shortNames)
1026 shortParamNames.add (n);
1027
1028 struct LengthComparator
1029 {
1030 static int compareElements (const juce::String& first, const juce::String& second) noexcept
1031 {
1032 return first.length() - second.length();
1033 }
1034 };
1035
1036 LengthComparator comp;
1037 shortParamNames.sort (comp);
1038
1039 defaultValue = param->defaultValue;
1040 label = param->label;
1041
1042 if (param->type == "switch")
1043 {
1044 isBoolSwitch = true;
1045 numSteps = 2;
1046 valueType = &xmlInfo->switchValueType;
1047 }
1048 else
1049 {
1050 valueType = xmlInfo->getValueType (param->type);
1051 }
1052
1053 if (param->numberOfStates >= 2)
1054 {
1055 numSteps = param->numberOfStates;
1056
1057 if (valueType != nullptr)
1058 {
1059 for (auto* entry : valueType->entries)
1060 parameterValueStrings.add (entry->name);
1061
1062 parameterValueStrings.removeEmptyStrings();
1063 }
1064 }
1065
1066 isDiscrete = (numSteps != AudioProcessor::getDefaultNumParameterSteps());
1067 }
1068 }
1069
1070 newParameterTree.addChild (std::make_unique<VSTParameter> (*this, paramName, shortParamNames, defaultValue,
1071 label, isAutomatable, isDiscrete, numSteps,
1072 isBoolSwitch, parameterValueStrings, valueType));
1073 }
1074
1075 setHostedParameterTree (std::move (newParameterTree));
1076 }
1077
1078 ~VSTPluginInstance() override
1079 {
1080 if (vstEffect != nullptr && vstEffect->interfaceIdentifier == Vst2::juceVstInterfaceIdentifier)
1081 callOnMessageThread ([this] { cleanup(); });
1082 }
1083
1084 void cleanup()
1085 {
1086 if (vstEffect != nullptr && vstEffect->interfaceIdentifier == Vst2::juceVstInterfaceIdentifier)
1087 {
1088 #if JUCE_MAC
1089 if (vstModule->resFileId != 0)
1090 UseResFile (vstModule->resFileId);
1091 #endif
1092
1093 // Must delete any editors before deleting the plugin instance!
1094 jassert (getActiveEditor() == nullptr);
1095
1096 _fpreset(); // some dodgy plug-ins mess around with this
1097
1098 vstModule->closeEffect (vstEffect);
1099 }
1100
1101 vstModule = nullptr;
1102 vstEffect = nullptr;
1103 }
1104
1105 static VSTPluginInstance* create (const ModuleHandle::Ptr& newModule,
1106 double initialSampleRate,
1107 int initialBlockSize)
1108 {
1109 if (auto* newEffect = constructEffect (newModule))
1110 {
1111 newEffect->hostSpace2 = 0;
1112
1113 newEffect->dispatchFunction (newEffect, Vst2::plugInOpcodeIdentify, 0, 0, nullptr, 0);
1114
1115 auto blockSize = jmax (32, initialBlockSize);
1116
1117 newEffect->dispatchFunction (newEffect, Vst2::plugInOpcodeSetSampleRate, 0, 0, nullptr, static_cast<float> (initialSampleRate));
1118 newEffect->dispatchFunction (newEffect, Vst2::plugInOpcodeSetBlockSize, 0, blockSize, nullptr, 0);
1119
1120 newEffect->dispatchFunction (newEffect, Vst2::plugInOpcodeOpen, 0, 0, nullptr, 0);
1121 BusesProperties ioConfig = queryBusIO (newEffect);
1122
1123 return new VSTPluginInstance (newModule, ioConfig, newEffect, initialSampleRate, blockSize);
1124 }
1125
1126 return nullptr;
1127 }
1128
1129 //==============================================================================
1130 void fillInPluginDescription (PluginDescription& desc) const override
1131 {
1132 desc.name = name;
1133
1134 {
1135 char buffer[512] = { 0 };
1136 dispatch (Vst2::plugInOpcodeGetPlugInName, 0, 0, buffer, 0);
1137
1138 desc.descriptiveName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim();
1139
1140 if (desc.descriptiveName.isEmpty())
1141 desc.descriptiveName = name;
1142 }
1143
1144 desc.fileOrIdentifier = vstModule->file.getFullPathName();
1145 desc.uniqueId = desc.deprecatedUid = getUID();
1146 desc.lastFileModTime = vstModule->file.getLastModificationTime();
1147 desc.lastInfoUpdateTime = Time::getCurrentTime();
1148 desc.pluginFormatName = "VST";
1149 desc.category = getCategory();
1150
1151 {
1152 char buffer[512] = { 0 };
1153 dispatch (Vst2::plugInOpcodeGetManufacturerName, 0, 0, buffer, 0);
1154 desc.manufacturerName = String::createStringFromData (buffer, (int) sizeof (buffer)).trim();
1155 }
1156
1157 desc.version = getVersion();
1158 desc.numInputChannels = getTotalNumInputChannels();
1159 desc.numOutputChannels = getTotalNumOutputChannels();
1160 desc.isInstrument = isSynthPlugin();
1161 }
1162
1163 bool initialiseEffect (double initialSampleRate, int initialBlockSize)
1164 {
1165 if (vstEffect != nullptr)
1166 {
1167 vstEffect->hostSpace2 = (pointer_sized_int) (pointer_sized_int) this;
1168 initialise (initialSampleRate, initialBlockSize);
1169 return true;
1170 }
1171
1172 return false;
1173 }
1174
1175 void initialise (double initialSampleRate, int initialBlockSize)
1176 {
1177 if (initialised || vstEffect == nullptr)
1178 return;
1179
1180 #if JUCE_WINDOWS
1181 // On Windows it's highly advisable to create your plugins using the message thread,
1182 // because many plugins need a chance to create HWNDs that will get their
1183 // messages delivered by the main message thread, and that's not possible from
1184 // a background thread.
1186 #endif
1187
1188 JUCE_VST_LOG ("Initialising VST: " + vstModule->pluginName + " (" + getVersion() + ")");
1189 initialised = true;
1190
1191 setRateAndBufferSizeDetails (initialSampleRate, initialBlockSize);
1192
1193 dispatch (Vst2::plugInOpcodeIdentify, 0, 0, nullptr, 0);
1194
1195 if (getSampleRate() > 0)
1196 dispatch (Vst2::plugInOpcodeSetSampleRate, 0, 0, nullptr, (float) getSampleRate());
1197
1198 if (getBlockSize() > 0)
1199 dispatch (Vst2::plugInOpcodeSetBlockSize, 0, jmax (32, getBlockSize()), nullptr, 0);
1200
1201 dispatch (Vst2::plugInOpcodeOpen, 0, 0, nullptr, 0);
1202
1203 setRateAndBufferSizeDetails (getSampleRate(), getBlockSize());
1204
1205 if (getNumPrograms() > 1)
1206 setCurrentProgram (0);
1207 else
1208 dispatch (Vst2::plugInOpcodeSetCurrentProgram, 0, 0, nullptr, 0);
1209
1210 for (int i = vstEffect->numInputChannels; --i >= 0;) dispatch (Vst2::plugInOpcodeConnectInput, i, 1, nullptr, 0);
1211 for (int i = vstEffect->numOutputChannels; --i >= 0;) dispatch (Vst2::plugInOpcodeConnectOutput, i, 1, nullptr, 0);
1212
1213 if (getVstCategory() != Vst2::kPlugCategShell) // (workaround for Waves 5 plugins which crash during this call)
1214 updateStoredProgramNames();
1215
1216 wantsMidiMessages = pluginCanDo ("receiveVstMidiEvent") > 0 || isSynthPlugin();
1217
1218 setLatencySamples (vstEffect->latency);
1219 }
1220
1221 void getExtensions (ExtensionsVisitor& visitor) const override
1222 {
1223 struct Extensions : public ExtensionsVisitor::VSTClient
1224 {
1225 explicit Extensions (const VSTPluginInstance* instanceIn) : instance (instanceIn) {}
1226
1227 AEffect* getAEffectPtr() const noexcept override { return reinterpret_cast<AEffect*> (instance->vstEffect); }
1228
1229 const VSTPluginInstance* instance = nullptr;
1230 };
1231
1232 visitor.visitVSTClient (Extensions { this });
1233 }
1234
1235 void* getPlatformSpecificData() override { return vstEffect; }
1236
1237 const String getName() const override
1238 {
1239 if (vstEffect != nullptr)
1240 {
1241 char buffer[512] = { 0 };
1242
1243 if (dispatch (Vst2::plugInOpcodeGetManufacturerProductName, 0, 0, buffer, 0) != 0)
1244 {
1245 String productName = String::createStringFromData (buffer, (int) sizeof (buffer));
1246
1247 if (productName.isNotEmpty())
1248 return productName;
1249 }
1250 }
1251
1252 return name;
1253 }
1254
1255 int getUID() const
1256 {
1257 int uid = vstEffect != nullptr ? vstEffect->plugInIdentifier : 0;
1258
1259 if (uid == 0)
1260 uid = vstModule->file.hashCode();
1261
1262 return uid;
1263 }
1264
1265 double getTailLengthSeconds() const override
1266 {
1267 if (vstEffect == nullptr)
1268 return 0.0;
1269
1270 if ((vstEffect->flags & 512) != 0)
1271 return 0.0;
1272
1273 auto tailSize = dispatch (Vst2::plugInOpcodeGetTailSize, 0, 0, nullptr, 0);
1274 auto sampleRate = getSampleRate();
1275
1276 // remain backward compatible with old JUCE plug-ins: anything larger
1277 // than INT32_MAX is an invalid tail time but old JUCE 64-bit plug-ins
1278 // would return INT64_MAX for infinite tail time. So treat anything
1279 // equal or greater than INT32_MAX as infinite tail time.
1280 if (tailSize >= std::numeric_limits<int32>::max())
1281 return std::numeric_limits<double>::infinity();
1282
1283 if (tailSize >= 0 && sampleRate > 0)
1284 return static_cast<double> (tailSize) / sampleRate;
1285
1286 return 0.0;
1287 }
1288
1289 bool acceptsMidi() const override { return wantsMidiMessages; }
1290 bool producesMidi() const override { return pluginCanDo ("sendVstMidiEvent") > 0; }
1291 bool supportsMPE() const override { return pluginCanDo ("MPE") > 0; }
1292
1293 Vst2::VstPlugInCategory getVstCategory() const noexcept { return (Vst2::VstPlugInCategory) dispatch (Vst2::plugInOpcodeGetPlugInCategory, 0, 0, nullptr, 0); }
1294
1295 bool isSynthPlugin() const { return (vstEffect != nullptr && (vstEffect->flags & Vst2::vstEffectFlagIsSynth) != 0); }
1296
1297 int pluginCanDo (const char* text) const { return (int) dispatch (Vst2::plugInOpcodeCanPlugInDo, 0, 0, (void*) text, 0); }
1298
1299 //==============================================================================
1300 void prepareToPlay (double rate, int samplesPerBlockExpected) override
1301 {
1302 auto numInputBuses = getBusCount (true);
1303 auto numOutputBuses = getBusCount (false);
1304
1305 setRateAndBufferSizeDetails (rate, samplesPerBlockExpected);
1306
1307 if (numInputBuses <= 1 && numOutputBuses <= 1)
1308 {
1309 SpeakerMappings::VstSpeakerConfigurationHolder inArr (getChannelLayoutOfBus (true, 0));
1310 SpeakerMappings::VstSpeakerConfigurationHolder outArr (getChannelLayoutOfBus (false, 0));
1311
1312 dispatch (Vst2::plugInOpcodeSetSpeakerConfiguration, 0, (pointer_sized_int) &inArr.get(), (void*) &outArr.get(), 0.0f);
1313 }
1314
1315 vstHostTime.tempoBPM = 120.0;
1316 vstHostTime.timeSignatureNumerator = 4;
1317 vstHostTime.timeSignatureDenominator = 4;
1318 vstHostTime.sampleRate = rate;
1319 vstHostTime.samplePosition = 0;
1320 vstHostTime.flags = Vst2::vstTimingInfoFlagNanosecondsValid
1323
1324 initialise (rate, samplesPerBlockExpected);
1325
1326 if (initialised)
1327 {
1328 wantsMidiMessages = wantsMidiMessages || (pluginCanDo ("receiveVstMidiEvent") > 0) || isSynthPlugin();
1329
1330 if (wantsMidiMessages)
1331 midiEventsToSend.ensureSize (256);
1332 else
1333 midiEventsToSend.freeEvents();
1334
1335 incomingMidi.clear();
1336
1337 dispatch (Vst2::plugInOpcodeSetSampleRate, 0, 0, nullptr, (float) rate);
1338 dispatch (Vst2::plugInOpcodeSetBlockSize, 0, jmax (16, samplesPerBlockExpected), nullptr, 0);
1339
1340 if (supportsDoublePrecisionProcessing())
1341 {
1342 int32 vstPrecision = isUsingDoublePrecision() ? Vst2::vstProcessingSampleTypeDouble
1344
1345 dispatch (Vst2::plugInOpcodeSetSampleFloatType, 0, (pointer_sized_int) vstPrecision, nullptr, 0);
1346 }
1347
1348 auto maxChannels = jmax (1, jmax (vstEffect->numInputChannels, vstEffect->numOutputChannels));
1349
1350 tmpBufferFloat .setSize (maxChannels, samplesPerBlockExpected);
1351 tmpBufferDouble.setSize (maxChannels, samplesPerBlockExpected);
1352
1353 channelBufferFloat .calloc (static_cast<size_t> (maxChannels));
1354 channelBufferDouble.calloc (static_cast<size_t> (maxChannels));
1355
1356 outOfPlaceBuffer.setSize (jmax (1, vstEffect->numOutputChannels), samplesPerBlockExpected);
1357
1358 if (! isPowerOn)
1359 setPower (true);
1360
1361 // dodgy hack to force some plugins to initialise the sample rate.
1362 if (! hasEditor())
1363 {
1364 if (auto* firstParam = getParameters()[0])
1365 {
1366 auto old = firstParam->getValue();
1367 firstParam->setValue ((old < 0.5f) ? 1.0f : 0.0f);
1368 firstParam->setValue (old);
1369 }
1370 }
1371
1372 dispatch (Vst2::plugInOpcodeStartProcess, 0, 0, nullptr, 0);
1373
1374 setLatencySamples (vstEffect->latency);
1375 }
1376 }
1377
1378 void releaseResources() override
1379 {
1380 if (initialised)
1381 {
1382 dispatch (Vst2::plugInOpcodeStopProcess, 0, 0, nullptr, 0);
1383 setPower (false);
1384 }
1385
1386 channelBufferFloat.free();
1387 tmpBufferFloat.setSize (0, 0);
1388
1389 channelBufferDouble.free();
1390 tmpBufferDouble.setSize (0, 0);
1391
1392 outOfPlaceBuffer.setSize (1, 1);
1393 incomingMidi.clear();
1394
1395 midiEventsToSend.freeEvents();
1396 }
1397
1398 void reset() override
1399 {
1400 if (isPowerOn)
1401 {
1402 setPower (false);
1403 setPower (true);
1404 }
1405 }
1406
1407 //==============================================================================
1408 void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override
1409 {
1410 jassert (! isUsingDoublePrecision());
1411 processAudio (buffer, midiMessages, tmpBufferFloat, channelBufferFloat, false);
1412 }
1413
1414 void processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages) override
1415 {
1416 jassert (isUsingDoublePrecision());
1417 processAudio (buffer, midiMessages, tmpBufferDouble, channelBufferDouble, false);
1418 }
1419
1420 void processBlockBypassed (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) override
1421 {
1422 jassert (! isUsingDoublePrecision());
1423 processAudio (buffer, midiMessages, tmpBufferFloat, channelBufferFloat, true);
1424 }
1425
1426 void processBlockBypassed (AudioBuffer<double>& buffer, MidiBuffer& midiMessages) override
1427 {
1428 jassert (isUsingDoublePrecision());
1429 processAudio (buffer, midiMessages, tmpBufferDouble, channelBufferDouble, true);
1430 }
1431
1432 //==============================================================================
1433 bool supportsDoublePrecisionProcessing() const override
1434 {
1435 return ((vstEffect->flags & Vst2::vstEffectFlagInplaceAudio) != 0
1436 && (vstEffect->flags & Vst2::vstEffectFlagInplaceDoubleAudio) != 0);
1437 }
1438
1439 AudioProcessorParameter* getBypassParameter() const override { return vstSupportsBypass ? bypassParam.get() : nullptr; }
1440
1441 //==============================================================================
1442 bool canAddBus (bool) const override { return false; }
1443 bool canRemoveBus (bool) const override { return false; }
1444
1445 bool isBusesLayoutSupported (const BusesLayout& layouts) const override
1446 {
1447 auto numInputBuses = getBusCount (true);
1448 auto numOutputBuses = getBusCount (false);
1449
1450 // it's not possible to change layout if there are sidechains/aux buses
1451 if (numInputBuses > 1 || numOutputBuses > 1)
1452 return (layouts == getBusesLayout());
1453
1454 return (layouts.getNumChannels (true, 0) <= vstEffect->numInputChannels
1455 && layouts.getNumChannels (false, 0) <= vstEffect->numOutputChannels);
1456 }
1457
1458 //==============================================================================
1459 #if JUCE_IOS || JUCE_ANDROID
1460 bool hasEditor() const override { return false; }
1461 #else
1462 bool hasEditor() const override { return vstEffect != nullptr && (vstEffect->flags & Vst2::vstEffectFlagHasEditor) != 0; }
1463 #endif
1464
1465 AudioProcessorEditor* createEditor() override;
1466
1467 //==============================================================================
1468 const String getInputChannelName (int index) const override
1469 {
1470 if (isValidChannel (index, true))
1471 {
1472 Vst2::VstPinInfo pinProps;
1473 if (dispatch (Vst2::plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0)
1474 return String (pinProps.text, sizeof (pinProps.text));
1475 }
1476
1477 return {};
1478 }
1479
1480 bool isInputChannelStereoPair (int index) const override
1481 {
1482 if (! isValidChannel (index, true))
1483 return false;
1484
1485 Vst2::VstPinInfo pinProps;
1486 if (dispatch (Vst2::plugInOpcodeGetInputPinProperties, index, 0, &pinProps, 0.0f) != 0)
1487 return (pinProps.flags & Vst2::vstPinInfoFlagIsStereo) != 0;
1488
1489 return true;
1490 }
1491
1492 const String getOutputChannelName (int index) const override
1493 {
1494 if (isValidChannel (index, false))
1495 {
1496 Vst2::VstPinInfo pinProps;
1497 if (dispatch (Vst2::plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0)
1498 return String (pinProps.text, sizeof (pinProps.text));
1499 }
1500
1501 return {};
1502 }
1503
1504 bool isOutputChannelStereoPair (int index) const override
1505 {
1506 if (! isValidChannel (index, false))
1507 return false;
1508
1509 Vst2::VstPinInfo pinProps;
1510 if (dispatch (Vst2::plugInOpcodeGetOutputPinProperties, index, 0, &pinProps, 0.0f) != 0)
1511 return (pinProps.flags & Vst2::vstPinInfoFlagIsStereo) != 0;
1512
1513 return true;
1514 }
1515
1516 bool isValidChannel (int index, bool isInput) const noexcept
1517 {
1518 return isPositiveAndBelow (index, isInput ? getTotalNumInputChannels()
1519 : getTotalNumOutputChannels());
1520 }
1521
1522 //==============================================================================
1523 int getNumPrograms() override { return vstEffect != nullptr ? jmax (0, vstEffect->numPrograms) : 0; }
1524
1525 // NB: some plugs return negative numbers from this function.
1526 int getCurrentProgram() override { return (int) dispatch (Vst2::plugInOpcodeGetCurrentProgram, 0, 0, nullptr, 0); }
1527
1528 void setCurrentProgram (int newIndex) override
1529 {
1530 if (getNumPrograms() > 0 && newIndex != getCurrentProgram())
1531 dispatch (Vst2::plugInOpcodeSetCurrentProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), nullptr, 0);
1532 }
1533
1534 const String getProgramName (int index) override
1535 {
1536 if (index >= 0)
1537 {
1538 if (index == getCurrentProgram())
1539 return getCurrentProgramName();
1540
1541 if (vstEffect != nullptr)
1542 {
1543 char nm[264] = { 0 };
1544
1545 if (dispatch (Vst2::plugInOpcodeGetProgramName, jlimit (0, getNumPrograms() - 1, index), -1, nm, 0) != 0)
1546 return String::fromUTF8 (nm).trim();
1547 }
1548 }
1549
1550 return {};
1551 }
1552
1553 void changeProgramName (int index, const String& newName) override
1554 {
1555 if (index >= 0 && index == getCurrentProgram())
1556 {
1557 if (getNumPrograms() > 0 && newName != getCurrentProgramName())
1558 dispatch (Vst2::plugInOpcodeSetCurrentProgramName, 0, 0, (void*) newName.substring (0, 24).toRawUTF8(), 0.0f);
1559 }
1560 else
1561 {
1562 jassertfalse; // xxx not implemented!
1563 }
1564 }
1565
1566 //==============================================================================
1567 void getStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, true); }
1568 void getCurrentProgramStateInformation (MemoryBlock& mb) override { saveToFXBFile (mb, false); }
1569
1570 void setStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); }
1571 void setCurrentProgramStateInformation (const void* data, int size) override { loadFromFXBFile (data, (size_t) size); }
1572
1573 //==============================================================================
1574 void timerCallback() override
1575 {
1576 if (dispatch (Vst2::plugInOpcodeIdle, 0, 0, nullptr, 0) == 0)
1577 stopTimer();
1578 }
1579
1580 void handleAsyncUpdate() override
1581 {
1582 updateHostDisplay (AudioProcessorListener::ChangeDetails().withProgramChanged (true)
1583 .withParameterInfoChanged (true));
1584 }
1585
1586 pointer_sized_int handleCallback (int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt)
1587 {
1588 switch (opcode)
1589 {
1591 if (auto* param = getParameters()[index])
1592 param->sendValueChangedMessageToListeners (opt);
1593 else
1594 jassertfalse; // Invalid parameter index!
1595
1596 break;
1597
1598 case Vst2::hostOpcodePreAudioProcessingEvents: handleMidiFromPlugin ((const Vst2::VstEventBlock*) ptr); break;
1599 case Vst2::hostOpcodeGetTimingInfo: return getVSTTime();
1600 case Vst2::hostOpcodeIdle: handleIdle(); break;
1601 case Vst2::hostOpcodeWindowSize: setWindowSize (index, (int) value); return 1;
1602 case Vst2::hostOpcodeUpdateView: triggerAsyncUpdate(); break;
1603 case Vst2::hostOpcodeIOModified: setLatencySamples (vstEffect->latency); break;
1604 case Vst2::hostOpcodeNeedsIdle: startTimer (50); break;
1605
1606 case Vst2::hostOpcodeGetSampleRate: return (pointer_sized_int) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue);
1607 case Vst2::hostOpcodeGetBlockSize: return (pointer_sized_int) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue);
1608 case Vst2::hostOpcodePlugInWantsMidi: wantsMidiMessages = true; break;
1609 case Vst2::hostOpcodeGetDirectory: return getVstDirectory();
1610
1611 case Vst2::hostOpcodeTempoAt: return (pointer_sized_int) (extraFunctions != nullptr ? extraFunctions->getTempoAt ((int64) value) : 0);
1612 case Vst2::hostOpcodeGetAutomationState: return (pointer_sized_int) (extraFunctions != nullptr ? extraFunctions->getAutomationState() : 0);
1613
1615 if (auto* param = getParameters()[index])
1616 param->beginChangeGesture();
1617 else
1618 jassertfalse; // Invalid parameter index!
1619
1620 break;
1621
1623 if (auto* param = getParameters()[index])
1624 param->endChangeGesture();
1625 else
1626 jassertfalse; // Invalid parameter index!
1627
1628 break;
1629
1630 case Vst2::hostOpcodePinConnected: return isValidChannel (index, value == 0) ? 0 : 1; // (yes, 0 = true)
1631 case Vst2::hostOpcodeGetCurrentAudioProcessingLevel: return isNonRealtime() ? 4 : 0;
1632
1633 // none of these are handled (yet)...
1652 break;
1653
1654 default:
1655 return handleGeneralCallback (opcode, index, value, ptr, opt);
1656 }
1657
1658 return 0;
1659 }
1660
1661 // handles non plugin-specific callbacks.
1662 static pointer_sized_int handleGeneralCallback (int32 opcode, int32 /*index*/, pointer_sized_int /*value*/, void* ptr, float /*opt*/)
1663 {
1664 switch (opcode)
1665 {
1666 case Vst2::hostOpcodeCanHostDo: return handleCanDo ((const char*) ptr);
1667 case Vst2::hostOpcodeVstVersion: return 2400;
1668 case Vst2::hostOpcodeCurrentId: return shellUIDToCreate;
1671 case Vst2::hostOpcodeGetManufacturerVersion: return 0x0101;
1672
1674 case Vst2::hostOpcodeGetProductName: return getHostName ((char*) ptr);
1675
1676 case Vst2::hostOpcodeGetSampleRate: return (pointer_sized_int) defaultVSTSampleRateValue;
1677 case Vst2::hostOpcodeGetBlockSize: return (pointer_sized_int) defaultVSTBlockSizeValue;
1679
1680 default:
1681 DBG ("*** Unhandled VST Callback: " + String ((int) opcode));
1682 break;
1683 }
1684
1685 return 0;
1686 }
1687
1688 //==============================================================================
1689 pointer_sized_int dispatch (int opcode, int index, pointer_sized_int value, void* const ptr, float opt) const
1690 {
1692
1693 if (vstEffect != nullptr)
1694 {
1695 const ScopedLock sl (lock);
1696 const IdleCallRecursionPreventer icrp;
1697
1698 try
1699 {
1700 #if JUCE_MAC
1701 auto oldResFile = CurResFile();
1702
1703 if (vstModule->resFileId != 0)
1704 UseResFile (vstModule->resFileId);
1705 #endif
1706
1707 result = vstEffect->dispatchFunction (vstEffect, opcode, index, value, ptr, opt);
1708
1709 #if JUCE_MAC
1710 auto newResFile = CurResFile();
1711
1712 if (newResFile != oldResFile) // avoid confusing the parent app's resource file with the plug-in's
1713 {
1714 vstModule->resFileId = newResFile;
1715 UseResFile (oldResFile);
1716 }
1717 #endif
1718 }
1719 catch (...)
1720 {}
1721 }
1722
1723 return result;
1724 }
1725
1726 bool loadFromFXBFile (const void* const data, const size_t dataSize)
1727 {
1728 if (dataSize < 28)
1729 return false;
1730
1731 auto set = (const fxSet*) data;
1732
1733 if ((! compareMagic (set->chunkMagic, "CcnK")) || fxbSwap (set->version) > fxbVersionNum)
1734 return false;
1735
1736 if (compareMagic (set->fxMagic, "FxBk"))
1737 {
1738 // bank of programs
1739 if (fxbSwap (set->numPrograms) >= 0)
1740 {
1741 auto oldProg = getCurrentProgram();
1742 auto numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
1743 auto progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);
1744
1745 for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
1746 {
1747 if (i != oldProg)
1748 {
1749 auto prog = addBytesToPointer (set->programs, i * progLen);
1750
1751 if (getAddressDifference (prog, set) >= (int) dataSize)
1752 return false;
1753
1754 if (fxbSwap (set->numPrograms) > 0)
1755 setCurrentProgram (i);
1756
1757 if (! restoreProgramSettings (prog))
1758 return false;
1759 }
1760 }
1761
1762 if (fxbSwap (set->numPrograms) > 0)
1763 setCurrentProgram (oldProg);
1764
1765 auto prog = addBytesToPointer (set->programs, oldProg * progLen);
1766
1767 if (getAddressDifference (prog, set) >= (int) dataSize)
1768 return false;
1769
1770 if (! restoreProgramSettings (prog))
1771 return false;
1772 }
1773 }
1774 else if (compareMagic (set->fxMagic, "FxCk"))
1775 {
1776 // single program
1777 auto prog = (const fxProgram*) data;
1778
1779 if (! compareMagic (prog->chunkMagic, "CcnK"))
1780 return false;
1781
1782 changeProgramName (getCurrentProgram(), prog->prgName);
1783
1784 for (int i = 0; i < fxbSwap (prog->numParams); ++i)
1785 if (auto* param = getParameters()[i])
1786 param->setValue (fxbSwapFloat (prog->params[i]));
1787 }
1788 else if (compareMagic (set->fxMagic, "FBCh"))
1789 {
1790 // non-preset chunk
1791 auto cset = (const fxChunkSet*) data;
1792
1793 if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (size_t) dataSize)
1794 return false;
1795
1796 setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false);
1797 }
1798 else if (compareMagic (set->fxMagic, "FPCh"))
1799 {
1800 // preset chunk
1801 auto cset = (const fxProgramSet*) data;
1802
1803 if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (size_t) dataSize)
1804 return false;
1805
1806 setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true);
1807
1808 changeProgramName (getCurrentProgram(), cset->name);
1809 }
1810 else
1811 {
1812 return false;
1813 }
1814
1815 return true;
1816 }
1817
1818 bool saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB = 128)
1819 {
1820 auto numPrograms = getNumPrograms();
1821 auto numParams = getParameters().size();
1822
1823 if (usesChunks())
1824 {
1825 MemoryBlock chunk;
1826 getChunkData (chunk, ! isFXB, maxSizeMB);
1827
1828 if (isFXB)
1829 {
1830 auto totalLen = sizeof (fxChunkSet) + chunk.getSize() - 8;
1831 dest.setSize (totalLen, true);
1832
1833 auto set = (fxChunkSet*) dest.getData();
1834 set->chunkMagic = fxbName ("CcnK");
1835 set->byteSize = 0;
1836 set->fxMagic = fxbName ("FBCh");
1837 set->version = fxbSwap (fxbVersionNum);
1838 set->fxID = fxbSwap (getUID());
1839 set->fxVersion = fxbSwap (getVersionNumber());
1840 set->numPrograms = fxbSwap (numPrograms);
1841 set->chunkSize = fxbSwap ((int32) chunk.getSize());
1842
1843 chunk.copyTo (set->chunk, 0, chunk.getSize());
1844 }
1845 else
1846 {
1847 auto totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8;
1848 dest.setSize (totalLen, true);
1849
1850 auto set = (fxProgramSet*) dest.getData();
1851 set->chunkMagic = fxbName ("CcnK");
1852 set->byteSize = 0;
1853 set->fxMagic = fxbName ("FPCh");
1854 set->version = fxbSwap (fxbVersionNum);
1855 set->fxID = fxbSwap (getUID());
1856 set->fxVersion = fxbSwap (getVersionNumber());
1857 set->numPrograms = fxbSwap (numPrograms);
1858 set->chunkSize = fxbSwap ((int32) chunk.getSize());
1859
1860 getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1);
1861 chunk.copyTo (set->chunk, 0, chunk.getSize());
1862 }
1863 }
1864 else
1865 {
1866 if (isFXB)
1867 {
1868 auto progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);
1869 auto len = (size_t) (progLen * jmax (1, numPrograms)) + (sizeof (fxSet) - sizeof (fxProgram));
1870 dest.setSize (len, true);
1871
1872 auto set = (fxSet*) dest.getData();
1873 set->chunkMagic = fxbName ("CcnK");
1874 set->byteSize = 0;
1875 set->fxMagic = fxbName ("FxBk");
1876 set->version = fxbSwap (fxbVersionNum);
1877 set->fxID = fxbSwap (getUID());
1878 set->fxVersion = fxbSwap (getVersionNumber());
1879 set->numPrograms = fxbSwap (numPrograms);
1880
1881 MemoryBlock oldSettings;
1882 createTempParameterStore (oldSettings);
1883
1884 auto oldProgram = getCurrentProgram();
1885
1886 if (oldProgram >= 0)
1887 setParamsInProgramBlock (addBytesToPointer (set->programs, oldProgram * progLen));
1888
1889 for (int i = 0; i < numPrograms; ++i)
1890 {
1891 if (i != oldProgram)
1892 {
1893 setCurrentProgram (i);
1894 setParamsInProgramBlock (addBytesToPointer (set->programs, i * progLen));
1895 }
1896 }
1897
1898 if (oldProgram >= 0)
1899 setCurrentProgram (oldProgram);
1900
1901 restoreFromTempParameterStore (oldSettings);
1902 }
1903 else
1904 {
1905 dest.setSize ((size_t) ((numParams - 1) * (int) sizeof (float)) + sizeof (fxProgram), true);
1906 setParamsInProgramBlock ((fxProgram*) dest.getData());
1907 }
1908 }
1909
1910 return true;
1911 }
1912
1913 bool usesChunks() const noexcept { return vstEffect != nullptr && (vstEffect->flags & Vst2::vstEffectFlagDataInChunks) != 0; }
1914
1915 bool getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const
1916 {
1917 if (usesChunks())
1918 {
1919 void* data = nullptr;
1920 auto bytes = (size_t) dispatch (Vst2::plugInOpcodeGetData, isPreset ? 1 : 0, 0, &data, 0.0f);
1921
1922 if (data != nullptr && bytes <= (size_t) maxSizeMB * 1024 * 1024)
1923 {
1924 mb.setSize (bytes);
1925 mb.copyFrom (data, 0, bytes);
1926
1927 return true;
1928 }
1929 }
1930
1931 return false;
1932 }
1933
1934 bool setChunkData (const void* data, const int size, bool isPreset)
1935 {
1936 if (size > 0 && usesChunks())
1937 {
1938 dispatch (Vst2::plugInOpcodeSetData, isPreset ? 1 : 0, size, (void*) data, 0.0f);
1939
1940 if (! isPreset)
1941 updateStoredProgramNames();
1942
1943 return true;
1944 }
1945
1946 return false;
1947 }
1948
1949 bool updateSizeFromEditor (int w, int h);
1950
1951 Vst2::VstEffectInterface* vstEffect;
1952 ModuleHandle::Ptr vstModule;
1953
1954 std::unique_ptr<VSTPluginFormat::ExtraFunctions> extraFunctions;
1955
1956private:
1957 //==============================================================================
1958 struct VST2BypassParameter final : public Parameter
1959 {
1960 VST2BypassParameter (VSTPluginInstance& effectToUse)
1961 : parent (effectToUse),
1962 vstOnStrings (TRANS("on"), TRANS("yes"), TRANS("true")),
1963 vstOffStrings (TRANS("off"), TRANS("no"), TRANS("false")),
1964 values (TRANS("Off"), TRANS("On"))
1965 {
1966 }
1967
1968 void setValue (float newValue) override
1969 {
1970 currentValue = (newValue != 0.0f);
1971
1972 if (parent.vstSupportsBypass)
1973 parent.dispatch (Vst2::plugInOpcodeSetBypass, 0, currentValue ? 1 : 0, nullptr, 0.0f);
1974 }
1975
1976 float getValueForText (const String& text) const override
1977 {
1978 String lowercaseText (text.toLowerCase());
1979
1980 for (auto& testText : vstOnStrings)
1981 if (lowercaseText == testText)
1982 return 1.0f;
1983
1984 for (auto& testText : vstOffStrings)
1985 if (lowercaseText == testText)
1986 return 0.0f;
1987
1988 return text.getIntValue() != 0 ? 1.0f : 0.0f;
1989 }
1990
1991 float getValue() const override { return currentValue; }
1992 float getDefaultValue() const override { return 0.0f; }
1993 String getName (int /*maximumStringLength*/) const override { return "Bypass"; }
1994 String getText (float value, int) const override { return (value != 0.0f ? TRANS("On") : TRANS("Off")); }
1995 bool isAutomatable() const override { return true; }
1996 bool isDiscrete() const override { return true; }
1997 bool isBoolean() const override { return true; }
1998 int getNumSteps() const override { return 2; }
1999 StringArray getAllValueStrings() const override { return values; }
2000 String getLabel() const override { return {}; }
2001 String getParameterID() const override { return {}; }
2002
2003 VSTPluginInstance& parent;
2004 bool currentValue = false;
2005 StringArray vstOnStrings, vstOffStrings, values;
2006 };
2007
2008 //==============================================================================
2009 String name;
2010 CriticalSection lock;
2011 std::atomic<bool> wantsMidiMessages { false };
2012 bool initialised = false;
2013 std::atomic<bool> isPowerOn { false };
2014 bool lastProcessBlockCallWasBypass = false, vstSupportsBypass = false;
2015 mutable StringArray programNames;
2016 AudioBuffer<float> outOfPlaceBuffer;
2017
2018 CriticalSection midiInLock;
2019 MidiBuffer incomingMidi;
2020 VSTMidiEventList midiEventsToSend;
2021 Vst2::VstTimingInformation vstHostTime;
2022
2023 AudioBuffer<float> tmpBufferFloat;
2024 HeapBlock<float*> channelBufferFloat;
2025
2026 AudioBuffer<double> tmpBufferDouble;
2027 HeapBlock<double*> channelBufferDouble;
2028 std::unique_ptr<VST2BypassParameter> bypassParam;
2029
2030 std::unique_ptr<VSTXMLInfo> xmlInfo;
2031
2032 static pointer_sized_int handleCanDo (const char* name)
2033 {
2034 static const char* canDos[] = { "supplyIdle",
2035 "sendVstEvents",
2036 "sendVstMidiEvent",
2037 "sendVstTimeInfo",
2038 "receiveVstEvents",
2039 "receiveVstMidiEvent",
2040 "supportShell",
2041 "sizeWindow",
2042 "shellCategory" };
2043
2044 for (int i = 0; i < numElementsInArray (canDos); ++i)
2045 if (strcmp (canDos[i], name) == 0)
2046 return 1;
2047
2048 return 0;
2049 }
2050
2051 static pointer_sized_int getHostName (char* name)
2052 {
2053 String hostName (JUCE_VST_FALLBACK_HOST_NAME);
2054
2055 if (auto* app = JUCEApplicationBase::getInstance())
2056 hostName = app->getApplicationName();
2057
2059 return 1;
2060 }
2061
2062 pointer_sized_int getVSTTime() noexcept
2063 {
2065
2066 return (pointer_sized_int) &vstHostTime;
2067
2069 }
2070
2071 void handleIdle()
2072 {
2073 if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread())
2074 {
2075 const IdleCallRecursionPreventer icrp;
2076
2077 #if JUCE_MAC
2078 if (getActiveEditor() != nullptr)
2079 dispatch (Vst2::plugInOpcodeEditorIdle, 0, 0, nullptr, 0);
2080 #endif
2081
2082 Timer::callPendingTimersSynchronously();
2083 handleUpdateNowIfNeeded();
2084
2085 for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
2086 if (auto* p = ComponentPeer::getPeer(i))
2087 p->performAnyPendingRepaintsNow();
2088 }
2089 }
2090
2091 void setWindowSize (int width, int height)
2092 {
2093 #if JUCE_LINUX || JUCE_BSD
2094 const MessageManagerLock mmLock;
2095 #endif
2096
2097 updateSizeFromEditor (width, height);
2098 }
2099
2100 //==============================================================================
2101 static Vst2::VstEffectInterface* constructEffect (const ModuleHandle::Ptr& module)
2102 {
2103 Vst2::VstEffectInterface* effect = nullptr;
2104 try
2105 {
2106 const IdleCallRecursionPreventer icrp;
2107 _fpreset();
2108
2109 JUCE_VST_LOG ("Creating VST instance: " + module->pluginName);
2110
2111 #if JUCE_MAC
2112 if (module->resFileId != 0)
2113 UseResFile (module->resFileId);
2114 #endif
2115
2116 {
2117 JUCE_VST_WRAPPER_INVOKE_MAIN
2118 }
2119
2120 if (effect != nullptr && effect->interfaceIdentifier == Vst2::juceVstInterfaceIdentifier)
2121 {
2122 jassert (effect->hostSpace2 == 0);
2123 jassert (effect->effectPointer != nullptr);
2124
2125 _fpreset(); // some dodgy plugs mess around with this
2126 }
2127 else
2128 {
2129 effect = nullptr;
2130 }
2131 }
2132 catch (...)
2133 {}
2134
2135 return effect;
2136 }
2137
2138 static BusesProperties queryBusIO (Vst2::VstEffectInterface* effect)
2139 {
2140 BusesProperties returnValue;
2141
2142 if (effect->numInputChannels == 0 && effect->numOutputChannels == 0)
2143 return returnValue;
2144
2145 // Workaround for old broken JUCE plug-ins which would return an invalid
2146 // speaker arrangement if the host didn't ask for a specific arrangement
2147 // beforehand.
2148 // Check if the plug-in reports any default layouts. If it doesn't, then
2149 // try setting a default layout compatible with the number of pins this
2150 // plug-in is reporting.
2151 if (! pluginHasDefaultChannelLayouts (effect))
2152 {
2153 SpeakerMappings::VstSpeakerConfigurationHolder canonicalIn (AudioChannelSet::canonicalChannelSet (effect->numInputChannels));
2154 SpeakerMappings::VstSpeakerConfigurationHolder canonicalOut (AudioChannelSet::canonicalChannelSet (effect->numOutputChannels));
2155
2156 effect->dispatchFunction (effect, Vst2::plugInOpcodeSetSpeakerConfiguration, 0,
2157 (pointer_sized_int) &canonicalIn.get(), (void*) &canonicalOut.get(), 0.0f);
2158 }
2159
2160 const auto arrangement = getSpeakerArrangementWrapper (effect);
2161
2162 for (int dir = 0; dir < 2; ++dir)
2163 {
2164 const bool isInput = (dir == 0);
2166 const int maxChannels = (isInput ? effect->numInputChannels : effect->numOutputChannels);
2167 const auto* arr = (isInput ? arrangement.in : arrangement.out);
2168 bool busAdded = false;
2169
2170 Vst2::VstPinInfo pinProps;
2171 AudioChannelSet layout;
2172
2173 for (int ch = 0; ch < maxChannels; ch += layout.size())
2174 {
2175 if (effect->dispatchFunction (effect, opcode, ch, 0, &pinProps, 0.0f) == 0)
2176 break;
2177
2178 if ((pinProps.flags & Vst2::vstPinInfoFlagValid) != 0)
2179 {
2180 layout = SpeakerMappings::vstArrangementTypeToChannelSet (pinProps.configurationType, 0);
2181
2182 if (layout.isDisabled())
2183 break;
2184 }
2185 else if (arr == nullptr)
2186 {
2187 layout = ((pinProps.flags & Vst2::vstPinInfoFlagIsStereo) != 0 ? AudioChannelSet::stereo() : AudioChannelSet::mono());
2188 }
2189 else
2190 break;
2191
2192 busAdded = true;
2193 returnValue.addBus (isInput, pinProps.text, layout, true);
2194 }
2195
2196 // no buses?
2197 if (! busAdded && maxChannels > 0)
2198 {
2199 String busName = (isInput ? "Input" : "Output");
2200
2201 if (effect->dispatchFunction (effect, opcode, 0, 0, &pinProps, 0.0f) != 0)
2202 busName = pinProps.text;
2203
2204 if (arr != nullptr)
2205 layout = SpeakerMappings::vstArrangementTypeToChannelSet (*arr);
2206 else
2207 layout = AudioChannelSet::canonicalChannelSet (maxChannels);
2208
2209 returnValue.addBus (isInput, busName, layout, true);
2210 }
2211 }
2212
2213 return returnValue;
2214 }
2215
2216 static bool pluginHasDefaultChannelLayouts (Vst2::VstEffectInterface* effect)
2217 {
2218 if (getSpeakerArrangementWrapper (effect).isValid())
2219 return true;
2220
2221 for (int dir = 0; dir < 2; ++dir)
2222 {
2223 const bool isInput = (dir == 0);
2225 const int maxChannels = (isInput ? effect->numInputChannels : effect->numOutputChannels);
2226
2227 int channels = 1;
2228
2229 for (int ch = 0; ch < maxChannels; ch += channels)
2230 {
2231 Vst2::VstPinInfo pinProps;
2232
2233 if (effect->dispatchFunction (effect, opcode, ch, 0, &pinProps, 0.0f) == 0)
2234 return false;
2235
2236 if ((pinProps.flags & Vst2::vstPinInfoFlagValid) != 0)
2237 return true;
2238
2239 channels = (pinProps.flags & Vst2::vstPinInfoFlagIsStereo) != 0 ? 2 : 1;
2240 }
2241 }
2242
2243 return false;
2244 }
2245
2246 struct SpeakerArrangements
2247 {
2248 const Vst2::VstSpeakerConfiguration* in;
2249 const Vst2::VstSpeakerConfiguration* out;
2250
2251 bool isValid() const noexcept { return in != nullptr && out != nullptr; }
2252 };
2253
2254 static SpeakerArrangements getSpeakerArrangementWrapper (Vst2::VstEffectInterface* effect)
2255 {
2256 // Workaround: unfortunately old JUCE VST-2 plug-ins had a bug and would crash if
2257 // you try to get the speaker arrangement when there are no input channels present.
2258 // Hopefully, one day (when there are no more old JUCE plug-ins around), we can
2259 // comment out the next two lines.
2260 if (effect->numInputChannels == 0)
2261 return { nullptr, nullptr };
2262
2263 SpeakerArrangements result { nullptr, nullptr };
2264 const auto dispatchResult = effect->dispatchFunction (effect,
2266 0,
2267 reinterpret_cast<pointer_sized_int> (&result.in),
2268 &result.out,
2269 0.0f);
2270
2271 if (dispatchResult != 0)
2272 return result;
2273
2274 return { nullptr, nullptr };
2275 }
2276
2277 template <typename Member, typename Value>
2278 void setFromOptional (Member& target, Optional<Value> opt, int32_t flag)
2279 {
2280 if (opt.hasValue())
2281 {
2282 target = static_cast<Member> (*opt);
2283 vstHostTime.flags |= flag;
2284 }
2285 else
2286 {
2287 vstHostTime.flags &= ~flag;
2288 }
2289 }
2290
2291 //==============================================================================
2292 template <typename FloatType>
2293 void processAudio (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages,
2294 AudioBuffer<FloatType>& tmpBuffer,
2295 HeapBlock<FloatType*>& channelBuffer,
2296 bool processBlockBypassedCalled)
2297 {
2298 if (vstSupportsBypass)
2299 {
2300 updateBypass (processBlockBypassedCalled);
2301 }
2302 else if (processBlockBypassedCalled)
2303 {
2304 // if this vst does not support bypass then we will have to do this ourselves
2305 AudioProcessor::processBlockBypassed (buffer, midiMessages);
2306 return;
2307 }
2308
2309 auto numSamples = buffer.getNumSamples();
2310 auto numChannels = buffer.getNumChannels();
2311
2312 if (initialised)
2313 {
2314 if (auto* currentPlayHead = getPlayHead())
2315 {
2316 if (const auto position = currentPlayHead->getPosition())
2317 {
2318 if (const auto samplePos = position->getTimeInSamples())
2319 vstHostTime.samplePosition = (double) *samplePos;
2320 else
2321 jassertfalse; // VST hosts *must* call setTimeInSamples on the audio playhead
2322
2323 if (auto sig = position->getTimeSignature())
2324 {
2325 vstHostTime.flags |= Vst2::vstTimingInfoFlagTimeSignatureValid;
2326 vstHostTime.timeSignatureNumerator = sig->numerator;
2327 vstHostTime.timeSignatureDenominator = sig->denominator;
2328 }
2329 else
2330 {
2331 vstHostTime.flags &= ~Vst2::vstTimingInfoFlagTimeSignatureValid;
2332 }
2333
2334 setFromOptional (vstHostTime.musicalPosition, position->getPpqPosition(), Vst2::vstTimingInfoFlagMusicalPositionValid);
2335 setFromOptional (vstHostTime.lastBarPosition, position->getPpqPositionOfLastBarStart(), Vst2::vstTimingInfoFlagLastBarPositionValid);
2336 setFromOptional (vstHostTime.systemTimeNanoseconds, position->getHostTimeNs(), Vst2::vstTimingInfoFlagNanosecondsValid);
2337 setFromOptional (vstHostTime.tempoBPM, position->getBpm(), Vst2::vstTimingInfoFlagTempoValid);
2338
2339 int32 newTransportFlags = 0;
2340 if (position->getIsPlaying()) newTransportFlags |= Vst2::vstTimingInfoFlagCurrentlyPlaying;
2341 if (position->getIsRecording()) newTransportFlags |= Vst2::vstTimingInfoFlagCurrentlyRecording;
2342
2343 if (newTransportFlags != (vstHostTime.flags & (Vst2::vstTimingInfoFlagCurrentlyPlaying
2346 else
2347 vstHostTime.flags &= ~Vst2::vstTimingInfoFlagTransportChanged;
2348
2349 const auto optionalFrameRate = [fr = position->getFrameRate()]() -> Optional<int32>
2350 {
2351 if (! fr.hasValue())
2352 return {};
2353
2354 switch (fr->getBaseRate())
2355 {
2356 case 24: return fr->isPullDown() ? Vst2::vstSmpteRateFps239 : Vst2::vstSmpteRateFps24;
2357 case 25: return fr->isPullDown() ? Vst2::vstSmpteRateFps249 : Vst2::vstSmpteRateFps25;
2358 case 30: return fr->isPullDown() ? (fr->isDrop() ? Vst2::vstSmpteRateFps2997drop : Vst2::vstSmpteRateFps2997)
2360 case 60: return fr->isPullDown() ? Vst2::vstSmpteRateFps599 : Vst2::vstSmpteRateFps60;
2361 }
2362
2363 return {};
2364 }();
2365
2366 vstHostTime.flags |= optionalFrameRate ? Vst2::vstTimingInfoFlagSmpteValid : 0;
2367 vstHostTime.smpteRate = optionalFrameRate.orFallback (0);
2368 const auto effectiveRate = position->getFrameRate().hasValue() ? position->getFrameRate()->getEffectiveRate() : 0.0;
2369 vstHostTime.smpteOffset = (int32) (position->getTimeInSeconds().orFallback (0.0) * 80.0 * effectiveRate + 0.5);
2370
2371 if (const auto loop = position->getLoopPoints())
2372 {
2373 vstHostTime.flags |= Vst2::vstTimingInfoFlagLoopPositionValid;
2374 vstHostTime.loopStartPosition = loop->ppqStart;
2375 vstHostTime.loopEndPosition = loop->ppqEnd;
2376 }
2377 else
2378 {
2379 vstHostTime.flags &= ~Vst2::vstTimingInfoFlagLoopPositionValid;
2380 }
2381
2382 if (position->getIsLooping())
2383 vstHostTime.flags |= Vst2::vstTimingInfoFlagLoopActive;
2384 else
2385 vstHostTime.flags &= ~Vst2::vstTimingInfoFlagLoopActive;
2386 }
2387 }
2388
2389 vstHostTime.systemTimeNanoseconds = getVSTHostTimeNanoseconds();
2390
2391 if (wantsMidiMessages)
2392 {
2393 midiEventsToSend.clear();
2394 midiEventsToSend.ensureSize (1);
2395
2396 for (const auto metadata : midiMessages)
2397 midiEventsToSend.addEvent (metadata.data, metadata.numBytes,
2398 jlimit (0, numSamples - 1, metadata.samplePosition));
2399
2400 vstEffect->dispatchFunction (vstEffect, Vst2::plugInOpcodePreAudioProcessingEvents, 0, 0, midiEventsToSend.events, 0);
2401 }
2402
2403 _clearfp();
2404
2405 // always ensure that the buffer is at least as large as the maximum number of channels
2406 auto maxChannels = jmax (vstEffect->numInputChannels, vstEffect->numOutputChannels);
2407 auto channels = channelBuffer.get();
2408
2409 if (numChannels < maxChannels)
2410 {
2411 if (numSamples > tmpBuffer.getNumSamples())
2412 tmpBuffer.setSize (tmpBuffer.getNumChannels(), numSamples);
2413
2414 tmpBuffer.clear();
2415 }
2416
2417 for (int ch = 0; ch < maxChannels; ++ch)
2418 channels[ch] = (ch < numChannels ? buffer.getWritePointer (ch) : tmpBuffer.getWritePointer (ch));
2419
2420 {
2421 AudioBuffer<FloatType> processBuffer (channels, maxChannels, numSamples);
2422
2423 invokeProcessFunction (processBuffer, numSamples);
2424 }
2425 }
2426 else
2427 {
2428 // Not initialised, so just bypass.
2429 for (int i = getTotalNumOutputChannels(); --i >= 0;)
2430 buffer.clear (i, 0, buffer.getNumSamples());
2431 }
2432
2433 {
2434 // copy any incoming midi.
2435 const ScopedLock sl (midiInLock);
2436
2437 midiMessages.swapWith (incomingMidi);
2438 incomingMidi.clear();
2439 }
2440 }
2441
2442 //==============================================================================
2443 inline void invokeProcessFunction (AudioBuffer<float>& buffer, int32 sampleFrames)
2444 {
2445 if ((vstEffect->flags & Vst2::vstEffectFlagInplaceAudio) != 0)
2446 {
2447 vstEffect->processAudioInplaceFunction (vstEffect, buffer.getArrayOfWritePointers(),
2448 buffer.getArrayOfWritePointers(), sampleFrames);
2449 }
2450 else
2451 {
2452 outOfPlaceBuffer.setSize (vstEffect->numOutputChannels, sampleFrames);
2453 outOfPlaceBuffer.clear();
2454
2455 vstEffect->processAudioFunction (vstEffect, buffer.getArrayOfWritePointers(),
2456 outOfPlaceBuffer.getArrayOfWritePointers(), sampleFrames);
2457
2458 for (int i = vstEffect->numOutputChannels; --i >= 0;)
2459 buffer.copyFrom (i, 0, outOfPlaceBuffer.getReadPointer (i), sampleFrames);
2460 }
2461 }
2462
2463 inline void invokeProcessFunction (AudioBuffer<double>& buffer, int32 sampleFrames)
2464 {
2465 vstEffect->processDoubleAudioInplaceFunction (vstEffect, buffer.getArrayOfWritePointers(),
2466 buffer.getArrayOfWritePointers(), sampleFrames);
2467 }
2468
2469 //==============================================================================
2470 bool restoreProgramSettings (const fxProgram* const prog)
2471 {
2472 if (compareMagic (prog->chunkMagic, "CcnK")
2473 && compareMagic (prog->fxMagic, "FxCk"))
2474 {
2475 changeProgramName (getCurrentProgram(), prog->prgName);
2476
2477 for (int i = 0; i < fxbSwap (prog->numParams); ++i)
2478 if (auto* param = getParameters()[i])
2479 param->setValue (fxbSwapFloat (prog->params[i]));
2480
2481 return true;
2482 }
2483
2484 return false;
2485 }
2486
2487 String getTextForOpcode (const int index, const int opcode) const
2488 {
2489 if (vstEffect == nullptr)
2490 return {};
2491
2492 jassert (index >= 0 && index < vstEffect->numParameters);
2493 char nm[256] = { 0 };
2494 dispatch (opcode, index, 0, nm, 0);
2495 return String::createStringFromData (nm, (int) sizeof (nm)).trim();
2496 }
2497
2498 String getCurrentProgramName()
2499 {
2500 String progName;
2501
2502 if (vstEffect != nullptr)
2503 {
2504 {
2505 char nm[256] = { 0 };
2506 dispatch (Vst2::plugInOpcodeGetCurrentProgramName, 0, 0, nm, 0);
2507 progName = String::createStringFromData (nm, (int) sizeof (nm)).trim();
2508 }
2509
2510 const int index = getCurrentProgram();
2511
2512 if (index >= 0 && programNames[index].isEmpty())
2513 {
2514 while (programNames.size() < index)
2515 programNames.add (String());
2516
2517 programNames.set (index, progName);
2518 }
2519 }
2520
2521 return progName;
2522 }
2523
2524 void setParamsInProgramBlock (fxProgram* prog)
2525 {
2526 auto numParams = getParameters().size();
2527
2528 prog->chunkMagic = fxbName ("CcnK");
2529 prog->byteSize = 0;
2530 prog->fxMagic = fxbName ("FxCk");
2531 prog->version = fxbSwap (fxbVersionNum);
2532 prog->fxID = fxbSwap (getUID());
2533 prog->fxVersion = fxbSwap (getVersionNumber());
2534 prog->numParams = fxbSwap (numParams);
2535
2536 getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1);
2537
2538 for (int i = 0; i < numParams; ++i)
2539 if (auto* param = getParameters()[i])
2540 prog->params[i] = fxbSwapFloat (param->getValue());
2541 }
2542
2543 void updateStoredProgramNames()
2544 {
2545 if (vstEffect != nullptr && getNumPrograms() > 0)
2546 {
2547 char nm[256] = { 0 };
2548
2549 // only do this if the plugin can't use indexed names.
2550 if (dispatch (Vst2::plugInOpcodeGetProgramName, 0, -1, nm, 0) == 0)
2551 {
2552 auto oldProgram = getCurrentProgram();
2553 MemoryBlock oldSettings;
2554 createTempParameterStore (oldSettings);
2555
2556 for (int i = 0; i < getNumPrograms(); ++i)
2557 {
2558 setCurrentProgram (i);
2559 getCurrentProgramName(); // (this updates the list)
2560 }
2561
2562 setCurrentProgram (oldProgram);
2563 restoreFromTempParameterStore (oldSettings);
2564 }
2565 }
2566 }
2567
2568 void handleMidiFromPlugin (const Vst2::VstEventBlock* events)
2569 {
2570 if (events != nullptr)
2571 {
2572 const ScopedLock sl (midiInLock);
2573 VSTMidiEventList::addEventsToMidiBuffer (events, incomingMidi);
2574 }
2575 }
2576
2577 //==============================================================================
2578 void createTempParameterStore (MemoryBlock& dest)
2579 {
2580 auto numParameters = getParameters().size();
2581 dest.setSize (64 + 4 * (size_t) numParameters);
2582 dest.fillWith (0);
2583
2584 getCurrentProgramName().copyToUTF8 ((char*) dest.getData(), 63);
2585
2586 auto p = unalignedPointerCast<float*> (((char*) dest.getData()) + 64);
2587
2588 for (int i = 0; i < numParameters; ++i)
2589 if (auto* param = getParameters()[i])
2590 p[i] = param->getValue();
2591 }
2592
2593 void restoreFromTempParameterStore (const MemoryBlock& m)
2594 {
2595 changeProgramName (getCurrentProgram(), (const char*) m.getData());
2596
2597 auto p = unalignedPointerCast<float*> (((char*) m.getData()) + 64);
2598 auto numParameters = getParameters().size();
2599
2600 for (int i = 0; i < numParameters; ++i)
2601 if (auto* param = getParameters()[i])
2602 param->setValue (p[i]);
2603 }
2604
2605 pointer_sized_int getVstDirectory() const
2606 {
2607 #if JUCE_MAC
2608 return (pointer_sized_int) (void*) &vstModule->parentDirFSSpec;
2609 #else
2610 return (pointer_sized_int) (pointer_sized_uint) vstModule->fullParentDirectoryPathName.toRawUTF8();
2611 #endif
2612 }
2613
2614 //==============================================================================
2615 int getVersionNumber() const noexcept { return vstEffect != nullptr ? vstEffect->plugInVersion : 0; }
2616
2617 String getVersion() const
2618 {
2619 auto v = (unsigned int) dispatch (Vst2::plugInOpcodeGetManufacturerVersion, 0, 0, nullptr, 0);
2620
2621 String s;
2622
2623 if (v == 0 || (int) v == -1)
2624 v = (unsigned int) getVersionNumber();
2625
2626 if (v != 0)
2627 {
2628 // See yfede's post for the rational on this encoding
2629 // https://forum.juce.com/t/issues-with-version-integer-reported-by-vst2/23867/6
2630
2631 unsigned int major = 0, minor = 0, bugfix = 0, build = 0;
2632
2633 if (v < 10) // Encoding A
2634 {
2635 major = v;
2636 }
2637 else if (v < 10000) // Encoding B
2638 {
2639 major = (v / 1000);
2640 minor = (v % 1000) / 100;
2641 bugfix = (v % 100) / 10;
2642 build = (v % 10);
2643 }
2644 else if (v < 0x10000) // Encoding C
2645 {
2646 major = (v / 10000);
2647 minor = (v % 10000) / 1000;
2648 bugfix = (v % 1000) / 100;
2649 build = (v % 100) / 10;
2650 }
2651 else if (v < 0x650000) // Encoding D
2652 {
2653 major = (v >> 16) & 0xff;
2654 minor = (v >> 8) & 0xff;
2655 bugfix = (v >> 0) & 0xff;
2656 }
2657 else // Encoding E
2658 {
2659 major = (v / 10000000);
2660 minor = (v % 10000000) / 100000;
2661 bugfix = (v % 100000) / 1000;
2662 build = (v % 1000);
2663 }
2664
2665 s << (int) major << '.' << (int) minor << '.' << (int) bugfix << '.' << (int) build;
2666 }
2667
2668 return s;
2669 }
2670
2671 const char* getCategory() const
2672 {
2673 switch (getVstCategory())
2674 {
2675 case Vst2::kPlugCategEffect: return "Effect";
2676 case Vst2::kPlugCategSynth: return "Synth";
2677 case Vst2::kPlugCategAnalysis: return "Analysis";
2678 case Vst2::kPlugCategMastering: return "Mastering";
2679 case Vst2::kPlugCategSpacializer: return "Spacial";
2680 case Vst2::kPlugCategRoomFx: return "Reverb";
2681 case Vst2::kPlugSurroundFx: return "Surround";
2682 case Vst2::kPlugCategRestoration: return "Restoration";
2683 case Vst2::kPlugCategGenerator: return "Tone generation";
2684 case Vst2::kPlugCategOfflineProcess: return "Offline Process";
2685 case Vst2::kPlugCategShell: return "Shell";
2686 case Vst2::kPlugCategUnknown: return "Unknown";
2687 default: break;
2688 }
2689
2690 return nullptr;
2691 }
2692
2693 void setPower (const bool on)
2694 {
2695 dispatch (Vst2::plugInOpcodeResumeSuspend, 0, on ? 1 : 0, nullptr, 0);
2696 isPowerOn = on;
2697 }
2698
2699 //==============================================================================
2700 void updateBypass (bool processBlockBypassedCalled)
2701 {
2702 if (processBlockBypassedCalled)
2703 {
2704 if (bypassParam->getValue() == 0.0f || ! lastProcessBlockCallWasBypass)
2705 bypassParam->setValue (1.0f);
2706 }
2707 else
2708 {
2709 if (lastProcessBlockCallWasBypass)
2710 bypassParam->setValue (0.0f);
2711 }
2712
2713 lastProcessBlockCallWasBypass = processBlockBypassedCalled;
2714 }
2715
2717};
2718
2719//==============================================================================
2720#if ! (JUCE_IOS || JUCE_ANDROID)
2721struct VSTPluginWindow;
2722static Array<VSTPluginWindow*> activeVSTWindows;
2723
2724//==============================================================================
2725struct VSTPluginWindow : public AudioProcessorEditor,
2726 #if ! JUCE_MAC
2727 private ComponentMovementWatcher,
2728 #endif
2729 private Timer
2730{
2731public:
2732 VSTPluginWindow (VSTPluginInstance& plug)
2733 : AudioProcessorEditor (&plug),
2734 #if ! JUCE_MAC
2735 ComponentMovementWatcher (this),
2736 #endif
2737 plugin (plug)
2738 {
2739 #if JUCE_LINUX || JUCE_BSD
2740 pluginWindow = None;
2741 ignoreUnused (pluginRefusesToResize, alreadyInside);
2742 #elif JUCE_MAC
2743 ignoreUnused (recursiveResize, pluginRefusesToResize, alreadyInside);
2744
2745 cocoaWrapper.reset (new NSViewComponentWithParent (plugin));
2746 addAndMakeVisible (cocoaWrapper.get());
2747 #endif
2748
2749 activeVSTWindows.add (this);
2750
2751 Vst2::VstEditorBounds* rect = nullptr;
2752 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0);
2753
2754 if (rect != nullptr)
2755 updateSizeFromEditor (rect->rightmost - rect->leftmost, rect->lower - rect->upper);
2756 else
2757 updateSizeFromEditor (1, 1);
2758
2759 setOpaque (true);
2760 setVisible (true);
2761
2762 #if JUCE_WINDOWS
2763 addAndMakeVisible (embeddedComponent);
2764 #endif
2765 }
2766
2767 ~VSTPluginWindow() override
2768 {
2769 closePluginWindow();
2770
2771 #if JUCE_MAC
2772 cocoaWrapper.reset();
2773 #endif
2774
2775 activeVSTWindows.removeFirstMatchingValue (this);
2776 plugin.editorBeingDeleted (this);
2777 }
2778
2779 //==============================================================================
2780 /* Convert from the hosted VST's coordinate system to the component's coordinate system. */
2781 Rectangle<int> vstToComponentRect (Component& editor, const Rectangle<int>& vr) const
2782 {
2783 return editor.getLocalArea (nullptr, vr / (nativeScaleFactor * getDesktopScaleFactor()));
2784 }
2785
2786 Rectangle<int> componentToVstRect (Component& editor, const Rectangle<int>& vr) const
2787 {
2788 if (auto* tl = editor.getTopLevelComponent())
2789 return tl->getLocalArea (&editor, vr) * nativeScaleFactor * tl->getDesktopScaleFactor();
2790
2791 return {};
2792 }
2793
2794 bool updateSizeFromEditor (int w, int h)
2795 {
2796 const auto correctedBounds = vstToComponentRect (*this, { w, h });
2797 setSize (correctedBounds.getWidth(), correctedBounds.getHeight());
2798
2799 #if JUCE_MAC
2800 if (cocoaWrapper != nullptr)
2801 cocoaWrapper->setSize (correctedBounds.getWidth(), correctedBounds.getHeight());
2802 #endif
2803
2804 return true;
2805 }
2806
2807 #if JUCE_MAC
2808 void paint (Graphics& g) override
2809 {
2810 g.fillAll (Colours::black);
2811 }
2812
2813 void visibilityChanged() override
2814 {
2815 if (isShowing())
2816 openPluginWindow ((NSView*) cocoaWrapper->getView());
2817 else
2818 closePluginWindow();
2819 }
2820
2821 void childBoundsChanged (Component*) override
2822 {
2823 auto w = cocoaWrapper->getWidth();
2824 auto h = cocoaWrapper->getHeight();
2825
2826 if (w != getWidth() || h != getHeight())
2827 setSize (w, h);
2828 }
2829
2830 void parentHierarchyChanged() override { visibilityChanged(); }
2831 #else
2832 float getEffectiveScale() const
2833 {
2834 return nativeScaleFactor * userScaleFactor;
2835 }
2836
2837 void paint (Graphics& g) override
2838 {
2839 #if JUCE_LINUX || JUCE_BSD
2840 if (isOpen)
2841 {
2842 if (pluginWindow != 0)
2843 {
2844 auto clip = componentToVstRect (*this, g.getClipBounds().toNearestInt());
2845
2846 X11Symbols::getInstance()->xClearArea (display, pluginWindow, clip.getX(), clip.getY(),
2847 static_cast<unsigned int> (clip.getWidth()),
2848 static_cast<unsigned int> (clip.getHeight()), True);
2849 }
2850 }
2851 else
2852 #endif
2853 {
2854 g.fillAll (Colours::black);
2855 }
2856 }
2857
2858 void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
2859 {
2860 if (recursiveResize)
2861 return;
2862
2863 if (getPeer() != nullptr)
2864 {
2865 const ScopedValueSetter<bool> recursiveResizeSetter (recursiveResize, true);
2866
2867 #if JUCE_WINDOWS
2868 embeddedComponent.setBounds (getLocalBounds());
2869 #elif JUCE_LINUX || JUCE_BSD
2870 const auto pos = componentToVstRect (*this, getLocalBounds());
2871
2872 if (pluginWindow != 0)
2873 {
2874 auto* symbols = X11Symbols::getInstance();
2875 symbols->xMoveResizeWindow (display,
2876 pluginWindow,
2877 pos.getX(),
2878 pos.getY(),
2879 (unsigned int) pos.getWidth(),
2880 (unsigned int) pos.getHeight());
2881 symbols->xMapRaised (display, pluginWindow);
2882 symbols->xFlush (display);
2883 }
2884 #endif
2885 }
2886 }
2887
2888 using ComponentMovementWatcher::componentMovedOrResized;
2889
2890 void componentVisibilityChanged() override
2891 {
2892 if (isShowing())
2893 openPluginWindow();
2894 else if (! shouldAvoidDeletingWindow())
2895 closePluginWindow();
2896
2897 setContentScaleFactor();
2898
2899 #if JUCE_LINUX || JUCE_BSD
2900 MessageManager::callAsync ([safeThis = SafePointer<VSTPluginWindow> { this }]
2901 {
2902 if (safeThis != nullptr)
2903 safeThis->componentMovedOrResized (true, true);
2904 });
2905 #else
2906 componentMovedOrResized (true, true);
2907 #endif
2908 }
2909
2910 using ComponentMovementWatcher::componentVisibilityChanged;
2911
2912 void componentPeerChanged() override
2913 {
2914 closePluginWindow();
2915
2916 if (getPeer() != nullptr)
2917 {
2918 openPluginWindow();
2919 componentMovedOrResized (true, true);
2920 }
2921 }
2922
2923 void setContentScaleFactor()
2924 {
2925 if (pluginRespondsToDPIChanges)
2927 (int) ByteOrder::bigEndianInt ("PreS"),
2928 (int) ByteOrder::bigEndianInt ("AeCs"),
2929 nullptr, getEffectiveScale());
2930 }
2931 #endif
2932
2933 void setScaleFactor (float scale) override
2934 {
2935 userScaleFactor = scale;
2936
2937 #if ! JUCE_MAC
2938 setContentScaleFactor();
2939 #endif
2940
2941 #if JUCE_WINDOWS
2942 resizeToFit();
2943 #endif
2944 }
2945
2946 //==============================================================================
2947 bool keyStateChanged (bool) override { return pluginWantsKeys; }
2948 bool keyPressed (const juce::KeyPress&) override { return pluginWantsKeys; }
2949
2950 //==============================================================================
2951 void timerCallback() override
2952 {
2953 if (isShowing())
2954 {
2955 #if JUCE_WINDOWS
2956 if (--sizeCheckCount <= 0)
2957 {
2958 sizeCheckCount = 10;
2959 checkPluginWindowSize();
2960 }
2961 #endif
2962
2963 static bool reentrantGuard = false;
2964
2965 if (! reentrantGuard)
2966 {
2967 reentrantGuard = true;
2968
2969 #if JUCE_WINDOWS
2970 // Some plugins may draw/resize inside their idle callback, so ensure that
2971 // DPI awareness is set correctly inside this call.
2972 ScopedThreadDPIAwarenessSetter scope (getPluginHWND());
2973 #endif
2974 plugin.dispatch (Vst2::plugInOpcodeEditorIdle, 0, 0, nullptr, 0);
2975
2976 reentrantGuard = false;
2977 }
2978
2979 #if JUCE_LINUX || JUCE_BSD
2980 if (pluginWindow == 0)
2981 {
2982 updatePluginWindowHandle();
2983
2984 if (pluginWindow != 0)
2985 componentMovedOrResized (true, true);
2986 }
2987 #endif
2988 }
2989 }
2990
2991 //==============================================================================
2992 void mouseDown (const MouseEvent& e) override
2993 {
2994 ignoreUnused (e);
2995
2996 #if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD
2997 toFront (true);
2998 #endif
2999 }
3000
3001 void broughtToFront() override
3002 {
3003 activeVSTWindows.removeFirstMatchingValue (this);
3004 activeVSTWindows.add (this);
3005
3006 #if JUCE_MAC
3007 dispatch (Vst2::plugInOpcodeeffEditorTop, 0, 0, nullptr, 0);
3008 #endif
3009 }
3010
3011private:
3012 //==============================================================================
3013 // This is a workaround for old Mackie plugins that crash if their
3014 // window is deleted more than once.
3015 bool shouldAvoidDeletingWindow() const
3016 {
3017 return plugin.getPluginDescription()
3018 .manufacturerName.containsIgnoreCase ("Loud Technologies");
3019 }
3020
3021 // This is an old workaround for some plugins that need a repaint when their
3022 // windows are first created, but it breaks some Izotope plugins.
3023 bool shouldRepaintCarbonWindowWhenCreated()
3024 {
3025 return ! plugin.getName().containsIgnoreCase ("izotope");
3026 }
3027
3028 //==============================================================================
3029 #if JUCE_MAC
3030 void openPluginWindow (void* parentWindow)
3031 {
3032 if (isOpen || parentWindow == nullptr)
3033 return;
3034
3035 isOpen = true;
3036
3037 Vst2::VstEditorBounds* rect = nullptr;
3038 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0);
3039 dispatch (Vst2::plugInOpcodeOpenEditor, 0, 0, parentWindow, 0);
3040
3041 // do this before and after like in the steinberg example
3042 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0);
3043 dispatch (Vst2::plugInOpcodeGetCurrentProgram, 0, 0, nullptr, 0); // also in steinberg code
3044
3045 // Install keyboard hooks
3046 pluginWantsKeys = (dispatch (Vst2::plugInOpcodeKeyboardFocusRequired, 0, 0, nullptr, 0) == 0);
3047
3048 // double-check it's not too tiny
3049 int w = 250, h = 150;
3050
3051 if (rect != nullptr)
3052 {
3053 w = rect->rightmost - rect->leftmost;
3054 h = rect->lower - rect->upper;
3055
3056 if (w == 0 || h == 0)
3057 {
3058 w = 250;
3059 h = 150;
3060 }
3061 }
3062
3063 w = jmax (w, 32);
3064 h = jmax (h, 32);
3065
3066 updateSizeFromEditor (w, h);
3067
3068 startTimer (18 + juce::Random::getSystemRandom().nextInt (5));
3069 repaint();
3070 }
3071 #else
3072 void openPluginWindow()
3073 {
3074 if (isOpen)
3075 return;
3076
3077 JUCE_VST_LOG ("Opening VST UI: " + plugin.getName());
3078 isOpen = true;
3079
3080 pluginRespondsToDPIChanges = plugin.pluginCanDo ("supportsViewDpiScaling") > 0;
3081
3082 setContentScaleFactor();
3083
3084 Vst2::VstEditorBounds* rect = nullptr;
3085
3086 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0);
3087
3088 #if JUCE_WINDOWS
3089 auto* handle = embeddedComponent.getHWND();
3090 #else
3091 auto* handle = getWindowHandle();
3092 #endif
3093 dispatch (Vst2::plugInOpcodeOpenEditor, 0, 0, handle, 0);
3094 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0); // do this before and after like in the steinberg example
3095 dispatch (Vst2::plugInOpcodeGetCurrentProgram, 0, 0, nullptr, 0); // also in steinberg code
3096
3097 pluginWantsKeys = (dispatch (Vst2::plugInOpcodeKeyboardFocusRequired, 0, 0, nullptr, 0) == 0);
3098
3099 #if JUCE_WINDOWS
3100 originalWndProc = 0;
3101 auto* pluginHWND = getPluginHWND();
3102
3103 if (pluginHWND == 0)
3104 {
3105 isOpen = false;
3106 setSize (300, 150);
3107 return;
3108 }
3109
3111
3112 if (! pluginWantsKeys)
3113 {
3114 originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
3115 SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc);
3116 }
3117
3119
3120 RECT r;
3121
3122 {
3123 ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
3124 GetWindowRect (pluginHWND, &r);
3125 }
3126
3127 auto w = (int) (r.right - r.left);
3128 auto h = (int) (r.bottom - r.top);
3129
3130 if (rect != nullptr)
3131 {
3132 auto rw = rect->rightmost - rect->leftmost;
3133 auto rh = rect->lower - rect->upper;
3134
3135 if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && (! isWithin (w, rw, 2) || ! isWithin (h, rh, 2)))
3136 || ((w == 0 && rw > 0) || (h == 0 && rh > 0)))
3137 {
3138 // very dodgy logic to decide which size is right.
3139 if (std::abs (rw - w) > 350 || std::abs (rh - h) > 350)
3140 {
3141 ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
3142
3143 SetWindowPos (pluginHWND, 0,
3144 0, 0, rw, rh,
3145 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
3146
3147 GetWindowRect (pluginHWND, &r);
3148
3149 w = r.right - r.left;
3150 h = r.bottom - r.top;
3151
3152 pluginRefusesToResize = (w != rw) || (h != rh);
3153
3154 w = rw;
3155 h = rh;
3156 }
3157 }
3158 }
3159 #elif JUCE_LINUX || JUCE_BSD
3160 updatePluginWindowHandle();
3161
3162 int w = 250, h = 150;
3163
3164 if (rect != nullptr)
3165 {
3166 w = rect->rightmost - rect->leftmost;
3167 h = rect->lower - rect->upper;
3168
3169 if (w == 0 || h == 0)
3170 {
3171 w = 250;
3172 h = 150;
3173 }
3174 }
3175
3176 if (pluginWindow != 0)
3177 X11Symbols::getInstance()->xMapRaised (display, pluginWindow);
3178 #endif
3179
3180 // double-check it's not too tiny
3181 w = jmax (w, 32);
3182 h = jmax (h, 32);
3183
3184 updateSizeFromEditor (w, h);
3185
3186 #if JUCE_WINDOWS
3187 checkPluginWindowSize();
3188 #endif
3189
3190 startTimer (18 + juce::Random::getSystemRandom().nextInt (5));
3191 repaint();
3192 }
3193 #endif
3194
3195 //==============================================================================
3196 void closePluginWindow()
3197 {
3198 if (isOpen)
3199 {
3200 // You shouldn't end up hitting this assertion unless the host is trying to do GUI
3201 // cleanup on a non-GUI thread. If it does that, bad things could happen in here.
3203
3204 JUCE_VST_LOG ("Closing VST UI: " + plugin.getName());
3205 isOpen = false;
3206 dispatch (Vst2::plugInOpcodeCloseEditor, 0, 0, nullptr, 0);
3207 stopTimer();
3208
3209 #if JUCE_WINDOWS
3211 auto* pluginHWND = getPluginHWND();
3212
3213 if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND))
3214 SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
3216
3217 originalWndProc = 0;
3218 #elif JUCE_LINUX || JUCE_BSD
3219 pluginWindow = 0;
3220 #endif
3221 }
3222 }
3223
3224 //==============================================================================
3225 pointer_sized_int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt)
3226 {
3227 return plugin.dispatch (opcode, index, value, ptr, opt);
3228 }
3229
3230 //==============================================================================
3231 #if JUCE_WINDOWS
3232 bool isWindowSizeCorrectForPlugin (int w, int h)
3233 {
3234 if (pluginRefusesToResize)
3235 return true;
3236
3237 const auto converted = vstToComponentRect (*this, { w, h });
3238 return (isWithin (converted.getWidth(), getWidth(), 5) && isWithin (converted.getHeight(), getHeight(), 5));
3239 }
3240
3241 void resizeToFit()
3242 {
3243 Vst2::VstEditorBounds* rect = nullptr;
3244 dispatch (Vst2::plugInOpcodeGetEditorBounds, 0, 0, &rect, 0);
3245
3246 auto w = rect->rightmost - rect->leftmost;
3247 auto h = rect->lower - rect->upper;
3248
3249 if (! isWindowSizeCorrectForPlugin (w, h))
3250 {
3251 updateSizeFromEditor (w, h);
3252 sizeCheckCount = 0;
3253 }
3254
3255 embeddedComponent.updateHWNDBounds();
3256 }
3257
3258 void checkPluginWindowSize()
3259 {
3260 if (! pluginRespondsToDPIChanges)
3261 resizeToFit();
3262 }
3263
3264 // hooks to get keyboard events from VST windows.
3265 static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam)
3266 {
3267 for (int i = activeVSTWindows.size(); --i >= 0;)
3268 {
3269 Component::SafePointer<VSTPluginWindow> w (activeVSTWindows[i]);
3270
3271 auto* pluginHWND = w->getPluginHWND();
3272
3273 if (w != nullptr && pluginHWND == hW)
3274 {
3275 if (message == WM_CHAR
3276 || message == WM_KEYDOWN
3278 || message == WM_KEYUP
3279 || message == WM_SYSKEYUP
3280 || message == WM_APPCOMMAND)
3281 {
3282 SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(),
3283 message, wParam, lParam);
3284 }
3285
3286 if (w != nullptr) // (may have been deleted in SendMessage callback)
3287 return CallWindowProc ((WNDPROC) w->originalWndProc,
3288 (HWND) pluginHWND,
3289 message, wParam, lParam);
3290 }
3291 }
3292
3293 return DefWindowProc (hW, message, wParam, lParam);
3294 }
3295 #endif
3296
3297 #if JUCE_LINUX || JUCE_BSD
3298 void updatePluginWindowHandle()
3299 {
3300 pluginWindow = getChildWindow ((Window) getWindowHandle());
3301 }
3302 #endif
3303
3304 //==============================================================================
3305 #if JUCE_MAC
3306 std::unique_ptr<NSViewComponentWithParent> cocoaWrapper;
3307
3308 void resized() override
3309 {
3310 }
3311 #endif
3312
3313 //==============================================================================
3314 VSTPluginInstance& plugin;
3315 float userScaleFactor = 1.0f;
3316 bool isOpen = false, recursiveResize = false;
3317 bool pluginWantsKeys = false, pluginRefusesToResize = false, alreadyInside = false;
3318
3319 #if ! JUCE_MAC
3320 bool pluginRespondsToDPIChanges = false;
3321
3322 float nativeScaleFactor = 1.0f;
3323
3324 struct ScaleNotifierCallback
3325 {
3326 VSTPluginWindow& window;
3327
3328 void operator() (float platformScale) const
3329 {
3330 MessageManager::callAsync ([ref = Component::SafePointer<VSTPluginWindow> (&window), platformScale]
3331 {
3332 if (auto* r = ref.getComponent())
3333 {
3334 r->nativeScaleFactor = platformScale;
3335 r->setContentScaleFactor();
3336
3337 #if JUCE_WINDOWS
3338 r->resizeToFit();
3339 #endif
3340 r->componentMovedOrResized (true, true);
3341 }
3342 });
3343 }
3344 };
3345
3346 NativeScaleFactorNotifier scaleNotifier { this, ScaleNotifierCallback { *this } };
3347
3348 #if JUCE_WINDOWS
3349 struct ViewComponent : public HWNDComponent
3350 {
3351 ViewComponent()
3352 {
3353 setOpaque (true);
3354 inner.addToDesktop (0);
3355
3356 if (auto* peer = inner.getPeer())
3357 setHWND (peer->getNativeHandle());
3358 }
3359
3360 void paint (Graphics& g) override { g.fillAll (Colours::black); }
3361
3362 private:
3363 struct Inner : public Component
3364 {
3365 Inner() { setOpaque (true); }
3366 void paint (Graphics& g) override { g.fillAll (Colours::black); }
3367 };
3368
3369 Inner inner;
3370 };
3371
3372 HWND getPluginHWND() const
3373 {
3374 return GetWindow ((HWND) embeddedComponent.getHWND(), GW_CHILD);
3375 }
3376
3377 ViewComponent embeddedComponent;
3378 void* originalWndProc = {};
3379 int sizeCheckCount = 0;
3380 #elif JUCE_LINUX || JUCE_BSD
3381 ::Display* display = XWindowSystem::getInstance()->getDisplay();
3382 Window pluginWindow = 0;
3383 #endif
3384 #else
3385 static constexpr auto nativeScaleFactor = 1.0f;
3386 #endif
3387
3388 //==============================================================================
3390};
3391#endif
3392
3394
3395//==============================================================================
3396AudioProcessorEditor* VSTPluginInstance::createEditor()
3397{
3398 #if JUCE_IOS || JUCE_ANDROID
3399 return nullptr;
3400 #else
3401 return hasEditor() ? new VSTPluginWindow (*this)
3402 : nullptr;
3403 #endif
3404}
3405
3406bool VSTPluginInstance::updateSizeFromEditor (int w, int h)
3407{
3408 if (auto* editor = dynamic_cast<VSTPluginWindow*> (getActiveEditor()))
3409 return editor->updateSizeFromEditor (w, h);
3410
3411 return false;
3412}
3413
3414//==============================================================================
3415// entry point for all callbacks from the plugin
3416static pointer_sized_int VSTINTERFACECALL audioMaster (Vst2::VstEffectInterface* effect, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt)
3417{
3418 if (effect != nullptr)
3419 if (auto* instance = (VSTPluginInstance*) (effect->hostSpace2))
3420 return instance->handleCallback (opcode, index, value, ptr, opt);
3421
3422 return VSTPluginInstance::handleGeneralCallback (opcode, index, value, ptr, opt);
3423}
3424
3425//==============================================================================
3426VSTPluginFormat::VSTPluginFormat() {}
3427VSTPluginFormat::~VSTPluginFormat() {}
3428
3429static std::unique_ptr<VSTPluginInstance> createAndUpdateDesc (VSTPluginFormat& format, PluginDescription& desc)
3430{
3431 if (auto p = format.createInstanceFromDescription (desc, 44100.0, 512))
3432 {
3433 if (auto instance = dynamic_cast<VSTPluginInstance*> (p.release()))
3434 {
3435 #if JUCE_MAC
3436 if (instance->vstModule->resFileId != 0)
3437 UseResFile (instance->vstModule->resFileId);
3438 #endif
3439
3440 instance->fillInPluginDescription (desc);
3441 return std::unique_ptr<VSTPluginInstance> (instance);
3442 }
3443
3445 }
3446
3447 return {};
3448}
3449
3450void VSTPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results,
3451 const String& fileOrIdentifier)
3452{
3453 if (! fileMightContainThisPluginType (fileOrIdentifier))
3454 return;
3455
3456 PluginDescription desc;
3457 desc.fileOrIdentifier = fileOrIdentifier;
3458 desc.uniqueId = desc.deprecatedUid = 0;
3459
3460 auto instance = createAndUpdateDesc (*this, desc);
3461
3462 if (instance == nullptr)
3463 return;
3464
3465 if (instance->getVstCategory() != Vst2::kPlugCategShell)
3466 {
3467 // Normal plugin...
3468 results.add (new PluginDescription (desc));
3469
3470 instance->dispatch (Vst2::plugInOpcodeOpen, 0, 0, nullptr, 0);
3471 }
3472 else
3473 {
3474 // It's a shell plugin, so iterate all the subtypes...
3475 for (;;)
3476 {
3477 char shellEffectName [256] = { 0 };
3478 auto uid = (int) instance->dispatch (Vst2::plugInOpcodeNextPlugInUniqueID, 0, 0, shellEffectName, 0);
3479
3480 if (uid == 0)
3481 break;
3482
3483 desc.uniqueId = desc.deprecatedUid = uid;
3484 desc.name = shellEffectName;
3485
3486 aboutToScanVSTShellPlugin (desc);
3487
3488 std::unique_ptr<VSTPluginInstance> shellInstance (createAndUpdateDesc (*this, desc));
3489
3490 if (shellInstance != nullptr)
3491 {
3492 jassert (desc.deprecatedUid == uid);
3493 jassert (desc.uniqueId == uid);
3494 desc.hasSharedContainer = true;
3495 desc.name = shellEffectName;
3496
3497 if (! arrayContainsPlugin (results, desc))
3498 results.add (new PluginDescription (desc));
3499 }
3500 }
3501 }
3502}
3503
3504void VSTPluginFormat::createPluginInstance (const PluginDescription& desc,
3505 double sampleRate, int blockSize,
3506 PluginCreationCallback callback)
3507{
3508 std::unique_ptr<VSTPluginInstance> result;
3509
3510 if (fileMightContainThisPluginType (desc.fileOrIdentifier))
3511 {
3512 File file (desc.fileOrIdentifier);
3513
3514 auto previousWorkingDirectory = File::getCurrentWorkingDirectory();
3515 file.getParentDirectory().setAsCurrentWorkingDirectory();
3516
3517 if (auto module = ModuleHandle::findOrCreateModule (file))
3518 {
3519 shellUIDToCreate = desc.uniqueId != 0 ? desc.uniqueId : desc.deprecatedUid;
3520
3521 result.reset (VSTPluginInstance::create (module, sampleRate, blockSize));
3522
3523 if (result != nullptr && ! result->initialiseEffect (sampleRate, blockSize))
3524 result.reset();
3525 }
3526
3527 previousWorkingDirectory.setAsCurrentWorkingDirectory();
3528 }
3529
3530 String errorMsg;
3531
3532 if (result == nullptr)
3533 errorMsg = TRANS ("Unable to load XXX plug-in file").replace ("XXX", "VST-2");
3534
3535 callback (std::move (result), errorMsg);
3536}
3537
3538bool VSTPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const
3539{
3540 return false;
3541}
3542
3543bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier)
3544{
3545 auto f = File::createFileWithoutCheckingPath (fileOrIdentifier);
3546
3547 #if JUCE_MAC || JUCE_IOS
3548 return f.isDirectory() && f.hasFileExtension (".vst");
3549 #elif JUCE_WINDOWS
3550 return f.existsAsFile() && f.hasFileExtension (".dll");
3551 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
3552 return f.existsAsFile() && f.hasFileExtension (".so");
3553 #endif
3554}
3555
3556String VSTPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier)
3557{
3558 return fileOrIdentifier;
3559}
3560
3561bool VSTPluginFormat::pluginNeedsRescanning (const PluginDescription& desc)
3562{
3563 return File (desc.fileOrIdentifier).getLastModificationTime() != desc.lastFileModTime;
3564}
3565
3566bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc)
3567{
3568 return File (desc.fileOrIdentifier).exists();
3569}
3570
3571StringArray VSTPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive, bool)
3572{
3573 StringArray results;
3574
3575 for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j)
3576 recursiveFileSearch (results, directoriesToSearch [j], recursive);
3577
3578 return results;
3579}
3580
3581void VSTPluginFormat::recursiveFileSearch (StringArray& results, const File& dir, const bool recursive)
3582{
3583 // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside
3584 // .component or .vst directories.
3585 for (const auto& iter : RangedDirectoryIterator (dir, false, "*", File::findFilesAndDirectories))
3586 {
3587 auto f = iter.getFile();
3588 bool isPlugin = false;
3589
3590 if (fileMightContainThisPluginType (f.getFullPathName()))
3591 {
3592 isPlugin = true;
3593 results.add (f.getFullPathName());
3594 }
3595
3596 if (recursive && (! isPlugin) && f.isDirectory())
3597 recursiveFileSearch (results, f, true);
3598 }
3599}
3600
3601FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch()
3602{
3603 #if JUCE_MAC
3604 return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST");
3605 #elif JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
3606 return FileSearchPath (SystemStats::getEnvironmentVariable ("VST_PATH",
3607 "/usr/lib/vst;/usr/local/lib/vst;~/.vst")
3608 .replace (":", ";"));
3609 #elif JUCE_WINDOWS
3610 auto programFiles = File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName();
3611
3612 FileSearchPath paths;
3613 paths.add (WindowsRegistry::getValue ("HKEY_LOCAL_MACHINE\\Software\\VST\\VSTPluginsPath"));
3614 paths.addIfNotAlreadyThere (programFiles + "\\Steinberg\\VstPlugins");
3615 paths.addIfNotAlreadyThere (programFiles + "\\VstPlugins");
3616 paths.removeRedundantPaths();
3617 return paths;
3618 #elif JUCE_IOS
3619 // on iOS you can only load plug-ins inside the hosts bundle folder
3620 CFUniquePtr<CFURLRef> relativePluginDir (CFBundleCopyBuiltInPlugInsURL (CFBundleGetMainBundle()));
3621 CFUniquePtr<CFURLRef> pluginDir (CFURLCopyAbsoluteURL (relativePluginDir.get()));
3622
3623 CFUniquePtr<CFStringRef> path (CFURLCopyFileSystemPath (pluginDir.get(), kCFURLPOSIXPathStyle));
3624 FileSearchPath retval (String (CFStringGetCStringPtr (path.get(), kCFStringEncodingUTF8)));
3625 return retval;
3626 #endif
3627}
3628
3629const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
3630{
3631 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3632 if (vst->vstModule != nullptr)
3633 return vst->vstModule->vstXml.get();
3634
3635 return nullptr;
3636}
3637
3638bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize)
3639{
3640 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3641 return vst->loadFromFXBFile (data, dataSize);
3642
3643 return false;
3644}
3645
3646bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest, bool asFXB)
3647{
3648 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3649 return vst->saveToFXBFile (dest, asFXB);
3650
3651 return false;
3652}
3653
3654bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset)
3655{
3656 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3657 return vst->getChunkData (result, isPreset, 128);
3658
3659 return false;
3660}
3661
3662bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset)
3663{
3664 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3665 return vst->setChunkData (data, size, isPreset);
3666
3667 return false;
3668}
3669
3670AudioPluginInstance* VSTPluginFormat::createCustomVSTFromMainCall (void* entryPointFunction,
3671 double initialSampleRate, int initialBufferSize)
3672{
3673 ModuleHandle::Ptr module = new ModuleHandle (File(), (MainCall) entryPointFunction);
3674
3675 if (module->open())
3676 {
3677 std::unique_ptr<VSTPluginInstance> result (VSTPluginInstance::create (module, initialSampleRate, initialBufferSize));
3678
3679 if (result != nullptr)
3680 if (result->initialiseEffect (initialSampleRate, initialBufferSize))
3681 return result.release();
3682 }
3683
3684 return nullptr;
3685}
3686
3687void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunctions* functions)
3688{
3689 std::unique_ptr<ExtraFunctions> f (functions);
3690
3691 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3692 std::swap (vst->extraFunctions, f);
3693}
3694
3695AudioPluginInstance* VSTPluginFormat::getPluginInstanceFromVstEffectInterface (void* aEffect)
3696{
3697 if (auto* vstAEffect = reinterpret_cast<Vst2::VstEffectInterface*> (aEffect))
3698 if (auto* instanceVST = reinterpret_cast<VSTPluginInstance*> (vstAEffect->hostSpace2))
3699 return dynamic_cast<AudioPluginInstance*> (instanceVST);
3700
3701 return nullptr;
3702}
3703
3704pointer_sized_int JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, pointer_sized_int value, void* ptr, float opt)
3705{
3706 if (auto* vst = dynamic_cast<VSTPluginInstance*> (plugin))
3707 return vst->dispatch (opcode, index, value, ptr, opt);
3708
3709 return {};
3710}
3711
3712void VSTPluginFormat::aboutToScanVSTShellPlugin (const PluginDescription&) {}
3713
3714} // namespace juce
3715
3718
3719#endif
#define JUCE_VST_FALLBACK_HOST_NAME
Definition AppConfig.h:212
struct _AEffect AEffect
Definition vestige.h:315
Type jmin(const Type a, const Type b)
Definition MathsFunctions.h:60
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
#define final
Definition DistrhoDefines.h:74
#define nullptr
Definition DistrhoDefines.h:75
static Audio_Scope * scope
Definition player.cpp:26
opcode
Definition Spc_Cpu.h:173
goto loop
Definition Spc_Cpu.h:155
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
static void message(int level, const char *fmt,...)
Definition adplugdb.cpp:120
int64_t int64
Definition basics.h:91
int32_t int32
Definition basics.h:89
uint32_t uint32
Definition basics.h:90
void removeFirstMatchingValue(ParameterType valueToRemove)
Definition Array.h:789
bool add(const ElementType &newElement) noexcept
Definition Array.h:354
int size() const noexcept
Definition Array.h:187
void sort()
Definition Array.h:1014
static uint32 littleEndianInt(const void *bytes) noexcept
Definition ByteOrder.h:236
static uint16 swapIfLittleEndian(uint16 value) noexcept
Definition ByteOrder.h:227
static uint32 bigEndianInt(const void *bytes) noexcept
Definition ByteOrder.h:239
static uint16 swap(uint16 value) noexcept
Definition ByteOrder.h:151
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
Definition File.cpp:65
static File getCurrentWorkingDirectory()
Definition File.cpp:1395
@ findFiles
Definition File.h:462
@ findFilesAndDirectories
Definition File.h:463
const String & getFullPathName() const noexcept
Definition File.h:152
static File getSpecialLocation(const SpecialLocationType type)
Definition File.cpp:1642
void copyFrom(const void *srcData, int destinationOffset, size_t numBytes) noexcept
Definition MemoryBlock.cpp:222
size_t getSize() const noexcept
Definition MemoryBlock.h:102
void setSize(const size_t newSize, bool initialiseNewSpaceToZero=false)
Definition MemoryBlock.cpp:109
void fillWith(uint8 valueToUse) noexcept
Definition MemoryBlock.cpp:162
void * getData() const noexcept
Definition MemoryBlock.h:91
void copyTo(void *destData, int sourceOffset, size_t numBytes) const noexcept
Definition MemoryBlock.cpp:240
void clear() noexcept
Definition MidiBuffer.cpp:106
void set(int index, const String &newString)
Definition StringArray.cpp:147
bool add(const String &stringToAdd)
Definition StringArray.cpp:108
int size() const noexcept
Definition StringArray.h:97
void removeEmptyStrings(bool removeWhitespaceStrings=true)
Definition StringArray.cpp:208
bool isNotEmpty() const noexcept
Definition String.h:244
String substring(int startIndex, int endIndex) const
Definition String.cpp:1373
static String createStringFromData(const void *data, int size)
Definition String.cpp:1721
const char * toRawUTF8() const
Definition String.cpp:1925
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition String.cpp:1159
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition String.cpp:1961
bool isEmpty() const noexcept
Definition String.h:238
void add(const ElementType &newElement)
Definition juce_Array.h:418
const String & getFullPathName() const noexcept
Definition juce_File.h:153
ObjectClass * add(ObjectClass *newObject)
Definition juce_OwnedArray.h:294
int size() const noexcept
Definition juce_StringArray.h:136
void trim()
Definition juce_StringArray.cpp:266
void add(String stringToAdd)
Definition juce_StringArray.cpp:136
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition juce_StringArray.cpp:329
String trim() const
Definition juce_String.cpp:1656
const char * toRawUTF8() const
Definition juce_String.cpp:2074
String retainCharacters(StringRef charactersToRetain) const
Definition juce_String.cpp:1735
int indexOfWholeWord(StringRef wordToLookFor) const noexcept
Definition juce_String.cpp:1050
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition juce_String.cpp:1279
String replaceSection(int startIndex, int numCharactersToReplace, StringRef stringToInsert) const
Definition juce_String.cpp:1218
int getNumChildElements() const noexcept
Definition juce_XmlElement.cpp:668
XmlElement * getChildByName(StringRef tagNameToLookFor) const noexcept
Definition juce_XmlElement.cpp:678
double getDoubleAttribute(StringRef attributeName, double defaultReturnValue=0.0) const
Definition juce_XmlElement.cpp:579
Iterator< GetNextElementWithTagName > getChildWithTagNameIterator(StringRef name) const
Definition juce_XmlElement.h:730
bool hasAttribute(StringRef attributeName) const noexcept
Definition juce_XmlElement.cpp:549
bool hasTagName(StringRef possibleTagName) const noexcept
Definition juce_XmlElement.cpp:470
Iterator< GetNextElement > getChildIterator() const
Definition juce_XmlElement.h:715
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
Definition juce_XmlElement.cpp:571
const String & getStringAttribute(StringRef attributeName) const noexcept
Definition juce_XmlElement.cpp:555
* e
Definition inflate.c:1404
UINT_D64 w
Definition inflate.c:942
unsigned * m
Definition inflate.c:1559
register unsigned j
Definition inflate.c:1576
unsigned v[N_MAX]
Definition inflate.c:1584
int g
Definition inflate.c:1573
register unsigned i
Definition inflate.c:1575
int retval
Definition inflate.c:947
unsigned s
Definition inflate.c:1555
unsigned x[BMAX+1]
Definition inflate.c:1586
unsigned f
Definition inflate.c:1572
static PuglViewHint int value
Definition pugl.h:1708
static const char * name
Definition pugl.h:1582
static int int height
Definition pugl.h:1594
static int width
Definition pugl.h:1593
static uintptr_t parent
Definition pugl.h:1644
virtual ASIOError future(long selector, void *opt)=0
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate)=0
int val
Definition jpeglib.h:956
JSAMPIMAGE data
Definition jpeglib.h:945
int version
Definition jpeglib.h:901
#define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...)
Definition juce_CompilerWarnings.h:181
#define JUCE_END_IGNORE_WARNINGS_GCC_LIKE
Definition juce_CompilerWarnings.h:182
#define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings)
Definition juce_CompilerWarnings.h:198
#define JUCE_END_IGNORE_WARNINGS_MSVC
Definition juce_CompilerWarnings.h:199
#define TRANS(stringLiteral)
Definition juce_LocalisedStrings.h:208
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
Definition juce_MessageManager.h:465
#define JUCE_ASSERT_MESSAGE_THREAD
Definition juce_MessageManager.h:473
#define jassert(expression)
#define DBG(textToWrite)
#define JUCE_DECLARE_NON_COPYABLE(className)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define jassertfalse
#define JUCE_CALLTYPE
#define VSTINTERFACECALL
Definition juce_VSTInterface.h:44
@ vstTimingInfoFlagLoopPositionValid
Definition juce_VSTInterface.h:379
@ vstTimingInfoFlagTransportChanged
Definition juce_VSTInterface.h:369
@ vstTimingInfoFlagTimeSignatureValid
Definition juce_VSTInterface.h:380
@ vstTimingInfoFlagLoopActive
Definition juce_VSTInterface.h:371
#define WM_APPCOMMAND
Definition juce_win32_Windowing.cpp:49
static void cleanup(void)
Definition lilv_test.c:152
float in
Definition lilv_test.c:1460
float out
Definition lilv_test.c:1461
static int JUCE_CDECL comp(const void *a, const void *b)
Definition lsp.c:298
struct Param Param
int int32_t
Definition mid.cpp:97
const char * getVersion()
Definition carla_juce.cpp:57
Definition juce_VSTMidiEventList.h:29
@ vstEffectFlagInplaceDoubleAudio
Definition juce_VSTMidiEventList.h:92
@ vstEffectFlagInplaceAudio
Definition juce_VSTMidiEventList.h:89
@ vstEffectFlagIsSynth
Definition juce_VSTMidiEventList.h:91
@ vstEffectFlagHasEditor
Definition juce_VSTMidiEventList.h:88
@ vstEffectFlagDataInChunks
Definition juce_VSTMidiEventList.h:90
@ vstMaxPlugInNameStringLength
Definition juce_VSTMidiEventList.h:250
@ vstMaxManufacturerStringLength
Definition juce_VSTMidiEventList.h:249
@ hostOpcodeGetProductName
Definition juce_VSTMidiEventList.h:189
@ hostOpcodeOfflineStart
Definition juce_VSTMidiEventList.h:181
@ hostOpcodeGetBlockSize
Definition juce_VSTMidiEventList.h:173
@ hostOpcodeParameterChanged
Definition juce_VSTMidiEventList.h:157
@ hostOpcodeGetNextPlugIn
Definition juce_VSTMidiEventList.h:177
@ hostOpcodeOfflineGetCurrentPass
Definition juce_VSTMidiEventList.h:184
@ hostOpcodeIdle
Definition juce_VSTMidiEventList.h:160
@ hostOpcodeGetDirectory
Definition juce_VSTMidiEventList.h:197
@ hostOpcodeSetIcon
Definition juce_VSTMidiEventList.h:192
@ hostOpcodeSetOutputSampleRate
Definition juce_VSTMidiEventList.h:186
@ hostOpcodeOfflineGetCurrentMetaPass
Definition juce_VSTMidiEventList.h:185
@ hostOpcodeGetLanguage
Definition juce_VSTMidiEventList.h:194
@ hostOpcodeManufacturerSpecific
Definition juce_VSTMidiEventList.h:191
@ hostOpcodePinConnected
Definition juce_VSTMidiEventList.h:161
@ hostOpcodeGetNumberOfAutomatableParameters
Definition juce_VSTMidiEventList.h:167
@ hostOpcodeGetManufacturerName
Definition juce_VSTMidiEventList.h:188
@ hostOpcodeGetManufacturerVersion
Definition juce_VSTMidiEventList.h:190
@ hostOpcodeSetTime
Definition juce_VSTMidiEventList.h:165
@ hostOpcodeGetOutputLatency
Definition juce_VSTMidiEventList.h:175
@ hostOpcodeWillReplace
Definition juce_VSTMidiEventList.h:178
@ hostOpcodeUpdateView
Definition juce_VSTMidiEventList.h:198
@ hostOpcodeWindowSize
Definition juce_VSTMidiEventList.h:171
@ hostOpcodeVstVersion
Definition juce_VSTMidiEventList.h:158
@ hostOpcodeTempoAt
Definition juce_VSTMidiEventList.h:166
@ hostOpcodePlugInWantsMidi
Definition juce_VSTMidiEventList.h:162
@ hostOpcodeGetAutomationState
Definition juce_VSTMidiEventList.h:180
@ hostOpcodeNeedsIdle
Definition juce_VSTMidiEventList.h:170
@ hostOpcodeGetInputLatency
Definition juce_VSTMidiEventList.h:174
@ hostOpcodeCanHostDo
Definition juce_VSTMidiEventList.h:193
@ hostOpcodeIOModified
Definition juce_VSTMidiEventList.h:169
@ hostOpcodeCurrentId
Definition juce_VSTMidiEventList.h:159
@ hostOpcodeOpenEditorWindow
Definition juce_VSTMidiEventList.h:195
@ hostOpcodeGetParameterInterval
Definition juce_VSTMidiEventList.h:168
@ hostOpcodeGetTimingInfo
Definition juce_VSTMidiEventList.h:163
@ hostOpcodeGetPreviousPlugIn
Definition juce_VSTMidiEventList.h:176
@ hostOpcodePreAudioProcessingEvents
Definition juce_VSTMidiEventList.h:164
@ hostOpcodeCloseEditorWindow
Definition juce_VSTMidiEventList.h:196
@ hostOpcodeGetOutputSpeakerConfiguration
Definition juce_VSTMidiEventList.h:187
@ hostOpcodeOfflineWrite
Definition juce_VSTMidiEventList.h:183
@ hostOpcodeGetSampleRate
Definition juce_VSTMidiEventList.h:172
@ hostOpcodeParameterChangeGestureBegin
Definition juce_VSTMidiEventList.h:199
@ hostOpcodeParameterChangeGestureEnd
Definition juce_VSTMidiEventList.h:200
@ hostOpcodeGetCurrentAudioProcessingLevel
Definition juce_VSTMidiEventList.h:179
@ hostOpcodeOfflineReadSource
Definition juce_VSTMidiEventList.h:182
@ vstTimingInfoFlagAutomationReadModeActive
Definition juce_VSTMidiEventList.h:375
@ vstTimingInfoFlagMusicalPositionValid
Definition juce_VSTMidiEventList.h:377
@ vstTimingInfoFlagTransportChanged
Definition juce_VSTMidiEventList.h:370
@ vstTimingInfoFlagTempoValid
Definition juce_VSTMidiEventList.h:378
@ vstTimingInfoFlagCurrentlyPlaying
Definition juce_VSTMidiEventList.h:371
@ vstTimingInfoFlagAutomationWriteModeActive
Definition juce_VSTMidiEventList.h:374
@ vstTimingInfoFlagSmpteValid
Definition juce_VSTMidiEventList.h:382
@ vstTimingInfoFlagTimeSignatureValid
Definition juce_VSTMidiEventList.h:381
@ vstTimingInfoFlagNanosecondsValid
Definition juce_VSTMidiEventList.h:376
@ vstTimingInfoFlagLoopPositionValid
Definition juce_VSTMidiEventList.h:380
@ vstTimingInfoFlagLoopActive
Definition juce_VSTMidiEventList.h:372
@ vstTimingInfoFlagCurrentlyRecording
Definition juce_VSTMidiEventList.h:373
@ vstTimingInfoFlagLastBarPositionValid
Definition juce_VSTMidiEventList.h:379
@ plugInOpcodeStopProcess
Definition juce_VSTMidiEventList.h:146
@ plugInOpcodeManufacturerSpecific
Definition juce_VSTMidiEventList.h:136
@ plugInOpcodeSetCurrentProgramName
Definition juce_VSTMidiEventList.h:102
@ plugInOpcodeGetTailSize
Definition juce_VSTMidiEventList.h:138
@ plugInOpcodeIdle
Definition juce_VSTMidiEventList.h:139
@ plugInOpcodeSetBlockSize
Definition juce_VSTMidiEventList.h:108
@ plugInOpcodeGetProgramName
Definition juce_VSTMidiEventList.h:124
@ plugInOpcodePreAudioProcessingEvents
Definition juce_VSTMidiEventList.h:121
@ plugInOpcodeSetSpeakerConfiguration
Definition juce_VSTMidiEventList.h:130
@ plugInOpcodeGetParameterLabel
Definition juce_VSTMidiEventList.h:104
@ plugInOpcodeIsParameterAutomatable
Definition juce_VSTMidiEventList.h:122
@ plugInOpcodeeffEditorTop
Definition juce_VSTMidiEventList.h:116
@ plugInOpcodeOpen
Definition juce_VSTMidiEventList.h:98
@ plugInOpcodeGetSpeakerArrangement
Definition juce_VSTMidiEventList.h:143
@ plugInOpcodeGetData
Definition juce_VSTMidiEventList.h:119
@ plugInOpcodeSetSampleRate
Definition juce_VSTMidiEventList.h:107
@ plugInOpcodeSetCurrentProgram
Definition juce_VSTMidiEventList.h:100
@ plugInOpcodeGetEditorBounds
Definition juce_VSTMidiEventList.h:110
@ plugInOpcodeGetPlugInName
Definition juce_VSTMidiEventList.h:132
@ plugInOpcodeGetManufacturerName
Definition juce_VSTMidiEventList.h:133
@ plugInOpcodeNextPlugInUniqueID
Definition juce_VSTMidiEventList.h:144
@ plugInOpcodeIdentify
Definition juce_VSTMidiEventList.h:118
@ plugInOpcodeSetData
Definition juce_VSTMidiEventList.h:120
@ plugInOpcodeGetPlugInCategory
Definition juce_VSTMidiEventList.h:129
@ plugInOpcodeKeyboardFocusRequired
Definition juce_VSTMidiEventList.h:140
@ plugInOpcodeGetCurrentProgramName
Definition juce_VSTMidiEventList.h:103
@ plugInOpcodeGetManufacturerVersion
Definition juce_VSTMidiEventList.h:135
@ plugInOpcodeEditorIdle
Definition juce_VSTMidiEventList.h:115
@ plugInOpcodeOpenEditor
Definition juce_VSTMidiEventList.h:111
@ plugInOpcodeSetSampleFloatType
Definition juce_VSTMidiEventList.h:148
@ plugInOpcodeGetParameterText
Definition juce_VSTMidiEventList.h:105
@ plugInOpcodeStartProcess
Definition juce_VSTMidiEventList.h:145
@ plugInOpcodeGetOutputPinProperties
Definition juce_VSTMidiEventList.h:128
@ plugInOpcodeCanPlugInDo
Definition juce_VSTMidiEventList.h:137
@ plugInOpcodeGetCurrentProgram
Definition juce_VSTMidiEventList.h:101
@ plugInOpcodeGetParameterName
Definition juce_VSTMidiEventList.h:106
@ plugInOpcodeConnectOutput
Definition juce_VSTMidiEventList.h:126
@ plugInOpcodeClose
Definition juce_VSTMidiEventList.h:99
@ plugInOpcodeGetManufacturerProductName
Definition juce_VSTMidiEventList.h:134
@ plugInOpcodeSetBypass
Definition juce_VSTMidiEventList.h:131
@ plugInOpcodeConnectInput
Definition juce_VSTMidiEventList.h:125
@ plugInOpcodeGetInputPinProperties
Definition juce_VSTMidiEventList.h:127
@ plugInOpcodeCloseEditor
Definition juce_VSTMidiEventList.h:112
@ plugInOpcodeResumeSuspend
Definition juce_VSTMidiEventList.h:109
VstPlugInCategory
Definition juce_VSTMidiEventList.h:214
@ kPlugCategMastering
Definition juce_VSTMidiEventList.h:219
@ kPlugCategGenerator
Definition juce_VSTMidiEventList.h:226
@ kPlugCategSpacializer
Definition juce_VSTMidiEventList.h:220
@ kPlugCategAnalysis
Definition juce_VSTMidiEventList.h:218
@ kPlugCategEffect
Definition juce_VSTMidiEventList.h:216
@ kPlugCategSynth
Definition juce_VSTMidiEventList.h:217
@ kPlugCategRoomFx
Definition juce_VSTMidiEventList.h:221
@ kPlugCategUnknown
Definition juce_VSTMidiEventList.h:215
@ kPlugCategOfflineProcess
Definition juce_VSTMidiEventList.h:224
@ kPlugCategShell
Definition juce_VSTMidiEventList.h:225
@ kPlugSurroundFx
Definition juce_VSTMidiEventList.h:222
@ kPlugCategRestoration
Definition juce_VSTMidiEventList.h:223
@ vstProcessingSampleTypeFloat
Definition juce_VSTMidiEventList.h:206
@ vstProcessingSampleTypeDouble
Definition juce_VSTMidiEventList.h:207
@ vstSmpteRateFps30drop
Definition juce_VSTMidiEventList.h:394
@ vstSmpteRateFps239
Definition juce_VSTMidiEventList.h:399
@ vstSmpteRateFps249
Definition juce_VSTMidiEventList.h:400
@ vstSmpteRateFps599
Definition juce_VSTMidiEventList.h:401
@ vstSmpteRateFps25
Definition juce_VSTMidiEventList.h:390
@ vstSmpteRateFps60
Definition juce_VSTMidiEventList.h:402
@ vstSmpteRateFps2997
Definition juce_VSTMidiEventList.h:391
@ vstSmpteRateFps30
Definition juce_VSTMidiEventList.h:392
@ vstSmpteRateFps24
Definition juce_VSTMidiEventList.h:389
@ vstSmpteRateFps2997drop
Definition juce_VSTMidiEventList.h:393
const int32 juceVstInterfaceIdentifier
Definition juce_VSTMidiEventList.h:50
pointer_sized_int(VSTINTERFACECALL * VstHostCallback)(VstEffectInterface *, int32 op, int32 index, pointer_sized_int value, void *ptr, float opt)
Definition juce_VSTMidiEventList.h:84
@ vstPinInfoFlagValid
Definition juce_VSTMidiEventList.h:271
@ vstPinInfoFlagIsStereo
Definition juce_VSTMidiEventList.h:270
float mono(T v)
Convert a single value to single value = do nothing :) (but it's a generic with specialisation for st...
Definition primitives.h:219
T clip(T value, T min, T max)
Clip a value to [min, max].
Definition primitives.h:231
void initialise()
Definition hardgate.cpp:79
JOCTET * buffer
Definition juce_JPEGLoader.cpp:302
Definition carla_juce.cpp:31
CriticalSection::ScopedLockType ScopedLock
Definition juce_CriticalSection.h:186
void callOnMessageThread(Callback &&callback)
Definition juce_audio_processors.cpp:81
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Definition juce_MathsFunctions.h:262
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
Definition juce_XmlDocument.cpp:41
void ignoreUnused(Types &&...) noexcept
Definition juce_MathsFunctions.h:333
Type * addBytesToPointer(Type *basePointer, IntegerType bytes) noexcept
Definition juce_Memory.h:111
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Definition juce_MathsFunctions.h:279
int pointer_sized_int
Definition juce_MathsFunctions.h:80
unsigned int pointer_sized_uint
Definition juce_MathsFunctions.h:82
@ window
Definition juce_AccessibilityRole.h:63
@ label
Definition juce_AccessibilityRole.h:44
@ group
Definition juce_AccessibilityRole.h:61
constexpr int numElementsInArray(Type(&)[N]) noexcept
Definition juce_MathsFunctions.h:344
void add(SampleFrame *dst, const SampleFrame *src, int frames)
Add samples from src to dst.
Definition MixHelpers.cpp:135
Base
Definition PathUtil.h:34
auto getText(std::string_view name) -> QString
Definition embed.cpp:125
QPoint position(const QDropEvent *de)
position is a backwards-compatible adapter for QDropEvent::position and pos functions.
Definition DeprecationHelper.h:47
osc_element< 1, rtMsg< Types... > >::type second(rtMsg< Types... > &Tuple)
Definition typed-message.h:159
osc_element< 0, rtMsg< Types... > >::type first(rtMsg< Types... > &Tuple)
Definition typed-message.h:152
bool isPlugin
Definition Util.cpp:41
png_uint_32 length
Definition png.c:2247
int16 lower
Definition juce_VSTMidiEventList.h:238
int16 upper
Definition juce_VSTMidiEventList.h:236
int16 rightmost
Definition juce_VSTMidiEventList.h:239
int16 leftmost
Definition juce_VSTMidiEventList.h:237
int32 interfaceIdentifier
Definition juce_VSTMidiEventList.h:59
int32 plugInVersion
Definition juce_VSTMidiEventList.h:78
int32 numInputChannels
Definition juce_VSTMidiEventList.h:66
int32 flags
Definition juce_VSTMidiEventList.h:68
pointer_sized_int hostSpace2
Definition juce_VSTMidiEventList.h:70
int32 numOutputChannels
Definition juce_VSTMidiEventList.h:67
void * effectPointer
Definition juce_VSTMidiEventList.h:75
int32 flags
Definition juce_VSTMidiEventList.h:261
char text[vstMaxParameterOrPinLabelLength]
Definition juce_VSTMidiEventList.h:260
int32 configurationType
Definition juce_VSTMidiEventList.h:262
#define SWP_NOACTIVATE
#define WM_KEYUP
#define SWP_NOMOVE
#define CallWindowProc(A, B, C, D, E)
#define WM_SYSKEYUP
#define WM_CHAR
#define WM_KEYDOWN
#define GW_CHILD
#define SWP_NOZORDER
#define WM_SYSKEYDOWN
const char * text
Definition swell-functions.h:167
RECT const char void(* callback)(const char *droppath))) SWELL_API_DEFINE(BOOL
Definition swell-functions.h:1004
#define timeGetTime()
Definition swell-functions.h:83
bool GetWindowRect(HWND hwnd, RECT *r)
Definition swell-generic-headless.cpp:130
LONG_PTR LRESULT
Definition swell-types.h:171
unsigned int UINT
Definition swell-types.h:166
LONG_PTR LPARAM
Definition swell-types.h:170
intptr_t LONG_PTR
Definition swell-types.h:42
ULONG_PTR WPARAM
Definition swell-types.h:169
LRESULT(* WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition swell-types.h:587
struct HWND__ * HWND
Definition swell-types.h:210
#define CALLBACK
Definition swell-types.h:635
#define MAKEINTRESOURCE(x)
Definition swell-types.h:1157
LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Definition swell-wnd-generic.cpp:7223
LRESULT SendMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Definition swell-wnd-generic.cpp:315
HWND GetWindow(HWND hwnd, int what)
Definition swell-wnd-generic.cpp:737
void SetWindowPos(HWND hwnd, HWND zorder, int x, int y, int cx, int cy, int flags)
Definition swell-wnd-generic.cpp:637
bool IsWindow(HWND hwnd)
Definition swell-wnd-generic.cpp:289
int n
Definition crypt.c:458
uch * p
Definition crypt.c:594
int r
Definition crypt.c:458
uch h[RAND_HEAD_LEN]
Definition crypt.c:459
if(compr_offset< 4) return PK_OK
Definition fileio.c:737
return
Definition extract.c:2364
ulg size
Definition extract.c:2350
int result
Definition process.c:1455
int flag
Definition unix.c:754
static ZCONST char Far None[]
Definition unzip.c:380
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396
struct zdirent * file
Definition win32.c:1500
_WDL_CSTRING_PREFIX void INT_PTR const char * format
Definition wdlcstring.h:263
#define GetWindowLongPtr(a, b)
Definition wdltypes.h:63
#define SetWindowLongPtr(a, b, c)
Definition wdltypes.h:62
#define GWLP_WNDPROC
Definition wdltypes.h:56
#define const
Definition zconf.h:137