2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_TargetPlatform.h"
27 #include "../../../../juce_Config.h"
29 #if JUCE_PLUGINHOST_VST && (JUCE_MAC_VST_INCLUDED || ! JUCE_MAC)
33 #define _WIN32_WINNT 0x500
38 #pragma warning (disable : 4312 4355)
39 #ifdef __INTEL_COMPILER
40 #pragma warning (disable : 1899)
46 #include <X11/Xutil.h>
47 #include <X11/Xatom.h>
53 #include <Cocoa/Cocoa.h>
54 #include <Carbon/Carbon.h>
57 //==============================================================================
58 #include "../../../core/juce_StandardHeader.h"
60 #if ! (JUCE_MAC && JUCE_64BIT)
64 #include "juce_VSTPluginFormat.h"
65 #include "../../../threads/juce_Process.h"
66 #include "../../../threads/juce_CriticalSection.h"
67 #include "../../../maths/juce_Random.h"
68 #include "../../../io/files/juce_DirectoryIterator.h"
69 #include "../../../events/juce_Timer.h"
70 #include "../../../events/juce_AsyncUpdater.h"
71 #include "../../../events/juce_MessageManager.h"
72 #include "../../../gui/components/layout/juce_ComponentMovementWatcher.h"
73 #include "../../../gui/components/windows/juce_ComponentPeer.h"
74 #include "../../../application/juce_Application.h"
75 #include "../../../core/juce_PlatformUtilities.h"
77 #if JUCE_MAC && JUCE_SUPPORT_CARBON
78 #include "../../../native/mac/juce_mac_CarbonViewWrapperComponent.h"
81 //==============================================================================
82 #undef PRAGMA_ALIGN_SUPPORTED
83 #define VST_FORCE_DEPRECATED 0
86 #pragma warning (push)
87 #pragma warning (disable: 4996)
90 /* Obviously you're going to need the Steinberg vstsdk2.4 folder in
91 your include path if you want to add VST support.
93 If you're not interested in VSTs, you can disable them by changing the
94 JUCE_PLUGINHOST_VST flag in juce_Config.h
96 #include <pluginterfaces/vst2.x/aeffectx.h>
102 //==============================================================================
104 #define Font JUCE_NAMESPACE::Font
105 #define KeyPress JUCE_NAMESPACE::KeyPress
106 #define Drawable JUCE_NAMESPACE::Drawable
107 #define Time JUCE_NAMESPACE::Time
110 #include "../juce_PluginDescription.h"
111 #include "juce_VSTMidiEventList.h"
114 static void _fpreset() {}
115 static void _clearfp() {}
118 extern void juce_callAnyTimersSynchronously();
121 //==============================================================================
122 const int fxbVersionNum
= 1;
126 long chunkMagic
; // 'CcnK'
127 long byteSize
; // of this chunk, excl. magic + byteSize
128 long fxMagic
; // 'FxCk'
130 long fxID
; // fx unique id
134 float params
[1]; // variable no. of parameters
139 long chunkMagic
; // 'CcnK'
140 long byteSize
; // of this chunk, excl. magic + byteSize
141 long fxMagic
; // 'FxBk'
143 long fxID
; // fx unique id
147 fxProgram programs
[1]; // variable no. of programs
152 long chunkMagic
; // 'CcnK'
153 long byteSize
; // of this chunk, excl. magic + byteSize
154 long fxMagic
; // 'FxCh', 'FPCh', or 'FBCh'
156 long fxID
; // fx unique id
161 char chunk
[8]; // variable
166 long chunkMagic
; // 'CcnK'
167 long byteSize
; // of this chunk, excl. magic + byteSize
168 long fxMagic
; // 'FxCh', 'FPCh', or 'FBCh'
170 long fxID
; // fx unique id
175 char chunk
[8]; // variable
180 long vst_swap (const long x
) noexcept
182 #ifdef JUCE_LITTLE_ENDIAN
183 return (long) ByteOrder::swap ((uint32
) x
);
189 float vst_swapFloat (const float x
) noexcept
191 #ifdef JUCE_LITTLE_ENDIAN
192 union { uint32 asInt
; float asFloat
; } n
;
194 n
.asInt
= ByteOrder::swap (n
.asInt
);
201 double getVSTHostTimeNanoseconds()
204 return timeGetTime() * 1000000.0;
207 gettimeofday (µ
, 0);
208 return micro
.tv_usec
* 1000.0;
211 Microseconds (µ
);
212 return micro
.lo
* 1000.0;
217 //==============================================================================
218 typedef AEffect
* (VSTCALLBACK
*MainCall
) (audioMasterCallback
);
220 static VstIntPtr VSTCALLBACK
audioMaster (AEffect
* effect
, VstInt32 opcode
, VstInt32 index
, VstIntPtr value
, void* ptr
, float opt
);
222 static int shellUIDToCreate
= 0;
223 static int insideVSTCallback
= 0;
225 class IdleCallRecursionPreventer
228 IdleCallRecursionPreventer()
229 : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
235 ~IdleCallRecursionPreventer()
242 const bool isMessageThread
;
244 JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer
);
247 class VSTPluginWindow
;
249 //==============================================================================
250 // Change this to disable logging of various VST activities
252 #define VST_LOGGING 1
256 #define log(a) Logger::writeToLog(a);
261 //==============================================================================
262 #if JUCE_MAC && JUCE_PPC
263 static void* NewCFMFromMachO (void* const machofp
) noexcept
265 void* result
= (void*) new char[8];
267 ((void**) result
)[0] = machofp
;
268 ((void**) result
)[1] = result
;
274 //==============================================================================
277 extern Display
* display
;
278 extern XContext windowHandleXContext
;
280 typedef void (*EventProcPtr
) (XEvent
* ev
);
282 static bool xErrorTriggered
;
286 int temporaryErrorHandler (Display
*, XErrorEvent
*)
288 xErrorTriggered
= true;
292 int getPropertyFromXWindow (Window handle
, Atom atom
)
294 XErrorHandler oldErrorHandler
= XSetErrorHandler (temporaryErrorHandler
);
295 xErrorTriggered
= false;
298 unsigned long bytes
, userCount
;
302 XGetWindowProperty (display
, handle
, atom
, 0, 1, false, AnyPropertyType
,
303 &userType
, &userSize
, &userCount
, &bytes
, &data
);
305 XSetErrorHandler (oldErrorHandler
);
307 return (userCount
== 1 && ! xErrorTriggered
) ? *reinterpret_cast<int*> (data
)
311 Window
getChildWindow (Window windowToCheck
)
313 Window rootWindow
, parentWindow
;
314 Window
* childWindows
;
315 unsigned int numChildren
;
325 return childWindows
[0];
330 void translateJuceToXButtonModifiers (const MouseEvent
& e
, XEvent
& ev
) noexcept
332 if (e
.mods
.isLeftButtonDown())
334 ev
.xbutton
.button
= Button1
;
335 ev
.xbutton
.state
|= Button1Mask
;
337 else if (e
.mods
.isRightButtonDown())
339 ev
.xbutton
.button
= Button3
;
340 ev
.xbutton
.state
|= Button3Mask
;
342 else if (e
.mods
.isMiddleButtonDown())
344 ev
.xbutton
.button
= Button2
;
345 ev
.xbutton
.state
|= Button2Mask
;
349 void translateJuceToXMotionModifiers (const MouseEvent
& e
, XEvent
& ev
) noexcept
351 if (e
.mods
.isLeftButtonDown()) ev
.xmotion
.state
|= Button1Mask
;
352 else if (e
.mods
.isRightButtonDown()) ev
.xmotion
.state
|= Button3Mask
;
353 else if (e
.mods
.isMiddleButtonDown()) ev
.xmotion
.state
|= Button2Mask
;
356 void translateJuceToXCrossingModifiers (const MouseEvent
& e
, XEvent
& ev
) noexcept
358 if (e
.mods
.isLeftButtonDown()) ev
.xcrossing
.state
|= Button1Mask
;
359 else if (e
.mods
.isRightButtonDown()) ev
.xcrossing
.state
|= Button3Mask
;
360 else if (e
.mods
.isMiddleButtonDown()) ev
.xcrossing
.state
|= Button2Mask
;
363 void translateJuceToXMouseWheelModifiers (const MouseEvent
& e
, const float increment
, XEvent
& ev
) noexcept
367 ev
.xbutton
.button
= Button5
;
368 ev
.xbutton
.state
|= Button5Mask
;
370 else if (increment
> 0)
372 ev
.xbutton
.button
= Button4
;
373 ev
.xbutton
.state
|= Button4Mask
;
380 //==============================================================================
381 class ModuleHandle
: public ReferenceCountedObject
384 //==============================================================================
389 static Array
<ModuleHandle
*>& getActiveModules()
391 static Array
<ModuleHandle
*> activeModules
;
392 return activeModules
;
395 //==============================================================================
396 static ModuleHandle
* findOrCreateModule (const File
& file
)
398 for (int i
= getActiveModules().size(); --i
>= 0;)
400 ModuleHandle
* const module
= getActiveModules().getUnchecked(i
);
402 if (module
->file
== file
)
406 _fpreset(); // (doesn't do any harm)
408 const IdleCallRecursionPreventer icrp
;
409 shellUIDToCreate
= 0;
411 log ("Attempting to load VST: " + file
.getFullPathName());
413 ScopedPointer
<ModuleHandle
> m (new ModuleHandle (file
));
418 _fpreset(); // (doesn't do any harm)
423 //==============================================================================
424 ModuleHandle (const File
& file_
)
427 #if JUCE_WINDOWS || JUCE_LINUX
430 fragId (0), resHandle (0), bundleRef (0), resFileId (0)
433 getActiveModules().add (this);
435 #if JUCE_WINDOWS || JUCE_LINUX
436 fullParentDirectoryPathName
= file_
.getParentDirectory().getFullPathName();
439 PlatformUtilities::makeFSRefFromPath (&ref
, file_
.getParentDirectory().getFullPathName());
440 FSGetCatalogInfo (&ref
, kFSCatInfoNone
, 0, 0, &parentDirFSSpec
, 0);
446 getActiveModules().removeValue (this);
450 //==============================================================================
451 #if JUCE_WINDOWS || JUCE_LINUX
453 String fullParentDirectoryPathName
;
458 static bool timePeriodSet
= false;
462 timePeriodSet
= true;
467 pluginName
= file
.getFileNameWithoutExtension();
469 hModule
= PlatformUtilities::loadDynamicLibrary (file
.getFullPathName());
471 moduleMain
= (MainCall
) PlatformUtilities::getProcedureEntryPoint (hModule
, "VSTPluginMain");
474 moduleMain
= (MainCall
) PlatformUtilities::getProcedureEntryPoint (hModule
, "main");
476 return moduleMain
!= 0;
481 _fpreset(); // (doesn't do any harm)
483 PlatformUtilities::freeDynamicLibrary (hModule
);
486 void closeEffect (AEffect
* eff
)
488 eff
->dispatcher (eff
, effClose
, 0, 0, 0, 0);
492 CFragConnectionID fragId
;
494 CFBundleRef bundleRef
;
495 FSSpec parentDirFSSpec
;
501 const String
filename (file
.getFullPathName());
503 if (file
.hasFileExtension (".vst"))
505 const char* const utf8
= filename
.toUTF8().getAddress();
506 CFURLRef url
= CFURLCreateFromFileSystemRepresentation (0, (const UInt8
*) utf8
,
507 strlen (utf8
), file
.isDirectory());
511 bundleRef
= CFBundleCreate (kCFAllocatorDefault
, url
);
516 if (CFBundleLoadExecutable (bundleRef
))
518 moduleMain
= (MainCall
) CFBundleGetFunctionPointerForName (bundleRef
, CFSTR("main_macho"));
521 moduleMain
= (MainCall
) CFBundleGetFunctionPointerForName (bundleRef
, CFSTR("VSTPluginMain"));
525 CFTypeRef name
= CFBundleGetValueForInfoDictionaryKey (bundleRef
, CFSTR("CFBundleName"));
529 if (CFGetTypeID (name
) == CFStringGetTypeID())
533 if (CFStringGetCString ((CFStringRef
) name
, buffer
, sizeof (buffer
), CFStringGetSystemEncoding()))
538 if (pluginName
.isEmpty())
539 pluginName
= file
.getFileNameWithoutExtension();
541 resFileId
= CFBundleOpenBundleResourceMap (bundleRef
);
549 CFBundleUnloadExecutable (bundleRef
);
550 CFRelease (bundleRef
);
561 if (FSPathMakeRef ((UInt8
*) filename
.toUTF8().getAddress(), &fn
, 0) == noErr
)
563 resFileId
= FSOpenResFile (&fn
, fsRdPerm
);
567 const int numEffs
= Count1Resources ('aEff');
569 for (int i
= 0; i
< numEffs
; ++i
)
571 resHandle
= Get1IndResource ('aEff', i
+ 1);
578 GetResInfo (resHandle
, &id
, &type
, name
);
579 pluginName
= String ((const char*) name
+ 1, name
[0]);
580 DetachResource (resHandle
);
586 OSErr err
= GetMemFragment (*resHandle
, GetHandleSize (resHandle
),
587 name
, kPrivateCFragCopy
,
588 &fragId
, &ptr
, errorText
);
592 moduleMain
= (MainCall
) newMachOFromCFM (ptr
);
605 CloseResFile (resFileId
);
620 disposeMachOFromCFM ((void*) moduleMain
);
622 CloseConnection (&fragId
);
626 CloseResFile (resFileId
);
632 CFBundleCloseBundleResourceMap (bundleRef
, resFileId
);
634 if (CFGetRetainCount (bundleRef
) == 1)
635 CFBundleUnloadExecutable (bundleRef
);
637 if (CFGetRetainCount (bundleRef
) > 0)
638 CFRelease (bundleRef
);
642 void closeEffect (AEffect
* eff
)
647 Array
<void*> thingsToDelete
;
648 thingsToDelete
.add ((void*) eff
->dispatcher
);
649 thingsToDelete
.add ((void*) eff
->process
);
650 thingsToDelete
.add ((void*) eff
->setParameter
);
651 thingsToDelete
.add ((void*) eff
->getParameter
);
652 thingsToDelete
.add ((void*) eff
->processReplacing
);
654 eff
->dispatcher (eff
, effClose
, 0, 0, 0, 0);
656 for (int i
= thingsToDelete
.size(); --i
>= 0;)
657 disposeMachOFromCFM (thingsToDelete
[i
]);
662 eff
->dispatcher (eff
, effClose
, 0, 0, 0, 0);
667 static void* newMachOFromCFM (void* cfmfp
)
672 UInt32
* const mfp
= new UInt32
[6];
674 mfp
[0] = 0x3d800000 | ((UInt32
) cfmfp
>> 16);
675 mfp
[1] = 0x618c0000 | ((UInt32
) cfmfp
& 0xffff);
681 MakeDataExecutable (mfp
, sizeof (UInt32
) * 6);
685 static void disposeMachOFromCFM (void* ptr
)
687 delete[] static_cast <UInt32
*> (ptr
);
690 void coerceAEffectFunctionCalls (AEffect
* eff
)
694 eff
->dispatcher
= (AEffectDispatcherProc
) newMachOFromCFM ((void*) eff
->dispatcher
);
695 eff
->process
= (AEffectProcessProc
) newMachOFromCFM ((void*) eff
->process
);
696 eff
->setParameter
= (AEffectSetParameterProc
) newMachOFromCFM ((void*) eff
->setParameter
);
697 eff
->getParameter
= (AEffectGetParameterProc
) newMachOFromCFM ((void*) eff
->getParameter
);
698 eff
->processReplacing
= (AEffectProcessProc
) newMachOFromCFM ((void*) eff
->processReplacing
);
706 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModuleHandle
);
709 //==============================================================================
711 An instance of a plugin, created by a VSTPluginFormat.
714 class VSTPluginInstance
: public AudioPluginInstance
,
719 //==============================================================================
720 ~VSTPluginInstance();
722 //==============================================================================
723 // AudioPluginInstance methods:
725 void fillInPluginDescription (PluginDescription
& desc
) const
730 char buffer
[512] = { 0 };
731 dispatch (effGetEffectName
, 0, 0, buffer
, 0);
733 desc
.descriptiveName
= String (buffer
).trim();
735 if (desc
.descriptiveName
.isEmpty())
736 desc
.descriptiveName
= name
;
739 desc
.fileOrIdentifier
= module
->file
.getFullPathName();
741 desc
.lastFileModTime
= module
->file
.getLastModificationTime();
742 desc
.pluginFormatName
= "VST";
743 desc
.category
= getCategory();
746 char buffer
[kVstMaxVendorStrLen
+ 8] = { 0 };
747 dispatch (effGetVendorString
, 0, 0, buffer
, 0);
748 desc
.manufacturerName
= buffer
;
751 desc
.version
= getVersion();
752 desc
.numInputChannels
= getNumInputChannels();
753 desc
.numOutputChannels
= getNumOutputChannels();
754 desc
.isInstrument
= (effect
!= nullptr && (effect
->flags
& effFlagsIsSynth
) != 0);
757 void* getPlatformSpecificData() { return effect
; }
758 const String
getName() const { return name
; }
760 bool acceptsMidi() const { return wantsMidiMessages
; }
761 bool producesMidi() const { return dispatch (effCanDo
, 0, 0, (void*) "sendVstMidiEvent", 0) > 0; }
763 //==============================================================================
764 // AudioProcessor methods:
766 void prepareToPlay (double sampleRate
, int estimatedSamplesPerBlock
);
767 void releaseResources();
768 void processBlock (AudioSampleBuffer
& buffer
,
769 MidiBuffer
& midiMessages
);
771 bool hasEditor() const { return effect
!= nullptr && (effect
->flags
& effFlagsHasEditor
) != 0; }
772 AudioProcessorEditor
* createEditor();
774 const String
getInputChannelName (int index
) const;
775 bool isInputChannelStereoPair (int index
) const;
777 const String
getOutputChannelName (int index
) const;
778 bool isOutputChannelStereoPair (int index
) const;
780 //==============================================================================
781 int getNumParameters() { return effect
!= nullptr ? effect
->numParams
: 0; }
782 float getParameter (int index
);
783 void setParameter (int index
, float newValue
);
784 const String
getParameterName (int index
);
785 const String
getParameterText (int index
);
786 bool isParameterAutomatable (int index
) const;
788 //==============================================================================
789 int getNumPrograms() { return effect
!= nullptr ? effect
->numPrograms
: 0; }
790 int getCurrentProgram() { return dispatch (effGetProgram
, 0, 0, 0, 0); }
791 void setCurrentProgram (int index
);
792 const String
getProgramName (int index
);
793 void changeProgramName (int index
, const String
& newName
);
795 //==============================================================================
796 void getStateInformation (MemoryBlock
& destData
);
797 void getCurrentProgramStateInformation (MemoryBlock
& destData
);
798 void setStateInformation (const void* data
, int sizeInBytes
);
799 void setCurrentProgramStateInformation (const void* data
, int sizeInBytes
);
801 //==============================================================================
802 void timerCallback();
803 void handleAsyncUpdate();
804 VstIntPtr
handleCallback (VstInt32 opcode
, VstInt32 index
, VstInt32 value
, void *ptr
, float opt
);
807 //==============================================================================
808 friend class VSTPluginWindow
;
809 friend class VSTPluginFormat
;
813 CriticalSection lock
;
814 bool wantsMidiMessages
, initialised
, isPowerOn
;
815 mutable StringArray programNames
;
816 AudioSampleBuffer tempBuffer
;
817 CriticalSection midiInLock
;
818 MidiBuffer incomingMidi
;
819 VSTMidiEventList midiEventsToSend
;
820 VstTimeInfo vstHostTime
;
822 ReferenceCountedObjectPtr
<ModuleHandle
> module
;
824 //==============================================================================
825 int dispatch (const int opcode
, const int index
, const int value
, void* const ptr
, float opt
) const;
826 bool restoreProgramSettings (const fxProgram
* const prog
);
827 const String
getCurrentProgramName();
828 void setParamsInProgramBlock (fxProgram
* const prog
);
829 void updateStoredProgramNames();
831 void handleMidiFromPlugin (const VstEvents
* const events
);
832 void createTempParameterStore (MemoryBlock
& dest
);
833 void restoreFromTempParameterStore (const MemoryBlock
& mb
);
834 const String
getParameterLabel (int index
) const;
836 bool usesChunks() const noexcept
{ return effect
!= nullptr && (effect
->flags
& effFlagsProgramChunks
) != 0; }
837 void getChunkData (MemoryBlock
& mb
, bool isPreset
, int maxSizeMB
) const;
838 void setChunkData (const char* data
, int size
, bool isPreset
);
839 bool loadFromFXBFile (const void* data
, int numBytes
);
840 bool saveToFXBFile (MemoryBlock
& dest
, bool isFXB
, int maxSizeMB
);
842 int getVersionNumber() const noexcept
{ return effect
!= nullptr ? effect
->version
: 0; }
843 const String
getVersion() const;
844 const String
getCategory() const;
846 void setPower (const bool on
);
848 VSTPluginInstance (const ReferenceCountedObjectPtr
<ModuleHandle
>& module
);
849 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginInstance
);
852 //==============================================================================
853 VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr
<ModuleHandle
>& module_
)
855 name (module_
->pluginName
),
856 wantsMidiMessages (false),
864 const IdleCallRecursionPreventer icrp
;
867 log ("Creating VST instance: " + name
);
870 if (module
->resFileId
!= 0)
871 UseResFile (module
->resFileId
);
874 if (module
->fragId
!= 0)
876 static void* audioMasterCoerced
= nullptr;
877 if (audioMasterCoerced
== nullptr)
878 audioMasterCoerced
= NewCFMFromMachO ((void*) &audioMaster
);
880 effect
= module
->moduleMain ((audioMasterCallback
) audioMasterCoerced
);
886 effect
= module
->moduleMain (&audioMaster
);
889 if (effect
!= nullptr && effect
->magic
== kEffectMagic
)
892 module
->coerceAEffectFunctionCalls (effect
);
895 jassert (effect
->resvd2
== 0);
896 jassert (effect
->object
!= 0);
898 _fpreset(); // some dodgy plugs fuck around with this
909 VSTPluginInstance::~VSTPluginInstance()
911 const ScopedLock
sl (lock
);
913 if (effect
!= nullptr && effect
->magic
== kEffectMagic
)
918 if (module
->resFileId
!= 0)
919 UseResFile (module
->resFileId
);
922 // Must delete any editors before deleting the plugin instance!
923 jassert (getActiveEditor() == 0);
925 _fpreset(); // some dodgy plugs fuck around with this
927 module
->closeEffect (effect
);
937 //==============================================================================
938 void VSTPluginInstance::initialise()
940 if (initialised
|| effect
== 0)
943 log ("Initialising VST: " + module
->pluginName
);
946 dispatch (effIdentify
, 0, 0, 0, 0);
948 if (getSampleRate() > 0)
949 dispatch (effSetSampleRate
, 0, 0, 0, (float) getSampleRate());
951 if (getBlockSize() > 0)
952 dispatch (effSetBlockSize
, 0, jmax (32, getBlockSize()), 0, 0);
954 dispatch (effOpen
, 0, 0, 0, 0);
956 setPlayConfigDetails (effect
->numInputs
, effect
->numOutputs
,
957 getSampleRate(), getBlockSize());
959 if (getNumPrograms() > 1)
960 setCurrentProgram (0);
962 dispatch (effSetProgram
, 0, 0, 0, 0);
965 for (i
= effect
->numInputs
; --i
>= 0;)
966 dispatch (effConnectInput
, i
, 1, 0, 0);
968 for (i
= effect
->numOutputs
; --i
>= 0;)
969 dispatch (effConnectOutput
, i
, 1, 0, 0);
971 updateStoredProgramNames();
973 wantsMidiMessages
= dispatch (effCanDo
, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0;
975 setLatencySamples (effect
->initialDelay
);
979 //==============================================================================
980 void VSTPluginInstance::prepareToPlay (double sampleRate_
,
981 int samplesPerBlockExpected
)
983 setPlayConfigDetails (effect
->numInputs
, effect
->numOutputs
,
984 sampleRate_
, samplesPerBlockExpected
);
986 setLatencySamples (effect
->initialDelay
);
988 vstHostTime
.tempo
= 120.0;
989 vstHostTime
.timeSigNumerator
= 4;
990 vstHostTime
.timeSigDenominator
= 4;
991 vstHostTime
.sampleRate
= sampleRate_
;
992 vstHostTime
.samplePos
= 0;
993 vstHostTime
.flags
= kVstNanosValid
; /*| kVstTransportPlaying | kVstTempoValid | kVstTimeSigValid*/;
999 wantsMidiMessages
= wantsMidiMessages
1000 || (dispatch (effCanDo
, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0);
1002 if (wantsMidiMessages
)
1003 midiEventsToSend
.ensureSize (256);
1005 midiEventsToSend
.freeEvents();
1007 incomingMidi
.clear();
1009 dispatch (effSetSampleRate
, 0, 0, 0, (float) sampleRate_
);
1010 dispatch (effSetBlockSize
, 0, jmax (16, samplesPerBlockExpected
), 0, 0);
1012 tempBuffer
.setSize (jmax (1, effect
->numOutputs
), samplesPerBlockExpected
);
1017 // dodgy hack to force some plugins to initialise the sample rate..
1018 if ((! hasEditor()) && getNumParameters() > 0)
1020 const float old
= getParameter (0);
1021 setParameter (0, (old
< 0.5f
) ? 1.0f
: 0.0f
);
1022 setParameter (0, old
);
1025 dispatch (effStartProcess
, 0, 0, 0, 0);
1029 void VSTPluginInstance::releaseResources()
1033 dispatch (effStopProcess
, 0, 0, 0, 0);
1037 tempBuffer
.setSize (1, 1);
1038 incomingMidi
.clear();
1040 midiEventsToSend
.freeEvents();
1043 void VSTPluginInstance::processBlock (AudioSampleBuffer
& buffer
,
1044 MidiBuffer
& midiMessages
)
1046 const int numSamples
= buffer
.getNumSamples();
1050 AudioPlayHead
* playHead
= getPlayHead();
1052 if (playHead
!= nullptr)
1054 AudioPlayHead::CurrentPositionInfo position
;
1055 playHead
->getCurrentPosition (position
);
1057 vstHostTime
.tempo
= position
.bpm
;
1058 vstHostTime
.timeSigNumerator
= position
.timeSigNumerator
;
1059 vstHostTime
.timeSigDenominator
= position
.timeSigDenominator
;
1060 vstHostTime
.ppqPos
= position
.ppqPosition
;
1061 vstHostTime
.barStartPos
= position
.ppqPositionOfLastBarStart
;
1062 vstHostTime
.flags
|= kVstTempoValid
| kVstTimeSigValid
| kVstPpqPosValid
| kVstBarsValid
;
1064 if (position
.isPlaying
)
1065 vstHostTime
.flags
|= kVstTransportPlaying
;
1067 vstHostTime
.flags
&= ~kVstTransportPlaying
;
1070 vstHostTime
.nanoSeconds
= getVSTHostTimeNanoseconds();
1072 if (wantsMidiMessages
)
1074 midiEventsToSend
.clear();
1075 midiEventsToSend
.ensureSize (1);
1077 MidiBuffer::Iterator
iter (midiMessages
);
1078 const uint8
* midiData
;
1079 int numBytesOfMidiData
, samplePosition
;
1081 while (iter
.getNextEvent (midiData
, numBytesOfMidiData
, samplePosition
))
1083 midiEventsToSend
.addEvent (midiData
, numBytesOfMidiData
,
1084 jlimit (0, numSamples
- 1, samplePosition
));
1089 effect
->dispatcher (effect
, effProcessEvents
, 0, 0, midiEventsToSend
.events
, 0);
1097 if ((effect
->flags
& effFlagsCanReplacing
) != 0)
1101 effect
->processReplacing (effect
, buffer
.getArrayOfChannels(), buffer
.getArrayOfChannels(), numSamples
);
1108 tempBuffer
.setSize (effect
->numOutputs
, numSamples
);
1113 effect
->process (effect
, buffer
.getArrayOfChannels(), tempBuffer
.getArrayOfChannels(), numSamples
);
1118 for (int i
= effect
->numOutputs
; --i
>= 0;)
1119 buffer
.copyFrom (i
, 0, tempBuffer
.getSampleData (i
), numSamples
);
1124 // Not initialised, so just bypass..
1125 for (int i
= getNumInputChannels(); i
< getNumOutputChannels(); ++i
)
1126 buffer
.clear (i
, 0, buffer
.getNumSamples());
1130 // copy any incoming midi..
1131 const ScopedLock
sl (midiInLock
);
1133 midiMessages
.swapWith (incomingMidi
);
1134 incomingMidi
.clear();
1138 //==============================================================================
1139 void VSTPluginInstance::handleMidiFromPlugin (const VstEvents
* const events
)
1141 if (events
!= nullptr)
1143 const ScopedLock
sl (midiInLock
);
1144 VSTMidiEventList::addEventsToMidiBuffer (events
, incomingMidi
);
1148 //==============================================================================
1149 static Array
<VSTPluginWindow
*> activeVSTWindows
;
1151 //==============================================================================
1152 class VSTPluginWindow
: public AudioProcessorEditor
,
1154 public ComponentMovementWatcher
,
1159 //==============================================================================
1160 VSTPluginWindow (VSTPluginInstance
& plugin_
)
1161 : AudioProcessorEditor (&plugin_
),
1163 ComponentMovementWatcher (this),
1167 recursiveResize (false),
1168 pluginWantsKeys (false),
1169 pluginRefusesToResize (false),
1170 alreadyInside (false)
1176 pluginWindow
= None
;
1179 addAndMakeVisible (innerWrapper
= new InnerWrapperComponent (this));
1182 activeVSTWindows
.add (this);
1192 innerWrapper
= nullptr;
1194 closePluginWindow();
1197 activeVSTWindows
.removeValue (this);
1198 plugin
.editorBeingDeleted (this);
1201 //==============================================================================
1203 void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
1205 if (recursiveResize
)
1208 Component
* const topComp
= getTopLevelComponent();
1210 if (topComp
->getPeer() != nullptr)
1212 const Point
<int> pos (topComp
->getLocalPoint (this, Point
<int>()));
1214 recursiveResize
= true;
1217 if (pluginHWND
!= 0)
1218 MoveWindow (pluginHWND
, pos
.getX(), pos
.getY(), getWidth(), getHeight(), TRUE
);
1220 if (pluginWindow
!= 0)
1222 XResizeWindow (display
, pluginWindow
, getWidth(), getHeight());
1223 XMoveWindow (display
, pluginWindow
, pos
.getX(), pos
.getY());
1224 XMapRaised (display
, pluginWindow
);
1228 recursiveResize
= false;
1232 void componentVisibilityChanged()
1237 closePluginWindow();
1239 componentMovedOrResized (true, true);
1242 void componentPeerChanged()
1244 closePluginWindow();
1249 //==============================================================================
1250 bool keyStateChanged (bool)
1252 return pluginWantsKeys
;
1255 bool keyPressed (const KeyPress
&)
1257 return pluginWantsKeys
;
1260 //==============================================================================
1262 void paint (Graphics
& g
)
1264 g
.fillAll (Colours::black
);
1267 void paint (Graphics
& g
)
1271 ComponentPeer
* const peer
= getPeer();
1273 if (peer
!= nullptr)
1275 const Point
<int> pos (getScreenPosition() - peer
->getScreenPosition());
1276 peer
->addMaskedRegion (pos
.getX(), pos
.getY(), getWidth(), getHeight());
1279 if (pluginWindow
!= 0)
1281 const Rectangle
<int> clip (g
.getClipBounds());
1284 ev
.xexpose
.type
= Expose
;
1285 ev
.xexpose
.display
= display
;
1286 ev
.xexpose
.window
= pluginWindow
;
1287 ev
.xexpose
.x
= clip
.getX();
1288 ev
.xexpose
.y
= clip
.getY();
1289 ev
.xexpose
.width
= clip
.getWidth();
1290 ev
.xexpose
.height
= clip
.getHeight();
1292 sendEventToChild (&ev
);
1299 g
.fillAll (Colours::black
);
1304 //==============================================================================
1305 void timerCallback()
1308 if (--sizeCheckCount
<= 0)
1310 sizeCheckCount
= 10;
1312 checkPluginWindowSize();
1318 static bool reentrant
= false;
1323 plugin
.dispatch (effEditIdle
, 0, 0, 0, 0);
1331 //==============================================================================
1332 void mouseDown (const MouseEvent
& e
)
1335 if (pluginWindow
== 0)
1341 ev
.xbutton
.display
= display
;
1342 ev
.xbutton
.type
= ButtonPress
;
1343 ev
.xbutton
.window
= pluginWindow
;
1344 ev
.xbutton
.root
= RootWindow (display
, DefaultScreen (display
));
1345 ev
.xbutton
.time
= CurrentTime
;
1348 ev
.xbutton
.x_root
= e
.getScreenX();
1349 ev
.xbutton
.y_root
= e
.getScreenY();
1351 translateJuceToXButtonModifiers (e
, ev
);
1353 sendEventToChild (&ev
);
1362 void broughtToFront()
1364 activeVSTWindows
.removeValue (this);
1365 activeVSTWindows
.add (this);
1368 dispatch (effEditTop
, 0, 0, 0, 0);
1372 //==============================================================================
1374 VSTPluginInstance
& plugin
;
1375 bool isOpen
, recursiveResize
;
1376 bool pluginWantsKeys
, pluginRefusesToResize
, alreadyInside
;
1380 void* originalWndProc
;
1383 Window pluginWindow
;
1384 EventProcPtr pluginProc
;
1387 //==============================================================================
1389 void openPluginWindow (WindowRef parentWindow
)
1391 if (isOpen
|| parentWindow
== 0)
1396 ERect
* rect
= nullptr;
1397 dispatch (effEditGetRect
, 0, 0, &rect
, 0);
1398 dispatch (effEditOpen
, 0, 0, parentWindow
, 0);
1400 // do this before and after like in the steinberg example
1401 dispatch (effEditGetRect
, 0, 0, &rect
, 0);
1402 dispatch (effGetProgram
, 0, 0, 0, 0); // also in steinberg code
1404 // Install keyboard hooks
1405 pluginWantsKeys
= (dispatch (effKeysRequired
, 0, 0, 0, 0) == 0);
1407 // double-check it's not too tiny
1408 int w
= 250, h
= 150;
1410 if (rect
!= nullptr)
1412 w
= rect
->right
- rect
->left
;
1413 h
= rect
->bottom
- rect
->top
;
1415 if (w
== 0 || h
== 0)
1427 startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5));
1432 void openPluginWindow()
1434 if (isOpen
|| getWindowHandle() == 0)
1437 log ("Opening VST UI: " + plugin
.name
);
1440 ERect
* rect
= nullptr;
1441 dispatch (effEditGetRect
, 0, 0, &rect
, 0);
1442 dispatch (effEditOpen
, 0, 0, getWindowHandle(), 0);
1444 // do this before and after like in the steinberg example
1445 dispatch (effEditGetRect
, 0, 0, &rect
, 0);
1446 dispatch (effGetProgram
, 0, 0, 0, 0); // also in steinberg code
1448 // Install keyboard hooks
1449 pluginWantsKeys
= (dispatch (effKeysRequired
, 0, 0, 0, 0) == 0);
1452 originalWndProc
= 0;
1453 pluginHWND
= GetWindow ((HWND
) getWindowHandle(), GW_CHILD
);
1455 if (pluginHWND
== 0)
1462 #pragma warning (push)
1463 #pragma warning (disable: 4244)
1465 originalWndProc
= (void*) GetWindowLongPtr (pluginHWND
, GWLP_WNDPROC
);
1467 if (! pluginWantsKeys
)
1468 SetWindowLongPtr (pluginHWND
, GWLP_WNDPROC
, (LONG_PTR
) vstHookWndProc
);
1470 #pragma warning (pop)
1474 GetWindowRect (pluginHWND
, &r
);
1475 w
= r
.right
- r
.left
;
1476 h
= r
.bottom
- r
.top
;
1478 if (rect
!= nullptr)
1480 const int rw
= rect
->right
- rect
->left
;
1481 const int rh
= rect
->bottom
- rect
->top
;
1483 if ((rw
> 50 && rh
> 50 && rw
< 2000 && rh
< 2000 && rw
!= w
&& rh
!= h
)
1484 || ((w
== 0 && rw
> 0) || (h
== 0 && rh
> 0)))
1486 // very dodgy logic to decide which size is right.
1487 if (abs (rw
- w
) > 350 || abs (rh
- h
) > 350)
1489 SetWindowPos (pluginHWND
, 0,
1491 SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOOWNERZORDER
| SWP_NOZORDER
);
1493 GetWindowRect (pluginHWND
, &r
);
1495 w
= r
.right
- r
.left
;
1496 h
= r
.bottom
- r
.top
;
1498 pluginRefusesToResize
= (w
!= rw
) || (h
!= rh
);
1507 pluginWindow
= getChildWindow ((Window
) getWindowHandle());
1509 if (pluginWindow
!= 0)
1510 pluginProc
= (EventProcPtr
) getPropertyFromXWindow (pluginWindow
,
1511 XInternAtom (display
, "_XEventProc", False
));
1513 int w
= 250, h
= 150;
1515 if (rect
!= nullptr)
1517 w
= rect
->right
- rect
->left
;
1518 h
= rect
->bottom
- rect
->top
;
1520 if (w
== 0 || h
== 0)
1527 if (pluginWindow
!= 0)
1528 XMapRaised (display
, pluginWindow
);
1531 // double-check it's not too tiny
1538 checkPluginWindowSize();
1541 startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5));
1546 //==============================================================================
1548 void closePluginWindow()
1552 log ("Closing VST UI: " + plugin
.getName());
1555 dispatch (effEditClose
, 0, 0, 0, 0);
1558 #pragma warning (push)
1559 #pragma warning (disable: 4244)
1561 if (pluginHWND
!= 0 && IsWindow (pluginHWND
))
1562 SetWindowLongPtr (pluginHWND
, GWLP_WNDPROC
, (LONG_PTR
) originalWndProc
);
1564 #pragma warning (pop)
1568 if (pluginHWND
!= 0 && IsWindow (pluginHWND
))
1569 DestroyWindow (pluginHWND
);
1581 //==============================================================================
1582 int dispatch (const int opcode
, const int index
, const int value
, void* const ptr
, float opt
)
1584 return plugin
.dispatch (opcode
, index
, value
, ptr
, opt
);
1587 //==============================================================================
1589 void checkPluginWindowSize()
1592 GetWindowRect (pluginHWND
, &r
);
1593 const int w
= r
.right
- r
.left
;
1594 const int h
= r
.bottom
- r
.top
;
1596 if (isShowing() && w
> 0 && h
> 0
1597 && (w
!= getWidth() || h
!= getHeight())
1598 && ! pluginRefusesToResize
)
1605 // hooks to get keyboard events from VST windows..
1606 static LRESULT CALLBACK
vstHookWndProc (HWND hW
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1608 for (int i
= activeVSTWindows
.size(); --i
>= 0;)
1610 const VSTPluginWindow
* const w
= activeVSTWindows
.getUnchecked (i
);
1612 if (w
->pluginHWND
== hW
)
1614 if (message
== WM_CHAR
1615 || message
== WM_KEYDOWN
1616 || message
== WM_SYSKEYDOWN
1617 || message
== WM_KEYUP
1618 || message
== WM_SYSKEYUP
1619 || message
== WM_APPCOMMAND
)
1621 SendMessage ((HWND
) w
->getTopLevelComponent()->getWindowHandle(),
1622 message
, wParam
, lParam
);
1625 return CallWindowProc ((WNDPROC
) (w
->originalWndProc
),
1626 (HWND
) w
->pluginHWND
,
1633 return DefWindowProc (hW
, message
, wParam
, lParam
);
1638 //==============================================================================
1639 // overload mouse/keyboard events to forward them to the plugin's inner window..
1640 void sendEventToChild (XEvent
* event
)
1642 if (pluginProc
!= 0)
1644 // if the plugin publishes an event procedure, pass the event directly..
1647 else if (pluginWindow
!= 0)
1649 // if the plugin has a window, then send the event to the window so that
1650 // its message thread will pick it up..
1651 XSendEvent (display
, pluginWindow
, False
, 0L, event
);
1656 void mouseEnter (const MouseEvent
& e
)
1658 if (pluginWindow
!= 0)
1661 ev
.xcrossing
.display
= display
;
1662 ev
.xcrossing
.type
= EnterNotify
;
1663 ev
.xcrossing
.window
= pluginWindow
;
1664 ev
.xcrossing
.root
= RootWindow (display
, DefaultScreen (display
));
1665 ev
.xcrossing
.time
= CurrentTime
;
1666 ev
.xcrossing
.x
= e
.x
;
1667 ev
.xcrossing
.y
= e
.y
;
1668 ev
.xcrossing
.x_root
= e
.getScreenX();
1669 ev
.xcrossing
.y_root
= e
.getScreenY();
1670 ev
.xcrossing
.mode
= NotifyNormal
; // NotifyGrab, NotifyUngrab
1671 ev
.xcrossing
.detail
= NotifyAncestor
; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual
1673 translateJuceToXCrossingModifiers (e
, ev
);
1675 sendEventToChild (&ev
);
1679 void mouseExit (const MouseEvent
& e
)
1681 if (pluginWindow
!= 0)
1684 ev
.xcrossing
.display
= display
;
1685 ev
.xcrossing
.type
= LeaveNotify
;
1686 ev
.xcrossing
.window
= pluginWindow
;
1687 ev
.xcrossing
.root
= RootWindow (display
, DefaultScreen (display
));
1688 ev
.xcrossing
.time
= CurrentTime
;
1689 ev
.xcrossing
.x
= e
.x
;
1690 ev
.xcrossing
.y
= e
.y
;
1691 ev
.xcrossing
.x_root
= e
.getScreenX();
1692 ev
.xcrossing
.y_root
= e
.getScreenY();
1693 ev
.xcrossing
.mode
= NotifyNormal
; // NotifyGrab, NotifyUngrab
1694 ev
.xcrossing
.detail
= NotifyAncestor
; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual
1695 ev
.xcrossing
.focus
= hasKeyboardFocus (true); // TODO - yes ?
1697 translateJuceToXCrossingModifiers (e
, ev
);
1699 sendEventToChild (&ev
);
1703 void mouseMove (const MouseEvent
& e
)
1705 if (pluginWindow
!= 0)
1708 ev
.xmotion
.display
= display
;
1709 ev
.xmotion
.type
= MotionNotify
;
1710 ev
.xmotion
.window
= pluginWindow
;
1711 ev
.xmotion
.root
= RootWindow (display
, DefaultScreen (display
));
1712 ev
.xmotion
.time
= CurrentTime
;
1713 ev
.xmotion
.is_hint
= NotifyNormal
;
1716 ev
.xmotion
.x_root
= e
.getScreenX();
1717 ev
.xmotion
.y_root
= e
.getScreenY();
1719 sendEventToChild (&ev
);
1723 void mouseDrag (const MouseEvent
& e
)
1725 if (pluginWindow
!= 0)
1728 ev
.xmotion
.display
= display
;
1729 ev
.xmotion
.type
= MotionNotify
;
1730 ev
.xmotion
.window
= pluginWindow
;
1731 ev
.xmotion
.root
= RootWindow (display
, DefaultScreen (display
));
1732 ev
.xmotion
.time
= CurrentTime
;
1733 ev
.xmotion
.x
= e
.x
;
1735 ev
.xmotion
.x_root
= e
.getScreenX();
1736 ev
.xmotion
.y_root
= e
.getScreenY();
1737 ev
.xmotion
.is_hint
= NotifyNormal
;
1739 translateJuceToXMotionModifiers (e
, ev
);
1740 sendEventToChild (&ev
);
1744 void mouseUp (const MouseEvent
& e
)
1746 if (pluginWindow
!= 0)
1749 ev
.xbutton
.display
= display
;
1750 ev
.xbutton
.type
= ButtonRelease
;
1751 ev
.xbutton
.window
= pluginWindow
;
1752 ev
.xbutton
.root
= RootWindow (display
, DefaultScreen (display
));
1753 ev
.xbutton
.time
= CurrentTime
;
1756 ev
.xbutton
.x_root
= e
.getScreenX();
1757 ev
.xbutton
.y_root
= e
.getScreenY();
1759 translateJuceToXButtonModifiers (e
, ev
);
1760 sendEventToChild (&ev
);
1764 void mouseWheelMove (const MouseEvent
& e
,
1768 if (pluginWindow
!= 0)
1771 ev
.xbutton
.display
= display
;
1772 ev
.xbutton
.type
= ButtonPress
;
1773 ev
.xbutton
.window
= pluginWindow
;
1774 ev
.xbutton
.root
= RootWindow (display
, DefaultScreen (display
));
1775 ev
.xbutton
.time
= CurrentTime
;
1778 ev
.xbutton
.x_root
= e
.getScreenX();
1779 ev
.xbutton
.y_root
= e
.getScreenY();
1781 translateJuceToXMouseWheelModifiers (e
, incrementY
, ev
);
1782 sendEventToChild (&ev
);
1784 // TODO - put a usleep here ?
1786 ev
.xbutton
.type
= ButtonRelease
;
1787 sendEventToChild (&ev
);
1794 #if ! JUCE_SUPPORT_CARBON
1795 #error "To build VSTs, you need to enable the JUCE_SUPPORT_CARBON flag in your config!"
1798 class InnerWrapperComponent
: public CarbonViewWrapperComponent
1801 InnerWrapperComponent (VSTPluginWindow
* const owner_
)
1803 alreadyInside (false)
1807 ~InnerWrapperComponent()
1812 HIViewRef
attachView (WindowRef windowRef
, HIViewRef rootView
)
1814 owner
->openPluginWindow (windowRef
);
1818 void removeView (HIViewRef
)
1820 owner
->dispatch (effEditClose
, 0, 0, 0, 0);
1821 owner
->dispatch (effEditSleep
, 0, 0, 0, 0);
1824 bool getEmbeddedViewSize (int& w
, int& h
)
1826 ERect
* rect
= nullptr;
1827 owner
->dispatch (effEditGetRect
, 0, 0, &rect
, 0);
1828 w
= rect
->right
- rect
->left
;
1829 h
= rect
->bottom
- rect
->top
;
1833 void mouseDown (int x
, int y
)
1835 if (! alreadyInside
)
1837 alreadyInside
= true;
1838 getTopLevelComponent()->toFront (true);
1839 owner
->dispatch (effEditMouse
, x
, y
, 0, 0);
1840 alreadyInside
= false;
1844 PostEvent (::mouseDown
, 0);
1850 ComponentPeer
* const peer
= getPeer();
1852 if (peer
!= nullptr)
1854 const Point
<int> pos (getScreenPosition() - peer
->getScreenPosition());
1856 r
.left
= pos
.getX();
1857 r
.right
= r
.left
+ getWidth();
1859 r
.bottom
= r
.top
+ getHeight();
1861 owner
->dispatch (effEditDraw
, 0, 0, &r
, 0);
1866 VSTPluginWindow
* const owner
;
1870 friend class InnerWrapperComponent
;
1871 ScopedPointer
<InnerWrapperComponent
> innerWrapper
;
1875 innerWrapper
->setSize (getWidth(), getHeight());
1880 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginWindow
);
1883 //==============================================================================
1884 AudioProcessorEditor
* VSTPluginInstance::createEditor()
1887 return new VSTPluginWindow (*this);
1893 //==============================================================================
1894 void VSTPluginInstance::handleAsyncUpdate()
1896 // indicates that something about the plugin has changed..
1897 updateHostDisplay();
1900 //==============================================================================
1901 bool VSTPluginInstance::restoreProgramSettings (const fxProgram
* const prog
)
1903 if (vst_swap (prog
->chunkMagic
) == 'CcnK' && vst_swap (prog
->fxMagic
) == 'FxCk')
1905 changeProgramName (getCurrentProgram(), prog
->prgName
);
1907 for (int i
= 0; i
< vst_swap (prog
->numParams
); ++i
)
1908 setParameter (i
, vst_swapFloat (prog
->params
[i
]));
1916 bool VSTPluginInstance::loadFromFXBFile (const void* const data
,
1922 const fxSet
* const set
= (const fxSet
*) data
;
1924 if ((vst_swap (set
->chunkMagic
) != 'CcnK' && vst_swap (set
->chunkMagic
) != 'KncC')
1925 || vst_swap (set
->version
) > fxbVersionNum
)
1928 if (vst_swap (set
->fxMagic
) == 'FxBk')
1931 if (vst_swap (set
->numPrograms
) >= 0)
1933 const int oldProg
= getCurrentProgram();
1934 const int numParams
= vst_swap (((const fxProgram
*) (set
->programs
))->numParams
);
1935 const int progLen
= sizeof (fxProgram
) + (numParams
- 1) * sizeof (float);
1937 for (int i
= 0; i
< vst_swap (set
->numPrograms
); ++i
)
1941 const fxProgram
* const prog
= (const fxProgram
*) (((const char*) (set
->programs
)) + i
* progLen
);
1942 if (((const char*) prog
) - ((const char*) set
) >= dataSize
)
1945 if (vst_swap (set
->numPrograms
) > 0)
1946 setCurrentProgram (i
);
1948 if (! restoreProgramSettings (prog
))
1953 if (vst_swap (set
->numPrograms
) > 0)
1954 setCurrentProgram (oldProg
);
1956 const fxProgram
* const prog
= (const fxProgram
*) (((const char*) (set
->programs
)) + oldProg
* progLen
);
1957 if (((const char*) prog
) - ((const char*) set
) >= dataSize
)
1960 if (! restoreProgramSettings (prog
))
1964 else if (vst_swap (set
->fxMagic
) == 'FxCk')
1967 const fxProgram
* const prog
= (const fxProgram
*) data
;
1969 if (vst_swap (prog
->chunkMagic
) != 'CcnK')
1972 changeProgramName (getCurrentProgram(), prog
->prgName
);
1974 for (int i
= 0; i
< vst_swap (prog
->numParams
); ++i
)
1975 setParameter (i
, vst_swapFloat (prog
->params
[i
]));
1977 else if (vst_swap (set
->fxMagic
) == 'FBCh' || vst_swap (set
->fxMagic
) == 'hCBF')
1980 const fxChunkSet
* const cset
= (const fxChunkSet
*) data
;
1982 if (vst_swap (cset
->chunkSize
) + sizeof (fxChunkSet
) - 8 > (unsigned int) dataSize
)
1985 setChunkData (cset
->chunk
, vst_swap (cset
->chunkSize
), false);
1987 else if (vst_swap (set
->fxMagic
) == 'FPCh' || vst_swap (set
->fxMagic
) == 'hCPF')
1990 const fxProgramSet
* const cset
= (const fxProgramSet
*) data
;
1992 if (vst_swap (cset
->chunkSize
) + sizeof (fxProgramSet
) - 8 > (unsigned int) dataSize
)
1995 setChunkData (cset
->chunk
, vst_swap (cset
->chunkSize
), true);
1997 changeProgramName (getCurrentProgram(), cset
->name
);
2007 //==============================================================================
2008 void VSTPluginInstance::setParamsInProgramBlock (fxProgram
* const prog
)
2010 const int numParams
= getNumParameters();
2012 prog
->chunkMagic
= vst_swap ('CcnK');
2014 prog
->fxMagic
= vst_swap ('FxCk');
2015 prog
->version
= vst_swap (fxbVersionNum
);
2016 prog
->fxID
= vst_swap (getUID());
2017 prog
->fxVersion
= vst_swap (getVersionNumber());
2018 prog
->numParams
= vst_swap (numParams
);
2020 getCurrentProgramName().copyToUTF8 (prog
->prgName
, sizeof (prog
->prgName
) - 1);
2022 for (int i
= 0; i
< numParams
; ++i
)
2023 prog
->params
[i
] = vst_swapFloat (getParameter (i
));
2026 bool VSTPluginInstance::saveToFXBFile (MemoryBlock
& dest
, bool isFXB
, int maxSizeMB
)
2028 const int numPrograms
= getNumPrograms();
2029 const int numParams
= getNumParameters();
2036 getChunkData (chunk
, false, maxSizeMB
);
2038 const size_t totalLen
= sizeof (fxChunkSet
) + chunk
.getSize() - 8;
2039 dest
.setSize (totalLen
, true);
2041 fxChunkSet
* const set
= (fxChunkSet
*) dest
.getData();
2042 set
->chunkMagic
= vst_swap ('CcnK');
2044 set
->fxMagic
= vst_swap ('FBCh');
2045 set
->version
= vst_swap (fxbVersionNum
);
2046 set
->fxID
= vst_swap (getUID());
2047 set
->fxVersion
= vst_swap (getVersionNumber());
2048 set
->numPrograms
= vst_swap (numPrograms
);
2049 set
->chunkSize
= vst_swap ((long) chunk
.getSize());
2051 chunk
.copyTo (set
->chunk
, 0, chunk
.getSize());
2056 getChunkData (chunk
, true, maxSizeMB
);
2058 const size_t totalLen
= sizeof (fxProgramSet
) + chunk
.getSize() - 8;
2059 dest
.setSize (totalLen
, true);
2061 fxProgramSet
* const set
= (fxProgramSet
*) dest
.getData();
2062 set
->chunkMagic
= vst_swap ('CcnK');
2064 set
->fxMagic
= vst_swap ('FPCh');
2065 set
->version
= vst_swap (fxbVersionNum
);
2066 set
->fxID
= vst_swap (getUID());
2067 set
->fxVersion
= vst_swap (getVersionNumber());
2068 set
->numPrograms
= vst_swap (numPrograms
);
2069 set
->chunkSize
= vst_swap ((long) chunk
.getSize());
2071 getCurrentProgramName().copyToUTF8 (set
->name
, sizeof (set
->name
) - 1);
2072 chunk
.copyTo (set
->chunk
, 0, chunk
.getSize());
2079 const int progLen
= sizeof (fxProgram
) + (numParams
- 1) * sizeof (float);
2080 const int len
= (sizeof (fxSet
) - sizeof (fxProgram
)) + progLen
* jmax (1, numPrograms
);
2081 dest
.setSize (len
, true);
2083 fxSet
* const set
= (fxSet
*) dest
.getData();
2084 set
->chunkMagic
= vst_swap ('CcnK');
2086 set
->fxMagic
= vst_swap ('FxBk');
2087 set
->version
= vst_swap (fxbVersionNum
);
2088 set
->fxID
= vst_swap (getUID());
2089 set
->fxVersion
= vst_swap (getVersionNumber());
2090 set
->numPrograms
= vst_swap (numPrograms
);
2092 const int oldProgram
= getCurrentProgram();
2093 MemoryBlock oldSettings
;
2094 createTempParameterStore (oldSettings
);
2096 setParamsInProgramBlock ((fxProgram
*) (((char*) (set
->programs
)) + oldProgram
* progLen
));
2098 for (int i
= 0; i
< numPrograms
; ++i
)
2100 if (i
!= oldProgram
)
2102 setCurrentProgram (i
);
2103 setParamsInProgramBlock ((fxProgram
*) (((char*) (set
->programs
)) + i
* progLen
));
2107 setCurrentProgram (oldProgram
);
2108 restoreFromTempParameterStore (oldSettings
);
2112 const int totalLen
= sizeof (fxProgram
) + (numParams
- 1) * sizeof (float);
2113 dest
.setSize (totalLen
, true);
2115 setParamsInProgramBlock ((fxProgram
*) dest
.getData());
2122 void VSTPluginInstance::getChunkData (MemoryBlock
& mb
, bool isPreset
, int maxSizeMB
) const
2126 void* data
= nullptr;
2127 const int bytes
= dispatch (effGetChunk
, isPreset
? 1 : 0, 0, &data
, 0.0f
);
2129 if (data
!= nullptr && bytes
<= maxSizeMB
* 1024 * 1024)
2132 mb
.copyFrom (data
, 0, bytes
);
2137 void VSTPluginInstance::setChunkData (const char* data
, int size
, bool isPreset
)
2139 if (size
> 0 && usesChunks())
2141 dispatch (effSetChunk
, isPreset
? 1 : 0, size
, (void*) data
, 0.0f
);
2144 updateStoredProgramNames();
2148 //==============================================================================
2149 void VSTPluginInstance::timerCallback()
2151 if (dispatch (effIdle
, 0, 0, 0, 0) == 0)
2155 int VSTPluginInstance::dispatch (const int opcode
, const int index
, const int value
, void* const ptr
, float opt
) const
2159 if (effect
!= nullptr)
2161 const ScopedLock
sl (lock
);
2162 const IdleCallRecursionPreventer icrp
;
2167 if (module
->resFileId
!= 0)
2168 UseResFile (module
->resFileId
);
2171 result
= effect
->dispatcher (effect
, opcode
, index
, value
, ptr
, opt
);
2174 module
->resFileId
= CurResFile();
2184 //==============================================================================
2187 static const int defaultVSTSampleRateValue
= 16384;
2188 static const int defaultVSTBlockSizeValue
= 512;
2190 // handles non plugin-specific callbacks..
2191 VstIntPtr
handleGeneralCallback (VstInt32 opcode
, VstInt32 index
, VstInt32 value
, void *ptr
, float opt
)
2199 case audioMasterCanDo
:
2201 static const char* canDos
[] = { "supplyIdle",
2206 "receiveVstMidiEvent",
2210 for (int i
= 0; i
< numElementsInArray (canDos
); ++i
)
2211 if (strcmp (canDos
[i
], (const char*) ptr
) == 0)
2217 case audioMasterVersion
: return 0x2400;
2218 case audioMasterCurrentId
: return shellUIDToCreate
;
2219 case audioMasterGetNumAutomatableParameters
: return 0;
2220 case audioMasterGetAutomationState
: return 1;
2221 case audioMasterGetVendorVersion
: return 0x0101;
2223 case audioMasterGetVendorString
:
2224 case audioMasterGetProductString
:
2226 String
hostName ("Juce VST Host");
2228 if (JUCEApplication::getInstance() != nullptr)
2229 hostName
= JUCEApplication::getInstance()->getApplicationName();
2231 hostName
.copyToUTF8 ((char*) ptr
, jmin (kVstMaxVendorStrLen
, kVstMaxProductStrLen
) - 1);
2235 case audioMasterGetSampleRate
: return (VstIntPtr
) defaultVSTSampleRateValue
;
2236 case audioMasterGetBlockSize
: return (VstIntPtr
) defaultVSTBlockSizeValue
;
2237 case audioMasterSetOutputSampleRate
: return 0;
2240 DBG ("*** Unhandled VST Callback: " + String ((int) opcode
));
2248 // handles callbacks for a specific plugin
2249 VstIntPtr
VSTPluginInstance::handleCallback (VstInt32 opcode
, VstInt32 index
, VstInt32 value
, void *ptr
, float opt
)
2253 case audioMasterAutomate
:
2254 sendParamChangeMessageToListeners (index
, opt
);
2257 case audioMasterProcessEvents
:
2258 handleMidiFromPlugin ((const VstEvents
*) ptr
);
2261 case audioMasterGetTime
:
2263 #pragma warning (push)
2264 #pragma warning (disable: 4311)
2267 return (VstIntPtr
) &vstHostTime
;
2270 #pragma warning (pop)
2274 case audioMasterIdle
:
2275 if (insideVSTCallback
== 0 && MessageManager::getInstance()->isThisTheMessageThread())
2277 const IdleCallRecursionPreventer icrp
;
2280 if (getActiveEditor() != nullptr)
2281 dispatch (effEditIdle
, 0, 0, 0, 0);
2284 juce_callAnyTimersSynchronously();
2286 handleUpdateNowIfNeeded();
2288 for (int i
= ComponentPeer::getNumPeers(); --i
>= 0;)
2289 ComponentPeer::getPeer (i
)->performAnyPendingRepaintsNow();
2293 case audioMasterUpdateDisplay
:
2294 triggerAsyncUpdate();
2297 case audioMasterTempoAt
:
2298 // returns (10000 * bpm)
2301 case audioMasterNeedIdle
:
2305 case audioMasterSizeWindow
:
2306 if (getActiveEditor() != nullptr)
2307 getActiveEditor()->setSize (index
, value
);
2311 case audioMasterGetSampleRate
:
2312 return (VstIntPtr
) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue
);
2314 case audioMasterGetBlockSize
:
2315 return (VstIntPtr
) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue
);
2317 case audioMasterWantMidi
:
2318 wantsMidiMessages
= true;
2321 case audioMasterGetDirectory
:
2323 return (VstIntPtr
) (void*) &module
->parentDirFSSpec
;
2325 return (VstIntPtr
) (pointer_sized_uint
) module
->fullParentDirectoryPathName
.toUTF8().getAddress();
2328 case audioMasterGetAutomationState
:
2329 // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write
2332 // none of these are handled (yet)..
2333 case audioMasterBeginEdit
:
2334 case audioMasterEndEdit
:
2335 case audioMasterSetTime
:
2336 case audioMasterPinConnected
:
2337 case audioMasterGetParameterQuantization
:
2338 case audioMasterIOChanged
:
2339 case audioMasterGetInputLatency
:
2340 case audioMasterGetOutputLatency
:
2341 case audioMasterGetPreviousPlug
:
2342 case audioMasterGetNextPlug
:
2343 case audioMasterWillReplaceOrAccumulate
:
2344 case audioMasterGetCurrentProcessLevel
:
2345 case audioMasterOfflineStart
:
2346 case audioMasterOfflineRead
:
2347 case audioMasterOfflineWrite
:
2348 case audioMasterOfflineGetCurrentPass
:
2349 case audioMasterOfflineGetCurrentMetaPass
:
2350 case audioMasterVendorSpecific
:
2351 case audioMasterSetIcon
:
2352 case audioMasterGetLanguage
:
2353 case audioMasterOpenWindow
:
2354 case audioMasterCloseWindow
:
2358 return handleGeneralCallback (opcode
, index
, value
, ptr
, opt
);
2364 // entry point for all callbacks from the plugin
2365 static VstIntPtr VSTCALLBACK
audioMaster (AEffect
* effect
, VstInt32 opcode
, VstInt32 index
, VstIntPtr value
, void* ptr
, float opt
)
2369 if (effect
!= nullptr && effect
->resvd2
!= 0)
2371 return ((VSTPluginInstance
*)(effect
->resvd2
))
2372 ->handleCallback (opcode
, index
, value
, ptr
, opt
);
2375 return handleGeneralCallback (opcode
, index
, value
, ptr
, opt
);
2383 //==============================================================================
2384 const String
VSTPluginInstance::getVersion() const
2386 unsigned int v
= dispatch (effGetVendorVersion
, 0, 0, 0, 0);
2390 if (v
== 0 || v
== -1)
2391 v
= getVersionNumber();
2400 versionBits
[n
++] = (v
& 0xff);
2408 s
<< versionBits
[--n
];
2418 int VSTPluginInstance::getUID() const
2420 int uid
= effect
!= nullptr ? effect
->uniqueID
: 0;
2423 uid
= module
->file
.hashCode();
2428 const String
VSTPluginInstance::getCategory() const
2430 const char* result
= nullptr;
2432 switch (dispatch (effGetPlugCategory
, 0, 0, 0, 0))
2434 case kPlugCategEffect
: result
= "Effect"; break;
2435 case kPlugCategSynth
: result
= "Synth"; break;
2436 case kPlugCategAnalysis
: result
= "Anaylsis"; break;
2437 case kPlugCategMastering
: result
= "Mastering"; break;
2438 case kPlugCategSpacializer
: result
= "Spacial"; break;
2439 case kPlugCategRoomFx
: result
= "Reverb"; break;
2440 case kPlugSurroundFx
: result
= "Surround"; break;
2441 case kPlugCategRestoration
: result
= "Restoration"; break;
2442 case kPlugCategGenerator
: result
= "Tone generation"; break;
2449 //==============================================================================
2450 float VSTPluginInstance::getParameter (int index
)
2452 if (effect
!= nullptr && isPositiveAndBelow (index
, (int) effect
->numParams
))
2456 const ScopedLock
sl (lock
);
2457 return effect
->getParameter (effect
, index
);
2467 void VSTPluginInstance::setParameter (int index
, float newValue
)
2469 if (effect
!= nullptr && isPositiveAndBelow (index
, (int) effect
->numParams
))
2473 const ScopedLock
sl (lock
);
2475 if (effect
->getParameter (effect
, index
) != newValue
)
2476 effect
->setParameter (effect
, index
, newValue
);
2484 const String
VSTPluginInstance::getParameterName (int index
)
2486 if (effect
!= nullptr)
2488 jassert (index
>= 0 && index
< effect
->numParams
);
2490 char nm
[256] = { 0 };
2491 dispatch (effGetParamName
, index
, 0, nm
, 0);
2492 return String (nm
).trim();
2495 return String::empty
;
2498 const String
VSTPluginInstance::getParameterLabel (int index
) const
2500 if (effect
!= nullptr)
2502 jassert (index
>= 0 && index
< effect
->numParams
);
2504 char nm
[256] = { 0 };
2505 dispatch (effGetParamLabel
, index
, 0, nm
, 0);
2506 return String (nm
).trim();
2509 return String::empty
;
2512 const String
VSTPluginInstance::getParameterText (int index
)
2514 if (effect
!= nullptr)
2516 jassert (index
>= 0 && index
< effect
->numParams
);
2518 char nm
[256] = { 0 };
2519 dispatch (effGetParamDisplay
, index
, 0, nm
, 0);
2520 return String (nm
).trim();
2523 return String::empty
;
2526 bool VSTPluginInstance::isParameterAutomatable (int index
) const
2528 if (effect
!= nullptr)
2530 jassert (index
>= 0 && index
< effect
->numParams
);
2531 return dispatch (effCanBeAutomated
, index
, 0, 0, 0) != 0;
2537 void VSTPluginInstance::createTempParameterStore (MemoryBlock
& dest
)
2539 dest
.setSize (64 + 4 * getNumParameters());
2542 getCurrentProgramName().copyToUTF8 ((char*) dest
.getData(), 63);
2544 float* const p
= (float*) (((char*) dest
.getData()) + 64);
2545 for (int i
= 0; i
< getNumParameters(); ++i
)
2546 p
[i
] = getParameter(i
);
2549 void VSTPluginInstance::restoreFromTempParameterStore (const MemoryBlock
& m
)
2551 changeProgramName (getCurrentProgram(), (const char*) m
.getData());
2553 float* p
= (float*) (((char*) m
.getData()) + 64);
2554 for (int i
= 0; i
< getNumParameters(); ++i
)
2555 setParameter (i
, p
[i
]);
2558 //==============================================================================
2559 void VSTPluginInstance::setCurrentProgram (int newIndex
)
2561 if (getNumPrograms() > 0 && newIndex
!= getCurrentProgram())
2562 dispatch (effSetProgram
, 0, jlimit (0, getNumPrograms() - 1, newIndex
), 0, 0);
2565 const String
VSTPluginInstance::getProgramName (int index
)
2567 if (index
== getCurrentProgram())
2569 return getCurrentProgramName();
2571 else if (effect
!= nullptr)
2573 char nm
[256] = { 0 };
2575 if (dispatch (effGetProgramNameIndexed
,
2576 jlimit (0, getNumPrograms(), index
),
2579 return String (nm
).trim();
2583 return programNames
[index
];
2586 void VSTPluginInstance::changeProgramName (int index
, const String
& newName
)
2588 if (index
== getCurrentProgram())
2590 if (getNumPrograms() > 0 && newName
!= getCurrentProgramName())
2591 dispatch (effSetProgramName
, 0, 0, (void*) newName
.substring (0, 24).toUTF8().getAddress(), 0.0f
);
2595 jassertfalse
; // xxx not implemented!
2599 void VSTPluginInstance::updateStoredProgramNames()
2601 if (effect
!= nullptr && getNumPrograms() > 0)
2603 char nm
[256] = { 0 };
2605 // only do this if the plugin can't use indexed names..
2606 if (dispatch (effGetProgramNameIndexed
, 0, -1, nm
, 0) == 0)
2608 const int oldProgram
= getCurrentProgram();
2609 MemoryBlock oldSettings
;
2610 createTempParameterStore (oldSettings
);
2612 for (int i
= 0; i
< getNumPrograms(); ++i
)
2614 setCurrentProgram (i
);
2615 getCurrentProgramName(); // (this updates the list)
2618 setCurrentProgram (oldProgram
);
2619 restoreFromTempParameterStore (oldSettings
);
2624 const String
VSTPluginInstance::getCurrentProgramName()
2626 if (effect
!= nullptr)
2628 char nm
[256] = { 0 };
2629 dispatch (effGetProgramName
, 0, 0, nm
, 0);
2631 const int index
= getCurrentProgram();
2632 if (programNames
[index
].isEmpty())
2634 while (programNames
.size() < index
)
2635 programNames
.add (String::empty
);
2637 programNames
.set (index
, String (nm
).trim());
2640 return String (nm
).trim();
2643 return String::empty
;
2646 //==============================================================================
2647 const String
VSTPluginInstance::getInputChannelName (int index
) const
2649 if (index
>= 0 && index
< getNumInputChannels())
2651 VstPinProperties pinProps
;
2652 if (dispatch (effGetInputProperties
, index
, 0, &pinProps
, 0.0f
) != 0)
2653 return String (pinProps
.label
, sizeof (pinProps
.label
));
2656 return String::empty
;
2659 bool VSTPluginInstance::isInputChannelStereoPair (int index
) const
2661 if (index
< 0 || index
>= getNumInputChannels())
2664 VstPinProperties pinProps
;
2665 if (dispatch (effGetInputProperties
, index
, 0, &pinProps
, 0.0f
) != 0)
2666 return (pinProps
.flags
& kVstPinIsStereo
) != 0;
2671 const String
VSTPluginInstance::getOutputChannelName (int index
) const
2673 if (index
>= 0 && index
< getNumOutputChannels())
2675 VstPinProperties pinProps
;
2676 if (dispatch (effGetOutputProperties
, index
, 0, &pinProps
, 0.0f
) != 0)
2677 return String (pinProps
.label
, sizeof (pinProps
.label
));
2680 return String::empty
;
2683 bool VSTPluginInstance::isOutputChannelStereoPair (int index
) const
2685 if (index
< 0 || index
>= getNumOutputChannels())
2688 VstPinProperties pinProps
;
2689 if (dispatch (effGetOutputProperties
, index
, 0, &pinProps
, 0.0f
) != 0)
2690 return (pinProps
.flags
& kVstPinIsStereo
) != 0;
2695 //==============================================================================
2696 void VSTPluginInstance::setPower (const bool on
)
2698 dispatch (effMainsChanged
, 0, on
? 1 : 0, 0, 0);
2702 //==============================================================================
2703 const int defaultMaxSizeMB
= 64;
2705 void VSTPluginInstance::getStateInformation (MemoryBlock
& destData
)
2707 saveToFXBFile (destData
, true, defaultMaxSizeMB
);
2710 void VSTPluginInstance::getCurrentProgramStateInformation (MemoryBlock
& destData
)
2712 saveToFXBFile (destData
, false, defaultMaxSizeMB
);
2715 void VSTPluginInstance::setStateInformation (const void* data
, int sizeInBytes
)
2717 loadFromFXBFile (data
, sizeInBytes
);
2720 void VSTPluginInstance::setCurrentProgramStateInformation (const void* data
, int sizeInBytes
)
2722 loadFromFXBFile (data
, sizeInBytes
);
2725 //==============================================================================
2726 //==============================================================================
2727 VSTPluginFormat::VSTPluginFormat()
2731 VSTPluginFormat::~VSTPluginFormat()
2735 void VSTPluginFormat::findAllTypesForFile (OwnedArray
<PluginDescription
>& results
,
2736 const String
& fileOrIdentifier
)
2738 if (! fileMightContainThisPluginType (fileOrIdentifier
))
2741 PluginDescription desc
;
2742 desc
.fileOrIdentifier
= fileOrIdentifier
;
2745 ScopedPointer
<VSTPluginInstance
> instance (dynamic_cast <VSTPluginInstance
*> (createInstanceFromDescription (desc
)));
2753 if (instance
->module
->resFileId
!= 0)
2754 UseResFile (instance
->module
->resFileId
);
2757 instance
->fillInPluginDescription (desc
);
2759 VstPlugCategory category
= (VstPlugCategory
) instance
->dispatch (effGetPlugCategory
, 0, 0, 0, 0);
2761 if (category
!= kPlugCategShell
)
2764 results
.add (new PluginDescription (desc
));
2766 instance
->dispatch (effOpen
, 0, 0, 0, 0);
2770 // It's a shell plugin, so iterate all the subtypes...
2773 char shellEffectName
[64] = { 0 };
2774 const int uid
= instance
->dispatch (effShellGetNextPlugin
, 0, 0, shellEffectName
, 0);
2783 desc
.name
= shellEffectName
;
2784 desc
.descriptiveName
= shellEffectName
;
2786 bool alreadyThere
= false;
2788 for (int i
= results
.size(); --i
>= 0;)
2790 PluginDescription
* const d
= results
.getUnchecked(i
);
2792 if (d
->isDuplicateOf (desc
))
2794 alreadyThere
= true;
2800 results
.add (new PluginDescription (desc
));
2807 // crashed while loading...
2811 AudioPluginInstance
* VSTPluginFormat::createInstanceFromDescription (const PluginDescription
& desc
)
2813 ScopedPointer
<VSTPluginInstance
> result
;
2815 if (fileMightContainThisPluginType (desc
.fileOrIdentifier
))
2817 File
file (desc
.fileOrIdentifier
);
2819 const File
previousWorkingDirectory (File::getCurrentWorkingDirectory());
2820 file
.getParentDirectory().setAsCurrentWorkingDirectory();
2822 const ReferenceCountedObjectPtr
<ModuleHandle
> module (ModuleHandle::findOrCreateModule (file
));
2824 if (module
!= nullptr)
2826 shellUIDToCreate
= desc
.uid
;
2828 result
= new VSTPluginInstance (module
);
2830 if (result
->effect
!= nullptr)
2832 result
->effect
->resvd2
= (VstIntPtr
) (pointer_sized_int
) (VSTPluginInstance
*) result
;
2833 result
->initialise();
2841 previousWorkingDirectory
.setAsCurrentWorkingDirectory();
2844 return result
.release();
2847 bool VSTPluginFormat::fileMightContainThisPluginType (const String
& fileOrIdentifier
)
2849 const File
f (fileOrIdentifier
);
2852 if (f
.isDirectory() && f
.hasFileExtension (".vst"))
2857 if (PlatformUtilities::makeFSRefFromPath (&fileRef
, f
.getFullPathName()))
2859 const short resFileId
= FSOpenResFile (&fileRef
, fsRdPerm
);
2861 if (resFileId
!= -1)
2863 const int numEffects
= Count1Resources ('aEff');
2864 CloseResFile (resFileId
);
2874 return f
.existsAsFile() && f
.hasFileExtension (".dll");
2876 return f
.existsAsFile() && f
.hasFileExtension (".so");
2880 String
VSTPluginFormat::getNameOfPluginFromIdentifier (const String
& fileOrIdentifier
)
2882 return fileOrIdentifier
;
2885 bool VSTPluginFormat::doesPluginStillExist (const PluginDescription
& desc
)
2887 return File (desc
.fileOrIdentifier
).exists();
2890 StringArray
VSTPluginFormat::searchPathsForPlugins (const FileSearchPath
& directoriesToSearch
, const bool recursive
)
2892 StringArray results
;
2894 for (int j
= 0; j
< directoriesToSearch
.getNumPaths(); ++j
)
2895 recursiveFileSearch (results
, directoriesToSearch
[j
], recursive
);
2900 void VSTPluginFormat::recursiveFileSearch (StringArray
& results
, const File
& dir
, const bool recursive
)
2902 // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside
2903 // .component or .vst directories.
2904 DirectoryIterator
iter (dir
, false, "*", File::findFilesAndDirectories
);
2908 const File
f (iter
.getFile());
2909 bool isPlugin
= false;
2911 if (fileMightContainThisPluginType (f
.getFullPathName()))
2914 results
.add (f
.getFullPathName());
2917 if (recursive
&& (! isPlugin
) && f
.isDirectory())
2918 recursiveFileSearch (results
, f
, true);
2922 FileSearchPath
VSTPluginFormat::getDefaultLocationsToSearch()
2925 return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST");
2927 const String
programFiles (File::getSpecialLocation (File::globalApplicationsDirectory
).getFullPathName());
2929 return FileSearchPath (programFiles
+ "\\Steinberg\\VstPlugins");
2931 return FileSearchPath ("/usr/lib/vst");