The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2953 lines
87KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../../../core/juce_TargetPlatform.h"
  19. #include "../../../../juce_Config.h"
  20. #if JUCE_PLUGINHOST_VST && (JUCE_MAC_VST_INCLUDED || ! JUCE_MAC)
  21. #if JUCE_WINDOWS
  22. #undef _WIN32_WINNT
  23. #define _WIN32_WINNT 0x500
  24. #undef STRICT
  25. #define STRICT
  26. #include <windows.h>
  27. #include <float.h>
  28. #pragma warning (disable : 4312 4355)
  29. #elif JUCE_LINUX
  30. #include <float.h>
  31. #include <sys/time.h>
  32. #include <X11/Xlib.h>
  33. #include <X11/Xutil.h>
  34. #include <X11/Xatom.h>
  35. #undef Font
  36. #undef KeyPress
  37. #undef Drawable
  38. #undef Time
  39. #else
  40. #include <Cocoa/Cocoa.h>
  41. #include <Carbon/Carbon.h>
  42. #endif
  43. //==============================================================================
  44. #include "../../../core/juce_StandardHeader.h"
  45. #if ! (JUCE_MAC && JUCE_64BIT)
  46. BEGIN_JUCE_NAMESPACE
  47. #include "juce_VSTPluginFormat.h"
  48. #include "../../../threads/juce_Process.h"
  49. #include "../../../threads/juce_ScopedLock.h"
  50. #include "../../../core/juce_Random.h"
  51. #include "../../../io/files/juce_DirectoryIterator.h"
  52. #include "../../../events/juce_Timer.h"
  53. #include "../../../events/juce_AsyncUpdater.h"
  54. #include "../../../events/juce_MessageManager.h"
  55. #include "../../../gui/components/layout/juce_ComponentMovementWatcher.h"
  56. #include "../../../gui/components/windows/juce_ComponentPeer.h"
  57. #include "../../../application/juce_Application.h"
  58. #include "../../../core/juce_PlatformUtilities.h"
  59. #if JUCE_MAC && JUCE_SUPPORT_CARBON
  60. #include "../../../native/mac/juce_mac_CarbonViewWrapperComponent.h"
  61. #endif
  62. //==============================================================================
  63. #undef PRAGMA_ALIGN_SUPPORTED
  64. #define VST_FORCE_DEPRECATED 0
  65. #if JUCE_MSVC
  66. #pragma warning (push)
  67. #pragma warning (disable: 4996)
  68. #endif
  69. /* Obviously you're going to need the Steinberg vstsdk2.4 folder in
  70. your include path if you want to add VST support.
  71. If you're not interested in VSTs, you can disable them by changing the
  72. JUCE_PLUGINHOST_VST flag in juce_Config.h
  73. */
  74. #include "pluginterfaces/vst2.x/aeffectx.h"
  75. #if JUCE_MSVC
  76. #pragma warning (pop)
  77. #endif
  78. //==============================================================================
  79. #if JUCE_LINUX
  80. #define Font JUCE_NAMESPACE::Font
  81. #define KeyPress JUCE_NAMESPACE::KeyPress
  82. #define Drawable JUCE_NAMESPACE::Drawable
  83. #define Time JUCE_NAMESPACE::Time
  84. #endif
  85. #include "../juce_PluginDescription.h"
  86. #include "juce_VSTMidiEventList.h"
  87. #if ! JUCE_WINDOWS
  88. static void _fpreset() {}
  89. static void _clearfp() {}
  90. #endif
  91. extern void juce_callAnyTimersSynchronously();
  92. //==============================================================================
  93. const int fxbVersionNum = 1;
  94. struct fxProgram
  95. {
  96. long chunkMagic; // 'CcnK'
  97. long byteSize; // of this chunk, excl. magic + byteSize
  98. long fxMagic; // 'FxCk'
  99. long version;
  100. long fxID; // fx unique id
  101. long fxVersion;
  102. long numParams;
  103. char prgName[28];
  104. float params[1]; // variable no. of parameters
  105. };
  106. struct fxSet
  107. {
  108. long chunkMagic; // 'CcnK'
  109. long byteSize; // of this chunk, excl. magic + byteSize
  110. long fxMagic; // 'FxBk'
  111. long version;
  112. long fxID; // fx unique id
  113. long fxVersion;
  114. long numPrograms;
  115. char future[128];
  116. fxProgram programs[1]; // variable no. of programs
  117. };
  118. struct fxChunkSet
  119. {
  120. long chunkMagic; // 'CcnK'
  121. long byteSize; // of this chunk, excl. magic + byteSize
  122. long fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
  123. long version;
  124. long fxID; // fx unique id
  125. long fxVersion;
  126. long numPrograms;
  127. char future[128];
  128. long chunkSize;
  129. char chunk[8]; // variable
  130. };
  131. struct fxProgramSet
  132. {
  133. long chunkMagic; // 'CcnK'
  134. long byteSize; // of this chunk, excl. magic + byteSize
  135. long fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
  136. long version;
  137. long fxID; // fx unique id
  138. long fxVersion;
  139. long numPrograms;
  140. char name[28];
  141. long chunkSize;
  142. char chunk[8]; // variable
  143. };
  144. static long vst_swap (const long x) throw()
  145. {
  146. #ifdef JUCE_LITTLE_ENDIAN
  147. return (long) ByteOrder::swap ((uint32) x);
  148. #else
  149. return x;
  150. #endif
  151. }
  152. static float vst_swapFloat (const float x) throw()
  153. {
  154. #ifdef JUCE_LITTLE_ENDIAN
  155. union { uint32 asInt; float asFloat; } n;
  156. n.asFloat = x;
  157. n.asInt = ByteOrder::swap (n.asInt);
  158. return n.asFloat;
  159. #else
  160. return x;
  161. #endif
  162. }
  163. static double getVSTHostTimeNanoseconds()
  164. {
  165. #if JUCE_WINDOWS
  166. return timeGetTime() * 1000000.0;
  167. #elif JUCE_LINUX
  168. timeval micro;
  169. gettimeofday (&micro, 0);
  170. return micro.tv_usec * 1000.0;
  171. #elif JUCE_MAC
  172. UnsignedWide micro;
  173. Microseconds (&micro);
  174. return micro.lo * 1000.0;
  175. #endif
  176. }
  177. //==============================================================================
  178. typedef AEffect* (*MainCall) (audioMasterCallback);
  179. static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);
  180. static int shellUIDToCreate = 0;
  181. static int insideVSTCallback = 0;
  182. class VSTPluginWindow;
  183. //==============================================================================
  184. // Change this to disable logging of various VST activities
  185. #ifndef VST_LOGGING
  186. #define VST_LOGGING 1
  187. #endif
  188. #if VST_LOGGING
  189. #define log(a) Logger::writeToLog(a);
  190. #else
  191. #define log(a)
  192. #endif
  193. //==============================================================================
  194. #if JUCE_MAC && JUCE_PPC
  195. static void* NewCFMFromMachO (void* const machofp) throw()
  196. {
  197. void* result = juce_malloc (8);
  198. ((void**) result)[0] = machofp;
  199. ((void**) result)[1] = result;
  200. return result;
  201. }
  202. #endif
  203. //==============================================================================
  204. #if JUCE_LINUX
  205. extern Display* display;
  206. extern XContext windowHandleXContext;
  207. typedef void (*EventProcPtr) (XEvent* ev);
  208. static bool xErrorTriggered;
  209. static int temporaryErrorHandler (Display*, XErrorEvent*)
  210. {
  211. xErrorTriggered = true;
  212. return 0;
  213. }
  214. static int getPropertyFromXWindow (Window handle, Atom atom)
  215. {
  216. XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler);
  217. xErrorTriggered = false;
  218. int userSize;
  219. unsigned long bytes, userCount;
  220. unsigned char* data;
  221. Atom userType;
  222. XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType,
  223. &userType, &userSize, &userCount, &bytes, &data);
  224. XSetErrorHandler (oldErrorHandler);
  225. return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast<int*> (data)
  226. : 0;
  227. }
  228. static Window getChildWindow (Window windowToCheck)
  229. {
  230. Window rootWindow, parentWindow;
  231. Window* childWindows;
  232. unsigned int numChildren;
  233. XQueryTree (display,
  234. windowToCheck,
  235. &rootWindow,
  236. &parentWindow,
  237. &childWindows,
  238. &numChildren);
  239. if (numChildren > 0)
  240. return childWindows [0];
  241. return 0;
  242. }
  243. static void translateJuceToXButtonModifiers (const MouseEvent& e, XEvent& ev) throw()
  244. {
  245. if (e.mods.isLeftButtonDown())
  246. {
  247. ev.xbutton.button = Button1;
  248. ev.xbutton.state |= Button1Mask;
  249. }
  250. else if (e.mods.isRightButtonDown())
  251. {
  252. ev.xbutton.button = Button3;
  253. ev.xbutton.state |= Button3Mask;
  254. }
  255. else if (e.mods.isMiddleButtonDown())
  256. {
  257. ev.xbutton.button = Button2;
  258. ev.xbutton.state |= Button2Mask;
  259. }
  260. }
  261. static void translateJuceToXMotionModifiers (const MouseEvent& e, XEvent& ev) throw()
  262. {
  263. if (e.mods.isLeftButtonDown()) ev.xmotion.state |= Button1Mask;
  264. else if (e.mods.isRightButtonDown()) ev.xmotion.state |= Button3Mask;
  265. else if (e.mods.isMiddleButtonDown()) ev.xmotion.state |= Button2Mask;
  266. }
  267. static void translateJuceToXCrossingModifiers (const MouseEvent& e, XEvent& ev) throw()
  268. {
  269. if (e.mods.isLeftButtonDown()) ev.xcrossing.state |= Button1Mask;
  270. else if (e.mods.isRightButtonDown()) ev.xcrossing.state |= Button3Mask;
  271. else if (e.mods.isMiddleButtonDown()) ev.xcrossing.state |= Button2Mask;
  272. }
  273. static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) throw()
  274. {
  275. if (increment < 0)
  276. {
  277. ev.xbutton.button = Button5;
  278. ev.xbutton.state |= Button5Mask;
  279. }
  280. else if (increment > 0)
  281. {
  282. ev.xbutton.button = Button4;
  283. ev.xbutton.state |= Button4Mask;
  284. }
  285. }
  286. #endif
  287. //==============================================================================
  288. class ModuleHandle : public ReferenceCountedObject
  289. {
  290. public:
  291. //==============================================================================
  292. File file;
  293. MainCall moduleMain;
  294. String pluginName;
  295. static Array <ModuleHandle*>& getActiveModules()
  296. {
  297. static Array <ModuleHandle*> activeModules;
  298. return activeModules;
  299. }
  300. //==============================================================================
  301. static ModuleHandle* findOrCreateModule (const File& file)
  302. {
  303. for (int i = getActiveModules().size(); --i >= 0;)
  304. {
  305. ModuleHandle* const module = getActiveModules().getUnchecked(i);
  306. if (module->file == file)
  307. return module;
  308. }
  309. _fpreset(); // (doesn't do any harm)
  310. ++insideVSTCallback;
  311. shellUIDToCreate = 0;
  312. log ("Attempting to load VST: " + file.getFullPathName());
  313. ScopedPointer <ModuleHandle> m (new ModuleHandle (file));
  314. if (! m->open())
  315. m = 0;
  316. --insideVSTCallback;
  317. _fpreset(); // (doesn't do any harm)
  318. return m.release();
  319. }
  320. //==============================================================================
  321. ModuleHandle (const File& file_)
  322. : file (file_),
  323. moduleMain (0),
  324. #if JUCE_WINDOWS || JUCE_LINUX
  325. hModule (0)
  326. #elif JUCE_MAC
  327. fragId (0),
  328. resHandle (0),
  329. bundleRef (0),
  330. resFileId (0)
  331. #endif
  332. {
  333. getActiveModules().add (this);
  334. #if JUCE_WINDOWS || JUCE_LINUX
  335. fullParentDirectoryPathName = file_.getParentDirectory().getFullPathName();
  336. #elif JUCE_MAC
  337. FSRef ref;
  338. PlatformUtilities::makeFSRefFromPath (&ref, file_.getParentDirectory().getFullPathName());
  339. FSGetCatalogInfo (&ref, kFSCatInfoNone, 0, 0, &parentDirFSSpec, 0);
  340. #endif
  341. }
  342. ~ModuleHandle()
  343. {
  344. getActiveModules().removeValue (this);
  345. close();
  346. }
  347. //==============================================================================
  348. juce_UseDebuggingNewOperator
  349. //==============================================================================
  350. #if JUCE_WINDOWS || JUCE_LINUX
  351. void* hModule;
  352. String fullParentDirectoryPathName;
  353. bool open()
  354. {
  355. #if JUCE_WINDOWS
  356. static bool timePeriodSet = false;
  357. if (! timePeriodSet)
  358. {
  359. timePeriodSet = true;
  360. timeBeginPeriod (2);
  361. }
  362. #endif
  363. pluginName = file.getFileNameWithoutExtension();
  364. hModule = PlatformUtilities::loadDynamicLibrary (file.getFullPathName());
  365. moduleMain = (MainCall) PlatformUtilities::getProcedureEntryPoint (hModule, "VSTPluginMain");
  366. if (moduleMain == 0)
  367. moduleMain = (MainCall) PlatformUtilities::getProcedureEntryPoint (hModule, "main");
  368. return moduleMain != 0;
  369. }
  370. void close()
  371. {
  372. _fpreset(); // (doesn't do any harm)
  373. PlatformUtilities::freeDynamicLibrary (hModule);
  374. }
  375. void closeEffect (AEffect* eff)
  376. {
  377. eff->dispatcher (eff, effClose, 0, 0, 0, 0);
  378. }
  379. #else
  380. CFragConnectionID fragId;
  381. Handle resHandle;
  382. CFBundleRef bundleRef;
  383. FSSpec parentDirFSSpec;
  384. short resFileId;
  385. bool open()
  386. {
  387. bool ok = false;
  388. const String filename (file.getFullPathName());
  389. if (file.hasFileExtension (".vst"))
  390. {
  391. const char* const utf8 = filename.toUTF8();
  392. CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8,
  393. strlen (utf8), file.isDirectory());
  394. if (url != 0)
  395. {
  396. bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
  397. CFRelease (url);
  398. if (bundleRef != 0)
  399. {
  400. if (CFBundleLoadExecutable (bundleRef))
  401. {
  402. moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho"));
  403. if (moduleMain == 0)
  404. moduleMain = (MainCall) CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain"));
  405. if (moduleMain != 0)
  406. {
  407. CFTypeRef name = CFBundleGetValueForInfoDictionaryKey (bundleRef, CFSTR("CFBundleName"));
  408. if (name != 0)
  409. {
  410. if (CFGetTypeID (name) == CFStringGetTypeID())
  411. {
  412. char buffer[1024];
  413. if (CFStringGetCString ((CFStringRef) name, buffer, sizeof (buffer), CFStringGetSystemEncoding()))
  414. pluginName = buffer;
  415. }
  416. }
  417. if (pluginName.isEmpty())
  418. pluginName = file.getFileNameWithoutExtension();
  419. resFileId = CFBundleOpenBundleResourceMap (bundleRef);
  420. ok = true;
  421. }
  422. }
  423. if (! ok)
  424. {
  425. CFBundleUnloadExecutable (bundleRef);
  426. CFRelease (bundleRef);
  427. bundleRef = 0;
  428. }
  429. }
  430. }
  431. }
  432. #if JUCE_PPC
  433. else
  434. {
  435. FSRef fn;
  436. if (FSPathMakeRef ((UInt8*) filename.toUTF8(), &fn, 0) == noErr)
  437. {
  438. resFileId = FSOpenResFile (&fn, fsRdPerm);
  439. if (resFileId != -1)
  440. {
  441. const int numEffs = Count1Resources ('aEff');
  442. for (int i = 0; i < numEffs; ++i)
  443. {
  444. resHandle = Get1IndResource ('aEff', i + 1);
  445. if (resHandle != 0)
  446. {
  447. OSType type;
  448. Str255 name;
  449. SInt16 id;
  450. GetResInfo (resHandle, &id, &type, name);
  451. pluginName = String ((const char*) name + 1, name[0]);
  452. DetachResource (resHandle);
  453. HLock (resHandle);
  454. Ptr ptr;
  455. Str255 errorText;
  456. OSErr err = GetMemFragment (*resHandle, GetHandleSize (resHandle),
  457. name, kPrivateCFragCopy,
  458. &fragId, &ptr, errorText);
  459. if (err == noErr)
  460. {
  461. moduleMain = (MainCall) newMachOFromCFM (ptr);
  462. ok = true;
  463. }
  464. else
  465. {
  466. HUnlock (resHandle);
  467. }
  468. break;
  469. }
  470. }
  471. if (! ok)
  472. CloseResFile (resFileId);
  473. }
  474. }
  475. }
  476. #endif
  477. return ok;
  478. }
  479. void close()
  480. {
  481. #if JUCE_PPC
  482. if (fragId != 0)
  483. {
  484. if (moduleMain != 0)
  485. disposeMachOFromCFM ((void*) moduleMain);
  486. CloseConnection (&fragId);
  487. HUnlock (resHandle);
  488. if (resFileId != 0)
  489. CloseResFile (resFileId);
  490. }
  491. else
  492. #endif
  493. if (bundleRef != 0)
  494. {
  495. CFBundleCloseBundleResourceMap (bundleRef, resFileId);
  496. if (CFGetRetainCount (bundleRef) == 1)
  497. CFBundleUnloadExecutable (bundleRef);
  498. if (CFGetRetainCount (bundleRef) > 0)
  499. CFRelease (bundleRef);
  500. }
  501. }
  502. void closeEffect (AEffect* eff)
  503. {
  504. #if JUCE_PPC
  505. if (fragId != 0)
  506. {
  507. Array<void*> thingsToDelete;
  508. thingsToDelete.add ((void*) eff->dispatcher);
  509. thingsToDelete.add ((void*) eff->process);
  510. thingsToDelete.add ((void*) eff->setParameter);
  511. thingsToDelete.add ((void*) eff->getParameter);
  512. thingsToDelete.add ((void*) eff->processReplacing);
  513. eff->dispatcher (eff, effClose, 0, 0, 0, 0);
  514. for (int i = thingsToDelete.size(); --i >= 0;)
  515. disposeMachOFromCFM (thingsToDelete[i]);
  516. }
  517. else
  518. #endif
  519. {
  520. eff->dispatcher (eff, effClose, 0, 0, 0, 0);
  521. }
  522. }
  523. #if JUCE_PPC
  524. static void* newMachOFromCFM (void* cfmfp)
  525. {
  526. if (cfmfp == 0)
  527. return 0;
  528. UInt32* const mfp = new UInt32[6];
  529. mfp[0] = 0x3d800000 | ((UInt32) cfmfp >> 16);
  530. mfp[1] = 0x618c0000 | ((UInt32) cfmfp & 0xffff);
  531. mfp[2] = 0x800c0000;
  532. mfp[3] = 0x804c0004;
  533. mfp[4] = 0x7c0903a6;
  534. mfp[5] = 0x4e800420;
  535. MakeDataExecutable (mfp, sizeof (UInt32) * 6);
  536. return mfp;
  537. }
  538. static void disposeMachOFromCFM (void* ptr)
  539. {
  540. delete[] static_cast <UInt32*> (ptr);
  541. }
  542. void coerceAEffectFunctionCalls (AEffect* eff)
  543. {
  544. if (fragId != 0)
  545. {
  546. eff->dispatcher = (AEffectDispatcherProc) newMachOFromCFM ((void*) eff->dispatcher);
  547. eff->process = (AEffectProcessProc) newMachOFromCFM ((void*) eff->process);
  548. eff->setParameter = (AEffectSetParameterProc) newMachOFromCFM ((void*) eff->setParameter);
  549. eff->getParameter = (AEffectGetParameterProc) newMachOFromCFM ((void*) eff->getParameter);
  550. eff->processReplacing = (AEffectProcessProc) newMachOFromCFM ((void*) eff->processReplacing);
  551. }
  552. }
  553. #endif
  554. #endif
  555. };
  556. //==============================================================================
  557. /**
  558. An instance of a plugin, created by a VSTPluginFormat.
  559. */
  560. class VSTPluginInstance : public AudioPluginInstance,
  561. private Timer,
  562. private AsyncUpdater
  563. {
  564. public:
  565. //==============================================================================
  566. ~VSTPluginInstance();
  567. //==============================================================================
  568. // AudioPluginInstance methods:
  569. void fillInPluginDescription (PluginDescription& desc) const
  570. {
  571. desc.name = name;
  572. desc.fileOrIdentifier = module->file.getFullPathName();
  573. desc.uid = getUID();
  574. desc.lastFileModTime = module->file.getLastModificationTime();
  575. desc.pluginFormatName = "VST";
  576. desc.category = getCategory();
  577. {
  578. char buffer [kVstMaxVendorStrLen + 8];
  579. zerostruct (buffer);
  580. dispatch (effGetVendorString, 0, 0, buffer, 0);
  581. desc.manufacturerName = buffer;
  582. }
  583. desc.version = getVersion();
  584. desc.numInputChannels = getNumInputChannels();
  585. desc.numOutputChannels = getNumOutputChannels();
  586. desc.isInstrument = (effect != 0 && (effect->flags & effFlagsIsSynth) != 0);
  587. }
  588. const String getName() const { return name; }
  589. int getUID() const;
  590. bool acceptsMidi() const { return wantsMidiMessages; }
  591. bool producesMidi() const { return dispatch (effCanDo, 0, 0, (void*) "sendVstMidiEvent", 0) > 0; }
  592. //==============================================================================
  593. // AudioProcessor methods:
  594. void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock);
  595. void releaseResources();
  596. void processBlock (AudioSampleBuffer& buffer,
  597. MidiBuffer& midiMessages);
  598. AudioProcessorEditor* createEditor();
  599. const String getInputChannelName (int index) const;
  600. bool isInputChannelStereoPair (int index) const;
  601. const String getOutputChannelName (int index) const;
  602. bool isOutputChannelStereoPair (int index) const;
  603. //==============================================================================
  604. int getNumParameters() { return effect != 0 ? effect->numParams : 0; }
  605. float getParameter (int index);
  606. void setParameter (int index, float newValue);
  607. const String getParameterName (int index);
  608. const String getParameterText (int index);
  609. bool isParameterAutomatable (int index) const;
  610. //==============================================================================
  611. int getNumPrograms() { return effect != 0 ? effect->numPrograms : 0; }
  612. int getCurrentProgram() { return dispatch (effGetProgram, 0, 0, 0, 0); }
  613. void setCurrentProgram (int index);
  614. const String getProgramName (int index);
  615. void changeProgramName (int index, const String& newName);
  616. //==============================================================================
  617. void getStateInformation (MemoryBlock& destData);
  618. void getCurrentProgramStateInformation (MemoryBlock& destData);
  619. void setStateInformation (const void* data, int sizeInBytes);
  620. void setCurrentProgramStateInformation (const void* data, int sizeInBytes);
  621. //==============================================================================
  622. void timerCallback();
  623. void handleAsyncUpdate();
  624. VstIntPtr handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt);
  625. //==============================================================================
  626. juce_UseDebuggingNewOperator
  627. private:
  628. friend class VSTPluginWindow;
  629. friend class VSTPluginFormat;
  630. AEffect* effect;
  631. String name;
  632. CriticalSection lock;
  633. bool wantsMidiMessages, initialised, isPowerOn;
  634. mutable StringArray programNames;
  635. AudioSampleBuffer tempBuffer;
  636. CriticalSection midiInLock;
  637. MidiBuffer incomingMidi;
  638. VSTMidiEventList midiEventsToSend;
  639. VstTimeInfo vstHostTime;
  640. ReferenceCountedObjectPtr <ModuleHandle> module;
  641. //==============================================================================
  642. int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const;
  643. bool restoreProgramSettings (const fxProgram* const prog);
  644. const String getCurrentProgramName();
  645. void setParamsInProgramBlock (fxProgram* const prog);
  646. void updateStoredProgramNames();
  647. void initialise();
  648. void handleMidiFromPlugin (const VstEvents* const events);
  649. void createTempParameterStore (MemoryBlock& dest);
  650. void restoreFromTempParameterStore (const MemoryBlock& mb);
  651. const String getParameterLabel (int index) const;
  652. bool usesChunks() const throw() { return effect != 0 && (effect->flags & effFlagsProgramChunks) != 0; }
  653. void getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const;
  654. void setChunkData (const char* data, int size, bool isPreset);
  655. bool loadFromFXBFile (const void* data, int numBytes);
  656. bool saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB);
  657. int getVersionNumber() const throw() { return effect != 0 ? effect->version : 0; }
  658. const String getVersion() const;
  659. const String getCategory() const;
  660. bool hasEditor() const throw() { return effect != 0 && (effect->flags & effFlagsHasEditor) != 0; }
  661. void setPower (const bool on);
  662. VSTPluginInstance (const ReferenceCountedObjectPtr <ModuleHandle>& module);
  663. };
  664. //==============================================================================
  665. VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr <ModuleHandle>& module_)
  666. : effect (0),
  667. wantsMidiMessages (false),
  668. initialised (false),
  669. isPowerOn (false),
  670. tempBuffer (1, 1),
  671. module (module_)
  672. {
  673. try
  674. {
  675. _fpreset();
  676. ++insideVSTCallback;
  677. name = module->pluginName;
  678. log ("Creating VST instance: " + name);
  679. #if JUCE_MAC
  680. if (module->resFileId != 0)
  681. UseResFile (module->resFileId);
  682. #if JUCE_PPC
  683. if (module->fragId != 0)
  684. {
  685. static void* audioMasterCoerced = 0;
  686. if (audioMasterCoerced == 0)
  687. audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster);
  688. effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced);
  689. }
  690. else
  691. #endif
  692. #endif
  693. {
  694. effect = module->moduleMain (&audioMaster);
  695. }
  696. --insideVSTCallback;
  697. if (effect != 0 && effect->magic == kEffectMagic)
  698. {
  699. #if JUCE_PPC
  700. module->coerceAEffectFunctionCalls (effect);
  701. #endif
  702. jassert (effect->resvd2 == 0);
  703. jassert (effect->object != 0);
  704. _fpreset(); // some dodgy plugs fuck around with this
  705. }
  706. else
  707. {
  708. effect = 0;
  709. }
  710. }
  711. catch (...)
  712. {
  713. --insideVSTCallback;
  714. }
  715. }
  716. VSTPluginInstance::~VSTPluginInstance()
  717. {
  718. const ScopedLock sl (lock);
  719. jassert (insideVSTCallback == 0);
  720. if (effect != 0 && effect->magic == kEffectMagic)
  721. {
  722. try
  723. {
  724. #if JUCE_MAC
  725. if (module->resFileId != 0)
  726. UseResFile (module->resFileId);
  727. #endif
  728. // Must delete any editors before deleting the plugin instance!
  729. jassert (getActiveEditor() == 0);
  730. _fpreset(); // some dodgy plugs fuck around with this
  731. module->closeEffect (effect);
  732. }
  733. catch (...)
  734. {}
  735. }
  736. module = 0;
  737. effect = 0;
  738. }
  739. //==============================================================================
  740. void VSTPluginInstance::initialise()
  741. {
  742. if (initialised || effect == 0)
  743. return;
  744. log ("Initialising VST: " + module->pluginName);
  745. initialised = true;
  746. dispatch (effIdentify, 0, 0, 0, 0);
  747. // this code would ask the plugin for its name, but so few plugins
  748. // actually bother implementing this correctly, that it's better to
  749. // just ignore it and use the file name instead.
  750. /* {
  751. char buffer [256];
  752. zerostruct (buffer);
  753. dispatch (effGetEffectName, 0, 0, buffer, 0);
  754. name = String (buffer).trim();
  755. if (name.isEmpty())
  756. name = module->pluginName;
  757. }
  758. */
  759. if (getSampleRate() > 0)
  760. dispatch (effSetSampleRate, 0, 0, 0, (float) getSampleRate());
  761. if (getBlockSize() > 0)
  762. dispatch (effSetBlockSize, 0, jmax (32, getBlockSize()), 0, 0);
  763. dispatch (effOpen, 0, 0, 0, 0);
  764. setPlayConfigDetails (effect->numInputs, effect->numOutputs,
  765. getSampleRate(), getBlockSize());
  766. if (getNumPrograms() > 1)
  767. setCurrentProgram (0);
  768. else
  769. dispatch (effSetProgram, 0, 0, 0, 0);
  770. int i;
  771. for (i = effect->numInputs; --i >= 0;)
  772. dispatch (effConnectInput, i, 1, 0, 0);
  773. for (i = effect->numOutputs; --i >= 0;)
  774. dispatch (effConnectOutput, i, 1, 0, 0);
  775. updateStoredProgramNames();
  776. wantsMidiMessages = dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0;
  777. setLatencySamples (effect->initialDelay);
  778. }
  779. //==============================================================================
  780. void VSTPluginInstance::prepareToPlay (double sampleRate_,
  781. int samplesPerBlockExpected)
  782. {
  783. setPlayConfigDetails (effect->numInputs, effect->numOutputs,
  784. sampleRate_, samplesPerBlockExpected);
  785. setLatencySamples (effect->initialDelay);
  786. vstHostTime.tempo = 120.0;
  787. vstHostTime.timeSigNumerator = 4;
  788. vstHostTime.timeSigDenominator = 4;
  789. vstHostTime.sampleRate = sampleRate_;
  790. vstHostTime.samplePos = 0;
  791. vstHostTime.flags = kVstNanosValid; /*| kVstTransportPlaying | kVstTempoValid | kVstTimeSigValid*/;
  792. initialise();
  793. if (initialised)
  794. {
  795. wantsMidiMessages = wantsMidiMessages
  796. || (dispatch (effCanDo, 0, 0, (void*) "receiveVstMidiEvent", 0) > 0);
  797. if (wantsMidiMessages)
  798. midiEventsToSend.ensureSize (256);
  799. else
  800. midiEventsToSend.freeEvents();
  801. incomingMidi.clear();
  802. dispatch (effSetSampleRate, 0, 0, 0, (float) sampleRate_);
  803. dispatch (effSetBlockSize, 0, jmax (16, samplesPerBlockExpected), 0, 0);
  804. tempBuffer.setSize (jmax (1, effect->numOutputs), samplesPerBlockExpected);
  805. if (! isPowerOn)
  806. setPower (true);
  807. // dodgy hack to force some plugins to initialise the sample rate..
  808. if ((! hasEditor()) && getNumParameters() > 0)
  809. {
  810. const float old = getParameter (0);
  811. setParameter (0, (old < 0.5f) ? 1.0f : 0.0f);
  812. setParameter (0, old);
  813. }
  814. dispatch (effStartProcess, 0, 0, 0, 0);
  815. }
  816. }
  817. void VSTPluginInstance::releaseResources()
  818. {
  819. if (initialised)
  820. {
  821. dispatch (effStopProcess, 0, 0, 0, 0);
  822. setPower (false);
  823. }
  824. tempBuffer.setSize (1, 1);
  825. incomingMidi.clear();
  826. midiEventsToSend.freeEvents();
  827. }
  828. void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer,
  829. MidiBuffer& midiMessages)
  830. {
  831. const int numSamples = buffer.getNumSamples();
  832. if (initialised)
  833. {
  834. AudioPlayHead* playHead = getPlayHead();
  835. if (playHead != 0)
  836. {
  837. AudioPlayHead::CurrentPositionInfo position;
  838. playHead->getCurrentPosition (position);
  839. vstHostTime.tempo = position.bpm;
  840. vstHostTime.timeSigNumerator = position.timeSigNumerator;
  841. vstHostTime.timeSigDenominator = position.timeSigDenominator;
  842. vstHostTime.ppqPos = position.ppqPosition;
  843. vstHostTime.barStartPos = position.ppqPositionOfLastBarStart;
  844. vstHostTime.flags |= kVstTempoValid | kVstTimeSigValid | kVstPpqPosValid | kVstBarsValid;
  845. if (position.isPlaying)
  846. vstHostTime.flags |= kVstTransportPlaying;
  847. else
  848. vstHostTime.flags &= ~kVstTransportPlaying;
  849. }
  850. vstHostTime.nanoSeconds = getVSTHostTimeNanoseconds();
  851. if (wantsMidiMessages)
  852. {
  853. midiEventsToSend.clear();
  854. midiEventsToSend.ensureSize (1);
  855. MidiBuffer::Iterator iter (midiMessages);
  856. const uint8* midiData;
  857. int numBytesOfMidiData, samplePosition;
  858. while (iter.getNextEvent (midiData, numBytesOfMidiData, samplePosition))
  859. {
  860. midiEventsToSend.addEvent (midiData, numBytesOfMidiData,
  861. jlimit (0, numSamples - 1, samplePosition));
  862. }
  863. try
  864. {
  865. effect->dispatcher (effect, effProcessEvents, 0, 0, midiEventsToSend.events, 0);
  866. }
  867. catch (...)
  868. {}
  869. }
  870. _clearfp();
  871. if ((effect->flags & effFlagsCanReplacing) != 0)
  872. {
  873. try
  874. {
  875. effect->processReplacing (effect, buffer.getArrayOfChannels(), buffer.getArrayOfChannels(), numSamples);
  876. }
  877. catch (...)
  878. {}
  879. }
  880. else
  881. {
  882. tempBuffer.setSize (effect->numOutputs, numSamples);
  883. tempBuffer.clear();
  884. try
  885. {
  886. effect->process (effect, buffer.getArrayOfChannels(), tempBuffer.getArrayOfChannels(), numSamples);
  887. }
  888. catch (...)
  889. {}
  890. for (int i = effect->numOutputs; --i >= 0;)
  891. buffer.copyFrom (i, 0, tempBuffer.getSampleData (i), numSamples);
  892. }
  893. }
  894. else
  895. {
  896. // Not initialised, so just bypass..
  897. for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
  898. buffer.clear (i, 0, buffer.getNumSamples());
  899. }
  900. {
  901. // copy any incoming midi..
  902. const ScopedLock sl (midiInLock);
  903. midiMessages.swapWith (incomingMidi);
  904. incomingMidi.clear();
  905. }
  906. }
  907. //==============================================================================
  908. void VSTPluginInstance::handleMidiFromPlugin (const VstEvents* const events)
  909. {
  910. if (events != 0)
  911. {
  912. const ScopedLock sl (midiInLock);
  913. VSTMidiEventList::addEventsToMidiBuffer (events, incomingMidi);
  914. }
  915. }
  916. //==============================================================================
  917. static Array <VSTPluginWindow*> activeVSTWindows;
  918. //==============================================================================
  919. class VSTPluginWindow : public AudioProcessorEditor,
  920. #if ! JUCE_MAC
  921. public ComponentMovementWatcher,
  922. #endif
  923. public Timer
  924. {
  925. public:
  926. //==============================================================================
  927. VSTPluginWindow (VSTPluginInstance& plugin_)
  928. : AudioProcessorEditor (&plugin_),
  929. #if ! JUCE_MAC
  930. ComponentMovementWatcher (this),
  931. #endif
  932. plugin (plugin_),
  933. isOpen (false),
  934. wasShowing (false),
  935. pluginRefusesToResize (false),
  936. pluginWantsKeys (false),
  937. alreadyInside (false),
  938. recursiveResize (false)
  939. {
  940. #if JUCE_WINDOWS
  941. sizeCheckCount = 0;
  942. pluginHWND = 0;
  943. #elif JUCE_LINUX
  944. pluginWindow = None;
  945. pluginProc = None;
  946. #else
  947. addAndMakeVisible (innerWrapper = new InnerWrapperComponent (this));
  948. #endif
  949. activeVSTWindows.add (this);
  950. setSize (1, 1);
  951. setOpaque (true);
  952. setVisible (true);
  953. }
  954. ~VSTPluginWindow()
  955. {
  956. #if JUCE_MAC
  957. innerWrapper = 0;
  958. #else
  959. closePluginWindow();
  960. #endif
  961. activeVSTWindows.removeValue (this);
  962. plugin.editorBeingDeleted (this);
  963. }
  964. //==============================================================================
  965. #if ! JUCE_MAC
  966. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  967. {
  968. if (recursiveResize)
  969. return;
  970. Component* const topComp = getTopLevelComponent();
  971. if (topComp->getPeer() != 0)
  972. {
  973. const Point<int> pos (relativePositionToOtherComponent (topComp, Point<int>()));
  974. recursiveResize = true;
  975. #if JUCE_WINDOWS
  976. if (pluginHWND != 0)
  977. MoveWindow (pluginHWND, pos.getX(), pos.getY(), getWidth(), getHeight(), TRUE);
  978. #elif JUCE_LINUX
  979. if (pluginWindow != 0)
  980. {
  981. XResizeWindow (display, pluginWindow, getWidth(), getHeight());
  982. XMoveWindow (display, pluginWindow, pos.getX(), pos.getY());
  983. XMapRaised (display, pluginWindow);
  984. }
  985. #endif
  986. recursiveResize = false;
  987. }
  988. }
  989. void componentVisibilityChanged (Component&)
  990. {
  991. const bool isShowingNow = isShowing();
  992. if (wasShowing != isShowingNow)
  993. {
  994. wasShowing = isShowingNow;
  995. if (isShowingNow)
  996. openPluginWindow();
  997. else
  998. closePluginWindow();
  999. }
  1000. componentMovedOrResized (true, true);
  1001. }
  1002. void componentPeerChanged()
  1003. {
  1004. closePluginWindow();
  1005. openPluginWindow();
  1006. }
  1007. #endif
  1008. //==============================================================================
  1009. bool keyStateChanged (bool)
  1010. {
  1011. return pluginWantsKeys;
  1012. }
  1013. bool keyPressed (const KeyPress&)
  1014. {
  1015. return pluginWantsKeys;
  1016. }
  1017. //==============================================================================
  1018. #if JUCE_MAC
  1019. void paint (Graphics& g)
  1020. {
  1021. g.fillAll (Colours::black);
  1022. }
  1023. #else
  1024. void paint (Graphics& g)
  1025. {
  1026. if (isOpen)
  1027. {
  1028. ComponentPeer* const peer = getPeer();
  1029. if (peer != 0)
  1030. {
  1031. const Point<int> pos (getScreenPosition() - peer->getScreenPosition());
  1032. peer->addMaskedRegion (pos.getX(), pos.getY(), getWidth(), getHeight());
  1033. #if JUCE_LINUX
  1034. if (pluginWindow != 0)
  1035. {
  1036. const Rectangle<int> clip (g.getClipBounds());
  1037. XEvent ev;
  1038. zerostruct (ev);
  1039. ev.xexpose.type = Expose;
  1040. ev.xexpose.display = display;
  1041. ev.xexpose.window = pluginWindow;
  1042. ev.xexpose.x = clip.getX();
  1043. ev.xexpose.y = clip.getY();
  1044. ev.xexpose.width = clip.getWidth();
  1045. ev.xexpose.height = clip.getHeight();
  1046. sendEventToChild (&ev);
  1047. }
  1048. #endif
  1049. }
  1050. }
  1051. else
  1052. {
  1053. g.fillAll (Colours::black);
  1054. }
  1055. }
  1056. #endif
  1057. //==============================================================================
  1058. void timerCallback()
  1059. {
  1060. #if JUCE_WINDOWS
  1061. if (--sizeCheckCount <= 0)
  1062. {
  1063. sizeCheckCount = 10;
  1064. checkPluginWindowSize();
  1065. }
  1066. #endif
  1067. try
  1068. {
  1069. static bool reentrant = false;
  1070. if (! reentrant)
  1071. {
  1072. reentrant = true;
  1073. plugin.dispatch (effEditIdle, 0, 0, 0, 0);
  1074. reentrant = false;
  1075. }
  1076. }
  1077. catch (...)
  1078. {}
  1079. }
  1080. //==============================================================================
  1081. void mouseDown (const MouseEvent& e)
  1082. {
  1083. #if JUCE_LINUX
  1084. if (pluginWindow == 0)
  1085. return;
  1086. toFront (true);
  1087. XEvent ev;
  1088. zerostruct (ev);
  1089. ev.xbutton.display = display;
  1090. ev.xbutton.type = ButtonPress;
  1091. ev.xbutton.window = pluginWindow;
  1092. ev.xbutton.root = RootWindow (display, DefaultScreen (display));
  1093. ev.xbutton.time = CurrentTime;
  1094. ev.xbutton.x = e.x;
  1095. ev.xbutton.y = e.y;
  1096. ev.xbutton.x_root = e.getScreenX();
  1097. ev.xbutton.y_root = e.getScreenY();
  1098. translateJuceToXButtonModifiers (e, ev);
  1099. sendEventToChild (&ev);
  1100. #elif JUCE_WINDOWS
  1101. (void) e;
  1102. toFront (true);
  1103. #endif
  1104. }
  1105. void broughtToFront()
  1106. {
  1107. activeVSTWindows.removeValue (this);
  1108. activeVSTWindows.add (this);
  1109. #if JUCE_MAC
  1110. dispatch (effEditTop, 0, 0, 0, 0);
  1111. #endif
  1112. }
  1113. //==============================================================================
  1114. juce_UseDebuggingNewOperator
  1115. private:
  1116. VSTPluginInstance& plugin;
  1117. bool isOpen, wasShowing, recursiveResize;
  1118. bool pluginWantsKeys, pluginRefusesToResize, alreadyInside;
  1119. #if JUCE_WINDOWS
  1120. HWND pluginHWND;
  1121. void* originalWndProc;
  1122. int sizeCheckCount;
  1123. #elif JUCE_LINUX
  1124. Window pluginWindow;
  1125. EventProcPtr pluginProc;
  1126. #endif
  1127. //==============================================================================
  1128. #if JUCE_MAC
  1129. void openPluginWindow (WindowRef parentWindow)
  1130. {
  1131. if (isOpen || parentWindow == 0)
  1132. return;
  1133. isOpen = true;
  1134. ERect* rect = 0;
  1135. dispatch (effEditGetRect, 0, 0, &rect, 0);
  1136. dispatch (effEditOpen, 0, 0, parentWindow, 0);
  1137. // do this before and after like in the steinberg example
  1138. dispatch (effEditGetRect, 0, 0, &rect, 0);
  1139. dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code
  1140. // Install keyboard hooks
  1141. pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0);
  1142. // double-check it's not too tiny
  1143. int w = 250, h = 150;
  1144. if (rect != 0)
  1145. {
  1146. w = rect->right - rect->left;
  1147. h = rect->bottom - rect->top;
  1148. if (w == 0 || h == 0)
  1149. {
  1150. w = 250;
  1151. h = 150;
  1152. }
  1153. }
  1154. w = jmax (w, 32);
  1155. h = jmax (h, 32);
  1156. setSize (w, h);
  1157. startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5));
  1158. repaint();
  1159. }
  1160. #else
  1161. void openPluginWindow()
  1162. {
  1163. if (isOpen || getWindowHandle() == 0)
  1164. return;
  1165. log ("Opening VST UI: " + plugin.name);
  1166. isOpen = true;
  1167. ERect* rect = 0;
  1168. dispatch (effEditGetRect, 0, 0, &rect, 0);
  1169. dispatch (effEditOpen, 0, 0, getWindowHandle(), 0);
  1170. // do this before and after like in the steinberg example
  1171. dispatch (effEditGetRect, 0, 0, &rect, 0);
  1172. dispatch (effGetProgram, 0, 0, 0, 0); // also in steinberg code
  1173. // Install keyboard hooks
  1174. pluginWantsKeys = (dispatch (effKeysRequired, 0, 0, 0, 0) == 0);
  1175. #if JUCE_WINDOWS
  1176. originalWndProc = 0;
  1177. pluginHWND = GetWindow ((HWND) getWindowHandle(), GW_CHILD);
  1178. if (pluginHWND == 0)
  1179. {
  1180. isOpen = false;
  1181. setSize (300, 150);
  1182. return;
  1183. }
  1184. #pragma warning (push)
  1185. #pragma warning (disable: 4244)
  1186. originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWL_WNDPROC);
  1187. if (! pluginWantsKeys)
  1188. SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc);
  1189. #pragma warning (pop)
  1190. int w, h;
  1191. RECT r;
  1192. GetWindowRect (pluginHWND, &r);
  1193. w = r.right - r.left;
  1194. h = r.bottom - r.top;
  1195. if (rect != 0)
  1196. {
  1197. const int rw = rect->right - rect->left;
  1198. const int rh = rect->bottom - rect->top;
  1199. if ((rw > 50 && rh > 50 && rw < 2000 && rh < 2000 && rw != w && rh != h)
  1200. || ((w == 0 && rw > 0) || (h == 0 && rh > 0)))
  1201. {
  1202. // very dodgy logic to decide which size is right.
  1203. if (abs (rw - w) > 350 || abs (rh - h) > 350)
  1204. {
  1205. SetWindowPos (pluginHWND, 0,
  1206. 0, 0, rw, rh,
  1207. SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  1208. GetWindowRect (pluginHWND, &r);
  1209. w = r.right - r.left;
  1210. h = r.bottom - r.top;
  1211. pluginRefusesToResize = (w != rw) || (h != rh);
  1212. w = rw;
  1213. h = rh;
  1214. }
  1215. }
  1216. }
  1217. #elif JUCE_LINUX
  1218. pluginWindow = getChildWindow ((Window) getWindowHandle());
  1219. if (pluginWindow != 0)
  1220. pluginProc = (EventProcPtr) getPropertyFromXWindow (pluginWindow,
  1221. XInternAtom (display, "_XEventProc", False));
  1222. int w = 250, h = 150;
  1223. if (rect != 0)
  1224. {
  1225. w = rect->right - rect->left;
  1226. h = rect->bottom - rect->top;
  1227. if (w == 0 || h == 0)
  1228. {
  1229. w = 250;
  1230. h = 150;
  1231. }
  1232. }
  1233. if (pluginWindow != 0)
  1234. XMapRaised (display, pluginWindow);
  1235. #endif
  1236. // double-check it's not too tiny
  1237. w = jmax (w, 32);
  1238. h = jmax (h, 32);
  1239. setSize (w, h);
  1240. #if JUCE_WINDOWS
  1241. checkPluginWindowSize();
  1242. #endif
  1243. startTimer (18 + JUCE_NAMESPACE::Random::getSystemRandom().nextInt (5));
  1244. repaint();
  1245. }
  1246. #endif
  1247. //==============================================================================
  1248. #if ! JUCE_MAC
  1249. void closePluginWindow()
  1250. {
  1251. if (isOpen)
  1252. {
  1253. log ("Closing VST UI: " + plugin.getName());
  1254. isOpen = false;
  1255. dispatch (effEditClose, 0, 0, 0, 0);
  1256. #if JUCE_WINDOWS
  1257. #pragma warning (push)
  1258. #pragma warning (disable: 4244)
  1259. if (pluginHWND != 0 && IsWindow (pluginHWND))
  1260. SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
  1261. #pragma warning (pop)
  1262. stopTimer();
  1263. if (pluginHWND != 0 && IsWindow (pluginHWND))
  1264. DestroyWindow (pluginHWND);
  1265. pluginHWND = 0;
  1266. #elif JUCE_LINUX
  1267. stopTimer();
  1268. pluginWindow = 0;
  1269. pluginProc = 0;
  1270. #endif
  1271. }
  1272. }
  1273. #endif
  1274. //==============================================================================
  1275. int dispatch (const int opcode, const int index, const int value, void* const ptr, float opt)
  1276. {
  1277. return plugin.dispatch (opcode, index, value, ptr, opt);
  1278. }
  1279. //==============================================================================
  1280. #if JUCE_WINDOWS
  1281. void checkPluginWindowSize()
  1282. {
  1283. RECT r;
  1284. GetWindowRect (pluginHWND, &r);
  1285. const int w = r.right - r.left;
  1286. const int h = r.bottom - r.top;
  1287. if (isShowing() && w > 0 && h > 0
  1288. && (w != getWidth() || h != getHeight())
  1289. && ! pluginRefusesToResize)
  1290. {
  1291. setSize (w, h);
  1292. sizeCheckCount = 0;
  1293. }
  1294. }
  1295. // hooks to get keyboard events from VST windows..
  1296. static LRESULT CALLBACK vstHookWndProc (HWND hW, UINT message, WPARAM wParam, LPARAM lParam)
  1297. {
  1298. for (int i = activeVSTWindows.size(); --i >= 0;)
  1299. {
  1300. const VSTPluginWindow* const w = activeVSTWindows.getUnchecked (i);
  1301. if (w->pluginHWND == hW)
  1302. {
  1303. if (message == WM_CHAR
  1304. || message == WM_KEYDOWN
  1305. || message == WM_SYSKEYDOWN
  1306. || message == WM_KEYUP
  1307. || message == WM_SYSKEYUP
  1308. || message == WM_APPCOMMAND)
  1309. {
  1310. SendMessage ((HWND) w->getTopLevelComponent()->getWindowHandle(),
  1311. message, wParam, lParam);
  1312. }
  1313. return CallWindowProc ((WNDPROC) (w->originalWndProc),
  1314. (HWND) w->pluginHWND,
  1315. message,
  1316. wParam,
  1317. lParam);
  1318. }
  1319. }
  1320. return DefWindowProc (hW, message, wParam, lParam);
  1321. }
  1322. #endif
  1323. #if JUCE_LINUX
  1324. //==============================================================================
  1325. // overload mouse/keyboard events to forward them to the plugin's inner window..
  1326. void sendEventToChild (XEvent* event)
  1327. {
  1328. if (pluginProc != 0)
  1329. {
  1330. // if the plugin publishes an event procedure, pass the event directly..
  1331. pluginProc (event);
  1332. }
  1333. else if (pluginWindow != 0)
  1334. {
  1335. // if the plugin has a window, then send the event to the window so that
  1336. // its message thread will pick it up..
  1337. XSendEvent (display, pluginWindow, False, 0L, event);
  1338. XFlush (display);
  1339. }
  1340. }
  1341. void mouseEnter (const MouseEvent& e)
  1342. {
  1343. if (pluginWindow != 0)
  1344. {
  1345. XEvent ev;
  1346. zerostruct (ev);
  1347. ev.xcrossing.display = display;
  1348. ev.xcrossing.type = EnterNotify;
  1349. ev.xcrossing.window = pluginWindow;
  1350. ev.xcrossing.root = RootWindow (display, DefaultScreen (display));
  1351. ev.xcrossing.time = CurrentTime;
  1352. ev.xcrossing.x = e.x;
  1353. ev.xcrossing.y = e.y;
  1354. ev.xcrossing.x_root = e.getScreenX();
  1355. ev.xcrossing.y_root = e.getScreenY();
  1356. ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab
  1357. ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual
  1358. translateJuceToXCrossingModifiers (e, ev);
  1359. sendEventToChild (&ev);
  1360. }
  1361. }
  1362. void mouseExit (const MouseEvent& e)
  1363. {
  1364. if (pluginWindow != 0)
  1365. {
  1366. XEvent ev;
  1367. zerostruct (ev);
  1368. ev.xcrossing.display = display;
  1369. ev.xcrossing.type = LeaveNotify;
  1370. ev.xcrossing.window = pluginWindow;
  1371. ev.xcrossing.root = RootWindow (display, DefaultScreen (display));
  1372. ev.xcrossing.time = CurrentTime;
  1373. ev.xcrossing.x = e.x;
  1374. ev.xcrossing.y = e.y;
  1375. ev.xcrossing.x_root = e.getScreenX();
  1376. ev.xcrossing.y_root = e.getScreenY();
  1377. ev.xcrossing.mode = NotifyNormal; // NotifyGrab, NotifyUngrab
  1378. ev.xcrossing.detail = NotifyAncestor; // NotifyVirtual, NotifyInferior, NotifyNonlinear,NotifyNonlinearVirtual
  1379. ev.xcrossing.focus = hasKeyboardFocus (true); // TODO - yes ?
  1380. translateJuceToXCrossingModifiers (e, ev);
  1381. sendEventToChild (&ev);
  1382. }
  1383. }
  1384. void mouseMove (const MouseEvent& e)
  1385. {
  1386. if (pluginWindow != 0)
  1387. {
  1388. XEvent ev;
  1389. zerostruct (ev);
  1390. ev.xmotion.display = display;
  1391. ev.xmotion.type = MotionNotify;
  1392. ev.xmotion.window = pluginWindow;
  1393. ev.xmotion.root = RootWindow (display, DefaultScreen (display));
  1394. ev.xmotion.time = CurrentTime;
  1395. ev.xmotion.is_hint = NotifyNormal;
  1396. ev.xmotion.x = e.x;
  1397. ev.xmotion.y = e.y;
  1398. ev.xmotion.x_root = e.getScreenX();
  1399. ev.xmotion.y_root = e.getScreenY();
  1400. sendEventToChild (&ev);
  1401. }
  1402. }
  1403. void mouseDrag (const MouseEvent& e)
  1404. {
  1405. if (pluginWindow != 0)
  1406. {
  1407. XEvent ev;
  1408. zerostruct (ev);
  1409. ev.xmotion.display = display;
  1410. ev.xmotion.type = MotionNotify;
  1411. ev.xmotion.window = pluginWindow;
  1412. ev.xmotion.root = RootWindow (display, DefaultScreen (display));
  1413. ev.xmotion.time = CurrentTime;
  1414. ev.xmotion.x = e.x ;
  1415. ev.xmotion.y = e.y;
  1416. ev.xmotion.x_root = e.getScreenX();
  1417. ev.xmotion.y_root = e.getScreenY();
  1418. ev.xmotion.is_hint = NotifyNormal;
  1419. translateJuceToXMotionModifiers (e, ev);
  1420. sendEventToChild (&ev);
  1421. }
  1422. }
  1423. void mouseUp (const MouseEvent& e)
  1424. {
  1425. if (pluginWindow != 0)
  1426. {
  1427. XEvent ev;
  1428. zerostruct (ev);
  1429. ev.xbutton.display = display;
  1430. ev.xbutton.type = ButtonRelease;
  1431. ev.xbutton.window = pluginWindow;
  1432. ev.xbutton.root = RootWindow (display, DefaultScreen (display));
  1433. ev.xbutton.time = CurrentTime;
  1434. ev.xbutton.x = e.x;
  1435. ev.xbutton.y = e.y;
  1436. ev.xbutton.x_root = e.getScreenX();
  1437. ev.xbutton.y_root = e.getScreenY();
  1438. translateJuceToXButtonModifiers (e, ev);
  1439. sendEventToChild (&ev);
  1440. }
  1441. }
  1442. void mouseWheelMove (const MouseEvent& e,
  1443. float incrementX,
  1444. float incrementY)
  1445. {
  1446. if (pluginWindow != 0)
  1447. {
  1448. XEvent ev;
  1449. zerostruct (ev);
  1450. ev.xbutton.display = display;
  1451. ev.xbutton.type = ButtonPress;
  1452. ev.xbutton.window = pluginWindow;
  1453. ev.xbutton.root = RootWindow (display, DefaultScreen (display));
  1454. ev.xbutton.time = CurrentTime;
  1455. ev.xbutton.x = e.x;
  1456. ev.xbutton.y = e.y;
  1457. ev.xbutton.x_root = e.getScreenX();
  1458. ev.xbutton.y_root = e.getScreenY();
  1459. translateJuceToXMouseWheelModifiers (e, incrementY, ev);
  1460. sendEventToChild (&ev);
  1461. // TODO - put a usleep here ?
  1462. ev.xbutton.type = ButtonRelease;
  1463. sendEventToChild (&ev);
  1464. }
  1465. }
  1466. #endif
  1467. #if JUCE_MAC
  1468. #if ! JUCE_SUPPORT_CARBON
  1469. #error "To build VSTs, you need to enable the JUCE_SUPPORT_CARBON flag in your config!"
  1470. #endif
  1471. class InnerWrapperComponent : public CarbonViewWrapperComponent
  1472. {
  1473. public:
  1474. InnerWrapperComponent (VSTPluginWindow* const owner_)
  1475. : owner (owner_),
  1476. alreadyInside (false)
  1477. {
  1478. }
  1479. ~InnerWrapperComponent()
  1480. {
  1481. deleteWindow();
  1482. }
  1483. HIViewRef attachView (WindowRef windowRef, HIViewRef rootView)
  1484. {
  1485. owner->openPluginWindow (windowRef);
  1486. return 0;
  1487. }
  1488. void removeView (HIViewRef)
  1489. {
  1490. owner->dispatch (effEditClose, 0, 0, 0, 0);
  1491. owner->dispatch (effEditSleep, 0, 0, 0, 0);
  1492. }
  1493. bool getEmbeddedViewSize (int& w, int& h)
  1494. {
  1495. ERect* rect = 0;
  1496. owner->dispatch (effEditGetRect, 0, 0, &rect, 0);
  1497. w = rect->right - rect->left;
  1498. h = rect->bottom - rect->top;
  1499. return true;
  1500. }
  1501. void mouseDown (int x, int y)
  1502. {
  1503. if (! alreadyInside)
  1504. {
  1505. alreadyInside = true;
  1506. getTopLevelComponent()->toFront (true);
  1507. owner->dispatch (effEditMouse, x, y, 0, 0);
  1508. alreadyInside = false;
  1509. }
  1510. else
  1511. {
  1512. PostEvent (::mouseDown, 0);
  1513. }
  1514. }
  1515. void paint()
  1516. {
  1517. ComponentPeer* const peer = getPeer();
  1518. if (peer != 0)
  1519. {
  1520. const Point<int> pos (getScreenPosition() - peer->getScreenPosition());
  1521. ERect r;
  1522. r.left = pos.getX();
  1523. r.right = r.left + getWidth();
  1524. r.top = pos.getY();
  1525. r.bottom = r.top + getHeight();
  1526. owner->dispatch (effEditDraw, 0, 0, &r, 0);
  1527. }
  1528. }
  1529. private:
  1530. VSTPluginWindow* const owner;
  1531. bool alreadyInside;
  1532. };
  1533. friend class InnerWrapperComponent;
  1534. ScopedPointer <InnerWrapperComponent> innerWrapper;
  1535. void resized()
  1536. {
  1537. innerWrapper->setSize (getWidth(), getHeight());
  1538. }
  1539. #endif
  1540. };
  1541. //==============================================================================
  1542. AudioProcessorEditor* VSTPluginInstance::createEditor()
  1543. {
  1544. if (hasEditor())
  1545. return new VSTPluginWindow (*this);
  1546. return 0;
  1547. }
  1548. //==============================================================================
  1549. void VSTPluginInstance::handleAsyncUpdate()
  1550. {
  1551. // indicates that something about the plugin has changed..
  1552. updateHostDisplay();
  1553. }
  1554. //==============================================================================
  1555. bool VSTPluginInstance::restoreProgramSettings (const fxProgram* const prog)
  1556. {
  1557. if (vst_swap (prog->chunkMagic) == 'CcnK' && vst_swap (prog->fxMagic) == 'FxCk')
  1558. {
  1559. changeProgramName (getCurrentProgram(), prog->prgName);
  1560. for (int i = 0; i < vst_swap (prog->numParams); ++i)
  1561. setParameter (i, vst_swapFloat (prog->params[i]));
  1562. return true;
  1563. }
  1564. return false;
  1565. }
  1566. bool VSTPluginInstance::loadFromFXBFile (const void* const data,
  1567. const int dataSize)
  1568. {
  1569. if (dataSize < 28)
  1570. return false;
  1571. const fxSet* const set = (const fxSet*) data;
  1572. if ((vst_swap (set->chunkMagic) != 'CcnK' && vst_swap (set->chunkMagic) != 'KncC')
  1573. || vst_swap (set->version) > fxbVersionNum)
  1574. return false;
  1575. if (vst_swap (set->fxMagic) == 'FxBk')
  1576. {
  1577. // bank of programs
  1578. if (vst_swap (set->numPrograms) >= 0)
  1579. {
  1580. const int oldProg = getCurrentProgram();
  1581. const int numParams = vst_swap (((const fxProgram*) (set->programs))->numParams);
  1582. const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
  1583. for (int i = 0; i < vst_swap (set->numPrograms); ++i)
  1584. {
  1585. if (i != oldProg)
  1586. {
  1587. const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen);
  1588. if (((const char*) prog) - ((const char*) set) >= dataSize)
  1589. return false;
  1590. if (vst_swap (set->numPrograms) > 0)
  1591. setCurrentProgram (i);
  1592. if (! restoreProgramSettings (prog))
  1593. return false;
  1594. }
  1595. }
  1596. if (vst_swap (set->numPrograms) > 0)
  1597. setCurrentProgram (oldProg);
  1598. const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen);
  1599. if (((const char*) prog) - ((const char*) set) >= dataSize)
  1600. return false;
  1601. if (! restoreProgramSettings (prog))
  1602. return false;
  1603. }
  1604. }
  1605. else if (vst_swap (set->fxMagic) == 'FxCk')
  1606. {
  1607. // single program
  1608. const fxProgram* const prog = (const fxProgram*) data;
  1609. if (vst_swap (prog->chunkMagic) != 'CcnK')
  1610. return false;
  1611. changeProgramName (getCurrentProgram(), prog->prgName);
  1612. for (int i = 0; i < vst_swap (prog->numParams); ++i)
  1613. setParameter (i, vst_swapFloat (prog->params[i]));
  1614. }
  1615. else if (vst_swap (set->fxMagic) == 'FBCh' || vst_swap (set->fxMagic) == 'hCBF')
  1616. {
  1617. // non-preset chunk
  1618. const fxChunkSet* const cset = (const fxChunkSet*) data;
  1619. if (vst_swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
  1620. return false;
  1621. setChunkData (cset->chunk, vst_swap (cset->chunkSize), false);
  1622. }
  1623. else if (vst_swap (set->fxMagic) == 'FPCh' || vst_swap (set->fxMagic) == 'hCPF')
  1624. {
  1625. // preset chunk
  1626. const fxProgramSet* const cset = (const fxProgramSet*) data;
  1627. if (vst_swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
  1628. return false;
  1629. setChunkData (cset->chunk, vst_swap (cset->chunkSize), true);
  1630. changeProgramName (getCurrentProgram(), cset->name);
  1631. }
  1632. else
  1633. {
  1634. return false;
  1635. }
  1636. return true;
  1637. }
  1638. //==============================================================================
  1639. void VSTPluginInstance::setParamsInProgramBlock (fxProgram* const prog)
  1640. {
  1641. const int numParams = getNumParameters();
  1642. prog->chunkMagic = vst_swap ('CcnK');
  1643. prog->byteSize = 0;
  1644. prog->fxMagic = vst_swap ('FxCk');
  1645. prog->version = vst_swap (fxbVersionNum);
  1646. prog->fxID = vst_swap (getUID());
  1647. prog->fxVersion = vst_swap (getVersionNumber());
  1648. prog->numParams = vst_swap (numParams);
  1649. getCurrentProgramName().copyToCString (prog->prgName, sizeof (prog->prgName) - 1);
  1650. for (int i = 0; i < numParams; ++i)
  1651. prog->params[i] = vst_swapFloat (getParameter (i));
  1652. }
  1653. bool VSTPluginInstance::saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSizeMB)
  1654. {
  1655. const int numPrograms = getNumPrograms();
  1656. const int numParams = getNumParameters();
  1657. if (usesChunks())
  1658. {
  1659. if (isFXB)
  1660. {
  1661. MemoryBlock chunk;
  1662. getChunkData (chunk, false, maxSizeMB);
  1663. const size_t totalLen = sizeof (fxChunkSet) + chunk.getSize() - 8;
  1664. dest.setSize (totalLen, true);
  1665. fxChunkSet* const set = (fxChunkSet*) dest.getData();
  1666. set->chunkMagic = vst_swap ('CcnK');
  1667. set->byteSize = 0;
  1668. set->fxMagic = vst_swap ('FBCh');
  1669. set->version = vst_swap (fxbVersionNum);
  1670. set->fxID = vst_swap (getUID());
  1671. set->fxVersion = vst_swap (getVersionNumber());
  1672. set->numPrograms = vst_swap (numPrograms);
  1673. set->chunkSize = vst_swap ((long) chunk.getSize());
  1674. chunk.copyTo (set->chunk, 0, chunk.getSize());
  1675. }
  1676. else
  1677. {
  1678. MemoryBlock chunk;
  1679. getChunkData (chunk, true, maxSizeMB);
  1680. const size_t totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8;
  1681. dest.setSize (totalLen, true);
  1682. fxProgramSet* const set = (fxProgramSet*) dest.getData();
  1683. set->chunkMagic = vst_swap ('CcnK');
  1684. set->byteSize = 0;
  1685. set->fxMagic = vst_swap ('FPCh');
  1686. set->version = vst_swap (fxbVersionNum);
  1687. set->fxID = vst_swap (getUID());
  1688. set->fxVersion = vst_swap (getVersionNumber());
  1689. set->numPrograms = vst_swap (numPrograms);
  1690. set->chunkSize = vst_swap ((long) chunk.getSize());
  1691. getCurrentProgramName().copyToCString (set->name, sizeof (set->name) - 1);
  1692. chunk.copyTo (set->chunk, 0, chunk.getSize());
  1693. }
  1694. }
  1695. else
  1696. {
  1697. if (isFXB)
  1698. {
  1699. const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
  1700. const int len = (sizeof (fxSet) - sizeof (fxProgram)) + progLen * jmax (1, numPrograms);
  1701. dest.setSize (len, true);
  1702. fxSet* const set = (fxSet*) dest.getData();
  1703. set->chunkMagic = vst_swap ('CcnK');
  1704. set->byteSize = 0;
  1705. set->fxMagic = vst_swap ('FxBk');
  1706. set->version = vst_swap (fxbVersionNum);
  1707. set->fxID = vst_swap (getUID());
  1708. set->fxVersion = vst_swap (getVersionNumber());
  1709. set->numPrograms = vst_swap (numPrograms);
  1710. const int oldProgram = getCurrentProgram();
  1711. MemoryBlock oldSettings;
  1712. createTempParameterStore (oldSettings);
  1713. setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + oldProgram * progLen));
  1714. for (int i = 0; i < numPrograms; ++i)
  1715. {
  1716. if (i != oldProgram)
  1717. {
  1718. setCurrentProgram (i);
  1719. setParamsInProgramBlock ((fxProgram*) (((char*) (set->programs)) + i * progLen));
  1720. }
  1721. }
  1722. setCurrentProgram (oldProgram);
  1723. restoreFromTempParameterStore (oldSettings);
  1724. }
  1725. else
  1726. {
  1727. const int totalLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
  1728. dest.setSize (totalLen, true);
  1729. setParamsInProgramBlock ((fxProgram*) dest.getData());
  1730. }
  1731. }
  1732. return true;
  1733. }
  1734. void VSTPluginInstance::getChunkData (MemoryBlock& mb, bool isPreset, int maxSizeMB) const
  1735. {
  1736. if (usesChunks())
  1737. {
  1738. void* data = 0;
  1739. const int bytes = dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f);
  1740. if (data != 0 && bytes <= maxSizeMB * 1024 * 1024)
  1741. {
  1742. mb.setSize (bytes);
  1743. mb.copyFrom (data, 0, bytes);
  1744. }
  1745. }
  1746. }
  1747. void VSTPluginInstance::setChunkData (const char* data, int size, bool isPreset)
  1748. {
  1749. if (size > 0 && usesChunks())
  1750. {
  1751. dispatch (effSetChunk, isPreset ? 1 : 0, size, (void*) data, 0.0f);
  1752. if (! isPreset)
  1753. updateStoredProgramNames();
  1754. }
  1755. }
  1756. //==============================================================================
  1757. void VSTPluginInstance::timerCallback()
  1758. {
  1759. if (dispatch (effIdle, 0, 0, 0, 0) == 0)
  1760. stopTimer();
  1761. }
  1762. int VSTPluginInstance::dispatch (const int opcode, const int index, const int value, void* const ptr, float opt) const
  1763. {
  1764. const ScopedLock sl (lock);
  1765. ++insideVSTCallback;
  1766. int result = 0;
  1767. try
  1768. {
  1769. if (effect != 0)
  1770. {
  1771. #if JUCE_MAC
  1772. if (module->resFileId != 0)
  1773. UseResFile (module->resFileId);
  1774. #endif
  1775. result = effect->dispatcher (effect, opcode, index, value, ptr, opt);
  1776. #if JUCE_MAC
  1777. module->resFileId = CurResFile();
  1778. #endif
  1779. --insideVSTCallback;
  1780. return result;
  1781. }
  1782. }
  1783. catch (...)
  1784. {
  1785. }
  1786. --insideVSTCallback;
  1787. return result;
  1788. }
  1789. //==============================================================================
  1790. // handles non plugin-specific callbacks..
  1791. static const int defaultVSTSampleRateValue = 16384;
  1792. static const int defaultVSTBlockSizeValue = 512;
  1793. static VstIntPtr handleGeneralCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt)
  1794. {
  1795. (void) index;
  1796. (void) value;
  1797. (void) opt;
  1798. switch (opcode)
  1799. {
  1800. case audioMasterCanDo:
  1801. {
  1802. static const char* canDos[] = { "supplyIdle",
  1803. "sendVstEvents",
  1804. "sendVstMidiEvent",
  1805. "sendVstTimeInfo",
  1806. "receiveVstEvents",
  1807. "receiveVstMidiEvent",
  1808. "supportShell",
  1809. "shellCategory" };
  1810. for (int i = 0; i < numElementsInArray (canDos); ++i)
  1811. if (strcmp (canDos[i], (const char*) ptr) == 0)
  1812. return 1;
  1813. return 0;
  1814. }
  1815. case audioMasterVersion: return 0x2400;
  1816. case audioMasterCurrentId: return shellUIDToCreate;
  1817. case audioMasterGetNumAutomatableParameters: return 0;
  1818. case audioMasterGetAutomationState: return 1;
  1819. case audioMasterGetVendorVersion: return 0x0101;
  1820. case audioMasterGetVendorString:
  1821. case audioMasterGetProductString:
  1822. {
  1823. String hostName ("Juce VST Host");
  1824. if (JUCEApplication::getInstance() != 0)
  1825. hostName = JUCEApplication::getInstance()->getApplicationName();
  1826. hostName.copyToCString ((char*) ptr, jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1);
  1827. break;
  1828. }
  1829. case audioMasterGetSampleRate: return (VstIntPtr) defaultVSTSampleRateValue;
  1830. case audioMasterGetBlockSize: return (VstIntPtr) defaultVSTBlockSizeValue;
  1831. case audioMasterSetOutputSampleRate: return 0;
  1832. default:
  1833. DBG ("*** Unhandled VST Callback: " + String ((int) opcode));
  1834. break;
  1835. }
  1836. return 0;
  1837. }
  1838. // handles callbacks for a specific plugin
  1839. VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, VstInt32 value, void *ptr, float opt)
  1840. {
  1841. switch (opcode)
  1842. {
  1843. case audioMasterAutomate:
  1844. sendParamChangeMessageToListeners (index, opt);
  1845. break;
  1846. case audioMasterProcessEvents:
  1847. handleMidiFromPlugin ((const VstEvents*) ptr);
  1848. break;
  1849. case audioMasterGetTime:
  1850. #if JUCE_MSVC
  1851. #pragma warning (push)
  1852. #pragma warning (disable: 4311)
  1853. #endif
  1854. return (VstIntPtr) &vstHostTime;
  1855. #if JUCE_MSVC
  1856. #pragma warning (pop)
  1857. #endif
  1858. break;
  1859. case audioMasterIdle:
  1860. if (insideVSTCallback == 0 && MessageManager::getInstance()->isThisTheMessageThread())
  1861. {
  1862. ++insideVSTCallback;
  1863. #if JUCE_MAC
  1864. if (getActiveEditor() != 0)
  1865. dispatch (effEditIdle, 0, 0, 0, 0);
  1866. #endif
  1867. juce_callAnyTimersSynchronously();
  1868. handleUpdateNowIfNeeded();
  1869. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  1870. ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow();
  1871. --insideVSTCallback;
  1872. }
  1873. break;
  1874. case audioMasterUpdateDisplay:
  1875. triggerAsyncUpdate();
  1876. break;
  1877. case audioMasterTempoAt:
  1878. // returns (10000 * bpm)
  1879. break;
  1880. case audioMasterNeedIdle:
  1881. startTimer (50);
  1882. break;
  1883. case audioMasterSizeWindow:
  1884. if (getActiveEditor() != 0)
  1885. getActiveEditor()->setSize (index, value);
  1886. return 1;
  1887. case audioMasterGetSampleRate:
  1888. return (VstIntPtr) (getSampleRate() > 0 ? getSampleRate() : defaultVSTSampleRateValue);
  1889. case audioMasterGetBlockSize:
  1890. return (VstIntPtr) (getBlockSize() > 0 ? getBlockSize() : defaultVSTBlockSizeValue);
  1891. case audioMasterWantMidi:
  1892. wantsMidiMessages = true;
  1893. break;
  1894. case audioMasterGetDirectory:
  1895. #if JUCE_MAC
  1896. return (VstIntPtr) (void*) &module->parentDirFSSpec;
  1897. #else
  1898. return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toUTF8();
  1899. #endif
  1900. case audioMasterGetAutomationState:
  1901. // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write
  1902. break;
  1903. // none of these are handled (yet)..
  1904. case audioMasterBeginEdit:
  1905. case audioMasterEndEdit:
  1906. case audioMasterSetTime:
  1907. case audioMasterPinConnected:
  1908. case audioMasterGetParameterQuantization:
  1909. case audioMasterIOChanged:
  1910. case audioMasterGetInputLatency:
  1911. case audioMasterGetOutputLatency:
  1912. case audioMasterGetPreviousPlug:
  1913. case audioMasterGetNextPlug:
  1914. case audioMasterWillReplaceOrAccumulate:
  1915. case audioMasterGetCurrentProcessLevel:
  1916. case audioMasterOfflineStart:
  1917. case audioMasterOfflineRead:
  1918. case audioMasterOfflineWrite:
  1919. case audioMasterOfflineGetCurrentPass:
  1920. case audioMasterOfflineGetCurrentMetaPass:
  1921. case audioMasterVendorSpecific:
  1922. case audioMasterSetIcon:
  1923. case audioMasterGetLanguage:
  1924. case audioMasterOpenWindow:
  1925. case audioMasterCloseWindow:
  1926. break;
  1927. default:
  1928. return handleGeneralCallback (opcode, index, value, ptr, opt);
  1929. }
  1930. return 0;
  1931. }
  1932. // entry point for all callbacks from the plugin
  1933. static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt)
  1934. {
  1935. try
  1936. {
  1937. if (effect != 0 && effect->resvd2 != 0)
  1938. {
  1939. return ((VSTPluginInstance*)(effect->resvd2))
  1940. ->handleCallback (opcode, index, value, ptr, opt);
  1941. }
  1942. return handleGeneralCallback (opcode, index, value, ptr, opt);
  1943. }
  1944. catch (...)
  1945. {
  1946. return 0;
  1947. }
  1948. }
  1949. //==============================================================================
  1950. const String VSTPluginInstance::getVersion() const
  1951. {
  1952. unsigned int v = dispatch (effGetVendorVersion, 0, 0, 0, 0);
  1953. String s;
  1954. if (v == 0 || v == -1)
  1955. v = getVersionNumber();
  1956. if (v != 0)
  1957. {
  1958. int versionBits[4];
  1959. int n = 0;
  1960. while (v != 0)
  1961. {
  1962. versionBits [n++] = (v & 0xff);
  1963. v >>= 8;
  1964. }
  1965. s << 'V';
  1966. while (n > 0)
  1967. {
  1968. s << versionBits [--n];
  1969. if (n > 0)
  1970. s << '.';
  1971. }
  1972. }
  1973. return s;
  1974. }
  1975. int VSTPluginInstance::getUID() const
  1976. {
  1977. int uid = effect != 0 ? effect->uniqueID : 0;
  1978. if (uid == 0)
  1979. uid = module->file.hashCode();
  1980. return uid;
  1981. }
  1982. const String VSTPluginInstance::getCategory() const
  1983. {
  1984. const char* result = 0;
  1985. switch (dispatch (effGetPlugCategory, 0, 0, 0, 0))
  1986. {
  1987. case kPlugCategEffect: result = "Effect"; break;
  1988. case kPlugCategSynth: result = "Synth"; break;
  1989. case kPlugCategAnalysis: result = "Anaylsis"; break;
  1990. case kPlugCategMastering: result = "Mastering"; break;
  1991. case kPlugCategSpacializer: result = "Spacial"; break;
  1992. case kPlugCategRoomFx: result = "Reverb"; break;
  1993. case kPlugSurroundFx: result = "Surround"; break;
  1994. case kPlugCategRestoration: result = "Restoration"; break;
  1995. case kPlugCategGenerator: result = "Tone generation"; break;
  1996. default: break;
  1997. }
  1998. return result;
  1999. }
  2000. //==============================================================================
  2001. float VSTPluginInstance::getParameter (int index)
  2002. {
  2003. if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams)
  2004. {
  2005. try
  2006. {
  2007. const ScopedLock sl (lock);
  2008. return effect->getParameter (effect, index);
  2009. }
  2010. catch (...)
  2011. {
  2012. }
  2013. }
  2014. return 0.0f;
  2015. }
  2016. void VSTPluginInstance::setParameter (int index, float newValue)
  2017. {
  2018. if (effect != 0 && ((unsigned int) index) < (unsigned int) effect->numParams)
  2019. {
  2020. try
  2021. {
  2022. const ScopedLock sl (lock);
  2023. if (effect->getParameter (effect, index) != newValue)
  2024. effect->setParameter (effect, index, newValue);
  2025. }
  2026. catch (...)
  2027. {
  2028. }
  2029. }
  2030. }
  2031. const String VSTPluginInstance::getParameterName (int index)
  2032. {
  2033. if (effect != 0)
  2034. {
  2035. jassert (index >= 0 && index < effect->numParams);
  2036. char nm [256];
  2037. zerostruct (nm);
  2038. dispatch (effGetParamName, index, 0, nm, 0);
  2039. return String (nm).trim();
  2040. }
  2041. return String::empty;
  2042. }
  2043. const String VSTPluginInstance::getParameterLabel (int index) const
  2044. {
  2045. if (effect != 0)
  2046. {
  2047. jassert (index >= 0 && index < effect->numParams);
  2048. char nm [256];
  2049. zerostruct (nm);
  2050. dispatch (effGetParamLabel, index, 0, nm, 0);
  2051. return String (nm).trim();
  2052. }
  2053. return String::empty;
  2054. }
  2055. const String VSTPluginInstance::getParameterText (int index)
  2056. {
  2057. if (effect != 0)
  2058. {
  2059. jassert (index >= 0 && index < effect->numParams);
  2060. char nm [256];
  2061. zerostruct (nm);
  2062. dispatch (effGetParamDisplay, index, 0, nm, 0);
  2063. return String (nm).trim();
  2064. }
  2065. return String::empty;
  2066. }
  2067. bool VSTPluginInstance::isParameterAutomatable (int index) const
  2068. {
  2069. if (effect != 0)
  2070. {
  2071. jassert (index >= 0 && index < effect->numParams);
  2072. return dispatch (effCanBeAutomated, index, 0, 0, 0) != 0;
  2073. }
  2074. return false;
  2075. }
  2076. void VSTPluginInstance::createTempParameterStore (MemoryBlock& dest)
  2077. {
  2078. dest.setSize (64 + 4 * getNumParameters());
  2079. dest.fillWith (0);
  2080. getCurrentProgramName().copyToCString ((char*) dest.getData(), 63);
  2081. float* const p = (float*) (((char*) dest.getData()) + 64);
  2082. for (int i = 0; i < getNumParameters(); ++i)
  2083. p[i] = getParameter(i);
  2084. }
  2085. void VSTPluginInstance::restoreFromTempParameterStore (const MemoryBlock& m)
  2086. {
  2087. changeProgramName (getCurrentProgram(), (const char*) m.getData());
  2088. float* p = (float*) (((char*) m.getData()) + 64);
  2089. for (int i = 0; i < getNumParameters(); ++i)
  2090. setParameter (i, p[i]);
  2091. }
  2092. //==============================================================================
  2093. void VSTPluginInstance::setCurrentProgram (int newIndex)
  2094. {
  2095. if (getNumPrograms() > 0 && newIndex != getCurrentProgram())
  2096. dispatch (effSetProgram, 0, jlimit (0, getNumPrograms() - 1, newIndex), 0, 0);
  2097. }
  2098. const String VSTPluginInstance::getProgramName (int index)
  2099. {
  2100. if (index == getCurrentProgram())
  2101. {
  2102. return getCurrentProgramName();
  2103. }
  2104. else if (effect != 0)
  2105. {
  2106. char nm [256];
  2107. zerostruct (nm);
  2108. if (dispatch (effGetProgramNameIndexed,
  2109. jlimit (0, getNumPrograms(), index),
  2110. -1, nm, 0) != 0)
  2111. {
  2112. return String (nm).trim();
  2113. }
  2114. }
  2115. return programNames [index];
  2116. }
  2117. void VSTPluginInstance::changeProgramName (int index, const String& newName)
  2118. {
  2119. if (index == getCurrentProgram())
  2120. {
  2121. if (getNumPrograms() > 0 && newName != getCurrentProgramName())
  2122. dispatch (effSetProgramName, 0, 0, (void*) newName.substring (0, 24).toCString(), 0.0f);
  2123. }
  2124. else
  2125. {
  2126. jassertfalse; // xxx not implemented!
  2127. }
  2128. }
  2129. void VSTPluginInstance::updateStoredProgramNames()
  2130. {
  2131. if (effect != 0 && getNumPrograms() > 0)
  2132. {
  2133. char nm [256];
  2134. zerostruct (nm);
  2135. // only do this if the plugin can't use indexed names..
  2136. if (dispatch (effGetProgramNameIndexed, 0, -1, nm, 0) == 0)
  2137. {
  2138. const int oldProgram = getCurrentProgram();
  2139. MemoryBlock oldSettings;
  2140. createTempParameterStore (oldSettings);
  2141. for (int i = 0; i < getNumPrograms(); ++i)
  2142. {
  2143. setCurrentProgram (i);
  2144. getCurrentProgramName(); // (this updates the list)
  2145. }
  2146. setCurrentProgram (oldProgram);
  2147. restoreFromTempParameterStore (oldSettings);
  2148. }
  2149. }
  2150. }
  2151. const String VSTPluginInstance::getCurrentProgramName()
  2152. {
  2153. if (effect != 0)
  2154. {
  2155. char nm [256];
  2156. zerostruct (nm);
  2157. dispatch (effGetProgramName, 0, 0, nm, 0);
  2158. const int index = getCurrentProgram();
  2159. if (programNames[index].isEmpty())
  2160. {
  2161. while (programNames.size() < index)
  2162. programNames.add (String::empty);
  2163. programNames.set (index, String (nm).trim());
  2164. }
  2165. return String (nm).trim();
  2166. }
  2167. return String::empty;
  2168. }
  2169. //==============================================================================
  2170. const String VSTPluginInstance::getInputChannelName (int index) const
  2171. {
  2172. if (index >= 0 && index < getNumInputChannels())
  2173. {
  2174. VstPinProperties pinProps;
  2175. if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0)
  2176. return String (pinProps.label, sizeof (pinProps.label));
  2177. }
  2178. return String::empty;
  2179. }
  2180. bool VSTPluginInstance::isInputChannelStereoPair (int index) const
  2181. {
  2182. if (index < 0 || index >= getNumInputChannels())
  2183. return false;
  2184. VstPinProperties pinProps;
  2185. if (dispatch (effGetInputProperties, index, 0, &pinProps, 0.0f) != 0)
  2186. return (pinProps.flags & kVstPinIsStereo) != 0;
  2187. return true;
  2188. }
  2189. const String VSTPluginInstance::getOutputChannelName (int index) const
  2190. {
  2191. if (index >= 0 && index < getNumOutputChannels())
  2192. {
  2193. VstPinProperties pinProps;
  2194. if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0)
  2195. return String (pinProps.label, sizeof (pinProps.label));
  2196. }
  2197. return String::empty;
  2198. }
  2199. bool VSTPluginInstance::isOutputChannelStereoPair (int index) const
  2200. {
  2201. if (index < 0 || index >= getNumOutputChannels())
  2202. return false;
  2203. VstPinProperties pinProps;
  2204. if (dispatch (effGetOutputProperties, index, 0, &pinProps, 0.0f) != 0)
  2205. return (pinProps.flags & kVstPinIsStereo) != 0;
  2206. return true;
  2207. }
  2208. //==============================================================================
  2209. void VSTPluginInstance::setPower (const bool on)
  2210. {
  2211. dispatch (effMainsChanged, 0, on ? 1 : 0, 0, 0);
  2212. isPowerOn = on;
  2213. }
  2214. //==============================================================================
  2215. const int defaultMaxSizeMB = 64;
  2216. void VSTPluginInstance::getStateInformation (MemoryBlock& destData)
  2217. {
  2218. saveToFXBFile (destData, true, defaultMaxSizeMB);
  2219. }
  2220. void VSTPluginInstance::getCurrentProgramStateInformation (MemoryBlock& destData)
  2221. {
  2222. saveToFXBFile (destData, false, defaultMaxSizeMB);
  2223. }
  2224. void VSTPluginInstance::setStateInformation (const void* data, int sizeInBytes)
  2225. {
  2226. loadFromFXBFile (data, sizeInBytes);
  2227. }
  2228. void VSTPluginInstance::setCurrentProgramStateInformation (const void* data, int sizeInBytes)
  2229. {
  2230. loadFromFXBFile (data, sizeInBytes);
  2231. }
  2232. //==============================================================================
  2233. //==============================================================================
  2234. VSTPluginFormat::VSTPluginFormat()
  2235. {
  2236. }
  2237. VSTPluginFormat::~VSTPluginFormat()
  2238. {
  2239. }
  2240. void VSTPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results,
  2241. const String& fileOrIdentifier)
  2242. {
  2243. if (! fileMightContainThisPluginType (fileOrIdentifier))
  2244. return;
  2245. PluginDescription desc;
  2246. desc.fileOrIdentifier = fileOrIdentifier;
  2247. desc.uid = 0;
  2248. ScopedPointer <VSTPluginInstance> instance (dynamic_cast <VSTPluginInstance*> (createInstanceFromDescription (desc)));
  2249. if (instance == 0)
  2250. return;
  2251. try
  2252. {
  2253. #if JUCE_MAC
  2254. if (instance->module->resFileId != 0)
  2255. UseResFile (instance->module->resFileId);
  2256. #endif
  2257. instance->fillInPluginDescription (desc);
  2258. VstPlugCategory category = (VstPlugCategory) instance->dispatch (effGetPlugCategory, 0, 0, 0, 0);
  2259. if (category != kPlugCategShell)
  2260. {
  2261. // Normal plugin...
  2262. results.add (new PluginDescription (desc));
  2263. ++insideVSTCallback;
  2264. instance->dispatch (effOpen, 0, 0, 0, 0);
  2265. --insideVSTCallback;
  2266. }
  2267. else
  2268. {
  2269. // It's a shell plugin, so iterate all the subtypes...
  2270. char shellEffectName [64];
  2271. for (;;)
  2272. {
  2273. zerostruct (shellEffectName);
  2274. const int uid = instance->dispatch (effShellGetNextPlugin, 0, 0, shellEffectName, 0);
  2275. if (uid == 0)
  2276. {
  2277. break;
  2278. }
  2279. else
  2280. {
  2281. desc.uid = uid;
  2282. desc.name = shellEffectName;
  2283. bool alreadyThere = false;
  2284. for (int i = results.size(); --i >= 0;)
  2285. {
  2286. PluginDescription* const d = results.getUnchecked(i);
  2287. if (d->isDuplicateOf (desc))
  2288. {
  2289. alreadyThere = true;
  2290. break;
  2291. }
  2292. }
  2293. if (! alreadyThere)
  2294. results.add (new PluginDescription (desc));
  2295. }
  2296. }
  2297. }
  2298. }
  2299. catch (...)
  2300. {
  2301. // crashed while loading...
  2302. }
  2303. }
  2304. AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const PluginDescription& desc)
  2305. {
  2306. ScopedPointer <VSTPluginInstance> result;
  2307. if (fileMightContainThisPluginType (desc.fileOrIdentifier))
  2308. {
  2309. File file (desc.fileOrIdentifier);
  2310. const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
  2311. file.getParentDirectory().setAsCurrentWorkingDirectory();
  2312. const ReferenceCountedObjectPtr <ModuleHandle> module (ModuleHandle::findOrCreateModule (file));
  2313. if (module != 0)
  2314. {
  2315. shellUIDToCreate = desc.uid;
  2316. result = new VSTPluginInstance (module);
  2317. if (result->effect != 0)
  2318. {
  2319. result->effect->resvd2 = (VstIntPtr) (pointer_sized_int) (VSTPluginInstance*) result;
  2320. result->initialise();
  2321. }
  2322. else
  2323. {
  2324. result = 0;
  2325. }
  2326. }
  2327. previousWorkingDirectory.setAsCurrentWorkingDirectory();
  2328. }
  2329. return result.release();
  2330. }
  2331. bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier)
  2332. {
  2333. const File f (fileOrIdentifier);
  2334. #if JUCE_MAC
  2335. if (f.isDirectory() && f.hasFileExtension (".vst"))
  2336. return true;
  2337. #if JUCE_PPC
  2338. FSRef fileRef;
  2339. if (PlatformUtilities::makeFSRefFromPath (&fileRef, f.getFullPathName()))
  2340. {
  2341. const short resFileId = FSOpenResFile (&fileRef, fsRdPerm);
  2342. if (resFileId != -1)
  2343. {
  2344. const int numEffects = Count1Resources ('aEff');
  2345. CloseResFile (resFileId);
  2346. if (numEffects > 0)
  2347. return true;
  2348. }
  2349. }
  2350. #endif
  2351. return false;
  2352. #elif JUCE_WINDOWS
  2353. return f.existsAsFile() && f.hasFileExtension (".dll");
  2354. #elif JUCE_LINUX
  2355. return f.existsAsFile() && f.hasFileExtension (".so");
  2356. #endif
  2357. }
  2358. const String VSTPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier)
  2359. {
  2360. return fileOrIdentifier;
  2361. }
  2362. bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc)
  2363. {
  2364. return File (desc.fileOrIdentifier).exists();
  2365. }
  2366. const StringArray VSTPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive)
  2367. {
  2368. StringArray results;
  2369. for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j)
  2370. recursiveFileSearch (results, directoriesToSearch [j], recursive);
  2371. return results;
  2372. }
  2373. void VSTPluginFormat::recursiveFileSearch (StringArray& results, const File& dir, const bool recursive)
  2374. {
  2375. // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside
  2376. // .component or .vst directories.
  2377. DirectoryIterator iter (dir, false, "*", File::findFilesAndDirectories);
  2378. while (iter.next())
  2379. {
  2380. const File f (iter.getFile());
  2381. bool isPlugin = false;
  2382. if (fileMightContainThisPluginType (f.getFullPathName()))
  2383. {
  2384. isPlugin = true;
  2385. results.add (f.getFullPathName());
  2386. }
  2387. if (recursive && (! isPlugin) && f.isDirectory())
  2388. recursiveFileSearch (results, f, true);
  2389. }
  2390. }
  2391. const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch()
  2392. {
  2393. #if JUCE_MAC
  2394. return FileSearchPath ("~/Library/Audio/Plug-Ins/VST;/Library/Audio/Plug-Ins/VST");
  2395. #elif JUCE_WINDOWS
  2396. const String programFiles (File::getSpecialLocation (File::globalApplicationsDirectory).getFullPathName());
  2397. return FileSearchPath (programFiles + "\\Steinberg\\VstPlugins");
  2398. #elif JUCE_LINUX
  2399. return FileSearchPath ("/usr/lib/vst");
  2400. #endif
  2401. }
  2402. END_JUCE_NAMESPACE
  2403. #endif
  2404. #undef log
  2405. #endif