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.

491 lines
12KB

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