DISTRHO Plugin Framework
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.

DistrhoPluginVST.cpp 44KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
5 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoPluginInternal.hpp"
  17. #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
  18. # undef DISTRHO_PLUGIN_HAS_UI
  19. # define DISTRHO_PLUGIN_HAS_UI 0
  20. #endif
  21. #if DISTRHO_PLUGIN_HAS_UI
  22. # include "DistrhoUIInternal.hpp"
  23. #endif
  24. #ifndef __cdecl
  25. # define __cdecl
  26. #endif
  27. #define VESTIGE_HEADER
  28. #define VST_FORCE_DEPRECATED 0
  29. #include <clocale>
  30. #include <map>
  31. #include <string>
  32. #ifdef VESTIGE_HEADER
  33. # include "vestige/vestige.h"
  34. #define effFlagsProgramChunks (1 << 5)
  35. #define effSetProgramName 4
  36. #define effGetParamLabel 6
  37. #define effGetParamDisplay 7
  38. #define effGetChunk 23
  39. #define effSetChunk 24
  40. #define effCanBeAutomated 26
  41. #define effGetProgramNameIndexed 29
  42. #define effGetPlugCategory 35
  43. #define effEditKeyDown 59
  44. #define effEditKeyUp 60
  45. #define kVstVersion 2400
  46. struct ERect {
  47. int16_t top, left, bottom, right;
  48. };
  49. #else
  50. # include "vst/aeffectx.h"
  51. #endif
  52. START_NAMESPACE_DISTRHO
  53. typedef std::map<const String, String> StringMap;
  54. static const int kVstMidiEventSize = static_cast<int>(sizeof(VstMidiEvent));
  55. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  56. static const writeMidiFunc writeMidiCallback = nullptr;
  57. #endif
  58. // -----------------------------------------------------------------------
  59. void strncpy(char* const dst, const char* const src, const size_t size)
  60. {
  61. std::strncpy(dst, src, size-1);
  62. dst[size-1] = '\0';
  63. }
  64. void snprintf_param(char* const dst, const float value, const size_t size)
  65. {
  66. std::snprintf(dst, size-1, "%f", value);
  67. dst[size-1] = '\0';
  68. }
  69. void snprintf_iparam(char* const dst, const int32_t value, const size_t size)
  70. {
  71. std::snprintf(dst, size-1, "%d", value);
  72. dst[size-1] = '\0';
  73. }
  74. // -----------------------------------------------------------------------
  75. class ScopedSafeLocale {
  76. public:
  77. ScopedSafeLocale() noexcept
  78. : locale(::strdup(::setlocale(LC_NUMERIC, nullptr)))
  79. {
  80. ::setlocale(LC_NUMERIC, "C");
  81. }
  82. ~ScopedSafeLocale() noexcept
  83. {
  84. if (locale != nullptr)
  85. {
  86. ::setlocale(LC_NUMERIC, locale);
  87. std::free(locale);
  88. }
  89. }
  90. private:
  91. char* const locale;
  92. DISTRHO_DECLARE_NON_COPY_CLASS(ScopedSafeLocale)
  93. DISTRHO_PREVENT_HEAP_ALLOCATION
  94. };
  95. // -----------------------------------------------------------------------
  96. class ParameterCheckHelper
  97. {
  98. public:
  99. ParameterCheckHelper()
  100. : parameterChecks(nullptr),
  101. parameterValues(nullptr) {}
  102. virtual ~ParameterCheckHelper()
  103. {
  104. if (parameterChecks != nullptr)
  105. {
  106. delete[] parameterChecks;
  107. parameterChecks = nullptr;
  108. }
  109. if (parameterValues != nullptr)
  110. {
  111. delete[] parameterValues;
  112. parameterValues = nullptr;
  113. }
  114. }
  115. bool* parameterChecks;
  116. float* parameterValues;
  117. #if DISTRHO_PLUGIN_WANT_STATE
  118. virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0;
  119. #endif
  120. };
  121. #if DISTRHO_PLUGIN_HAS_UI
  122. // -----------------------------------------------------------------------
  123. class UIVst
  124. {
  125. public:
  126. UIVst(const audioMasterCallback audioMaster, AEffect* const effect, ParameterCheckHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId)
  127. : fAudioMaster(audioMaster),
  128. fEffect(effect),
  129. fUiHelper(uiHelper),
  130. fPlugin(plugin),
  131. fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer()),
  132. fShouldCaptureVstKeys(false)
  133. {
  134. // FIXME only needed for windows?
  135. //#ifdef DISTRHO_OS_WINDOWS
  136. char strBuf[0xff+1];
  137. std::memset(strBuf, 0, sizeof(char)*(0xff+1));
  138. hostCallback(audioMasterGetProductString, 0, 0, strBuf);
  139. d_stdout("Plugin UI running in '%s'", strBuf);
  140. // TODO make a white-list of needed hosts
  141. if (/*std::strcmp(strBuf, "") == 0*/ true)
  142. fShouldCaptureVstKeys = true;
  143. //#endif
  144. }
  145. // -------------------------------------------------------------------
  146. void idle()
  147. {
  148. for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
  149. {
  150. if (fUiHelper->parameterChecks[i])
  151. {
  152. fUiHelper->parameterChecks[i] = false;
  153. fUI.parameterChanged(i, fUiHelper->parameterValues[i]);
  154. }
  155. }
  156. fUI.idle();
  157. }
  158. int16_t getWidth() const
  159. {
  160. return fUI.getWidth();
  161. }
  162. int16_t getHeight() const
  163. {
  164. return fUI.getHeight();
  165. }
  166. void setSampleRate(const double newSampleRate)
  167. {
  168. fUI.setSampleRate(newSampleRate, true);
  169. }
  170. // -------------------------------------------------------------------
  171. // functions called from the plugin side, may block
  172. # if DISTRHO_PLUGIN_WANT_STATE
  173. void setStateFromPlugin(const char* const key, const char* const value)
  174. {
  175. fUI.stateChanged(key, value);
  176. }
  177. # endif
  178. int handlePluginKeyEvent(const bool down, int32_t index, const intptr_t value)
  179. {
  180. # if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  181. if (! fShouldCaptureVstKeys)
  182. return 0;
  183. d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value);
  184. int special = 0;
  185. switch (value)
  186. {
  187. // convert some specials to normal keys
  188. case 1: index = kCharBackspace; break;
  189. case 6: index = kCharEscape; break;
  190. case 7: index = ' '; break;
  191. case 22: index = kCharDelete; break;
  192. // handle rest of special keys
  193. case 40: special = kKeyF1; break;
  194. case 41: special = kKeyF2; break;
  195. case 42: special = kKeyF3; break;
  196. case 43: special = kKeyF4; break;
  197. case 44: special = kKeyF5; break;
  198. case 45: special = kKeyF6; break;
  199. case 46: special = kKeyF7; break;
  200. case 47: special = kKeyF8; break;
  201. case 48: special = kKeyF9; break;
  202. case 49: special = kKeyF10; break;
  203. case 50: special = kKeyF11; break;
  204. case 51: special = kKeyF12; break;
  205. case 11: special = kKeyLeft; break;
  206. case 12: special = kKeyUp; break;
  207. case 13: special = kKeyRight; break;
  208. case 14: special = kKeyDown; break;
  209. case 15: special = kKeyPageUp; break;
  210. case 16: special = kKeyPageDown; break;
  211. case 10: special = kKeyHome; break;
  212. case 9: special = kKeyEnd; break;
  213. case 21: special = kKeyInsert; break;
  214. case 54: special = kKeyShift; break;
  215. case 55: special = kKeyControl; break;
  216. case 56: special = kKeyAlt; break;
  217. }
  218. if (special != 0)
  219. return fUI.handlePluginSpecial(down, static_cast<Key>(special));
  220. if (index >= 0)
  221. return fUI.handlePluginKeyboard(down, static_cast<uint>(index));
  222. # endif
  223. return 0;
  224. }
  225. // -------------------------------------------------------------------
  226. protected:
  227. intptr_t hostCallback(const int32_t opcode,
  228. const int32_t index = 0,
  229. const intptr_t value = 0,
  230. void* const ptr = nullptr,
  231. const float opt = 0.0f)
  232. {
  233. return fAudioMaster(fEffect, opcode, index, value, ptr, opt);
  234. }
  235. void editParameter(const uint32_t index, const bool started)
  236. {
  237. hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index);
  238. }
  239. void setParameterValue(const uint32_t index, const float realValue)
  240. {
  241. const ParameterRanges& ranges(fPlugin->getParameterRanges(index));
  242. const float perValue(ranges.getNormalizedValue(realValue));
  243. fPlugin->setParameterValue(index, realValue);
  244. hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
  245. }
  246. void setState(const char* const key, const char* const value)
  247. {
  248. # if DISTRHO_PLUGIN_WANT_STATE
  249. fUiHelper->setStateFromUI(key, value);
  250. # else
  251. return; // unused
  252. (void)key;
  253. (void)value;
  254. # endif
  255. }
  256. void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
  257. {
  258. # if 0 //DISTRHO_PLUGIN_WANT_MIDI_INPUT
  259. // TODO
  260. # else
  261. return; // unused
  262. (void)channel;
  263. (void)note;
  264. (void)velocity;
  265. # endif
  266. }
  267. void setSize(const uint width, const uint height)
  268. {
  269. fUI.setWindowSize(width, height);
  270. hostCallback(audioMasterSizeWindow, width, height);
  271. }
  272. private:
  273. // Vst stuff
  274. const audioMasterCallback fAudioMaster;
  275. AEffect* const fEffect;
  276. ParameterCheckHelper* const fUiHelper;
  277. PluginExporter* const fPlugin;
  278. // Plugin UI
  279. UIExporter fUI;
  280. bool fShouldCaptureVstKeys;
  281. // -------------------------------------------------------------------
  282. // Callbacks
  283. #define handlePtr ((UIVst*)ptr)
  284. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  285. {
  286. handlePtr->editParameter(index, started);
  287. }
  288. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  289. {
  290. handlePtr->setParameterValue(rindex, value);
  291. }
  292. static void setStateCallback(void* ptr, const char* key, const char* value)
  293. {
  294. handlePtr->setState(key, value);
  295. }
  296. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  297. {
  298. handlePtr->sendNote(channel, note, velocity);
  299. }
  300. static void setSizeCallback(void* ptr, uint width, uint height)
  301. {
  302. handlePtr->setSize(width, height);
  303. }
  304. #undef handlePtr
  305. };
  306. #endif
  307. // -----------------------------------------------------------------------
  308. class PluginVst : public ParameterCheckHelper
  309. {
  310. public:
  311. PluginVst(const audioMasterCallback audioMaster, AEffect* const effect)
  312. : fPlugin(this, writeMidiCallback),
  313. fAudioMaster(audioMaster),
  314. fEffect(effect)
  315. {
  316. std::memset(fProgramName, 0, sizeof(char)*(32+1));
  317. std::strcpy(fProgramName, "Default");
  318. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  319. fMidiEventCount = 0;
  320. #endif
  321. #if DISTRHO_PLUGIN_HAS_UI
  322. fVstUI = nullptr;
  323. fVstRect.top = 0;
  324. fVstRect.left = 0;
  325. fVstRect.bottom = 0;
  326. fVstRect.right = 0;
  327. if (const uint32_t paramCount = fPlugin.getParameterCount())
  328. {
  329. parameterChecks = new bool[paramCount];
  330. parameterValues = new float[paramCount];
  331. for (uint32_t i=0; i < paramCount; ++i)
  332. {
  333. parameterChecks[i] = false;
  334. parameterValues[i] = NAN;
  335. }
  336. }
  337. # if DISTRHO_OS_MAC
  338. # ifdef __LP64__
  339. fUsingNsView = true;
  340. # else
  341. # ifndef DISTRHO_NO_WARNINGS
  342. # warning 32bit VST UIs on OSX only work if the host supports "hasCockosViewAsConfig"
  343. # endif
  344. fUsingNsView = false;
  345. # endif
  346. # endif // DISTRHO_OS_MAC
  347. #endif // DISTRHO_PLUGIN_HAS_UI
  348. #if DISTRHO_PLUGIN_WANT_STATE
  349. fStateChunk = nullptr;
  350. for (uint32_t i=0, count=fPlugin.getStateCount(); i<count; ++i)
  351. {
  352. const String& dkey(fPlugin.getStateKey(i));
  353. fStateMap[dkey] = fPlugin.getStateDefaultValue(i);
  354. }
  355. #endif
  356. }
  357. ~PluginVst()
  358. {
  359. #if DISTRHO_PLUGIN_WANT_STATE
  360. if (fStateChunk != nullptr)
  361. {
  362. delete[] fStateChunk;
  363. fStateChunk = nullptr;
  364. }
  365. fStateMap.clear();
  366. #endif
  367. }
  368. intptr_t vst_dispatcher(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  369. {
  370. #if DISTRHO_PLUGIN_WANT_STATE
  371. intptr_t ret = 0;
  372. #endif
  373. switch (opcode)
  374. {
  375. case effGetProgram:
  376. return 0;
  377. case effSetProgramName:
  378. if (char* const programName = (char*)ptr)
  379. {
  380. DISTRHO_NAMESPACE::strncpy(fProgramName, programName, 32);
  381. return 1;
  382. }
  383. break;
  384. case effGetProgramName:
  385. if (char* const programName = (char*)ptr)
  386. {
  387. DISTRHO_NAMESPACE::strncpy(programName, fProgramName, 24);
  388. return 1;
  389. }
  390. break;
  391. case effGetProgramNameIndexed:
  392. if (char* const programName = (char*)ptr)
  393. {
  394. DISTRHO_NAMESPACE::strncpy(programName, fProgramName, 24);
  395. return 1;
  396. }
  397. break;
  398. case effGetParamDisplay:
  399. if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.getParameterCount()))
  400. {
  401. const uint32_t hints = fPlugin.getParameterHints(index);
  402. float value = fPlugin.getParameterValue(index);
  403. if (hints & kParameterIsBoolean)
  404. {
  405. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  406. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  407. value = value > midRange ? ranges.max : ranges.min;
  408. }
  409. else if (hints & kParameterIsInteger)
  410. {
  411. value = std::round(value);
  412. }
  413. const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index));
  414. for (uint8_t i = 0; i < enumValues.count; ++i)
  415. {
  416. if (d_isNotEqual(value, enumValues.values[i].value))
  417. continue;
  418. DISTRHO_NAMESPACE::strncpy((char*)ptr, enumValues.values[i].label.buffer(), 24);
  419. return 1;
  420. }
  421. if (hints & kParameterIsInteger)
  422. DISTRHO_NAMESPACE::snprintf_iparam((char*)ptr, (int32_t)value, 24);
  423. else
  424. DISTRHO_NAMESPACE::snprintf_param((char*)ptr, value, 24);
  425. return 1;
  426. }
  427. break;
  428. case effSetSampleRate:
  429. fPlugin.setSampleRate(opt, true);
  430. #if DISTRHO_PLUGIN_HAS_UI
  431. if (fVstUI != nullptr)
  432. fVstUI->setSampleRate(opt);
  433. #endif
  434. break;
  435. case effSetBlockSize:
  436. fPlugin.setBufferSize(value, true);
  437. break;
  438. case effMainsChanged:
  439. if (value != 0)
  440. {
  441. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  442. fMidiEventCount = 0;
  443. // tell host we want MIDI events
  444. hostCallback(audioMasterWantMidi);
  445. #endif
  446. // deactivate for possible changes
  447. fPlugin.deactivateIfNeeded();
  448. // check if something changed
  449. const uint32_t bufferSize = static_cast<uint32_t>(hostCallback(audioMasterGetBlockSize));
  450. const double sampleRate = static_cast<double>(hostCallback(audioMasterGetSampleRate));
  451. if (bufferSize != 0)
  452. fPlugin.setBufferSize(bufferSize, true);
  453. if (sampleRate != 0.0)
  454. fPlugin.setSampleRate(sampleRate, true);
  455. fPlugin.activate();
  456. }
  457. else
  458. {
  459. fPlugin.deactivate();
  460. }
  461. break;
  462. #if DISTRHO_PLUGIN_HAS_UI
  463. case effEditGetRect:
  464. if (fVstUI != nullptr)
  465. {
  466. fVstRect.right = fVstUI->getWidth();
  467. fVstRect.bottom = fVstUI->getHeight();
  468. }
  469. else
  470. {
  471. d_lastUiSampleRate = fPlugin.getSampleRate();
  472. UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, fPlugin.getInstancePointer());
  473. fVstRect.right = tmpUI.getWidth();
  474. fVstRect.bottom = tmpUI.getHeight();
  475. tmpUI.quit();
  476. }
  477. *(ERect**)ptr = &fVstRect;
  478. return 1;
  479. case effEditOpen:
  480. if (fVstUI == nullptr)
  481. {
  482. # if DISTRHO_OS_MAC
  483. if (! fUsingNsView)
  484. {
  485. d_stderr("Host doesn't support hasCockosViewAsConfig, cannot use UI");
  486. return 0;
  487. }
  488. # endif
  489. d_lastUiSampleRate = fPlugin.getSampleRate();
  490. fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr);
  491. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  492. // Update current state from plugin side
  493. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  494. {
  495. const String& key = cit->first;
  496. fStateMap[key] = fPlugin.getState(key);
  497. }
  498. # endif
  499. # if DISTRHO_PLUGIN_WANT_STATE
  500. // Set state
  501. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  502. {
  503. const String& key = cit->first;
  504. const String& value = cit->second;
  505. fVstUI->setStateFromPlugin(key, value);
  506. }
  507. # endif
  508. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  509. setParameterValueFromPlugin(i, fPlugin.getParameterValue(i));
  510. fVstUI->idle();
  511. return 1;
  512. }
  513. break;
  514. case effEditClose:
  515. if (fVstUI != nullptr)
  516. {
  517. delete fVstUI;
  518. fVstUI = nullptr;
  519. return 1;
  520. }
  521. break;
  522. //case effIdle:
  523. case effEditIdle:
  524. if (fVstUI != nullptr)
  525. fVstUI->idle();
  526. break;
  527. case effEditKeyDown:
  528. if (fVstUI != nullptr)
  529. return fVstUI->handlePluginKeyEvent(true, index, value);
  530. break;
  531. case effEditKeyUp:
  532. if (fVstUI != nullptr)
  533. return fVstUI->handlePluginKeyEvent(false, index, value);
  534. break;
  535. #endif // DISTRHO_PLUGIN_HAS_UI
  536. #if DISTRHO_PLUGIN_WANT_STATE
  537. case effGetChunk:
  538. {
  539. if (ptr == nullptr)
  540. return 0;
  541. if (fStateChunk != nullptr)
  542. {
  543. delete[] fStateChunk;
  544. fStateChunk = nullptr;
  545. }
  546. const uint32_t paramCount = fPlugin.getParameterCount();
  547. if (fPlugin.getStateCount() == 0 && paramCount == 0)
  548. {
  549. fStateChunk = new char[1];
  550. fStateChunk[0] = '\0';
  551. ret = 1;
  552. }
  553. else
  554. {
  555. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  556. // Update current state
  557. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  558. {
  559. const String& key = cit->first;
  560. fStateMap[key] = fPlugin.getState(key);
  561. }
  562. # endif
  563. String chunkStr;
  564. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  565. {
  566. const String& key = cit->first;
  567. const String& value = cit->second;
  568. // join key and value
  569. String tmpStr;
  570. tmpStr = key;
  571. tmpStr += "\xff";
  572. tmpStr += value;
  573. tmpStr += "\xff";
  574. chunkStr += tmpStr;
  575. }
  576. if (paramCount != 0)
  577. {
  578. // add another separator
  579. chunkStr += "\xff";
  580. // temporarily set locale to "C" while converting floats
  581. const ScopedSafeLocale ssl;
  582. for (uint32_t i=0; i<paramCount; ++i)
  583. {
  584. if (fPlugin.isParameterOutputOrTrigger(i))
  585. continue;
  586. // join key and value
  587. String tmpStr;
  588. tmpStr = fPlugin.getParameterSymbol(i);
  589. tmpStr += "\xff";
  590. tmpStr += String(fPlugin.getParameterValue(i));
  591. tmpStr += "\xff";
  592. chunkStr += tmpStr;
  593. }
  594. }
  595. const std::size_t chunkSize(chunkStr.length()+1);
  596. fStateChunk = new char[chunkSize];
  597. std::memcpy(fStateChunk, chunkStr.buffer(), chunkStr.length());
  598. fStateChunk[chunkSize-1] = '\0';
  599. for (std::size_t i=0; i<chunkSize; ++i)
  600. {
  601. if (fStateChunk[i] == '\xff')
  602. fStateChunk[i] = '\0';
  603. }
  604. ret = chunkSize;
  605. }
  606. *(void**)ptr = fStateChunk;
  607. return ret;
  608. }
  609. case effSetChunk:
  610. {
  611. if (value <= 1 || ptr == nullptr)
  612. return 0;
  613. const size_t chunkSize = static_cast<size_t>(value);
  614. const char* key = (const char*)ptr;
  615. const char* value = nullptr;
  616. size_t size, bytesRead = 0;
  617. while (bytesRead < chunkSize)
  618. {
  619. if (key[0] == '\0')
  620. break;
  621. size = std::strlen(key)+1;
  622. value = key + size;
  623. bytesRead += size;
  624. setStateFromUI(key, value);
  625. # if DISTRHO_PLUGIN_HAS_UI
  626. if (fVstUI != nullptr)
  627. fVstUI->setStateFromPlugin(key, value);
  628. # endif
  629. // get next key
  630. size = std::strlen(value)+1;
  631. key = value + size;
  632. bytesRead += size;
  633. }
  634. const uint32_t paramCount = fPlugin.getParameterCount();
  635. if (bytesRead+4 < chunkSize && paramCount != 0)
  636. {
  637. ++key;
  638. float fvalue;
  639. // temporarily set locale to "C" while converting floats
  640. const ScopedSafeLocale ssl;
  641. while (bytesRead < chunkSize)
  642. {
  643. if (key[0] == '\0')
  644. break;
  645. size = std::strlen(key)+1;
  646. value = key + size;
  647. bytesRead += size;
  648. // find parameter with this symbol, and set its value
  649. for (uint32_t i=0; i<paramCount; ++i)
  650. {
  651. if (fPlugin.isParameterOutputOrTrigger(i))
  652. continue;
  653. if (fPlugin.getParameterSymbol(i) != key)
  654. continue;
  655. fvalue = std::atof(value);
  656. fPlugin.setParameterValue(i, fvalue);
  657. # if DISTRHO_PLUGIN_HAS_UI
  658. if (fVstUI != nullptr)
  659. setParameterValueFromPlugin(i, fvalue);
  660. # endif
  661. break;
  662. }
  663. // get next key
  664. size = std::strlen(value)+1;
  665. key = value + size;
  666. bytesRead += size;
  667. }
  668. }
  669. return 1;
  670. }
  671. #endif // DISTRHO_PLUGIN_WANT_STATE
  672. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  673. case effProcessEvents:
  674. if (! fPlugin.isActive())
  675. {
  676. // host has not activated the plugin yet, nasty!
  677. vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f);
  678. }
  679. if (const VstEvents* const events = (const VstEvents*)ptr)
  680. {
  681. if (events->numEvents == 0)
  682. break;
  683. for (int i=0, count=events->numEvents; i < count; ++i)
  684. {
  685. const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]);
  686. if (vstMidiEvent == nullptr)
  687. break;
  688. if (vstMidiEvent->type != kVstMidiType)
  689. continue;
  690. if (fMidiEventCount >= kMaxMidiEvents)
  691. break;
  692. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  693. midiEvent.frame = vstMidiEvent->deltaFrames;
  694. midiEvent.size = 3;
  695. std::memcpy(midiEvent.data, vstMidiEvent->midiData, sizeof(uint8_t)*3);
  696. }
  697. }
  698. break;
  699. #endif
  700. case effCanBeAutomated:
  701. if (index < static_cast<int32_t>(fPlugin.getParameterCount()))
  702. {
  703. const uint32_t hints(fPlugin.getParameterHints(index));
  704. // must be automable, and not output
  705. if ((hints & kParameterIsAutomable) != 0 && (hints & kParameterIsOutput) == 0)
  706. return 1;
  707. }
  708. break;
  709. case effCanDo:
  710. if (const char* const canDo = (const char*)ptr)
  711. {
  712. #if DISTRHO_OS_MAC && DISTRHO_PLUGIN_HAS_UI
  713. if (std::strcmp(canDo, "hasCockosViewAsConfig") == 0)
  714. {
  715. fUsingNsView = true;
  716. return 0xbeef0000;
  717. }
  718. #endif
  719. if (std::strcmp(canDo, "receiveVstEvents") == 0 ||
  720. std::strcmp(canDo, "receiveVstMidiEvent") == 0)
  721. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  722. return 1;
  723. #else
  724. return -1;
  725. #endif
  726. if (std::strcmp(canDo, "sendVstEvents") == 0 ||
  727. std::strcmp(canDo, "sendVstMidiEvent") == 0)
  728. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  729. return 1;
  730. #else
  731. return -1;
  732. #endif
  733. if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
  734. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  735. return 1;
  736. #else
  737. return -1;
  738. #endif
  739. }
  740. break;
  741. //case effStartProcess:
  742. //case effStopProcess:
  743. // unused
  744. // break;
  745. }
  746. return 0;
  747. }
  748. float vst_getParameter(const int32_t index)
  749. {
  750. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  751. return ranges.getNormalizedValue(fPlugin.getParameterValue(index));
  752. }
  753. void vst_setParameter(const int32_t index, float value)
  754. {
  755. const uint32_t hints(fPlugin.getParameterHints(index));
  756. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  757. if (hints & kParameterIsBoolean)
  758. {
  759. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  760. value = value > midRange ? ranges.max : ranges.min;
  761. }
  762. else if (hints & kParameterIsInteger)
  763. {
  764. value = std::round(value);
  765. }
  766. const float realValue(ranges.getUnnormalizedValue(value));
  767. fPlugin.setParameterValue(index, realValue);
  768. #if DISTRHO_PLUGIN_HAS_UI
  769. if (fVstUI != nullptr)
  770. setParameterValueFromPlugin(index, realValue);
  771. #endif
  772. }
  773. void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames)
  774. {
  775. if (sampleFrames <= 0)
  776. {
  777. updateParameterOutputsAndTriggers();
  778. return;
  779. }
  780. if (! fPlugin.isActive())
  781. {
  782. // host has not activated the plugin yet, nasty!
  783. vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f);
  784. }
  785. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  786. static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid);
  787. if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(audioMasterGetTime, 0, kWantVstTimeFlags))
  788. {
  789. fTimePosition.frame = vstTimeInfo->samplePos;
  790. fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying);
  791. fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0);
  792. // ticksPerBeat is not possible with VST
  793. fTimePosition.bbt.ticksPerBeat = 960.0;
  794. if (vstTimeInfo->flags & kVstTempoValid)
  795. fTimePosition.bbt.beatsPerMinute = vstTimeInfo->tempo;
  796. else
  797. fTimePosition.bbt.beatsPerMinute = 120.0;
  798. if (vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid))
  799. {
  800. const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator;
  801. const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigDenominator;
  802. const double rest = std::fmod(barBeats, 1.0);
  803. fTimePosition.bbt.bar = int(vstTimeInfo->ppqPos)/ppqPerBar + 1;
  804. fTimePosition.bbt.beat = barBeats-rest+1;
  805. fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5;
  806. fTimePosition.bbt.beatsPerBar = vstTimeInfo->timeSigNumerator;
  807. fTimePosition.bbt.beatType = vstTimeInfo->timeSigDenominator;
  808. }
  809. else
  810. {
  811. fTimePosition.bbt.bar = 1;
  812. fTimePosition.bbt.beat = 1;
  813. fTimePosition.bbt.tick = 0;
  814. fTimePosition.bbt.beatsPerBar = 4.0f;
  815. fTimePosition.bbt.beatType = 4.0f;
  816. }
  817. fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1);
  818. fPlugin.setTimePosition(fTimePosition);
  819. }
  820. #endif
  821. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  822. fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount);
  823. fMidiEventCount = 0;
  824. #else
  825. fPlugin.run(inputs, outputs, sampleFrames);
  826. #endif
  827. updateParameterOutputsAndTriggers();
  828. }
  829. // -------------------------------------------------------------------
  830. friend class UIVst;
  831. private:
  832. // Plugin
  833. PluginExporter fPlugin;
  834. // VST stuff
  835. const audioMasterCallback fAudioMaster;
  836. AEffect* const fEffect;
  837. // Temporary data
  838. char fProgramName[32+1];
  839. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  840. uint32_t fMidiEventCount;
  841. MidiEvent fMidiEvents[kMaxMidiEvents];
  842. #endif
  843. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  844. TimePosition fTimePosition;
  845. #endif
  846. // UI stuff
  847. #if DISTRHO_PLUGIN_HAS_UI
  848. UIVst* fVstUI;
  849. ERect fVstRect;
  850. # if DISTRHO_OS_MAC
  851. bool fUsingNsView;
  852. # endif
  853. #endif
  854. #if DISTRHO_PLUGIN_WANT_STATE
  855. char* fStateChunk;
  856. StringMap fStateMap;
  857. #endif
  858. // -------------------------------------------------------------------
  859. // host callback
  860. intptr_t hostCallback(const int32_t opcode,
  861. const int32_t index = 0,
  862. const intptr_t value = 0,
  863. void* const ptr = nullptr,
  864. const float opt = 0.0f)
  865. {
  866. return fAudioMaster(fEffect, opcode, index, value, ptr, opt);
  867. }
  868. // -------------------------------------------------------------------
  869. // functions called from the plugin side, RT no block
  870. void updateParameterOutputsAndTriggers()
  871. {
  872. float curValue;
  873. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  874. {
  875. if (fPlugin.isParameterOutput(i))
  876. {
  877. // NOTE: no output parameter support in VST, simulate it here
  878. curValue = fPlugin.getParameterValue(i);
  879. if (d_isEqual(curValue, parameterValues[i]))
  880. continue;
  881. #if DISTRHO_PLUGIN_HAS_UI
  882. if (fVstUI != nullptr)
  883. setParameterValueFromPlugin(i, curValue);
  884. else
  885. #endif
  886. parameterValues[i] = curValue;
  887. #ifndef DPF_VST_SHOW_PARAMETER_OUTPUTS
  888. // skip automating parameter outputs from plugin if we disable them on VST
  889. continue;
  890. #endif
  891. }
  892. else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger)
  893. {
  894. // NOTE: no trigger support in VST parameters, simulate it here
  895. curValue = fPlugin.getParameterValue(i);
  896. if (d_isEqual(curValue, fPlugin.getParameterRanges(i).def))
  897. continue;
  898. #if DISTRHO_PLUGIN_HAS_UI
  899. if (fVstUI != nullptr)
  900. setParameterValueFromPlugin(i, curValue);
  901. #endif
  902. fPlugin.setParameterValue(i, curValue);
  903. }
  904. else
  905. {
  906. continue;
  907. }
  908. const ParameterRanges& ranges(fPlugin.getParameterRanges(i));
  909. hostCallback(audioMasterAutomate, i, 0, nullptr, ranges.getNormalizedValue(curValue));
  910. }
  911. }
  912. #if DISTRHO_PLUGIN_HAS_UI
  913. void setParameterValueFromPlugin(const uint32_t index, const float realValue)
  914. {
  915. parameterValues[index] = realValue;
  916. parameterChecks[index] = true;
  917. }
  918. #endif
  919. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  920. bool writeMidi(const MidiEvent& midiEvent)
  921. {
  922. if (midiEvent.size > 4)
  923. return true;
  924. VstEvents vstEvents;
  925. std::memset(&vstEvents, 0, sizeof(VstEvents));
  926. VstMidiEvent vstMidiEvent;
  927. std::memset(&vstMidiEvent, 0, sizeof(VstMidiEvent));
  928. vstEvents.numEvents = 1;
  929. vstEvents.events[0] = (VstEvent*)&vstMidiEvent;
  930. vstMidiEvent.type = kVstMidiType;
  931. vstMidiEvent.byteSize = kVstMidiEventSize;
  932. vstMidiEvent.deltaFrames = midiEvent.frame;
  933. for (uint8_t i=0; i<midiEvent.size; ++i)
  934. vstMidiEvent.midiData[i] = midiEvent.data[i];
  935. return hostCallback(audioMasterProcessEvents, 0, 0, &vstEvents) == 1;
  936. }
  937. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  938. {
  939. return ((PluginVst*)ptr)->writeMidi(midiEvent);
  940. }
  941. #endif
  942. #if DISTRHO_PLUGIN_WANT_STATE
  943. // -------------------------------------------------------------------
  944. // functions called from the UI side, may block
  945. # if DISTRHO_PLUGIN_HAS_UI
  946. void setStateFromUI(const char* const key, const char* const newValue) override
  947. # else
  948. void setStateFromUI(const char* const key, const char* const newValue)
  949. # endif
  950. {
  951. fPlugin.setState(key, newValue);
  952. // check if we want to save this key
  953. if (! fPlugin.wantStateKey(key))
  954. return;
  955. // check if key already exists
  956. for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
  957. {
  958. const String& dkey(it->first);
  959. if (dkey == key)
  960. {
  961. it->second = newValue;
  962. return;
  963. }
  964. }
  965. d_stderr("Failed to find plugin state with key \"%s\"", key);
  966. }
  967. #endif
  968. };
  969. // -----------------------------------------------------------------------
  970. struct VstObject {
  971. audioMasterCallback audioMaster;
  972. PluginVst* plugin;
  973. };
  974. #define validObject effect != nullptr && effect->object != nullptr
  975. #define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr
  976. #define vstObjectPtr (VstObject*)effect->object
  977. #define pluginPtr (vstObjectPtr)->plugin
  978. static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  979. {
  980. // first internal init
  981. const bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d);
  982. if (doInternalInit)
  983. {
  984. // set valid but dummy values
  985. d_lastBufferSize = 512;
  986. d_lastSampleRate = 44100.0;
  987. }
  988. // Create dummy plugin to get data from
  989. static PluginExporter plugin(nullptr, nullptr);
  990. if (doInternalInit)
  991. {
  992. // unset
  993. d_lastBufferSize = 0;
  994. d_lastSampleRate = 0.0;
  995. *(PluginExporter**)ptr = &plugin;
  996. return 0;
  997. }
  998. // handle base opcodes
  999. switch (opcode)
  1000. {
  1001. case effOpen:
  1002. if (VstObject* const obj = vstObjectPtr)
  1003. {
  1004. // this must always be valid
  1005. DISTRHO_SAFE_ASSERT_RETURN(obj->audioMaster != nullptr, 0);
  1006. // some hosts call effOpen twice
  1007. DISTRHO_SAFE_ASSERT_RETURN(obj->plugin == nullptr, 1);
  1008. audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster;
  1009. d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
  1010. d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
  1011. // some hosts are not ready at this point or return 0 buffersize/samplerate
  1012. if (d_lastBufferSize == 0)
  1013. d_lastBufferSize = 2048;
  1014. if (d_lastSampleRate <= 0.0)
  1015. d_lastSampleRate = 44100.0;
  1016. obj->plugin = new PluginVst(audioMaster, effect);
  1017. return 1;
  1018. }
  1019. return 0;
  1020. case effClose:
  1021. if (VstObject* const obj = vstObjectPtr)
  1022. {
  1023. if (obj->plugin != nullptr)
  1024. {
  1025. delete obj->plugin;
  1026. obj->plugin = nullptr;
  1027. }
  1028. #if 0
  1029. /* This code invalidates the object created in VSTPluginMain
  1030. * Probably not safe against all hosts */
  1031. obj->audioMaster = nullptr;
  1032. effect->object = nullptr;
  1033. delete obj;
  1034. #endif
  1035. return 1;
  1036. }
  1037. //delete effect;
  1038. return 0;
  1039. case effGetParamLabel:
  1040. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
  1041. {
  1042. DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterUnit(index), 8);
  1043. return 1;
  1044. }
  1045. return 0;
  1046. case effGetParamName:
  1047. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
  1048. {
  1049. DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterName(index), 16);
  1050. return 1;
  1051. }
  1052. return 0;
  1053. case effGetParameterProperties:
  1054. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
  1055. {
  1056. if (VstParameterProperties* const properties = (VstParameterProperties*)ptr)
  1057. {
  1058. memset(properties, 0, sizeof(VstParameterProperties));
  1059. const uint32_t hints = plugin.getParameterHints(index);
  1060. if (hints & kParameterIsOutput)
  1061. return 1;
  1062. if (hints & kParameterIsBoolean)
  1063. {
  1064. properties->flags |= kVstParameterIsSwitch;
  1065. }
  1066. if (hints & kParameterIsInteger)
  1067. {
  1068. properties->flags |= kVstParameterUsesIntegerMinMax;
  1069. const ParameterRanges& ranges(plugin.getParameterRanges(index));
  1070. properties->minInteger = static_cast<int32_t>(ranges.min);
  1071. properties->maxInteger = static_cast<int32_t>(ranges.max);
  1072. }
  1073. if (hints & kParameterIsLogarithmic)
  1074. {
  1075. properties->flags |= kVstParameterCanRamp;
  1076. }
  1077. return 1;
  1078. }
  1079. }
  1080. return 0;
  1081. case effGetPlugCategory:
  1082. #if DISTRHO_PLUGIN_IS_SYNTH
  1083. return kPlugCategSynth;
  1084. #else
  1085. return kPlugCategEffect;
  1086. #endif
  1087. case effGetEffectName:
  1088. if (char* const cptr = (char*)ptr)
  1089. {
  1090. DISTRHO_NAMESPACE::strncpy(cptr, plugin.getName(), 32);
  1091. return 1;
  1092. }
  1093. return 0;
  1094. case effGetVendorString:
  1095. if (char* const cptr = (char*)ptr)
  1096. {
  1097. DISTRHO_NAMESPACE::strncpy(cptr, plugin.getMaker(), 32);
  1098. return 1;
  1099. }
  1100. return 0;
  1101. case effGetProductString:
  1102. if (char* const cptr = (char*)ptr)
  1103. {
  1104. DISTRHO_NAMESPACE::strncpy(cptr, plugin.getLabel(), 32);
  1105. return 1;
  1106. }
  1107. return 0;
  1108. case effGetVendorVersion:
  1109. return plugin.getVersion();
  1110. case effGetVstVersion:
  1111. return kVstVersion;
  1112. };
  1113. // handle advanced opcodes
  1114. if (validPlugin)
  1115. return pluginPtr->vst_dispatcher(opcode, index, value, ptr, opt);
  1116. return 0;
  1117. }
  1118. static float vst_getParameterCallback(AEffect* effect, int32_t index)
  1119. {
  1120. if (validPlugin)
  1121. return pluginPtr->vst_getParameter(index);
  1122. return 0.0f;
  1123. }
  1124. static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
  1125. {
  1126. if (validPlugin)
  1127. pluginPtr->vst_setParameter(index, value);
  1128. }
  1129. static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  1130. {
  1131. if (validPlugin)
  1132. pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  1133. }
  1134. static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  1135. {
  1136. if (validPlugin)
  1137. pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
  1138. }
  1139. #undef pluginPtr
  1140. #undef validObject
  1141. #undef validPlugin
  1142. #undef vstObjectPtr
  1143. // -----------------------------------------------------------------------
  1144. END_NAMESPACE_DISTRHO
  1145. DISTRHO_PLUGIN_EXPORT
  1146. #if DISTRHO_OS_WINDOWS || DISTRHO_OS_MAC
  1147. const AEffect* VSTPluginMain(audioMasterCallback audioMaster);
  1148. #else
  1149. const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main");
  1150. #endif
  1151. DISTRHO_PLUGIN_EXPORT
  1152. const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  1153. {
  1154. USE_NAMESPACE_DISTRHO
  1155. // old version
  1156. if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
  1157. return nullptr;
  1158. // first internal init
  1159. PluginExporter* plugin = nullptr;
  1160. vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f);
  1161. DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr);
  1162. AEffect* const effect(new AEffect);
  1163. std::memset(effect, 0, sizeof(AEffect));
  1164. // vst fields
  1165. effect->magic = kEffectMagic;
  1166. effect->uniqueID = plugin->getUniqueId();
  1167. effect->version = plugin->getVersion();
  1168. // VST doesn't support parameter outputs. we can fake them, but it is a hack. Disabled by default.
  1169. #ifdef DPF_VST_SHOW_PARAMETER_OUTPUTS
  1170. const int numParams = plugin->getParameterCount();
  1171. #else
  1172. int numParams = 0;
  1173. bool outputsReached = false;
  1174. for (uint32_t i=0, count=plugin->getParameterCount(); i < count; ++i)
  1175. {
  1176. if (plugin->isParameterInput(i))
  1177. {
  1178. // parameter outputs must be all at the end
  1179. DISTRHO_SAFE_ASSERT_BREAK(! outputsReached);
  1180. ++numParams;
  1181. continue;
  1182. }
  1183. outputsReached = true;
  1184. }
  1185. #endif
  1186. // plugin fields
  1187. effect->numParams = numParams;
  1188. effect->numPrograms = 1;
  1189. effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
  1190. effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;
  1191. // plugin flags
  1192. effect->flags |= effFlagsCanReplacing;
  1193. #if DISTRHO_PLUGIN_IS_SYNTH
  1194. effect->flags |= effFlagsIsSynth;
  1195. #endif
  1196. #if DISTRHO_PLUGIN_HAS_UI
  1197. effect->flags |= effFlagsHasEditor;
  1198. #endif
  1199. #if DISTRHO_PLUGIN_WANT_STATE
  1200. effect->flags |= effFlagsProgramChunks;
  1201. #endif
  1202. // static calls
  1203. effect->dispatcher = vst_dispatcherCallback;
  1204. effect->process = vst_processCallback;
  1205. effect->getParameter = vst_getParameterCallback;
  1206. effect->setParameter = vst_setParameterCallback;
  1207. effect->processReplacing = vst_processReplacingCallback;
  1208. // pointers
  1209. VstObject* const obj(new VstObject());
  1210. obj->audioMaster = audioMaster;
  1211. obj->plugin = nullptr;
  1212. // done
  1213. effect->object = obj;
  1214. return effect;
  1215. }
  1216. // -----------------------------------------------------------------------