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.

1003 lines
27KB

  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 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
  18. # include "DistrhoUIInternal.hpp"
  19. #endif
  20. #ifndef __cdecl
  21. # define __cdecl
  22. #endif
  23. // has some conflicts
  24. #ifdef noexcept
  25. # undef noexcept
  26. #endif
  27. #define VESTIGE_HEADER
  28. #define VST_FORCE_DEPRECATED 0
  29. #include <map>
  30. #include <string>
  31. #ifdef VESTIGE_HEADER
  32. # include "vestige/aeffectx.h"
  33. #define effFlagsProgramChunks (1 << 5)
  34. #define effGetParamLabel 6
  35. #define effGetParamDisplay 7
  36. #define effGetChunk 23
  37. #define effSetChunk 24
  38. #define effCanBeAutomated 26
  39. #define effGetProgramNameIndexed 29
  40. #define effGetPlugCategory 35
  41. #define effIdle 53
  42. #define kPlugCategEffect 1
  43. #define kPlugCategSynth 2
  44. #define kVstVersion 2400
  45. struct ERect {
  46. int16_t top, left, bottom, right;
  47. };
  48. #else
  49. # include "vst/aeffectx.h"
  50. #endif
  51. #if DISTRHO_PLUGIN_WANT_STATE
  52. # warning VST State still TODO (working but needs final testing)
  53. #endif
  54. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  55. # warning VST TimePos still TODO (only basic BBT working)
  56. #endif
  57. typedef std::map<d_string,d_string> StringMap;
  58. START_NAMESPACE_DISTRHO
  59. // -----------------------------------------------------------------------
  60. void strncpy(char* const dst, const char* const src, const size_t size)
  61. {
  62. std::strncpy(dst, src, size);
  63. dst[size] = '\0';
  64. }
  65. // -----------------------------------------------------------------------
  66. #if DISTRHO_PLUGIN_WANT_STATE
  67. class StateHelper
  68. {
  69. public:
  70. virtual ~StateHelper() {}
  71. virtual void setSharedState(const char* const newKey, const char* const newValue) = 0;
  72. };
  73. #else
  74. typedef void StateHelper;
  75. #endif
  76. // -----------------------------------------------------------------------
  77. #if DISTRHO_PLUGIN_HAS_UI
  78. class UIVst
  79. {
  80. public:
  81. UIVst(const audioMasterCallback audioMaster, AEffect* const effect, PluginExporter* const plugin, StateHelper* const stateHelper, const intptr_t winId)
  82. : fAudioMaster(audioMaster),
  83. fEffect(effect),
  84. fPlugin(plugin),
  85. fStateHelper(stateHelper),
  86. fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback),
  87. fParameterChecks(nullptr),
  88. fParameterValues(nullptr)
  89. {
  90. const uint32_t paramCount(plugin->getParameterCount());
  91. if (paramCount > 0)
  92. {
  93. fParameterChecks = new bool[paramCount];
  94. fParameterValues = new float[paramCount];
  95. for (uint32_t i=0; i < paramCount; ++i)
  96. {
  97. fParameterChecks[i] = false;
  98. fParameterValues[i] = 0.0f;
  99. }
  100. }
  101. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  102. fNextProgram = -1;
  103. #endif
  104. }
  105. ~UIVst()
  106. {
  107. if (fParameterChecks != nullptr)
  108. {
  109. delete[] fParameterChecks;
  110. fParameterChecks = nullptr;
  111. }
  112. if (fParameterValues != nullptr)
  113. {
  114. delete[] fParameterValues;
  115. fParameterValues = nullptr;
  116. }
  117. }
  118. // -------------------------------------------------------------------
  119. void idle()
  120. {
  121. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  122. if (fNextProgram != -1)
  123. {
  124. fUI.programChanged(fNextProgram);
  125. fNextProgram = -1;
  126. }
  127. #endif
  128. for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
  129. {
  130. if (fParameterChecks[i])
  131. {
  132. fParameterChecks[i] = false;
  133. fUI.parameterChanged(i, fParameterValues[i]);
  134. }
  135. }
  136. fUI.idle();
  137. }
  138. int16_t getWidth() const
  139. {
  140. return fUI.getWidth();
  141. }
  142. int16_t getHeight() const
  143. {
  144. return fUI.getHeight();
  145. }
  146. // -------------------------------------------------------------------
  147. // functions called from the plugin side, RT no block
  148. void setParameterValueFromPlugin(const uint32_t index, const float perValue)
  149. {
  150. fParameterChecks[index] = true;
  151. fParameterValues[index] = perValue;
  152. }
  153. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  154. void setProgramFromPlugin(const uint32_t index)
  155. {
  156. fNextProgram = index;
  157. // set previous parameters invalid
  158. for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
  159. fParameterChecks[i] = false;
  160. }
  161. #endif
  162. // -------------------------------------------------------------------
  163. // functions called from the plugin side, block
  164. #if DISTRHO_PLUGIN_WANT_STATE
  165. void setStateFromPlugin(const char* const key, const char* const value)
  166. {
  167. fUI.stateChanged(key, value);
  168. }
  169. #endif
  170. // -------------------------------------------------------------------
  171. protected:
  172. intptr_t hostCallback(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  173. {
  174. return fAudioMaster(fEffect, opcode, index, value, ptr, opt);
  175. }
  176. void editParameter(const uint32_t index, const bool started)
  177. {
  178. if (started)
  179. hostCallback(audioMasterBeginEdit, index, 0, nullptr, 0.0f);
  180. else
  181. hostCallback(audioMasterEndEdit, index, 0, nullptr, 0.0f);
  182. }
  183. void setParameterValue(const uint32_t index, const float realValue)
  184. {
  185. const ParameterRanges& ranges(fPlugin->getParameterRanges(index));
  186. const float perValue(ranges.getNormalizedValue(realValue));
  187. fPlugin->setParameterValue(index, realValue);
  188. hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
  189. }
  190. void setState(const char* const key, const char* const value)
  191. {
  192. #if DISTRHO_PLUGIN_WANT_STATE
  193. fStateHelper->setSharedState(key, value);
  194. #else
  195. return; // unused
  196. (void)key;
  197. (void)value;
  198. #endif
  199. }
  200. void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
  201. {
  202. #if 0 //DISTRHO_PLUGIN_IS_SYNTH
  203. // TODO
  204. #else
  205. return; // unused
  206. (void)channel;
  207. (void)note;
  208. (void)velocity;
  209. #endif
  210. }
  211. void uiResize(const unsigned int width, const unsigned int height)
  212. {
  213. fUI.setSize(width, height);
  214. hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f);
  215. }
  216. private:
  217. // Vst stuff
  218. const audioMasterCallback fAudioMaster;
  219. AEffect* const fEffect;
  220. PluginExporter* const fPlugin;
  221. StateHelper* const fStateHelper;
  222. // Plugin UI
  223. UIExporter fUI;
  224. // Temporary data
  225. bool* fParameterChecks;
  226. float* fParameterValues;
  227. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  228. int32_t fNextProgram;
  229. #endif
  230. // -------------------------------------------------------------------
  231. // Callbacks
  232. #define handlePtr ((UIVst*)ptr)
  233. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  234. {
  235. handlePtr->editParameter(index, started);
  236. }
  237. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  238. {
  239. handlePtr->setParameterValue(rindex, value);
  240. }
  241. static void setStateCallback(void* ptr, const char* key, const char* value)
  242. {
  243. handlePtr->setState(key, value);
  244. }
  245. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  246. {
  247. handlePtr->sendNote(channel, note, velocity);
  248. }
  249. static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
  250. {
  251. handlePtr->uiResize(width, height);
  252. }
  253. #undef handlePtr
  254. };
  255. #endif
  256. // -----------------------------------------------------------------------
  257. #if DISTRHO_PLUGIN_WANT_STATE
  258. class PluginVst : public StateHelper
  259. #else
  260. class PluginVst
  261. #endif
  262. {
  263. public:
  264. PluginVst(const audioMasterCallback audioMaster, AEffect* const effect)
  265. : fAudioMaster(audioMaster),
  266. fEffect(effect)
  267. {
  268. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  269. fCurProgram = -1;
  270. #endif
  271. #if DISTRHO_PLUGIN_IS_SYNTH
  272. fMidiEventCount = 0;
  273. #endif
  274. #if DISTRHO_PLUGIN_HAS_UI
  275. fVstUi = nullptr;
  276. fVstRect.top = 0;
  277. fVstRect.left = 0;
  278. fVstRect.bottom = 0;
  279. fVstRect.right = 0;
  280. #endif
  281. #if DISTRHO_PLUGIN_WANT_STATE
  282. fStateChunk = nullptr;
  283. #endif
  284. }
  285. #if DISTRHO_PLUGIN_WANT_STATE
  286. ~PluginVst()
  287. {
  288. if (fStateChunk != nullptr)
  289. {
  290. delete[] fStateChunk;
  291. fStateChunk = nullptr;
  292. }
  293. fStateMap.clear();
  294. }
  295. #endif
  296. intptr_t vst_dispatcher(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  297. {
  298. int32_t ret = 0;
  299. switch (opcode)
  300. {
  301. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  302. case effSetProgram:
  303. if (value >= 0 && value < static_cast<intptr_t>(fPlugin.getProgramCount()))
  304. {
  305. fCurProgram = value;
  306. fPlugin.setProgram(fCurProgram);
  307. #if DISTRHO_PLUGIN_HAS_UI
  308. if (fVstUi != nullptr)
  309. fVstUi->setProgramFromPlugin(fCurProgram);
  310. #endif
  311. ret = 1;
  312. }
  313. break;
  314. case effGetProgram:
  315. ret = fCurProgram;
  316. break;
  317. //case effSetProgramName:
  318. // unsupported
  319. // break;
  320. case effGetProgramName:
  321. if (ptr != nullptr && fCurProgram >= 0 && fCurProgram < static_cast<int32_t>(fPlugin.getProgramCount()))
  322. {
  323. DISTRHO::strncpy((char*)ptr, fPlugin.getProgramName(fCurProgram), 24);
  324. ret = 1;
  325. }
  326. break;
  327. #endif
  328. case effGetParamDisplay:
  329. if (ptr != nullptr && index < static_cast<int32_t>(fPlugin.getParameterCount()))
  330. {
  331. char* buf = (char*)ptr;
  332. std::snprintf((char*)ptr, 8, "%f", fPlugin.getParameterValue(index));
  333. buf[8] = '\0';
  334. ret = 1;
  335. }
  336. break;
  337. case effSetSampleRate:
  338. fPlugin.setSampleRate(opt, true);
  339. break;
  340. case effSetBlockSize:
  341. fPlugin.setBufferSize(value, true);
  342. break;
  343. case effMainsChanged:
  344. if (value != 0)
  345. {
  346. fPlugin.activate();
  347. #if DISTRHO_PLUGIN_IS_SYNTH
  348. fMidiEventCount = 0;
  349. #endif
  350. }
  351. else
  352. {
  353. fPlugin.deactivate();
  354. }
  355. break;
  356. #if DISTRHO_PLUGIN_HAS_UI
  357. case effEditGetRect:
  358. if (fVstUi != nullptr)
  359. {
  360. fVstRect.right = fVstUi->getWidth();
  361. fVstRect.bottom = fVstUi->getHeight();
  362. }
  363. else
  364. {
  365. d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
  366. UIExporter tmpUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr);
  367. fVstRect.right = tmpUI.getWidth();
  368. fVstRect.bottom = tmpUI.getHeight();
  369. }
  370. *(ERect**)ptr = &fVstRect;
  371. ret = 1;
  372. break;
  373. case effEditOpen:
  374. if (fVstUi == nullptr)
  375. {
  376. # if DISTRHO_OS_MAC && ! defined(__LP64__)
  377. if ((fEffect->dispatcher(fEffect, effCanDo, 0, 0, (void*)"hasCockosViewAsConfig", 0.0f) & 0xffff0000) != 0xbeef0000)
  378. return 0;
  379. # endif
  380. d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
  381. fVstUi = new UIVst(fAudioMaster, fEffect, &fPlugin, this, (intptr_t)ptr);
  382. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  383. if (fCurProgram >= 0)
  384. fVstUi->setProgramFromPlugin(fCurProgram);
  385. # endif
  386. for (uint32_t i=0, count = fPlugin.getParameterCount(); i < count; ++i)
  387. fVstUi->setParameterValueFromPlugin(i, fPlugin.getParameterValue(i));
  388. fVstUi->idle();
  389. #if DISTRHO_PLUGIN_WANT_STATE
  390. if (fStateMap.size() > 0)
  391. {
  392. for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
  393. {
  394. const d_string& key = it->first;
  395. const d_string& value = it->second;
  396. fVstUi->setStateFromPlugin((const char*)key, (const char*)value);
  397. }
  398. fVstUi->idle();
  399. }
  400. #endif
  401. ret = 1;
  402. }
  403. break;
  404. case effEditClose:
  405. if (fVstUi != nullptr)
  406. {
  407. delete fVstUi;
  408. fVstUi = nullptr;
  409. ret = 1;
  410. }
  411. break;
  412. case effEditIdle:
  413. case effIdle:
  414. if (fVstUi != nullptr)
  415. fVstUi->idle();
  416. break;
  417. #endif
  418. #if DISTRHO_PLUGIN_WANT_STATE
  419. case effGetChunk:
  420. if (ptr == nullptr)
  421. return 0;
  422. if (fStateChunk != nullptr)
  423. delete[] fStateChunk;
  424. if (fStateMap.size() == 0)
  425. {
  426. fStateChunk = new char[1];
  427. fStateChunk[0] = '\0';
  428. ret = 1;
  429. }
  430. else
  431. {
  432. std::string tmpStr;
  433. for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
  434. {
  435. const d_string& key = it->first;
  436. const d_string& value = it->second;
  437. tmpStr += (const char*)key;
  438. tmpStr += "\xff";
  439. tmpStr += (const char*)value;
  440. tmpStr += "\xff";
  441. }
  442. const size_t size(tmpStr.size());
  443. fStateChunk = new char[size];
  444. std::memcpy(fStateChunk, tmpStr.c_str(), size*sizeof(char));
  445. for (size_t i=0; i < size; ++i)
  446. {
  447. if (fStateChunk[i] == '\xff')
  448. fStateChunk[i] = '\0';
  449. }
  450. ret = size;
  451. }
  452. *(void**)ptr = fStateChunk;
  453. break;
  454. case effSetChunk:
  455. if (value <= 0)
  456. return 0;
  457. if (value == 1)
  458. return 1;
  459. if (const char* const state = (const char*)ptr)
  460. {
  461. const size_t stateSize = value;
  462. const char* stateKey = state;
  463. const char* stateValue = nullptr;
  464. for (size_t i=0; i < stateSize; ++i)
  465. {
  466. // find next null char
  467. if (state[i] != '\0')
  468. continue;
  469. // found, set value
  470. stateValue = &state[i+1];
  471. setSharedState(stateKey, stateValue);
  472. if (fVstUi != nullptr)
  473. fVstUi->setStateFromPlugin(stateKey, stateValue);
  474. // increment text position
  475. i += std::strlen(stateValue) + 2;
  476. // check if end of data
  477. if (i >= stateSize)
  478. break;
  479. // get next key
  480. stateKey = &state[i];
  481. }
  482. ret = 1;
  483. }
  484. break;
  485. #endif
  486. #if DISTRHO_PLUGIN_IS_SYNTH
  487. case effProcessEvents:
  488. if (const VstEvents* const events = (const VstEvents*)ptr)
  489. {
  490. if (events->numEvents == 0)
  491. break;
  492. for (int i=0, count=events->numEvents; i < count; ++i)
  493. {
  494. const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]);
  495. if (vstMidiEvent == nullptr)
  496. break;
  497. if (vstMidiEvent->type != kVstMidiType)
  498. continue;
  499. if (fMidiEventCount >= kMaxMidiEvents)
  500. break;
  501. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  502. midiEvent.frame = vstMidiEvent->deltaFrames;
  503. midiEvent.size = 3;
  504. std::memcpy(midiEvent.buf, vstMidiEvent->midiData, 3*sizeof(uint8_t));
  505. }
  506. }
  507. break;
  508. #endif
  509. case effCanBeAutomated:
  510. if (index < static_cast<int32_t>(fPlugin.getParameterCount()))
  511. {
  512. const uint32_t hints(fPlugin.getParameterHints(index));
  513. // must be automable, and not output
  514. if ((hints & PARAMETER_IS_AUTOMABLE) != 0 && (hints & PARAMETER_IS_OUTPUT) == 0)
  515. ret = 1;
  516. }
  517. break;
  518. #if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS)
  519. case effCanDo:
  520. if (const char* const canDo = (const char*)ptr)
  521. {
  522. # if DISTRHO_PLUGIN_IS_SYNTH
  523. if (std::strcmp(canDo, "receiveVstEvents") == 0)
  524. return 1;
  525. if (std::strcmp(canDo, "receiveVstMidiEvent") == 0)
  526. return 1;
  527. # endif
  528. # if DISTRHO_PLUGIN_WANT_TIMEPOS
  529. if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
  530. return 1;
  531. # endif
  532. }
  533. break;
  534. #endif
  535. //case effStartProcess:
  536. //case effStopProcess:
  537. // unused
  538. // break;
  539. }
  540. return ret;
  541. }
  542. float vst_getParameter(const int32_t index)
  543. {
  544. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  545. return ranges.getNormalizedValue(fPlugin.getParameterValue(index));
  546. }
  547. void vst_setParameter(const int32_t index, const float value)
  548. {
  549. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  550. const float realValue(ranges.getUnnormalizedValue(value));
  551. fPlugin.setParameterValue(index, realValue);
  552. #if DISTRHO_PLUGIN_HAS_UI
  553. if (fVstUi != nullptr)
  554. fVstUi->setParameterValueFromPlugin(index, realValue);
  555. #endif
  556. }
  557. void vst_processReplacing(float** const inputs, float** const outputs, const int32_t sampleFrames)
  558. {
  559. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  560. static const int kWantedVstTimeFlags(kVstTransportPlaying|kVstTempoValid|kVstTimeSigValid);
  561. if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantedVstTimeFlags, nullptr, 0.0f))
  562. {
  563. fTimePos.playing = (vstTimeInfo->flags & kVstTransportPlaying);
  564. fTimePos.frame = vstTimeInfo->samplePos;
  565. if (vstTimeInfo->flags & kVstTempoValid)
  566. {
  567. fTimePos.bbt.valid = true;
  568. fTimePos.bbt.beatsPerMinute = vstTimeInfo->tempo;
  569. }
  570. if (vstTimeInfo->flags & kVstTimeSigValid)
  571. {
  572. fTimePos.bbt.valid = true;
  573. fTimePos.bbt.beatsPerBar = vstTimeInfo->timeSigNumerator;
  574. fTimePos.bbt.beatType = vstTimeInfo->timeSigDenominator;
  575. }
  576. fPlugin.setTimePos(fTimePos);
  577. }
  578. #endif
  579. #if DISTRHO_PLUGIN_IS_SYNTH
  580. fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount);
  581. fMidiEventCount = 0;
  582. #else
  583. fPlugin.run(inputs, outputs, sampleFrames);
  584. #endif
  585. }
  586. // -------------------------------------------------------------------
  587. friend class UIVst;
  588. private:
  589. // VST stuff
  590. const audioMasterCallback fAudioMaster;
  591. AEffect* const fEffect;
  592. // Plugin
  593. PluginExporter fPlugin;
  594. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  595. // Current state
  596. int32_t fCurProgram;
  597. #endif
  598. // Temporary data
  599. #if DISTRHO_PLUGIN_IS_SYNTH
  600. uint32_t fMidiEventCount;
  601. MidiEvent fMidiEvents[kMaxMidiEvents];
  602. #endif
  603. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  604. TimePos fTimePos;
  605. #endif
  606. // UI stuff
  607. #if DISTRHO_PLUGIN_HAS_UI
  608. UIVst* fVstUi;
  609. ERect fVstRect;
  610. #endif
  611. #if DISTRHO_PLUGIN_WANT_STATE
  612. char* fStateChunk;
  613. StringMap fStateMap;
  614. void setSharedState(const char* const newKey, const char* const newValue) override
  615. {
  616. fPlugin.setState(newKey, newValue);
  617. // check if key already exists
  618. for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it)
  619. {
  620. const d_string& key = it->first;
  621. if (key == newKey)
  622. {
  623. it->second = newValue;
  624. return;
  625. }
  626. }
  627. // add a new one then
  628. d_string d_key(newKey);
  629. fStateMap[d_key] = newValue;
  630. }
  631. #endif
  632. };
  633. // -----------------------------------------------------------------------
  634. #ifdef VESTIGE_HEADER
  635. # define handlePtr ((PluginVst*)effect->ptr2)
  636. # define validEffect effect != nullptr && effect->ptr2 != nullptr
  637. #else
  638. # define handlePtr ((PluginVst*)effect->resvd2)
  639. # define validEffect effect != nullptr && effect->resvd2 != 0
  640. #endif
  641. static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  642. {
  643. // first internal init
  644. bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d);
  645. if (doInternalInit)
  646. {
  647. // set valid but dummy values
  648. d_lastBufferSize = 512;
  649. d_lastSampleRate = 44100.0;
  650. }
  651. // Create dummy plugin to get data from
  652. static PluginExporter plugin;
  653. if (doInternalInit)
  654. {
  655. // unset
  656. d_lastBufferSize = 0;
  657. d_lastSampleRate = 0.0;
  658. *(PluginExporter**)ptr = &plugin;
  659. return 0;
  660. }
  661. // handle base opcodes
  662. switch (opcode)
  663. {
  664. case effOpen:
  665. #ifdef VESTIGE_HEADER
  666. if (effect != nullptr && effect->ptr3 != nullptr)
  667. {
  668. audioMasterCallback audioMaster = (audioMasterCallback)effect->ptr3;
  669. #else
  670. if (effect != nullptr && effect->object != nullptr)
  671. {
  672. audioMasterCallback audioMaster = (audioMasterCallback)effect->object;
  673. #endif
  674. d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
  675. d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
  676. PluginVst* const plugin(new PluginVst(audioMaster, effect));
  677. #ifdef VESTIGE_HEADER
  678. effect->ptr2 = plugin;
  679. #else
  680. effect->resvd2 = (intptr_t)plugin;
  681. #endif
  682. return 1;
  683. }
  684. return 0;
  685. case effClose:
  686. if (validEffect)
  687. {
  688. #ifdef VESTIGE_HEADER
  689. delete (PluginVst*)effect->ptr2;
  690. effect->ptr2 = nullptr;
  691. effect->ptr3 = nullptr;
  692. #else
  693. delete (PluginVst*)effect->resvd2;
  694. effect->resvd2 = 0;
  695. effect->object = nullptr;
  696. #endif
  697. delete effect;
  698. return 1;
  699. }
  700. return 0;
  701. case effGetParamLabel:
  702. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
  703. {
  704. DISTRHO::strncpy((char*)ptr, plugin.getParameterUnit(index), 8);
  705. return 1;
  706. }
  707. return 0;
  708. case effGetParamName:
  709. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getParameterCount()))
  710. {
  711. DISTRHO::strncpy((char*)ptr, plugin.getParameterName(index), 8);
  712. return 1;
  713. }
  714. return 0;
  715. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  716. case effGetProgramNameIndexed:
  717. if (ptr != nullptr && index < static_cast<int32_t>(plugin.getProgramCount()))
  718. {
  719. DISTRHO::strncpy((char*)ptr, plugin.getProgramName(index), 24);
  720. return 1;
  721. }
  722. return 0;
  723. #endif
  724. case effGetPlugCategory:
  725. #if DISTRHO_PLUGIN_IS_SYNTH
  726. return kPlugCategSynth;
  727. #else
  728. return kPlugCategEffect;
  729. #endif
  730. case effGetEffectName:
  731. if (ptr != nullptr)
  732. {
  733. DISTRHO::strncpy((char*)ptr, plugin.getName(), 64);
  734. return 1;
  735. }
  736. return 0;
  737. case effGetVendorString:
  738. if (ptr != nullptr)
  739. {
  740. DISTRHO::strncpy((char*)ptr, plugin.getMaker(), 64);
  741. return 1;
  742. }
  743. return 0;
  744. case effGetProductString:
  745. if (ptr != nullptr)
  746. {
  747. DISTRHO::strncpy((char*)ptr, plugin.getLabel(), 32);
  748. return 1;
  749. }
  750. return 0;
  751. case effGetVendorVersion:
  752. return plugin.getVersion();
  753. case effGetVstVersion:
  754. return kVstVersion;
  755. };
  756. // handle advanced opcodes
  757. if (validEffect)
  758. return handlePtr->vst_dispatcher(opcode, index, value, ptr, opt);
  759. return 0;
  760. }
  761. static float vst_getParameterCallback(AEffect* effect, int32_t index)
  762. {
  763. if (validEffect)
  764. return handlePtr->vst_getParameter(index);
  765. return 0.0f;
  766. }
  767. static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
  768. {
  769. if (validEffect)
  770. handlePtr->vst_setParameter(index, value);
  771. }
  772. static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  773. {
  774. if (validEffect)
  775. handlePtr->vst_processReplacing(inputs, outputs, sampleFrames);
  776. }
  777. static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  778. {
  779. if (validEffect)
  780. handlePtr->vst_processReplacing(inputs, outputs, sampleFrames);
  781. }
  782. #undef handlePtr
  783. // -----------------------------------------------------------------------
  784. END_NAMESPACE_DISTRHO
  785. DISTRHO_PLUGIN_EXPORT
  786. const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  787. {
  788. USE_NAMESPACE_DISTRHO
  789. // old version
  790. if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0)
  791. return nullptr;
  792. // first internal init
  793. PluginExporter* plugin = nullptr;
  794. vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f);
  795. AEffect* const effect(new AEffect);
  796. std::memset(effect, 0, sizeof(AEffect));
  797. // vst fields
  798. effect->magic = kEffectMagic;
  799. effect->uniqueID = plugin->getUniqueId();
  800. #ifdef VESTIGE_HEADER
  801. *(int32_t*)&effect->unknown1 = plugin->getVersion();
  802. #else
  803. effect->version = plugin->getVersion();
  804. #endif
  805. // plugin fields
  806. effect->numParams = plugin->getParameterCount();
  807. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  808. effect->numPrograms = plugin->getProgramCount();
  809. #endif
  810. effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
  811. effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;
  812. // plugin flags
  813. effect->flags |= effFlagsCanReplacing;
  814. #if DISTRHO_PLUGIN_IS_SYNTH
  815. effect->flags |= effFlagsIsSynth;
  816. #endif
  817. #if DISTRHO_PLUGIN_HAS_UI
  818. effect->flags |= effFlagsHasEditor;
  819. #endif
  820. #if DISTRHO_PLUGIN_WANT_STATE
  821. effect->flags |= effFlagsProgramChunks;
  822. #endif
  823. // static calls
  824. effect->dispatcher = vst_dispatcherCallback;
  825. effect->process = vst_processCallback;
  826. effect->getParameter = vst_getParameterCallback;
  827. effect->setParameter = vst_setParameterCallback;
  828. effect->processReplacing = vst_processReplacingCallback;
  829. // pointers
  830. #ifdef VESTIGE_HEADER
  831. effect->ptr3 = (void*)audioMaster;
  832. #else
  833. effect->object = (void*)audioMaster;
  834. #endif
  835. return effect;
  836. }