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.

610 lines
16KB

  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. #ifdef DISTRHO_UI_QT
  17. # error We do not want Qt in the engine code!
  18. #endif
  19. #include "../CarlaNative.hpp"
  20. #include "CarlaString.hpp"
  21. #include "DistrhoPluginMain.cpp"
  22. #if DISTRHO_PLUGIN_HAS_UI
  23. # include "DistrhoUIMain.cpp"
  24. # ifdef DISTRHO_UI_OPENGL
  25. # include "dgl/App.hpp"
  26. # include "dgl/Window.hpp"
  27. # else
  28. # include "CarlaPipeUtils.hpp"
  29. # endif
  30. #endif
  31. using juce::ScopedPointer;
  32. // -----------------------------------------------------------------------
  33. START_NAMESPACE_DISTRHO
  34. #if DISTRHO_PLUGIN_HAS_UI
  35. // -----------------------------------------------------------------------
  36. // Carla UI
  37. #ifdef DISTRHO_UI_EXTERNAL
  38. class UICarla : public CarlaPipeServer
  39. #else
  40. class UICarla
  41. #endif
  42. {
  43. public:
  44. UICarla(const HostDescriptor* const host, PluginInternal* const plugin)
  45. : fHost(host),
  46. fPlugin(plugin),
  47. fUi(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback)
  48. #ifdef DISTRHO_UI_OPENGL
  49. , glWindow(fUi.getWindow())
  50. #endif
  51. {
  52. #ifdef DISTRHO_UI_OPENGL
  53. glWindow.setSize(fUi.getWidth(), fUi.getHeight());
  54. glWindow.setWindowTitle(host->uiName);
  55. #else
  56. CarlaString filename;
  57. filename += fHost->resourceDir;
  58. #ifdef CARLA_OS_WIN
  59. filename += "\\resources\\";
  60. #else
  61. filename += "/resources/";
  62. #endif
  63. filename += fUi.getExternalFilename();
  64. char sampleRateStr[12+1];
  65. sampleRateStr[12] = '\0';
  66. std::snprintf(sampleRateStr, 12, "%g", host->get_sample_rate(host->handle));
  67. CarlaPipeServer::start(filename, sampleRateStr, host->uiName);
  68. #endif
  69. }
  70. #ifdef DISTRHO_UI_EXTERNAL
  71. ~UICarla() override
  72. {
  73. CarlaPipeServer::stop();
  74. }
  75. void fail(const char* const error) override
  76. {
  77. carla_stderr2(error);
  78. fHost->dispatcher(fHost->handle, HOST_OPCODE_UI_UNAVAILABLE, 0, 0, nullptr, 0.0f);
  79. }
  80. void msgReceived(const char* const msg) override
  81. {
  82. if (std::strcmp(msg, "control") == 0)
  83. {
  84. int index;
  85. float value;
  86. if (readNextLineAsInt(index) && readNextLineAsFloat(value))
  87. handleSetParameterValue(index, value);
  88. }
  89. else if (std::strcmp(msg, "configure") == 0)
  90. {
  91. char* key;
  92. char* value;
  93. if (readNextLineAsString(key) && readNextLineAsString(value))
  94. {
  95. handleSetState(key, value);
  96. std::free(key);
  97. std::free(value);
  98. }
  99. }
  100. else if (std::strcmp(msg, "exiting") == 0)
  101. {
  102. waitChildClose();
  103. fHost->ui_closed(fHost->handle);
  104. }
  105. else
  106. {
  107. carla_stderr("unknown message HOST: \"%s\"", msg);
  108. }
  109. }
  110. #endif
  111. // ---------------------------------------------
  112. void carla_show(const bool yesNo)
  113. {
  114. #ifdef DISTRHO_UI_OPENGL
  115. glWindow.setVisible(yesNo);
  116. #else
  117. if (yesNo)
  118. writeMsg("show\n", 5);
  119. else
  120. writeMsg("hide\n", 5);
  121. #endif
  122. }
  123. void carla_idle()
  124. {
  125. fUi.idle();
  126. #ifdef DISTRHO_UI_EXTERNAL
  127. CarlaPipeServer::idle();
  128. #endif
  129. }
  130. void carla_setParameterValue(const uint32_t index, const float value)
  131. {
  132. #ifdef DISTRHO_UI_OPENGL
  133. fUi.parameterChanged(index, value);
  134. #else
  135. char msgParamIndex[0xff+1];
  136. char msgParamValue[0xff+1];
  137. std::snprintf(msgParamIndex, 0xff, "%d\n", index);
  138. std::snprintf(msgParamValue, 0xff, "%f\n", value);
  139. msgParamIndex[0xff] = '\0';
  140. msgParamValue[0xff] = '\0';
  141. writeMsg("control\n", 8);
  142. writeMsg(msgParamIndex);
  143. writeMsg(msgParamValue);
  144. #endif
  145. }
  146. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  147. void carla_setMidiProgram(const uint32_t realProgram)
  148. {
  149. #ifdef DISTRHO_UI_OPENGL
  150. fUi.programChanged(realProgram);
  151. #else
  152. char msgProgram[0xff+1];
  153. std::snprintf(msgProgram, 0xff, "%d\n", realProgram);
  154. msgProgram[0xff] = '\0';
  155. writeMsg("program\n", 8);
  156. writeMsg(msgProgram);
  157. #endif
  158. }
  159. #endif
  160. #if DISTRHO_PLUGIN_WANT_STATE
  161. void carla_setCustomData(const char* const key, const char* const value)
  162. {
  163. #ifdef DISTRHO_UI_OPENGL
  164. fUi.stateChanged(key, value);
  165. #else
  166. writeMsg("configure\n", 10);
  167. writeAndFixMsg(key);
  168. writeAndFixMsg(value);
  169. #endif
  170. }
  171. #endif
  172. void carla_setUiTitle(const char* const uiTitle)
  173. {
  174. #ifdef DISTRHO_UI_OPENGL
  175. glWindow.setWindowTitle(uiTitle);
  176. #else
  177. writeMsg("uiTitle\n", 8);
  178. writeAndFixMsg(uiTitle);
  179. #endif
  180. }
  181. // ---------------------------------------------
  182. protected:
  183. void handleEditParameter(uint32_t, bool)
  184. {
  185. // TODO
  186. }
  187. void handleSetParameterValue(uint32_t rindex, float value)
  188. {
  189. fHost->ui_parameter_changed(fHost->handle, rindex, value);
  190. }
  191. void handleSetState(const char* key, const char* value)
  192. {
  193. fHost->ui_custom_data_changed(fHost->handle, key, value);
  194. }
  195. void handleSendNote(bool, uint8_t, uint8_t, uint8_t)
  196. {
  197. // TODO
  198. }
  199. void handleUiResize(unsigned int /*width*/, unsigned int /*height*/)
  200. {
  201. // TODO
  202. }
  203. // ---------------------------------------------
  204. private:
  205. // Plugin stuff
  206. const HostDescriptor* const fHost;
  207. PluginInternal* const fPlugin;
  208. // UI
  209. UIInternal fUi;
  210. #ifdef DISTRHO_UI_OPENGL
  211. // OpenGL stuff
  212. Window& glWindow;
  213. #endif
  214. // ---------------------------------------------
  215. // Callbacks
  216. #ifdef DISTRHO_UI_OPENGL
  217. #define handlePtr ((UICarla*)ptr)
  218. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  219. {
  220. handlePtr->handleEditParameter(index, started);
  221. }
  222. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  223. {
  224. handlePtr->handleSetParameterValue(rindex, value);
  225. }
  226. #if DISTRHO_PLUGIN_WANT_STATE
  227. static void setStateCallback(void* ptr, const char* key, const char* value)
  228. {
  229. handlePtr->handleSetState(key, value);
  230. }
  231. #else
  232. static constexpr setStateFunc setStateCallback = nullptr;
  233. #endif
  234. #if DISTRHO_PLUGIN_IS_SYNTH
  235. static void sendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity)
  236. {
  237. handlePtr->handleSendNote(onOff, channel, note, velocity);
  238. }
  239. #else
  240. static constexpr sendNoteFunc sendNoteCallback = nullptr;
  241. #endif
  242. static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height)
  243. {
  244. handlePtr->handleUiResize(width, height);
  245. }
  246. #undef handlePtr
  247. #else
  248. static constexpr editParamFunc editParameterCallback = nullptr;
  249. static constexpr setParamFunc setParameterCallback = nullptr;
  250. static constexpr setStateFunc setStateCallback = nullptr;
  251. static constexpr sendNoteFunc sendNoteCallback = nullptr;
  252. static constexpr uiResizeFunc uiResizeCallback = nullptr;
  253. #endif
  254. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla)
  255. };
  256. #endif // DISTRHO_PLUGIN_HAS_UI
  257. // -----------------------------------------------------------------------
  258. // Carla Plugin
  259. class PluginCarla : public PluginClass
  260. {
  261. public:
  262. PluginCarla(const HostDescriptor* const host)
  263. : PluginClass(host)
  264. {
  265. #if DISTRHO_PLUGIN_HAS_UI
  266. fUiPtr = nullptr;
  267. #endif
  268. }
  269. ~PluginCarla() override
  270. {
  271. #if DISTRHO_PLUGIN_HAS_UI
  272. fUiPtr = nullptr;
  273. #endif
  274. }
  275. protected:
  276. // -------------------------------------------------------------------
  277. // Plugin parameter calls
  278. uint32_t getParameterCount() const override
  279. {
  280. return fPlugin.getParameterCount();
  281. }
  282. const ::Parameter* getParameterInfo(const uint32_t index) const override
  283. {
  284. CARLA_ASSERT(index < getParameterCount());
  285. static ::Parameter param;
  286. // reset
  287. param.hints = ::PARAMETER_IS_ENABLED;
  288. param.scalePointCount = 0;
  289. param.scalePoints = nullptr;
  290. {
  291. int nativeParamHints = ::PARAMETER_IS_ENABLED;
  292. const uint32_t paramHints = fPlugin.getParameterHints(index);
  293. if (paramHints & PARAMETER_IS_AUTOMABLE)
  294. nativeParamHints |= ::PARAMETER_IS_AUTOMABLE;
  295. if (paramHints & PARAMETER_IS_BOOLEAN)
  296. nativeParamHints |= ::PARAMETER_IS_BOOLEAN;
  297. if (paramHints & PARAMETER_IS_INTEGER)
  298. nativeParamHints |= ::PARAMETER_IS_INTEGER;
  299. if (paramHints & PARAMETER_IS_LOGARITHMIC)
  300. nativeParamHints |= ::PARAMETER_IS_LOGARITHMIC;
  301. if (paramHints & PARAMETER_IS_OUTPUT)
  302. nativeParamHints |= ::PARAMETER_IS_OUTPUT;
  303. param.hints = static_cast<ParameterHints>(nativeParamHints);
  304. }
  305. param.name = fPlugin.getParameterName(index);
  306. param.unit = fPlugin.getParameterUnit(index);
  307. {
  308. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  309. param.ranges.def = ranges.def;
  310. param.ranges.min = ranges.min;
  311. param.ranges.max = ranges.max;
  312. param.ranges.step = ranges.step;
  313. param.ranges.stepSmall = ranges.stepSmall;
  314. param.ranges.stepLarge = ranges.stepLarge;
  315. }
  316. return &param;
  317. }
  318. float getParameterValue(const uint32_t index) const override
  319. {
  320. CARLA_ASSERT(index < getParameterCount());
  321. return fPlugin.getParameterValue(index);
  322. }
  323. // -------------------------------------------------------------------
  324. // Plugin midi-program calls
  325. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  326. uint32_t getMidiProgramCount() const override
  327. {
  328. return fPlugin.getProgramCount();
  329. }
  330. const ::MidiProgram* getMidiProgramInfo(const uint32_t index) const override
  331. {
  332. CARLA_ASSERT(index < getMidiProgramCount());
  333. if (index >= fPlugin.getProgramCount())
  334. return nullptr;
  335. static ::MidiProgram midiProgram;
  336. midiProgram.bank = index / 128;
  337. midiProgram.program = index % 128;
  338. midiProgram.name = fPlugin.getProgramName(index);
  339. return &midiProgram;
  340. }
  341. #endif
  342. // -------------------------------------------------------------------
  343. // Plugin state calls
  344. void setParameterValue(const uint32_t index, const float value) override
  345. {
  346. CARLA_ASSERT(index < getParameterCount());
  347. fPlugin.setParameterValue(index, value);
  348. }
  349. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  350. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  351. {
  352. const uint32_t realProgram(bank * 128 + program);
  353. if (realProgram >= fPlugin.getProgramCount())
  354. return;
  355. fPlugin.setProgram(realProgram);
  356. }
  357. #endif
  358. #if DISTRHO_PLUGIN_WANT_STATE
  359. void setCustomData(const char* const key, const char* const value) override
  360. {
  361. CARLA_ASSERT(key != nullptr);
  362. CARLA_ASSERT(value != nullptr);
  363. fPlugin.setState(key, value);
  364. }
  365. #endif
  366. // -------------------------------------------------------------------
  367. // Plugin process calls
  368. void activate() override
  369. {
  370. fPlugin.activate();
  371. }
  372. void deactivate() override
  373. {
  374. fPlugin.deactivate();
  375. }
  376. #if DISTRHO_PLUGIN_IS_SYNTH
  377. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const ::MidiEvent* const midiEvents, const uint32_t midiEventCount) override
  378. {
  379. uint32_t i;
  380. for (i=0; i < midiEventCount && i < MAX_MIDI_EVENTS; ++i)
  381. {
  382. const ::MidiEvent* const midiEvent = &midiEvents[i];
  383. MidiEvent* const realMidiEvent = &fRealMidiEvents[i];
  384. realMidiEvent->frame = midiEvent->time;
  385. realMidiEvent->size = midiEvent->size;
  386. for (uint8_t j=0; j < midiEvent->size; ++j)
  387. realMidiEvent->buf[j] = midiEvent->data[j];
  388. }
  389. fPlugin.run(inBuffer, outBuffer, frames, fRealMidiEvents, i);
  390. }
  391. #else
  392. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const ::MidiEvent* const, const uint32_t) override
  393. {
  394. fPlugin.run(inBuffer, outBuffer, frames, nullptr, 0);
  395. }
  396. #endif
  397. // -------------------------------------------------------------------
  398. // Plugin UI calls
  399. #if DISTRHO_PLUGIN_HAS_UI
  400. void uiShow(const bool show) override
  401. {
  402. if (show)
  403. createUiIfNeeded();
  404. if (fUiPtr != nullptr)
  405. fUiPtr->carla_show(show);
  406. }
  407. void uiIdle() override
  408. {
  409. CARLA_ASSERT(fUiPtr != nullptr);
  410. if (fUiPtr != nullptr)
  411. fUiPtr->carla_idle();
  412. }
  413. void uiSetParameterValue(const uint32_t index, const float value) override
  414. {
  415. CARLA_ASSERT(fUiPtr != nullptr);
  416. CARLA_ASSERT(index < getParameterCount());
  417. if (fUiPtr != nullptr)
  418. fUiPtr->carla_setParameterValue(index, value);
  419. }
  420. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  421. void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  422. {
  423. CARLA_ASSERT(fUiPtr != nullptr);
  424. const uint32_t realProgram(bank * 128 + program);
  425. if (realProgram >= fPlugin.getProgramCount())
  426. return;
  427. if (fUiPtr != nullptr)
  428. fUiPtr->carla_setMidiProgram(realProgram);
  429. }
  430. # endif
  431. # if DISTRHO_PLUGIN_WANT_STATE
  432. void uiSetCustomData(const char* const key, const char* const value) override
  433. {
  434. CARLA_ASSERT(fUiPtr != nullptr);
  435. CARLA_ASSERT(key != nullptr);
  436. CARLA_ASSERT(value != nullptr);
  437. if (fUiPtr != nullptr)
  438. fUiPtr->carla_setCustomData(key, value);
  439. }
  440. # endif
  441. #endif
  442. // -------------------------------------------------------------------
  443. // Plugin dispatcher calls
  444. void bufferSizeChanged(const uint32_t bufferSize) override
  445. {
  446. fPlugin.setBufferSize(bufferSize, true);
  447. }
  448. void sampleRateChanged(const double sampleRate) override
  449. {
  450. fPlugin.setSampleRate(sampleRate, true);
  451. }
  452. #if DISTRHO_PLUGIN_HAS_UI
  453. void uiNameChanged(const char* const uiName) override
  454. {
  455. if (fUiPtr != nullptr)
  456. fUiPtr->carla_setUiTitle(uiName);
  457. }
  458. #endif
  459. // -------------------------------------------------------------------
  460. private:
  461. PluginInternal fPlugin;
  462. #if DISTRHO_PLUGIN_IS_SYNTH
  463. MidiEvent fRealMidiEvents[MAX_MIDI_EVENTS];
  464. #endif
  465. #if DISTRHO_PLUGIN_HAS_UI
  466. // UI
  467. ScopedPointer<UICarla> fUiPtr;
  468. void createUiIfNeeded()
  469. {
  470. if (fUiPtr == nullptr)
  471. {
  472. d_lastUiSampleRate = getSampleRate();
  473. fUiPtr = new UICarla(getHostHandle(), &fPlugin);
  474. }
  475. }
  476. #endif
  477. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
  478. // -------------------------------------------------------------------
  479. public:
  480. static PluginHandle _instantiate(const HostDescriptor* host)
  481. {
  482. d_lastBufferSize = host->get_buffer_size(host->handle);
  483. d_lastSampleRate = host->get_sample_rate(host->handle);
  484. return new PluginCarla(host);
  485. }
  486. static void _cleanup(PluginHandle handle)
  487. {
  488. delete (PluginCarla*)handle;
  489. }
  490. };
  491. END_NAMESPACE_DISTRHO
  492. // -----------------------------------------------------------------------