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.

1035 lines
28KB

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