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.

552 lines
15KB

  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. #include "DistrhoPluginInternal.hpp"
  17. #if DISTRHO_PLUGIN_HAS_UI
  18. # include "DistrhoUIInternal.hpp"
  19. #endif
  20. #include "CarlaNative.hpp"
  21. // TODO
  22. #undef DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  23. #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0
  24. // -----------------------------------------------------------------------
  25. START_NAMESPACE_DISTRHO
  26. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  27. static constexpr const writeMidiFunc writeMidiCallback = nullptr;
  28. #endif
  29. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  30. static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  31. #endif
  32. // TODO
  33. static constexpr const updateStateValueFunc updateStateValueCallback = nullptr;
  34. #if DISTRHO_PLUGIN_HAS_UI
  35. // -----------------------------------------------------------------------
  36. // Carla UI
  37. #if ! DISTRHO_PLUGIN_WANT_STATE
  38. static const setStateFunc setStateCallback = nullptr;
  39. #endif
  40. #if ! DISTRHO_PLUGIN_IS_SYNTH
  41. static const sendNoteFunc sendNoteCallback = nullptr;
  42. #endif
  43. class UICarla
  44. {
  45. public:
  46. UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin)
  47. : fHost(host),
  48. fUI(this, 0, plugin->getSampleRate(),
  49. editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback,
  50. nullptr, // window size
  51. nullptr, // TODO file request
  52. nullptr, // bundle path
  53. plugin->getInstancePointer())
  54. {
  55. fUI.setWindowTitle(host->uiName);
  56. if (host->uiParentId != 0)
  57. fUI.setWindowTransientWinId(host->uiParentId);
  58. }
  59. ~UICarla()
  60. {
  61. fUI.quit();
  62. }
  63. // ---------------------------------------------
  64. void carla_show(const bool yesNo)
  65. {
  66. fUI.setWindowVisible(yesNo);
  67. }
  68. bool carla_idle()
  69. {
  70. return fUI.plugin_idle();
  71. }
  72. void carla_setParameterValue(const uint32_t index, const float value)
  73. {
  74. fUI.parameterChanged(index, value);
  75. }
  76. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  77. void carla_setMidiProgram(const uint32_t realProgram)
  78. {
  79. fUI.programLoaded(realProgram);
  80. }
  81. #endif
  82. #if DISTRHO_PLUGIN_WANT_STATE
  83. void carla_setCustomData(const char* const key, const char* const value)
  84. {
  85. fUI.stateChanged(key, value);
  86. }
  87. #endif
  88. void carla_setUiTitle(const char* const uiTitle)
  89. {
  90. fUI.setWindowTitle(uiTitle);
  91. }
  92. // ---------------------------------------------
  93. protected:
  94. void handleEditParameter(const uint32_t, const bool)
  95. {
  96. // TODO
  97. }
  98. void handleSetParameterValue(const uint32_t rindex, const float value)
  99. {
  100. fHost->ui_parameter_changed(fHost->handle, rindex, value);
  101. }
  102. #if DISTRHO_PLUGIN_WANT_STATE
  103. void handleSetState(const char* const key, const char* const value)
  104. {
  105. fHost->ui_custom_data_changed(fHost->handle, key, value);
  106. }
  107. #endif
  108. #if DISTRHO_PLUGIN_IS_SYNTH
  109. void handleSendNote(const uint8_t, const uint8_t, const uint8_t)
  110. {
  111. // TODO
  112. }
  113. #endif
  114. // ---------------------------------------------
  115. private:
  116. // Plugin stuff
  117. const NativeHostDescriptor* const fHost;
  118. // UI
  119. UIExporter fUI;
  120. // ---------------------------------------------
  121. // Callbacks
  122. #define handlePtr ((UICarla*)ptr)
  123. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  124. {
  125. handlePtr->handleEditParameter(index, started);
  126. }
  127. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  128. {
  129. handlePtr->handleSetParameterValue(rindex, value);
  130. }
  131. #if DISTRHO_PLUGIN_WANT_STATE
  132. static void setStateCallback(void* ptr, const char* key, const char* value)
  133. {
  134. handlePtr->handleSetState(key, value);
  135. }
  136. #endif
  137. #if DISTRHO_PLUGIN_IS_SYNTH
  138. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  139. {
  140. handlePtr->handleSendNote(channel, note, velocity);
  141. }
  142. #endif
  143. #undef handlePtr
  144. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla)
  145. };
  146. #endif // DISTRHO_PLUGIN_HAS_UI
  147. // -----------------------------------------------------------------------
  148. // Carla Plugin
  149. class PluginCarla : public NativePluginClass
  150. {
  151. public:
  152. PluginCarla(const NativeHostDescriptor* const host)
  153. : NativePluginClass(host),
  154. fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback),
  155. fScalePointsCache(nullptr)
  156. {
  157. #if DISTRHO_PLUGIN_HAS_UI
  158. fUiPtr = nullptr;
  159. #endif
  160. }
  161. ~PluginCarla() override
  162. {
  163. #if DISTRHO_PLUGIN_HAS_UI
  164. if (fUiPtr != nullptr)
  165. {
  166. delete fUiPtr;
  167. fUiPtr = nullptr;
  168. }
  169. #endif
  170. if (fScalePointsCache != nullptr)
  171. {
  172. delete[] fScalePointsCache;
  173. fScalePointsCache = nullptr;
  174. }
  175. }
  176. protected:
  177. // -------------------------------------------------------------------
  178. // Plugin parameter calls
  179. uint32_t getParameterCount() const override
  180. {
  181. return fPlugin.getParameterCount();
  182. }
  183. const NativeParameter* getParameterInfo(const uint32_t index) const override
  184. {
  185. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), nullptr);
  186. static NativeParameter param;
  187. param.scalePointCount = 0;
  188. param.scalePoints = nullptr;
  189. {
  190. int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED;
  191. const uint32_t paramHints = fPlugin.getParameterHints(index);
  192. if (paramHints & kParameterIsAutomatable)
  193. nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE;
  194. if (paramHints & kParameterIsBoolean)
  195. nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN;
  196. if (paramHints & kParameterIsInteger)
  197. nativeParamHints |= ::NATIVE_PARAMETER_IS_INTEGER;
  198. if (paramHints & kParameterIsLogarithmic)
  199. nativeParamHints |= ::NATIVE_PARAMETER_IS_LOGARITHMIC;
  200. if (paramHints & kParameterIsOutput)
  201. nativeParamHints |= ::NATIVE_PARAMETER_IS_OUTPUT;
  202. param.hints = static_cast<NativeParameterHints>(nativeParamHints);
  203. }
  204. param.name = fPlugin.getParameterName(index);
  205. param.unit = fPlugin.getParameterUnit(index);
  206. {
  207. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  208. param.ranges.def = ranges.def;
  209. param.ranges.min = ranges.min;
  210. param.ranges.max = ranges.max;
  211. }
  212. {
  213. const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index));
  214. if (const uint32_t scalePointCount = enumValues.count)
  215. {
  216. NativeParameterScalePoint* const scalePoints = new NativeParameterScalePoint[scalePointCount];
  217. for (uint32_t i=0; i<scalePointCount; ++i)
  218. {
  219. scalePoints[i].label = enumValues.values[i].label.buffer();
  220. scalePoints[i].value = enumValues.values[i].value;
  221. }
  222. param.scalePoints = scalePoints;
  223. param.scalePointCount = scalePointCount;
  224. if (enumValues.restrictedMode)
  225. param.hints = static_cast<NativeParameterHints>(param.hints|::NATIVE_PARAMETER_USES_SCALEPOINTS);
  226. }
  227. else if (fScalePointsCache != nullptr)
  228. {
  229. delete[] fScalePointsCache;
  230. fScalePointsCache = nullptr;
  231. }
  232. }
  233. return &param;
  234. }
  235. float getParameterValue(const uint32_t index) const override
  236. {
  237. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), 0.0f);
  238. return fPlugin.getParameterValue(index);
  239. }
  240. // -------------------------------------------------------------------
  241. // Plugin midi-program calls
  242. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  243. uint32_t getMidiProgramCount() const override
  244. {
  245. return fPlugin.getProgramCount();
  246. }
  247. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override
  248. {
  249. CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(), nullptr);
  250. static NativeMidiProgram midiProgram;
  251. midiProgram.bank = index / 128;
  252. midiProgram.program = index % 128;
  253. midiProgram.name = fPlugin.getProgramName(index);
  254. return &midiProgram;
  255. }
  256. #endif
  257. // -------------------------------------------------------------------
  258. // Plugin state calls
  259. void setParameterValue(const uint32_t index, const float value) override
  260. {
  261. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  262. fPlugin.setParameterValue(index, value);
  263. }
  264. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  265. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  266. {
  267. const uint32_t realProgram(bank * 128 + program);
  268. CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
  269. fPlugin.loadProgram(realProgram);
  270. }
  271. #endif
  272. #if DISTRHO_PLUGIN_WANT_STATE
  273. void setCustomData(const char* const key, const char* const value) override
  274. {
  275. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  276. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  277. fPlugin.setState(key, value);
  278. }
  279. #endif
  280. // -------------------------------------------------------------------
  281. // Plugin process calls
  282. void activate() override
  283. {
  284. fPlugin.activate();
  285. }
  286. void deactivate() override
  287. {
  288. fPlugin.deactivate();
  289. }
  290. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  291. void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
  292. const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  293. {
  294. MidiEvent realMidiEvents[midiEventCount];
  295. for (uint32_t i=0; i < midiEventCount; ++i)
  296. {
  297. const NativeMidiEvent& midiEvent(midiEvents[i]);
  298. MidiEvent& realMidiEvent(realMidiEvents[i]);
  299. realMidiEvent.frame = midiEvent.time;
  300. realMidiEvent.size = midiEvent.size;
  301. uint8_t j=0;
  302. for (; j<midiEvent.size; ++j)
  303. realMidiEvent.data[j] = midiEvent.data[j];
  304. for (; j<midiEvent.size; ++j)
  305. realMidiEvent.data[j] = midiEvent.data[j];
  306. realMidiEvent.dataExt = nullptr;
  307. }
  308. fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount);
  309. }
  310. #else
  311. void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
  312. const NativeMidiEvent* const, const uint32_t) override
  313. {
  314. fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames);
  315. }
  316. #endif
  317. // -------------------------------------------------------------------
  318. // Plugin UI calls
  319. #if DISTRHO_PLUGIN_HAS_UI
  320. void uiShow(const bool show) override
  321. {
  322. if (show)
  323. {
  324. createUiIfNeeded();
  325. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  326. fUiPtr->carla_show(show);
  327. }
  328. else if (fUiPtr != nullptr)
  329. {
  330. delete fUiPtr;
  331. fUiPtr = nullptr;
  332. }
  333. }
  334. void uiIdle() override
  335. {
  336. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  337. if (! fUiPtr->carla_idle())
  338. {
  339. uiClosed();
  340. delete fUiPtr;
  341. fUiPtr = nullptr;
  342. }
  343. }
  344. void uiSetParameterValue(const uint32_t index, const float value) override
  345. {
  346. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  347. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  348. fUiPtr->carla_setParameterValue(index, value);
  349. }
  350. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  351. void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  352. {
  353. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  354. const uint32_t realProgram(bank * 128 + program);
  355. CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
  356. fUiPtr->carla_setMidiProgram(realProgram);
  357. }
  358. # endif
  359. # if DISTRHO_PLUGIN_WANT_STATE
  360. void uiSetCustomData(const char* const key, const char* const value) override
  361. {
  362. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  363. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  364. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  365. fUiPtr->carla_setCustomData(key, value);
  366. }
  367. # endif
  368. #endif
  369. // -------------------------------------------------------------------
  370. // Plugin dispatcher calls
  371. void bufferSizeChanged(const uint32_t bufferSize) override
  372. {
  373. fPlugin.setBufferSize(bufferSize, true);
  374. }
  375. void sampleRateChanged(const double sampleRate) override
  376. {
  377. fPlugin.setSampleRate(sampleRate, true);
  378. }
  379. #if DISTRHO_PLUGIN_HAS_UI
  380. void uiNameChanged(const char* const uiName) override
  381. {
  382. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  383. fUiPtr->carla_setUiTitle(uiName);
  384. }
  385. #endif
  386. // -------------------------------------------------------------------
  387. private:
  388. PluginExporter fPlugin;
  389. mutable NativeParameterScalePoint* fScalePointsCache;
  390. #if DISTRHO_PLUGIN_HAS_UI
  391. // UI
  392. UICarla* fUiPtr;
  393. void createUiIfNeeded()
  394. {
  395. if (fUiPtr == nullptr)
  396. fUiPtr = new UICarla(getHostHandle(), &fPlugin);
  397. }
  398. #endif
  399. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  400. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  401. {
  402. if (midiEvent.size > 4)
  403. return;
  404. const NativeMidiEvent event = {
  405. midiEvent.frame, 0, midiEvent.size, midiEvent.data
  406. };
  407. return ((PluginCarla*)ptr)->fPlugin.writeMidiEvent(midiEvent);
  408. }
  409. #endif
  410. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  411. bool requestParameterValueChange(const uint32_t index, const float value)
  412. {
  413. // TODO implementation
  414. return false;
  415. }
  416. static bool requestParameterValueChangeCallback(void* ptr, const uint32_t index, const float value)
  417. {
  418. return thisPtr->requestParameterValueChange(index, value);
  419. }
  420. #endif
  421. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
  422. // -------------------------------------------------------------------
  423. public:
  424. static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
  425. {
  426. d_nextBufferSize = host->get_buffer_size(host->handle);
  427. d_nextSampleRate = host->get_sample_rate(host->handle);
  428. return new PluginCarla(host);
  429. }
  430. static void _cleanup(NativePluginHandle handle)
  431. {
  432. delete (PluginCarla*)handle;
  433. }
  434. };
  435. END_NAMESPACE_DISTRHO
  436. // -----------------------------------------------------------------------