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.

498 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 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->buffer[0] = midiEvent->data[0];
  303. realMidiEvent->buffer[1] = midiEvent->data[1];
  304. realMidiEvent->buffer[2] = midiEvent->data[2];
  305. realMidiEvent->frame = midiEvent->time;
  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. if (fUiPtr != nullptr)
  323. fUiPtr->carla_show(show);
  324. }
  325. void uiIdle() override
  326. {
  327. CARLA_ASSERT(fUiPtr != nullptr);
  328. if (fUiPtr != nullptr)
  329. fUiPtr->carla_idle();
  330. }
  331. void uiSetParameterValue(const uint32_t index, const float value) override
  332. {
  333. CARLA_ASSERT(fUiPtr != nullptr);
  334. CARLA_ASSERT(index < getParameterCount());
  335. if (fUiPtr != nullptr)
  336. fUiPtr->carla_setParameterValue(index, value);
  337. }
  338. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  339. void uiSetMidiProgram(const uint32_t bank, const uint32_t program) override
  340. {
  341. CARLA_ASSERT(fUiPtr != nullptr);
  342. uint32_t realProgram = bank * 128 + program;
  343. if (realProgram >= fPlugin.programCount())
  344. return;
  345. if (fUiPtr != nullptr)
  346. fUiPtr->carla_setMidiProgram(realProgram);
  347. }
  348. # endif
  349. # if DISTRHO_PLUGIN_WANT_STATE
  350. void uiSetCustomData(const char* const key, const char* const value) override
  351. {
  352. CARLA_ASSERT(fUiPtr != nullptr);
  353. CARLA_ASSERT(key != nullptr);
  354. CARLA_ASSERT(value != nullptr);
  355. if (fUiPtr != nullptr)
  356. fUiPtr->carla_setCustomData(key, value);
  357. }
  358. # endif
  359. #endif
  360. // -------------------------------------------------------------------
  361. private:
  362. PluginInternal fPlugin;
  363. #if DISTRHO_PLUGIN_IS_SYNTH
  364. MidiEvent fRealMidiEvents[MAX_MIDI_EVENTS];
  365. #endif
  366. #if DISTRHO_PLUGIN_HAS_UI
  367. // UI
  368. ScopedPointer<UICarla> fUiPtr;
  369. void createUiIfNeeded()
  370. {
  371. if (fUiPtr == nullptr)
  372. {
  373. d_lastUiSampleRate = getSampleRate();
  374. fUiPtr = new UICarla(getHostHandle(), &fPlugin);
  375. }
  376. }
  377. #endif
  378. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
  379. // -------------------------------------------------------------------
  380. public:
  381. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  382. {
  383. d_lastBufferSize = host->get_buffer_size(host->handle);
  384. d_lastSampleRate = host->get_sample_rate(host->handle);
  385. return new PluginCarla(host);
  386. }
  387. static void _cleanup(PluginHandle handle)
  388. {
  389. delete (PluginCarla*)handle;
  390. }
  391. };
  392. END_NAMESPACE_DISTRHO
  393. // -----------------------------------------------------------------------