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.

536 lines
15KB

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