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.

454 lines
11KB

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