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.

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