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.

504 lines
13KB

  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. #include "CarlaNative.hpp"
  17. #include "CarlaUtils.hpp"
  18. #include "DistrhoPluginMain.cpp"
  19. #include <QtCore/QSettings>
  20. #if DISTRHO_PLUGIN_HAS_UI
  21. # if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  22. # include <QtWidgets/QMainWindow>
  23. # else
  24. # include <QtGui/QMainWindow>
  25. # endif
  26. # include "DistrhoUIMain.cpp"
  27. #endif
  28. // -----------------------------------------------------------------------
  29. START_NAMESPACE_DISTRHO
  30. #if DISTRHO_PLUGIN_HAS_UI
  31. // -----------------------------------------------------------------------
  32. // Carla UI
  33. class UICarla : public QMainWindow
  34. {
  35. public:
  36. UICarla(const HostDescriptor* const host, PluginInternal* const plugin)
  37. : QMainWindow(nullptr),
  38. kHost(host),
  39. kPlugin(plugin),
  40. #ifdef DISTRHO_UI_OPENGL
  41. fWidget(this),
  42. fUi(this, (intptr_t)fWidget.winId(), editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback)
  43. #else
  44. fUi(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback)
  45. #endif
  46. {
  47. #ifdef DISTRHO_UI_OPENGL
  48. setCentralWidget(&fWidget);
  49. #else
  50. QtUI* const qtUi(fUi.getQtUI());
  51. qtUi->setParent(this);
  52. setCentralWidget(qtUi);
  53. #endif
  54. setWindowTitle(QString("%1 (GUI)").arg(fUi.name()));
  55. uiResize(fUi.width(), fUi.height());
  56. {
  57. QSettings settings;
  58. if (settings.value("Engine/UIsAlwaysOnTop", true).toBool())
  59. setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint);
  60. }
  61. }
  62. ~UICarla()
  63. {
  64. }
  65. // ---------------------------------------------
  66. void carla_show(const bool yesNo)
  67. {
  68. setVisible(yesNo);
  69. }
  70. void carla_idle()
  71. {
  72. fUi.idle();
  73. }
  74. void carla_setParameterValue(const uint32_t index, const float value)
  75. {
  76. fUi.parameterChanged(index, value);
  77. }
  78. void carla_setMidiProgram(const uint32_t realProgram)
  79. {
  80. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  81. fUi.programChanged(realProgram);
  82. #else
  83. return;
  84. // unused
  85. (void)realProgram;
  86. #endif
  87. }
  88. void carla_setCustomData(const char* const key, const char* const value)
  89. {
  90. #if DISTRHO_PLUGIN_WANT_STATE
  91. fUi.stateChanged(key, value);
  92. #else
  93. return;
  94. // unused
  95. (void)key;
  96. (void)value;
  97. #endif
  98. }
  99. // ---------------------------------------------
  100. protected:
  101. void editParameter(uint32_t, bool)
  102. {
  103. // TODO
  104. }
  105. void setParameterValue(uint32_t rindex, float value)
  106. {
  107. kHost->ui_parameter_changed(kHost->handle, rindex, value);
  108. }
  109. void setState(const char* key, const char* value)
  110. {
  111. kHost->ui_custom_data_changed(kHost->handle, key, value);
  112. }
  113. void sendNote(bool, uint8_t, uint8_t, uint8_t)
  114. {
  115. // TODO
  116. }
  117. void uiResize(unsigned int width, unsigned int height)
  118. {
  119. #ifdef DISTRHO_UI_OPENGL
  120. fWidget.setFixedSize(width, height);
  121. setFixedSize(width, height);
  122. #else
  123. if (fUi.resizable())
  124. resize(width, height);
  125. else
  126. setFixedSize(width, height);
  127. #endif
  128. }
  129. // ---------------------------------------------
  130. void closeEvent(QCloseEvent* event) override
  131. {
  132. kHost->ui_closed(kHost->handle);
  133. // FIXME - ignore event?
  134. QMainWindow::closeEvent(event);
  135. }
  136. // ---------------------------------------------
  137. private:
  138. // Plugin stuff
  139. const HostDescriptor* const kHost;
  140. PluginInternal* const kPlugin;
  141. #ifdef DISTRHO_UI_OPENGL
  142. // Qt stuff, used for GL
  143. QWidget fWidget;
  144. #endif
  145. // UI
  146. UIInternal fUi;
  147. // ---------------------------------------------
  148. // Callbacks
  149. #define handlePtr ((UICarla*)ptr)
  150. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  151. {
  152. handlePtr->editParameter(index, started);
  153. }
  154. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  155. {
  156. handlePtr->setParameterValue(rindex, value);
  157. }
  158. static void setStateCallback(void* ptr, const char* key, const char* value)
  159. {
  160. handlePtr->setState(key, value);
  161. }
  162. static void sendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
  163. {
  164. handlePtr->sendNote(onOff, channel, note, velocity);
  165. }
  166. static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
  167. {
  168. handlePtr->uiResize(width, height);
  169. }
  170. #undef handlePtr
  171. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla)
  172. };
  173. #endif // DISTRHO_PLUGIN_HAS_UI
  174. // -----------------------------------------------------------------------
  175. // Carla Plugin
  176. class PluginCarla : public PluginDescriptorClass
  177. {
  178. public:
  179. PluginCarla(const HostDescriptor* const host)
  180. : PluginDescriptorClass(host)
  181. {
  182. #if DISTRHO_PLUGIN_HAS_UI
  183. fUiPtr = nullptr;
  184. #endif
  185. }
  186. ~PluginCarla() override
  187. {
  188. #if DISTRHO_PLUGIN_HAS_UI
  189. fUiPtr = nullptr;
  190. #endif
  191. }
  192. protected:
  193. // -------------------------------------------------------------------
  194. // Plugin parameter calls
  195. uint32_t getParameterCount() override
  196. {
  197. return fPlugin.parameterCount();
  198. }
  199. const ::Parameter* getParameterInfo(const uint32_t index) override
  200. {
  201. CARLA_ASSERT(index < getParameterCount());
  202. static ::Parameter param;
  203. // reset
  204. param.hints = ::PARAMETER_IS_ENABLED;
  205. param.scalePointCount = 0;
  206. param.scalePoints = nullptr;
  207. {
  208. int nativeParamHints = ::PARAMETER_IS_ENABLED;
  209. const uint32_t paramHints = fPlugin.parameterHints(index);
  210. if (paramHints & PARAMETER_IS_AUTOMABLE)
  211. nativeParamHints |= ::PARAMETER_IS_AUTOMABLE;
  212. if (paramHints & PARAMETER_IS_BOOLEAN)
  213. nativeParamHints |= ::PARAMETER_IS_BOOLEAN;
  214. if (paramHints & PARAMETER_IS_INTEGER)
  215. nativeParamHints |= ::PARAMETER_IS_INTEGER;
  216. if (paramHints & PARAMETER_IS_LOGARITHMIC)
  217. nativeParamHints |= ::PARAMETER_IS_LOGARITHMIC;
  218. if (paramHints & PARAMETER_IS_OUTPUT)
  219. nativeParamHints |= ::PARAMETER_IS_OUTPUT;
  220. param.hints = static_cast<ParameterHints>(nativeParamHints);
  221. }
  222. param.name = fPlugin.parameterName(index);
  223. param.unit = fPlugin.parameterUnit(index);
  224. {
  225. const ParameterRanges& ranges(fPlugin.parameterRanges(index));
  226. param.ranges.def = ranges.def;
  227. param.ranges.min = ranges.min;
  228. param.ranges.max = ranges.max;
  229. param.ranges.step = ranges.step;
  230. param.ranges.stepSmall = ranges.stepSmall;
  231. param.ranges.stepLarge = ranges.stepLarge;
  232. }
  233. return &param;
  234. }
  235. float getParameterValue(const uint32_t index) override
  236. {
  237. CARLA_ASSERT(index < getParameterCount());
  238. return fPlugin.parameterValue(index);
  239. }
  240. // getParameterText unused
  241. // -------------------------------------------------------------------
  242. // Plugin midi-program calls
  243. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  244. uint32_t getMidiProgramCount() override
  245. {
  246. return fPlugin.programCount();
  247. }
  248. const ::MidiProgram* getMidiProgramInfo(const uint32_t index) override
  249. {
  250. CARLA_ASSERT(index < getMidiProgramCount());
  251. if (index >= fPlugin.programCount())
  252. return nullptr;
  253. static ::MidiProgram midiProgram;
  254. midiProgram.bank = index / 128;
  255. midiProgram.program = index % 128;
  256. midiProgram.name = fPlugin.programName(index);
  257. return &midiProgram;
  258. }
  259. #endif
  260. // -------------------------------------------------------------------
  261. // Plugin state calls
  262. void setParameterValue(const uint32_t index, const float value) override
  263. {
  264. CARLA_ASSERT(index < getParameterCount());
  265. fPlugin.setParameterValue(index, value);
  266. }
  267. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  268. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  269. {
  270. const uint32_t realProgram = bank * 128 + program;
  271. if (realProgram >= fPlugin.programCount())
  272. return;
  273. fPlugin.setProgram(realProgram);
  274. }
  275. #endif
  276. #if DISTRHO_PLUGIN_WANT_STATE
  277. void setCustomData(const char* const key, const char* const value) override
  278. {
  279. CARLA_ASSERT(key != nullptr);
  280. CARLA_ASSERT(value != nullptr);
  281. fPlugin.setState(key, value);
  282. }
  283. #endif
  284. // -------------------------------------------------------------------
  285. // Plugin process calls
  286. void activate() override
  287. {
  288. fPlugin.activate();
  289. }
  290. void deactivate() override
  291. {
  292. fPlugin.deactivate();
  293. }
  294. #if DISTRHO_PLUGIN_IS_SYNTH
  295. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const ::MidiEvent* const midiEvents) override
  296. {
  297. uint32_t i;
  298. for (i=0; i < midiEventCount && i < MAX_MIDI_EVENTS; ++i)
  299. {
  300. const ::MidiEvent* const midiEvent = &midiEvents[i];
  301. MidiEvent* const realMidiEvent = &fRealMidiEvents[i];
  302. realMidiEvent->frame = midiEvent->time;
  303. realMidiEvent->size = midiEvent->size;
  304. carla_copy<uint8_t>(realMidiEvent->buf, midiEvent->data, midiEvent->size);
  305. }
  306. fPlugin.run(inBuffer, outBuffer, frames, i, fRealMidiEvents);
  307. }
  308. #else
  309. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t, const ::MidiEvent* const) override
  310. {
  311. fPlugin.run(inBuffer, outBuffer, frames, 0, nullptr);
  312. }
  313. #endif
  314. // -------------------------------------------------------------------
  315. // Plugin UI calls
  316. #if DISTRHO_PLUGIN_HAS_UI
  317. void uiShow(const bool show) override
  318. {
  319. if (show)
  320. createUiIfNeeded();
  321. else if (fUiPtr != nullptr)
  322. fUiGeometry = fUiPtr->saveGeometry();
  323. if (fUiPtr != nullptr)
  324. fUiPtr->carla_show(show);
  325. }
  326. void uiIdle() override
  327. {
  328. CARLA_ASSERT(fUiPtr != nullptr);
  329. if (fUiPtr != nullptr)
  330. fUiPtr->carla_idle();
  331. }
  332. void uiSetParameterValue(const uint32_t index, const float value) override
  333. {
  334. CARLA_ASSERT(fUiPtr != nullptr);
  335. CARLA_ASSERT(index < getParameterCount());
  336. if (fUiPtr != nullptr)
  337. fUiPtr->carla_setParameterValue(index, value);
  338. }
  339. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  340. void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  341. {
  342. CARLA_ASSERT(fUiPtr != nullptr);
  343. const uint32_t realProgram(bank * 128 + program);
  344. if (realProgram >= fPlugin.programCount())
  345. return;
  346. if (fUiPtr != nullptr)
  347. fUiPtr->carla_setMidiProgram(realProgram);
  348. }
  349. # endif
  350. # if DISTRHO_PLUGIN_WANT_STATE
  351. void uiSetCustomData(const char* const key, const char* const value) override
  352. {
  353. CARLA_ASSERT(fUiPtr != nullptr);
  354. CARLA_ASSERT(key != nullptr);
  355. CARLA_ASSERT(value != nullptr);
  356. if (fUiPtr != nullptr)
  357. fUiPtr->carla_setCustomData(key, value);
  358. }
  359. # endif
  360. #endif
  361. // -------------------------------------------------------------------
  362. private:
  363. PluginInternal fPlugin;
  364. #if DISTRHO_PLUGIN_IS_SYNTH
  365. MidiEvent fRealMidiEvents[MAX_MIDI_EVENTS];
  366. #endif
  367. #if DISTRHO_PLUGIN_HAS_UI
  368. // UI
  369. ScopedPointer<UICarla> fUiPtr;
  370. QByteArray fUiGeometry;
  371. void createUiIfNeeded()
  372. {
  373. if (fUiPtr == nullptr)
  374. {
  375. d_lastUiSampleRate = getSampleRate();
  376. fUiPtr = new UICarla(hostHandle(), &fPlugin);
  377. if (! fUiGeometry.isNull())
  378. fUiPtr->restoreGeometry(fUiGeometry);
  379. }
  380. }
  381. #endif
  382. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
  383. // -------------------------------------------------------------------
  384. public:
  385. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  386. {
  387. d_lastBufferSize = host->get_buffer_size(host->handle);
  388. d_lastSampleRate = host->get_sample_rate(host->handle);
  389. return new PluginCarla(host);
  390. }
  391. static void _cleanup(PluginHandle handle)
  392. {
  393. delete (PluginCarla*)handle;
  394. }
  395. };
  396. END_NAMESPACE_DISTRHO
  397. // -----------------------------------------------------------------------