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.

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