Audio plugin host https://kx.studio/carla
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.

726 lines
18KB

  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * For a full copy of the license see the LGPL.txt file
  15. */
  16. #ifdef DISTRHO_PLUGIN_TARGET_VST
  17. #include "DistrhoPluginInternal.h"
  18. #if DISTRHO_PLUGIN_HAS_UI
  19. # include "DistrhoUIInternal.h"
  20. #endif
  21. #define VST_FORCE_DEPRECATED 0
  22. #include <pluginterfaces/vst2.x/aeffectx.h>
  23. // -------------------------------------------------
  24. START_NAMESPACE_DISTRHO
  25. #if DISTRHO_PLUGIN_HAS_UI
  26. class UIVst
  27. {
  28. public:
  29. UIVst(audioMasterCallback audioMaster, AEffect* effect, PluginInternal* plugin, intptr_t winId)
  30. : m_audioMaster(audioMaster),
  31. m_effect(effect),
  32. m_plugin(plugin),
  33. ui(this, winId, setParameterCallback, setStateCallback, uiEditParameterCallback, uiSendNoteCallback, uiResizeCallback)
  34. {
  35. uint32_t paramCount = plugin->parameterCount();
  36. if (paramCount > 0)
  37. {
  38. parameterChecks = new bool [paramCount];
  39. parameterValues = new float [paramCount];
  40. for (uint32_t i=0; i < paramCount; i++)
  41. {
  42. parameterChecks[i] = false;
  43. parameterValues[i] = 0.0f;
  44. }
  45. }
  46. else
  47. {
  48. parameterChecks = nullptr;
  49. parameterValues = nullptr;
  50. }
  51. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  52. nextProgram = -1;
  53. #endif
  54. #if DISTRHO_PLUGIN_IS_SYNTH
  55. midiEventCount = 0;
  56. #endif
  57. }
  58. ~UIVst()
  59. {
  60. if (parameterChecks)
  61. delete[] parameterChecks;
  62. if (parameterValues)
  63. delete[] parameterValues;
  64. }
  65. // ---------------------------------------------
  66. void idle()
  67. {
  68. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  69. if (nextProgram != -1)
  70. {
  71. ui.programChanged(nextProgram);
  72. nextProgram = -1;
  73. }
  74. #endif
  75. for (uint32_t i=0, count = m_plugin->parameterCount(); i < count; i++)
  76. {
  77. if (parameterChecks[i])
  78. {
  79. parameterChecks[i] = false;
  80. ui.parameterChanged(i, parameterValues[i]);
  81. }
  82. }
  83. #if DISTRHO_PLUGIN_IS_SYNTH
  84. // TODO - notes
  85. #endif
  86. ui.idle();
  87. }
  88. int16_t getWidth()
  89. {
  90. return ui.getWidth();
  91. }
  92. int16_t getHeight()
  93. {
  94. return ui.getHeight();
  95. }
  96. void setParameterValueFromPlugin(uint32_t index, float perValue)
  97. {
  98. parameterChecks[index] = true;
  99. parameterValues[index] = perValue;
  100. }
  101. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  102. void setProgramFromPlugin(uint32_t index)
  103. {
  104. nextProgram = index;
  105. // set previous parameters invalid
  106. for (uint32_t i=0, count = m_plugin->parameterCount(); i < count; i++)
  107. parameterChecks[i] = false;
  108. }
  109. #endif
  110. // ---------------------------------------------
  111. protected:
  112. intptr_t hostCallback(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  113. {
  114. return m_audioMaster(m_effect, opcode, index, value, ptr, opt);
  115. }
  116. void setParameterValue(uint32_t index, float realValue)
  117. {
  118. const ParameterRanges* ranges = m_plugin->parameterRanges(index);
  119. float perValue = (realValue - ranges->min) / (ranges->max - ranges->min);
  120. m_plugin->setParameterValue(index, realValue);
  121. hostCallback(audioMasterAutomate, index, 0, nullptr, perValue);
  122. }
  123. #if DISTRHO_PLUGIN_WANT_STATE
  124. void setState(const char* key, const char* value)
  125. {
  126. m_plugin->setState(key, value);
  127. }
  128. #endif
  129. void uiEditParameter(uint32_t index, bool started)
  130. {
  131. if (started)
  132. hostCallback(audioMasterBeginEdit, index, 0, nullptr, 0.0f);
  133. else
  134. hostCallback(audioMasterEndEdit, index, 0, nullptr, 0.0f);
  135. }
  136. #if DISTRHO_PLUGIN_IS_SYNTH
  137. void uiSendNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
  138. {
  139. // TODO
  140. }
  141. #endif
  142. void uiResize(unsigned int width, unsigned int height)
  143. {
  144. hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f);
  145. }
  146. private:
  147. // Vst stuff
  148. audioMasterCallback const m_audioMaster;
  149. AEffect* const m_effect;
  150. PluginInternal* const m_plugin;
  151. // Plugin UI
  152. UIInternal ui;
  153. // Temporary data
  154. bool* parameterChecks;
  155. float* parameterValues;
  156. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  157. int32_t nextProgram;
  158. #endif
  159. #if DISTRHO_PLUGIN_IS_SYNTH
  160. uint32_t midiEventCount;
  161. MidiEvent midiEvents[MAX_MIDI_EVENTS];
  162. #endif
  163. // ---------------------------------------------
  164. // Callbacks
  165. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  166. {
  167. UIVst* _this_ = (UIVst*)ptr;
  168. assert(_this_);
  169. _this_->setParameterValue(rindex, value);
  170. }
  171. static void setStateCallback(void* ptr, const char* key, const char* value)
  172. {
  173. #if DISTRHO_PLUGIN_WANT_STATE
  174. UIVst* _this_ = (UIVst*)ptr;
  175. assert(_this_);
  176. _this_->setState(key, value);
  177. #else
  178. // unused
  179. (void)ptr;
  180. (void)key;
  181. (void)value;
  182. #endif
  183. }
  184. static void uiEditParameterCallback(void* ptr, uint32_t index, bool started)
  185. {
  186. UIVst* _this_ = (UIVst*)ptr;
  187. assert(_this_);
  188. _this_->uiEditParameter(index, started);
  189. }
  190. static void uiSendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
  191. {
  192. #if DISTRHO_PLUGIN_IS_SYNTH
  193. UIVst* _this_ = (UIVst*)ptr;
  194. assert(_this_);
  195. _this_->uiSendNote(onOff, channel, note, velocity);
  196. #else
  197. // unused
  198. (void)ptr;
  199. (void)onOff;
  200. (void)channel;
  201. (void)note;
  202. (void)velocity;
  203. #endif
  204. }
  205. static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
  206. {
  207. UIVst* _this_ = (UIVst*)ptr;
  208. assert(_this_);
  209. _this_->uiResize(width, height);
  210. }
  211. };
  212. #endif
  213. class PluginVst
  214. {
  215. public:
  216. PluginVst(audioMasterCallback audioMaster, AEffect* effect)
  217. : m_audioMaster(audioMaster),
  218. m_effect(effect)
  219. {
  220. #if DISTRHO_PLUGIN_HAS_UI
  221. vstui = nullptr;
  222. rect.top = 0;
  223. rect.left = 0;
  224. rect.bottom = 0;
  225. rect.right = 0;
  226. #endif
  227. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  228. curProgram = -1;
  229. #endif
  230. #if DISTRHO_PLUGIN_IS_SYNTH
  231. midiEventCount = 0;
  232. #endif
  233. }
  234. ~PluginVst()
  235. {
  236. }
  237. intptr_t vst_dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  238. {
  239. int32_t ret = 0;
  240. switch (opcode)
  241. {
  242. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  243. case effSetProgram:
  244. if (value >= 0 && value < plugin.programCount())
  245. {
  246. curProgram = value;
  247. plugin.setProgram(curProgram);
  248. if (vstui)
  249. vstui->setProgramFromPlugin(curProgram);
  250. ret = 1;
  251. }
  252. break;
  253. case effGetProgram:
  254. ret = curProgram;
  255. break;
  256. case effSetProgramName:
  257. break;
  258. case effGetProgramName:
  259. if (ptr && curProgram >= 0 && curProgram < (int32_t)plugin.programCount())
  260. {
  261. strncpy((char*)ptr, plugin.programName(curProgram), kVstMaxProgNameLen);
  262. ret = 1;
  263. }
  264. break;
  265. #endif
  266. case effGetParamDisplay:
  267. if (ptr && index < (int32_t)plugin.parameterCount())
  268. {
  269. snprintf((char*)ptr, kVstMaxParamStrLen, "%f", plugin.parameterValue(index));
  270. ret = 1;
  271. }
  272. break;
  273. case effSetSampleRate:
  274. // should not happen
  275. break;
  276. case effSetBlockSize:
  277. plugin.setBufferSize(value, true);
  278. break;
  279. case effMainsChanged:
  280. if (value)
  281. plugin.activate();
  282. else
  283. plugin.deactivate();
  284. break;
  285. #if DISTRHO_PLUGIN_HAS_UI
  286. case effEditGetRect:
  287. if (rect.bottom == 0 && ! vstui)
  288. {
  289. // This is stupid, but some hosts want to know the UI size before creating it,
  290. // so we have to create a temporary UI here
  291. setLastUiSampleRate(d_lastSampleRate);
  292. UIInternal tempUI(nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr);
  293. rect.bottom = tempUI.getHeight();
  294. rect.right = tempUI.getWidth();
  295. }
  296. else
  297. {
  298. rect.bottom = vstui->getHeight();
  299. rect.right = vstui->getWidth();
  300. }
  301. *(ERect**)ptr = &rect;
  302. ret = 1;
  303. break;
  304. case effEditOpen:
  305. if (! vstui)
  306. {
  307. setLastUiSampleRate(d_lastSampleRate);
  308. vstui = new UIVst(m_audioMaster, m_effect, &plugin, (intptr_t)ptr);
  309. }
  310. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  311. if (curProgram >= 0)
  312. vstui->setProgramFromPlugin(curProgram);
  313. #endif
  314. for (uint32_t i=0, count = plugin.parameterCount(); i < count; i++)
  315. vstui->setParameterValueFromPlugin(i, plugin.parameterValue(i));
  316. ret = 1;
  317. break;
  318. case effEditClose:
  319. if (vstui)
  320. {
  321. delete vstui;
  322. vstui = nullptr;
  323. ret = 1;
  324. }
  325. break;
  326. case effEditIdle:
  327. if (vstui)
  328. vstui->idle();
  329. break;
  330. #endif
  331. case effGetChunk:
  332. case effSetChunk:
  333. // TODO
  334. break;
  335. #if DISTRHO_PLUGIN_IS_SYNTH
  336. case effProcessEvents:
  337. if (ptr)
  338. {
  339. //VstEvents* events = (VstEvents*)ptr;
  340. // TODO
  341. }
  342. break;
  343. #endif
  344. case effCanBeAutomated:
  345. if (index < (int32_t)plugin.parameterCount())
  346. {
  347. uint32_t hints = plugin.parameterHints(index);
  348. // must be automable, and not output
  349. if ((hints & PARAMETER_IS_AUTOMABLE) > 0 && (hints & PARAMETER_IS_OUTPUT) == 0)
  350. ret = 1;
  351. }
  352. break;
  353. case effCanDo:
  354. // TODO
  355. break;
  356. case effStartProcess:
  357. case effStopProcess:
  358. break;
  359. }
  360. return ret;
  361. // unused
  362. (void)opt;
  363. }
  364. float vst_getParameter(int32_t index)
  365. {
  366. const ParameterRanges* ranges = plugin.parameterRanges(index);
  367. float realValue = plugin.parameterValue(index);
  368. float perValue = (realValue - ranges->min) / (ranges->max - ranges->min);
  369. return perValue;
  370. }
  371. void vst_setParameter(int32_t index, float value)
  372. {
  373. const ParameterRanges* ranges = plugin.parameterRanges(index);
  374. float realValue = ranges->min + (ranges->max - ranges->min) * value;
  375. plugin.setParameterValue(index, realValue);
  376. if (vstui)
  377. vstui->setParameterValueFromPlugin(index, realValue);
  378. }
  379. void vst_processReplacing(float** inputs, float** outputs, int32_t sampleFrames)
  380. {
  381. #if DISTRHO_PLUGIN_IS_SYNTH
  382. plugin.run((const float**)inputs, outputs, sampleFrames, midiEventCount, midiEvents);
  383. // TODO - send notes to UI
  384. #else
  385. plugin.run((const float**)inputs, outputs, sampleFrames, 0, nullptr);
  386. #endif
  387. }
  388. // ---------------------------------------------
  389. private:
  390. // VST stuff
  391. audioMasterCallback const m_audioMaster;
  392. AEffect* const m_effect;
  393. // Plugin
  394. PluginInternal plugin;
  395. #if DISTRHO_PLUGIN_HAS_UI
  396. // UI
  397. UIVst* vstui;
  398. ERect rect;
  399. #endif
  400. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  401. int32_t curProgram;
  402. #endif
  403. #if DISTRHO_PLUGIN_IS_SYNTH
  404. uint32_t midiEventCount;
  405. MidiEvent midiEvents[MAX_MIDI_EVENTS];
  406. #endif
  407. };
  408. // -------------------------------------------------
  409. static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
  410. {
  411. // first internal init
  412. bool doInternalInit = (opcode == -1 && index == 0xdead && value == 0xf00d);
  413. if (doInternalInit)
  414. {
  415. // set valid but dummy values
  416. d_lastBufferSize = 512;
  417. d_lastSampleRate = 44100.0;
  418. }
  419. // Create dummy plugin to get data from
  420. static PluginInternal plugin;
  421. if (doInternalInit)
  422. {
  423. // unset
  424. d_lastBufferSize = 0;
  425. d_lastSampleRate = 0.0;
  426. *(PluginInternal**)ptr = &plugin;
  427. return 0;
  428. }
  429. // handle opcodes
  430. switch (opcode)
  431. {
  432. case effOpen:
  433. if (! effect->object)
  434. {
  435. audioMasterCallback audioMaster = (audioMasterCallback)effect->user;
  436. d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
  437. d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
  438. effect->object = new PluginVst(audioMaster, effect);
  439. return 1;
  440. }
  441. return 0;
  442. case effClose:
  443. if (effect->object)
  444. {
  445. delete (PluginVst*)effect->object;
  446. effect->object = nullptr;
  447. delete effect;
  448. return 1;
  449. }
  450. return 0;
  451. case effGetParamLabel:
  452. if (ptr && index < (int32_t)plugin.parameterCount())
  453. {
  454. strncpy((char*)ptr, plugin.parameterUnit(index), kVstMaxParamStrLen);
  455. return 1;
  456. }
  457. return 0;
  458. case effGetParamName:
  459. if (ptr && index < (int32_t)plugin.parameterCount())
  460. {
  461. strncpy((char*)ptr, plugin.parameterName(index), kVstMaxParamStrLen);
  462. return 1;
  463. }
  464. return 0;
  465. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  466. case effGetProgramNameIndexed:
  467. if (ptr && index < (int32_t)plugin.programCount())
  468. {
  469. strncpy((char*)ptr, plugin.programName(index), kVstMaxProgNameLen);
  470. return 1;
  471. }
  472. return 0;
  473. #endif
  474. case effGetPlugCategory:
  475. #if DISTRHO_PLUGIN_IS_SYNTH
  476. return kPlugCategSynth;
  477. #else
  478. return kPlugCategUnknown;
  479. #endif
  480. case effGetEffectName:
  481. if (ptr)
  482. {
  483. strncpy((char*)ptr, plugin.name(), kVstMaxProductStrLen);
  484. return 1;
  485. }
  486. return 0;
  487. case effGetVendorString:
  488. if (ptr)
  489. {
  490. strncpy((char*)ptr, plugin.maker(), kVstMaxVendorStrLen);
  491. return 1;
  492. }
  493. return 0;
  494. case effGetProductString:
  495. if (ptr)
  496. {
  497. strncpy((char*)ptr, plugin.label(), kVstMaxEffectNameLen);
  498. return 1;
  499. }
  500. return 0;
  501. case effGetVendorVersion:
  502. return plugin.version();
  503. case effGetVstVersion:
  504. return kVstVersion;
  505. };
  506. if (effect->object)
  507. {
  508. PluginVst* _this_ = (PluginVst*)effect->object;
  509. return _this_->vst_dispatcher(opcode, index, value, ptr, opt);
  510. }
  511. return 0;
  512. }
  513. static float vst_getParameterCallback(AEffect* effect, int32_t index)
  514. {
  515. PluginVst* _this_ = (PluginVst*)effect->object;
  516. assert(_this_);
  517. if (_this_)
  518. return _this_->vst_getParameter(index);
  519. return 0.0f;
  520. }
  521. static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
  522. {
  523. PluginVst* _this_ = (PluginVst*)effect->object;
  524. assert(_this_);
  525. if (_this_)
  526. _this_->vst_setParameter(index, value);
  527. }
  528. static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  529. {
  530. PluginVst* _this_ = (PluginVst*)effect->object;
  531. assert(_this_);
  532. if (_this_)
  533. _this_->vst_processReplacing(inputs, outputs, sampleFrames);
  534. }
  535. static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
  536. {
  537. PluginVst* _this_ = (PluginVst*)effect->object;
  538. assert(_this_);
  539. if (_this_)
  540. _this_->vst_processReplacing(inputs, outputs, sampleFrames);
  541. }
  542. END_NAMESPACE_DISTRHO
  543. // -------------------------------------------------
  544. DISTRHO_PLUGIN_EXPORT
  545. const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
  546. {
  547. USE_NAMESPACE_DISTRHO
  548. // old version
  549. if (! audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f))
  550. return nullptr;
  551. PluginInternal* plugin = nullptr;
  552. vst_dispatcherCallback(nullptr, -1, 0xdead, 0xf00d, &plugin, 0.0f);
  553. AEffect* effect = new AEffect;
  554. memset(effect, 0, sizeof(AEffect));
  555. // vst fields
  556. effect->magic = kEffectMagic;
  557. effect->uniqueID = plugin->uniqueId();
  558. effect->version = plugin->version();
  559. // plugin fields
  560. effect->numParams = plugin->parameterCount();
  561. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  562. effect->numPrograms = plugin->programCount();
  563. #endif
  564. effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
  565. effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;
  566. // static calls
  567. effect->dispatcher = vst_dispatcherCallback;
  568. effect->process = vst_processCallback;
  569. effect->getParameter = vst_getParameterCallback;
  570. effect->setParameter = vst_setParameterCallback;
  571. effect->processReplacing = vst_processReplacingCallback;
  572. effect->processDoubleReplacing = nullptr;
  573. // plugin flags
  574. effect->flags |= effFlagsCanReplacing;
  575. #if DISTRHO_PLUGIN_HAS_UI
  576. # ifdef DISTRHO_UI_QT4
  577. if (QApplication::instance())
  578. # endif
  579. effect->flags |= effFlagsHasEditor;
  580. #endif
  581. #if DISTRHO_PLUGIN_WANT_STATE
  582. effect->flags |= effFlagsProgramChunks;
  583. #endif
  584. // pointers
  585. effect->object = nullptr;
  586. effect->user = (void*)audioMaster;
  587. return effect;
  588. }
  589. // -------------------------------------------------
  590. #endif // DISTRHO_PLUGIN_TARGET_VST