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.

641 lines
17KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
  17. #define DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED
  18. #include "../DistrhoPlugin.hpp"
  19. START_NAMESPACE_DISTRHO
  20. // -----------------------------------------------------------------------
  21. // Maxmimum values
  22. static const uint32_t kMaxMidiEvents = 512;
  23. // -----------------------------------------------------------------------
  24. // Static data, see DistrhoPlugin.cpp
  25. extern uint32_t d_lastBufferSize;
  26. extern double d_lastSampleRate;
  27. // -----------------------------------------------------------------------
  28. // DSP callbacks
  29. typedef bool (*writeMidiFunc) (void* ptr, const MidiEvent& midiEvent);
  30. // -----------------------------------------------------------------------
  31. // Plugin private data
  32. struct Plugin::PrivateData {
  33. bool isProcessing;
  34. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  35. AudioPort* audioPorts;
  36. #endif
  37. uint32_t parameterCount;
  38. uint32_t parameterOffset;
  39. Parameter* parameters;
  40. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  41. uint32_t programCount;
  42. String* programNames;
  43. #endif
  44. #if DISTRHO_PLUGIN_WANT_STATE
  45. uint32_t stateCount;
  46. String* stateKeys;
  47. String* stateDefValues;
  48. #endif
  49. #if DISTRHO_PLUGIN_WANT_LATENCY
  50. uint32_t latency;
  51. #endif
  52. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  53. TimePosition timePosition;
  54. #endif
  55. // Callbacks
  56. void* callbacksPtr;
  57. writeMidiFunc writeMidiCallbackFunc;
  58. uint32_t bufferSize;
  59. double sampleRate;
  60. PrivateData() noexcept
  61. : isProcessing(false),
  62. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  63. audioPorts(nullptr),
  64. #endif
  65. parameterCount(0),
  66. parameterOffset(0),
  67. parameters(nullptr),
  68. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  69. programCount(0),
  70. programNames(nullptr),
  71. #endif
  72. #if DISTRHO_PLUGIN_WANT_STATE
  73. stateCount(0),
  74. stateKeys(nullptr),
  75. stateDefValues(nullptr),
  76. #endif
  77. #if DISTRHO_PLUGIN_WANT_LATENCY
  78. latency(0),
  79. #endif
  80. callbacksPtr(nullptr),
  81. writeMidiCallbackFunc(nullptr),
  82. bufferSize(d_lastBufferSize),
  83. sampleRate(d_lastSampleRate)
  84. {
  85. DISTRHO_SAFE_ASSERT(bufferSize != 0);
  86. DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
  87. #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
  88. parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  89. # if DISTRHO_PLUGIN_WANT_LATENCY
  90. parameterOffset += 1;
  91. # endif
  92. #endif
  93. #ifdef DISTRHO_PLUGIN_TARGET_LV2
  94. # if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
  95. parameterOffset += 1;
  96. # if DISTRHO_PLUGIN_WANT_STATE
  97. parameterOffset += 1;
  98. # endif
  99. # endif
  100. #endif
  101. }
  102. ~PrivateData() noexcept
  103. {
  104. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  105. if (audioPorts != nullptr)
  106. {
  107. delete[] audioPorts;
  108. audioPorts = nullptr;
  109. }
  110. #endif
  111. if (parameters != nullptr)
  112. {
  113. delete[] parameters;
  114. parameters = nullptr;
  115. }
  116. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  117. if (programNames != nullptr)
  118. {
  119. delete[] programNames;
  120. programNames = nullptr;
  121. }
  122. #endif
  123. #if DISTRHO_PLUGIN_WANT_STATE
  124. if (stateKeys != nullptr)
  125. {
  126. delete[] stateKeys;
  127. stateKeys = nullptr;
  128. }
  129. if (stateDefValues != nullptr)
  130. {
  131. delete[] stateDefValues;
  132. stateDefValues = nullptr;
  133. }
  134. #endif
  135. }
  136. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  137. bool writeMidiCallback(const MidiEvent& midiEvent)
  138. {
  139. if (writeMidiCallbackFunc != nullptr)
  140. return writeMidiCallbackFunc(callbacksPtr, midiEvent);
  141. return false;
  142. }
  143. #endif
  144. };
  145. // -----------------------------------------------------------------------
  146. // Plugin exporter class
  147. class PluginExporter
  148. {
  149. public:
  150. PluginExporter(void* const callbacksPtr, const writeMidiFunc writeMidiCall)
  151. : fPlugin(createPlugin()),
  152. fData((fPlugin != nullptr) ? fPlugin->pData : nullptr),
  153. fIsActive(false)
  154. {
  155. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  156. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  157. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  158. {
  159. uint32_t j=0;
  160. # if DISTRHO_PLUGIN_NUM_INPUTS > 0
  161. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
  162. fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
  163. # endif
  164. # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  165. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
  166. fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
  167. # endif
  168. }
  169. #endif
  170. for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
  171. fPlugin->initParameter(i, fData->parameters[i]);
  172. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  173. for (uint32_t i=0, count=fData->programCount; i < count; ++i)
  174. fPlugin->initProgramName(i, fData->programNames[i]);
  175. #endif
  176. #if DISTRHO_PLUGIN_WANT_STATE
  177. for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
  178. fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]);
  179. #endif
  180. fData->callbacksPtr = callbacksPtr;
  181. fData->writeMidiCallbackFunc = writeMidiCall;
  182. }
  183. ~PluginExporter()
  184. {
  185. delete fPlugin;
  186. }
  187. // -------------------------------------------------------------------
  188. const char* getName() const noexcept
  189. {
  190. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  191. return fPlugin->getName();
  192. }
  193. const char* getLabel() const noexcept
  194. {
  195. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  196. return fPlugin->getLabel();
  197. }
  198. const char* getDescription() const noexcept
  199. {
  200. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  201. return fPlugin->getDescription();
  202. }
  203. const char* getMaker() const noexcept
  204. {
  205. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  206. return fPlugin->getMaker();
  207. }
  208. const char* getHomePage() const noexcept
  209. {
  210. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  211. return fPlugin->getHomePage();
  212. }
  213. const char* getLicense() const noexcept
  214. {
  215. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, "");
  216. return fPlugin->getLicense();
  217. }
  218. uint32_t getVersion() const noexcept
  219. {
  220. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
  221. return fPlugin->getVersion();
  222. }
  223. long getUniqueId() const noexcept
  224. {
  225. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0);
  226. return fPlugin->getUniqueId();
  227. }
  228. void* getInstancePointer() const noexcept
  229. {
  230. return fPlugin;
  231. }
  232. // -------------------------------------------------------------------
  233. #if DISTRHO_PLUGIN_WANT_LATENCY
  234. uint32_t getLatency() const noexcept
  235. {
  236. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  237. return fData->latency;
  238. }
  239. #endif
  240. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  241. const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept
  242. {
  243. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);
  244. if (input)
  245. {
  246. # if DISTRHO_PLUGIN_NUM_INPUTS > 0
  247. DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS, sFallbackAudioPort);
  248. # endif
  249. }
  250. else
  251. {
  252. # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  253. DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort);
  254. # endif
  255. }
  256. return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
  257. }
  258. #endif
  259. uint32_t getParameterCount() const noexcept
  260. {
  261. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  262. return fData->parameterCount;
  263. }
  264. uint32_t getParameterOffset() const noexcept
  265. {
  266. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  267. return fData->parameterOffset;
  268. }
  269. uint32_t getParameterHints(const uint32_t index) const noexcept
  270. {
  271. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0);
  272. return fData->parameters[index].hints;
  273. }
  274. ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept
  275. {
  276. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull);
  277. return fData->parameters[index].designation;
  278. }
  279. bool isParameterOutput(const uint32_t index) const noexcept
  280. {
  281. return (getParameterHints(index) & kParameterIsOutput);
  282. }
  283. const String& getParameterName(const uint32_t index) const noexcept
  284. {
  285. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  286. return fData->parameters[index].name;
  287. }
  288. const String& getParameterSymbol(const uint32_t index) const noexcept
  289. {
  290. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  291. return fData->parameters[index].symbol;
  292. }
  293. const String& getParameterUnit(const uint32_t index) const noexcept
  294. {
  295. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
  296. return fData->parameters[index].unit;
  297. }
  298. const ParameterRanges& getParameterRanges(const uint32_t index) const noexcept
  299. {
  300. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackRanges);
  301. return fData->parameters[index].ranges;
  302. }
  303. uint8_t getParameterMidiCC(const uint32_t index) const noexcept
  304. {
  305. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0);
  306. return fData->parameters[index].midiCC;
  307. }
  308. float getParameterValue(const uint32_t index) const
  309. {
  310. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
  311. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
  312. return fPlugin->getParameterValue(index);
  313. }
  314. void setParameterValue(const uint32_t index, const float value)
  315. {
  316. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  317. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,);
  318. fPlugin->setParameterValue(index, value);
  319. }
  320. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  321. uint32_t getProgramCount() const noexcept
  322. {
  323. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  324. return fData->programCount;
  325. }
  326. const String& getProgramName(const uint32_t index) const noexcept
  327. {
  328. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString);
  329. return fData->programNames[index];
  330. }
  331. void loadProgram(const uint32_t index)
  332. {
  333. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  334. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,);
  335. fPlugin->loadProgram(index);
  336. }
  337. #endif
  338. #if DISTRHO_PLUGIN_WANT_STATE
  339. uint32_t getStateCount() const noexcept
  340. {
  341. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  342. return fData->stateCount;
  343. }
  344. const String& getStateKey(const uint32_t index) const noexcept
  345. {
  346. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  347. return fData->stateKeys[index];
  348. }
  349. const String& getStateDefaultValue(const uint32_t index) const noexcept
  350. {
  351. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString);
  352. return fData->stateDefValues[index];
  353. }
  354. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  355. String getState(const char* key) const
  356. {
  357. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
  358. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', sFallbackString);
  359. return fPlugin->getState(key);
  360. }
  361. # endif
  362. void setState(const char* const key, const char* const value)
  363. {
  364. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  365. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  366. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
  367. fPlugin->setState(key, value);
  368. }
  369. bool wantStateKey(const char* const key) const noexcept
  370. {
  371. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
  372. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
  373. for (uint32_t i=0; i < fData->stateCount; ++i)
  374. {
  375. if (fData->stateKeys[i] == key)
  376. return true;
  377. }
  378. return false;
  379. }
  380. #endif
  381. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  382. void setTimePosition(const TimePosition& timePosition) noexcept
  383. {
  384. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  385. std::memcpy(&fData->timePosition, &timePosition, sizeof(TimePosition));
  386. }
  387. #endif
  388. // -------------------------------------------------------------------
  389. bool isActive() const noexcept
  390. {
  391. return fIsActive;
  392. }
  393. void activate()
  394. {
  395. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  396. DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,);
  397. fIsActive = true;
  398. fPlugin->activate();
  399. }
  400. void deactivate()
  401. {
  402. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  403. DISTRHO_SAFE_ASSERT_RETURN(fIsActive,);
  404. fIsActive = false;
  405. fPlugin->deactivate();
  406. }
  407. void deactivateIfNeeded()
  408. {
  409. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  410. if (fIsActive)
  411. {
  412. fIsActive = false;
  413. fPlugin->deactivate();
  414. }
  415. }
  416. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  417. void run(const float** const inputs, float** const outputs, const uint32_t frames,
  418. const MidiEvent* const midiEvents, const uint32_t midiEventCount)
  419. {
  420. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  421. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  422. if (! fIsActive)
  423. {
  424. fIsActive = true;
  425. fPlugin->activate();
  426. }
  427. fData->isProcessing = true;
  428. fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
  429. fData->isProcessing = false;
  430. }
  431. #else
  432. void run(const float** const inputs, float** const outputs, const uint32_t frames)
  433. {
  434. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  435. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  436. if (! fIsActive)
  437. {
  438. fIsActive = true;
  439. fPlugin->activate();
  440. }
  441. fData->isProcessing = true;
  442. fPlugin->run(inputs, outputs, frames);
  443. fData->isProcessing = false;
  444. }
  445. #endif
  446. // -------------------------------------------------------------------
  447. uint32_t getBufferSize() const noexcept
  448. {
  449. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  450. return fData->bufferSize;
  451. }
  452. double getSampleRate() const noexcept
  453. {
  454. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0.0);
  455. return fData->sampleRate;
  456. }
  457. void setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
  458. {
  459. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  460. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  461. DISTRHO_SAFE_ASSERT(bufferSize >= 2);
  462. if (fData->bufferSize == bufferSize)
  463. return;
  464. fData->bufferSize = bufferSize;
  465. if (doCallback)
  466. {
  467. if (fIsActive) fPlugin->deactivate();
  468. fPlugin->bufferSizeChanged(bufferSize);
  469. if (fIsActive) fPlugin->activate();
  470. }
  471. }
  472. void setSampleRate(const double sampleRate, const bool doCallback = false)
  473. {
  474. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  475. DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  476. DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
  477. if (d_isEqual(fData->sampleRate, sampleRate))
  478. return;
  479. fData->sampleRate = sampleRate;
  480. if (doCallback)
  481. {
  482. if (fIsActive) fPlugin->deactivate();
  483. fPlugin->sampleRateChanged(sampleRate);
  484. if (fIsActive) fPlugin->activate();
  485. }
  486. }
  487. private:
  488. // -------------------------------------------------------------------
  489. // Plugin and DistrhoPlugin data
  490. Plugin* const fPlugin;
  491. Plugin::PrivateData* const fData;
  492. bool fIsActive;
  493. // -------------------------------------------------------------------
  494. // Static fallback data, see DistrhoPlugin.cpp
  495. static const String sFallbackString;
  496. static const AudioPort sFallbackAudioPort;
  497. static const ParameterRanges sFallbackRanges;
  498. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
  499. DISTRHO_PREVENT_HEAP_ALLOCATION
  500. };
  501. // -----------------------------------------------------------------------
  502. END_NAMESPACE_DISTRHO
  503. #endif // DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED