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.

994 lines
29KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2022 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. #ifndef DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
  17. #define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
  18. #include "../DistrhoPlugin.hpp"
  19. #ifdef DISTRHO_PLUGIN_TARGET_VST3
  20. # include "DistrhoPluginVST.hpp"
  21. #endif
  22. #include <set>
  23. START_NAMESPACE_DISTRHO
  24. // -----------------------------------------------------------------------
  25. // Maxmimum values
  26. static const uint32_t kMaxMidiEvents = 512;
  27. // -----------------------------------------------------------------------
  28. // Static data, see DistrhoPlugin.cpp
  29. extern uint32_t d_nextBufferSize;
  30. extern double d_nextSampleRate;
  31. extern const char* d_nextBundlePath;
  32. extern bool d_nextPluginIsDummy;
  33. extern bool d_nextCanRequestParameterValueChanges;
  34. // -----------------------------------------------------------------------
  35. // DSP callbacks
  36. typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent);
  37. typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, float value);
  38. typedef bool (*updateStateValueFunc) (void* ptr, const char* key, const char* value);
  39. // -----------------------------------------------------------------------
  40. // Helpers
  41. struct AudioPortWithBusId : AudioPort {
  42. uint32_t busId;
  43. AudioPortWithBusId()
  44. : AudioPort(),
  45. busId(0) {}
  46. };
  47. struct PortGroupWithId : PortGroup {
  48. uint32_t groupId;
  49. PortGroupWithId()
  50. : PortGroup(),
  51. groupId(kPortGroupNone) {}
  52. };
  53. static void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& portGroup)
  54. {
  55. switch (groupId)
  56. {
  57. case kPortGroupNone:
  58. portGroup.name.clear();
  59. portGroup.symbol.clear();
  60. break;
  61. case kPortGroupMono:
  62. portGroup.name = "Mono";
  63. portGroup.symbol = "dpf_mono";
  64. break;
  65. case kPortGroupStereo:
  66. portGroup.name = "Stereo";
  67. portGroup.symbol = "dpf_stereo";
  68. break;
  69. }
  70. }
  71. // -----------------------------------------------------------------------
  72. // Plugin private data
  73. struct Plugin::PrivateData {
  74. const bool canRequestParameterValueChanges;
  75. const bool isDummy;
  76. bool isProcessing;
  77. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  78. AudioPortWithBusId* audioPorts;
  79. #endif
  80. uint32_t parameterCount;
  81. uint32_t parameterOffset;
  82. Parameter* parameters;
  83. uint32_t portGroupCount;
  84. PortGroupWithId* portGroups;
  85. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  86. uint32_t programCount;
  87. String* programNames;
  88. #endif
  89. #if DISTRHO_PLUGIN_WANT_STATE
  90. uint32_t stateCount;
  91. State* states;
  92. #endif
  93. #if DISTRHO_PLUGIN_WANT_LATENCY
  94. uint32_t latency;
  95. #endif
  96. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  97. TimePosition timePosition;
  98. #endif
  99. // Callbacks
  100. void* callbacksPtr;
  101. writeMidiFunc writeMidiCallbackFunc;
  102. requestParameterValueChangeFunc requestParameterValueChangeCallbackFunc;
  103. updateStateValueFunc updateStateValueCallbackFunc;
  104. uint32_t bufferSize;
  105. double sampleRate;
  106. char* bundlePath;
  107. PrivateData() noexcept
  108. : canRequestParameterValueChanges(d_nextCanRequestParameterValueChanges),
  109. isDummy(d_nextPluginIsDummy),
  110. isProcessing(false),
  111. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  112. audioPorts(nullptr),
  113. #endif
  114. parameterCount(0),
  115. parameterOffset(0),
  116. parameters(nullptr),
  117. portGroupCount(0),
  118. portGroups(nullptr),
  119. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  120. programCount(0),
  121. programNames(nullptr),
  122. #endif
  123. #if DISTRHO_PLUGIN_WANT_STATE
  124. stateCount(0),
  125. states(nullptr),
  126. #endif
  127. #if DISTRHO_PLUGIN_WANT_LATENCY
  128. latency(0),
  129. #endif
  130. callbacksPtr(nullptr),
  131. writeMidiCallbackFunc(nullptr),
  132. requestParameterValueChangeCallbackFunc(nullptr),
  133. updateStateValueCallbackFunc(nullptr),
  134. bufferSize(d_nextBufferSize),
  135. sampleRate(d_nextSampleRate),
  136. bundlePath(d_nextBundlePath != nullptr ? strdup(d_nextBundlePath) : nullptr)
  137. {
  138. DISTRHO_SAFE_ASSERT(bufferSize != 0);
  139. DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
  140. #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
  141. parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  142. # if DISTRHO_PLUGIN_WANT_LATENCY
  143. parameterOffset += 1;
  144. # endif
  145. #endif
  146. #ifdef DISTRHO_PLUGIN_TARGET_LV2
  147. # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS)
  148. parameterOffset += 1;
  149. # endif
  150. # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
  151. parameterOffset += 1;
  152. # endif
  153. #endif
  154. #ifdef DISTRHO_PLUGIN_TARGET_VST3
  155. parameterOffset += kVst3InternalParameterCount;
  156. #endif
  157. }
  158. ~PrivateData() noexcept
  159. {
  160. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  161. if (audioPorts != nullptr)
  162. {
  163. delete[] audioPorts;
  164. audioPorts = nullptr;
  165. }
  166. #endif
  167. if (parameters != nullptr)
  168. {
  169. delete[] parameters;
  170. parameters = nullptr;
  171. }
  172. if (portGroups != nullptr)
  173. {
  174. delete[] portGroups;
  175. portGroups = nullptr;
  176. }
  177. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  178. if (programNames != nullptr)
  179. {
  180. delete[] programNames;
  181. programNames = nullptr;
  182. }
  183. #endif
  184. #if DISTRHO_PLUGIN_WANT_STATE
  185. if (states != nullptr)
  186. {
  187. delete[] states;
  188. states = nullptr;
  189. }
  190. #endif
  191. if (bundlePath != nullptr)
  192. {
  193. std::free(bundlePath);
  194. bundlePath = nullptr;
  195. }
  196. }
  197. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  198. bool writeMidiCallback(const MidiEvent& midiEvent)
  199. {
  200. if (writeMidiCallbackFunc != nullptr)
  201. return writeMidiCallbackFunc(callbacksPtr, midiEvent);
  202. return false;
  203. }
  204. #endif
  205. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  206. bool requestParameterValueChangeCallback(const uint32_t index, const float value)
  207. {
  208. if (requestParameterValueChangeCallbackFunc != nullptr)
  209. return requestParameterValueChangeCallbackFunc(callbacksPtr, index, value);
  210. return false;
  211. }
  212. #endif
  213. #if DISTRHO_PLUGIN_WANT_STATE
  214. bool updateStateValueCallback(const char* const key, const char* const value)
  215. {
  216. d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc);
  217. if (updateStateValueCallbackFunc != nullptr)
  218. return updateStateValueCallbackFunc(callbacksPtr, key, value);
  219. return false;
  220. }
  221. #endif
  222. };
  223. // -----------------------------------------------------------------------
  224. // Plugin exporter class
  225. class PluginExporter
  226. {
  227. public:
  228. PluginExporter(void* const callbacksPtr,
  229. const writeMidiFunc writeMidiCall,
  230. const requestParameterValueChangeFunc requestParameterValueChangeCall,
  231. const updateStateValueFunc updateStateValueCall)
  232. : fPlugin(createPlugin()),
  233. fData((fPlugin != nullptr) ? fPlugin->pData : nullptr),
  234. fIsActive(false)
  235. {
  236. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  237. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  238. #if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__)
  239. /* Run-time testing build.
  240. * Verify that virtual functions are overriden if parameters, programs or states are in use.
  241. * This does not work on all compilers, but we use it purely as informational check anyway. */
  242. if (fData->parameterCount != 0)
  243. {
  244. if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter)
  245. {
  246. d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`");
  247. abort();
  248. }
  249. if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue)
  250. {
  251. d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`");
  252. abort();
  253. }
  254. if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue)
  255. {
  256. d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`");
  257. abort();
  258. }
  259. }
  260. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  261. if (fData->programCount != 0)
  262. {
  263. if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName)
  264. {
  265. d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`");
  266. abort();
  267. }
  268. if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram)
  269. {
  270. d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`");
  271. abort();
  272. }
  273. }
  274. # endif
  275. # if DISTRHO_PLUGIN_WANT_STATE
  276. if (fData->stateCount != 0)
  277. {
  278. if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState)
  279. {
  280. d_stderr2("DPF warning: Plugins with state must implement `initState`");
  281. abort();
  282. }
  283. if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
  284. {
  285. d_stderr2("DPF warning: Plugins with state must implement `setState`");
  286. abort();
  287. }
  288. }
  289. # endif
  290. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  291. if (fData->stateCount != 0)
  292. {
  293. if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState)
  294. {
  295. d_stderr2("DPF warning: Plugins with full state must implement `getState`");
  296. abort();
  297. }
  298. }
  299. else
  300. {
  301. d_stderr2("DPF warning: Plugins with full state must have at least 1 state");
  302. abort();
  303. }
  304. # endif
  305. #endif
  306. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  307. {
  308. uint32_t j=0;
  309. # if DISTRHO_PLUGIN_NUM_INPUTS > 0
  310. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
  311. fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
  312. # endif
  313. # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  314. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
  315. fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
  316. # endif
  317. }
  318. #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  319. for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
  320. fPlugin->initParameter(i, fData->parameters[i]);
  321. {
  322. std::set<uint32_t> portGroupIndices;
  323. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  324. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  325. portGroupIndices.insert(fData->audioPorts[i].groupId);
  326. #endif
  327. for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
  328. portGroupIndices.insert(fData->parameters[i].groupId);
  329. portGroupIndices.erase(kPortGroupNone);
  330. if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size()))
  331. {
  332. fData->portGroups = new PortGroupWithId[portGroupSize];
  333. fData->portGroupCount = portGroupSize;
  334. uint32_t index = 0;
  335. for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index)
  336. {
  337. PortGroupWithId& portGroup(fData->portGroups[index]);
  338. portGroup.groupId = *it;
  339. if (portGroup.groupId < portGroupSize)
  340. fPlugin->initPortGroup(portGroup.groupId, portGroup);
  341. else
  342. fillInPredefinedPortGroupData(portGroup.groupId, portGroup);
  343. }
  344. }
  345. }
  346. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  347. for (uint32_t i=0, count=fData->programCount; i < count; ++i)
  348. fPlugin->initProgramName(i, fData->programNames[i]);
  349. #endif
  350. #if DISTRHO_PLUGIN_WANT_STATE
  351. for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
  352. fPlugin->initState(i, fData->states[i]);
  353. #endif
  354. fData->callbacksPtr = callbacksPtr;
  355. fData->writeMidiCallbackFunc = writeMidiCall;
  356. fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall;
  357. fData->updateStateValueCallbackFunc = updateStateValueCall;
  358. }
  359. ~PluginExporter()
  360. {
  361. delete fPlugin;
  362. }
  363. // -------------------------------------------------------------------
  364. const char* getName() const noexcept
  365. {
  366. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  367. return fPlugin->getName();
  368. }
  369. const char* getLabel() const noexcept
  370. {
  371. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  372. return fPlugin->getLabel();
  373. }
  374. const char* getDescription() const noexcept
  375. {
  376. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  377. return fPlugin->getDescription();
  378. }
  379. const char* getMaker() const noexcept
  380. {
  381. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  382. return fPlugin->getMaker();
  383. }
  384. const char* getHomePage() const noexcept
  385. {
  386. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  387. return fPlugin->getHomePage();
  388. }
  389. const char* getLicense() const noexcept
  390. {
  391. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  392. return fPlugin->getLicense();
  393. }
  394. uint32_t getVersion() const noexcept
  395. {
  396. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
  397. return fPlugin->getVersion();
  398. }
  399. long getUniqueId() const noexcept
  400. {
  401. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
  402. return fPlugin->getUniqueId();
  403. }
  404. void* getInstancePointer() const noexcept
  405. {
  406. return fPlugin;
  407. }
  408. // -------------------------------------------------------------------
  409. #if DISTRHO_PLUGIN_WANT_LATENCY
  410. uint32_t getLatency() const noexcept
  411. {
  412. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  413. return fData->latency;
  414. }
  415. #endif
  416. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  417. AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept
  418. {
  419. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);
  420. if (input)
  421. {
  422. # if DISTRHO_PLUGIN_NUM_INPUTS > 0
  423. DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS, sFallbackAudioPort);
  424. # endif
  425. }
  426. else
  427. {
  428. # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  429. DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort);
  430. # endif
  431. }
  432. return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
  433. }
  434. uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept
  435. {
  436. return getAudioPort(input, index).hints;
  437. }
  438. uint32_t getAudioPortCountWithGroupId(const bool input, const uint32_t groupId) const noexcept
  439. {
  440. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  441. uint32_t numPorts = 0;
  442. if (input)
  443. {
  444. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  445. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  446. {
  447. if (fData->audioPorts[i].groupId == groupId)
  448. ++numPorts;
  449. }
  450. #endif
  451. }
  452. else
  453. {
  454. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  455. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  456. {
  457. if (fData->audioPorts[i + DISTRHO_PLUGIN_NUM_INPUTS].groupId == groupId)
  458. ++numPorts;
  459. }
  460. #endif
  461. }
  462. return numPorts;
  463. }
  464. #endif
  465. uint32_t getParameterCount() const noexcept
  466. {
  467. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  468. return fData->parameterCount;
  469. }
  470. uint32_t getParameterOffset() const noexcept
  471. {
  472. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  473. return fData->parameterOffset;
  474. }
  475. uint32_t getParameterHints(const uint32_t index) const noexcept
  476. {
  477. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0);
  478. return fData->parameters[index].hints;
  479. }
  480. ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept
  481. {
  482. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull);
  483. return fData->parameters[index].designation;
  484. }
  485. bool isParameterInput(const uint32_t index) const noexcept
  486. {
  487. return (getParameterHints(index) & kParameterIsOutput) == 0x0;
  488. }
  489. bool isParameterOutput(const uint32_t index) const noexcept
  490. {
  491. return (getParameterHints(index) & kParameterIsOutput) != 0x0;
  492. }
  493. bool isParameterTrigger(const uint32_t index) const noexcept
  494. {
  495. return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger;
  496. }
  497. bool isParameterOutputOrTrigger(const uint32_t index) const noexcept
  498. {
  499. const uint32_t hints = getParameterHints(index);
  500. if (hints & kParameterIsOutput)
  501. return true;
  502. if ((hints & kParameterIsTrigger) == kParameterIsTrigger)
  503. return true;
  504. return false;
  505. }
  506. const String& getParameterName(const uint32_t index) const noexcept
  507. {
  508. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  509. return fData->parameters[index].name;
  510. }
  511. const String& getParameterShortName(const uint32_t index) const noexcept
  512. {
  513. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  514. return fData->parameters[index].shortName;
  515. }
  516. const String& getParameterSymbol(const uint32_t index) const noexcept
  517. {
  518. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  519. return fData->parameters[index].symbol;
  520. }
  521. const String& getParameterUnit(const uint32_t index) const noexcept
  522. {
  523. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  524. return fData->parameters[index].unit;
  525. }
  526. const String& getParameterDescription(const uint32_t index) const noexcept
  527. {
  528. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  529. return fData->parameters[index].description;
  530. }
  531. const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
  532. {
  533. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
  534. return fData->parameters[index].enumValues;
  535. }
  536. const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
  537. {
  538. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges);
  539. return fData->parameters[index].ranges;
  540. }
  541. uint8_t getParameterMidiCC(const uint32_t index) const noexcept
  542. {
  543. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0);
  544. return fData->parameters[index].midiCC;
  545. }
  546. uint32_t getParameterGroupId(const uint32_t index) const noexcept
  547. {
  548. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kPortGroupNone);
  549. return fData->parameters[index].groupId;
  550. }
  551. float getParameterDefault(const uint32_t index) const
  552. {
  553. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
  554. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
  555. return fData->parameters[index].ranges.def;
  556. }
  557. float getParameterValue(const uint32_t index) const
  558. {
  559. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
  560. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
  561. return fPlugin->getParameterValue(index);
  562. }
  563. void setParameterValue(const uint32_t index, const float value)
  564. {
  565. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  566. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,);
  567. fPlugin->setParameterValue(index, value);
  568. }
  569. uint32_t getPortGroupCount() const noexcept
  570. {
  571. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  572. return fData->portGroupCount;
  573. }
  574. const PortGroupWithId& getPortGroupById(const uint32_t groupId) const noexcept
  575. {
  576. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && fData->portGroupCount != 0, sFallbackPortGroup);
  577. for (uint32_t i=0; i < fData->portGroupCount; ++i)
  578. {
  579. const PortGroupWithId& portGroup(fData->portGroups[i]);
  580. if (portGroup.groupId == groupId)
  581. return portGroup;
  582. }
  583. return sFallbackPortGroup;
  584. }
  585. const PortGroupWithId& getPortGroupByIndex(const uint32_t index) const noexcept
  586. {
  587. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->portGroupCount, sFallbackPortGroup);
  588. return fData->portGroups[index];
  589. }
  590. const String& getPortGroupSymbolForId(const uint32_t groupId) const noexcept
  591. {
  592. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
  593. return getPortGroupById(groupId).symbol;
  594. }
  595. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  596. uint32_t getProgramCount() const noexcept
  597. {
  598. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  599. return fData->programCount;
  600. }
  601. const String& getProgramName(const uint32_t index) const noexcept
  602. {
  603. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString);
  604. return fData->programNames[index];
  605. }
  606. void loadProgram(const uint32_t index)
  607. {
  608. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  609. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,);
  610. fPlugin->loadProgram(index);
  611. }
  612. #endif
  613. #if DISTRHO_PLUGIN_WANT_STATE
  614. uint32_t getStateCount() const noexcept
  615. {
  616. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  617. return fData->stateCount;
  618. }
  619. uint32_t getStateHints(const uint32_t index) const noexcept
  620. {
  621. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, 0x0);
  622. return fData->states[index].hints;
  623. }
  624. const String& getStateKey(const uint32_t index) const noexcept
  625. {
  626. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  627. return fData->states[index].key;
  628. }
  629. const String& getStateDefaultValue(const uint32_t index) const noexcept
  630. {
  631. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  632. return fData->states[index].defaultValue;
  633. }
  634. const String& getStateLabel(const uint32_t index) const noexcept
  635. {
  636. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  637. return fData->states[index].label;
  638. }
  639. const String& getStateDescription(const uint32_t index) const noexcept
  640. {
  641. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  642. return fData->states[index].description;
  643. }
  644. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  645. String getStateValue(const char* const key) const
  646. {
  647. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
  648. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString);
  649. return fPlugin->getState(key);
  650. }
  651. # endif
  652. void setState(const char* const key, const char* const value)
  653. {
  654. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  655. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  656. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
  657. fPlugin->setState(key, value);
  658. }
  659. bool wantStateKey(const char* const key) const noexcept
  660. {
  661. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
  662. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
  663. for (uint32_t i=0; i < fData->stateCount; ++i)
  664. {
  665. if (fData->states[i].key == key)
  666. return true;
  667. }
  668. return false;
  669. }
  670. #endif
  671. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  672. void setTimePosition(const TimePosition& timePosition) noexcept
  673. {
  674. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  675. std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition));
  676. }
  677. #endif
  678. // -------------------------------------------------------------------
  679. bool isActive() const noexcept
  680. {
  681. return fIsActive;
  682. }
  683. void activate()
  684. {
  685. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  686. DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,);
  687. fIsActive = true;
  688. fPlugin->activate();
  689. }
  690. void deactivate()
  691. {
  692. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  693. DISTRHO_SAFE_ASSERT_RETURN(fIsActive,);
  694. fIsActive = false;
  695. fPlugin->deactivate();
  696. }
  697. void deactivateIfNeeded()
  698. {
  699. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  700. if (fIsActive)
  701. {
  702. fIsActive = false;
  703. fPlugin->deactivate();
  704. }
  705. }
  706. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  707. void run(const float** const inputs, float** const outputs, const uint32_t frames,
  708. const MidiEvent* const midiEvents, const uint32_t midiEventCount)
  709. {
  710. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  711. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  712. if (! fIsActive)
  713. {
  714. fIsActive = true;
  715. fPlugin->activate();
  716. }
  717. fData->isProcessing = true;
  718. fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
  719. fData->isProcessing = false;
  720. }
  721. #else
  722. void run(const float** const inputs, float** const outputs, const uint32_t frames)
  723. {
  724. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  725. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  726. if (! fIsActive)
  727. {
  728. fIsActive = true;
  729. fPlugin->activate();
  730. }
  731. fData->isProcessing = true;
  732. fPlugin->run(inputs, outputs, frames);
  733. fData->isProcessing = false;
  734. }
  735. #endif
  736. // -------------------------------------------------------------------
  737. uint32_t getBufferSize() const noexcept
  738. {
  739. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  740. return fData->bufferSize;
  741. }
  742. double getSampleRate() const noexcept
  743. {
  744. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0);
  745. return fData->sampleRate;
  746. }
  747. void setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
  748. {
  749. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  750. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  751. DISTRHO_SAFE_ASSERT(bufferSize >= 2);
  752. if (fData->bufferSize == bufferSize)
  753. return;
  754. fData->bufferSize = bufferSize;
  755. if (doCallback)
  756. {
  757. if (fIsActive) fPlugin->deactivate();
  758. fPlugin->bufferSizeChanged(bufferSize);
  759. if (fIsActive) fPlugin->activate();
  760. }
  761. }
  762. void setSampleRate(const double sampleRate, const bool doCallback = false)
  763. {
  764. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  765. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  766. DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
  767. if (d_isEqual(fData->sampleRate, sampleRate))
  768. return;
  769. fData->sampleRate = sampleRate;
  770. if (doCallback)
  771. {
  772. if (fIsActive) fPlugin->deactivate();
  773. fPlugin->sampleRateChanged(sampleRate);
  774. if (fIsActive) fPlugin->activate();
  775. }
  776. }
  777. private:
  778. // -------------------------------------------------------------------
  779. // Plugin and DistrhoPlugin data
  780. Plugin* const fPlugin;
  781. Plugin::PrivateData* const fData;
  782. bool fIsActive;
  783. // -------------------------------------------------------------------
  784. // Static fallback data, see DistrhoPlugin.cpp
  785. static const String sFallbackString;
  786. static /* */ AudioPortWithBusId sFallbackAudioPort;
  787. static const ParameterRanges sFallbackRanges;
  788. static const ParameterEnumerationValues sFallbackEnumValues;
  789. static const PortGroupWithId sFallbackPortGroup;
  790. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
  791. };
  792. // -----------------------------------------------------------------------
  793. END_NAMESPACE_DISTRHO
  794. #endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED