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.

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