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.

689 lines
15KB

  1. /*
  2. * Carla Plugin
  3. * Copyright (C) 2011-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 General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the GPL.txt file
  16. */
  17. #ifndef __CARLA_PLUGIN_INTERNAL_HPP__
  18. #define __CARLA_PLUGIN_INTERNAL_HPP__
  19. #include "carla_plugin.hpp"
  20. #include "carla_plugin_thread.hpp"
  21. #include "carla_engine.hpp"
  22. #include "carla_osc_utils.hpp"
  23. //#include "carla_bridge_osc.hpp"
  24. #include "rt_list.hpp"
  25. #include <QtGui/QMainWindow>
  26. #define CARLA_DECLARE_NON_COPY_STRUCT(structName) \
  27. structName(const structName&) = delete;
  28. #define CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(structName) \
  29. CARLA_DECLARE_NON_COPY_STRUCT(structName) \
  30. CARLA_LEAK_DETECTOR(structName)
  31. #define CARLA_PROCESS_CONTINUE_CHECK if (! fData->enabled) { fData->engine->callback(CALLBACK_DEBUG, fData->id, 0, 0, 0.0, nullptr); return; }
  32. CARLA_BACKEND_START_NAMESPACE
  33. // -----------------------------------------------------------------------
  34. struct PluginAudioPort {
  35. uint32_t rindex;
  36. CarlaEngineAudioPort* port;
  37. PluginAudioPort()
  38. : rindex(0),
  39. port(nullptr) {}
  40. ~PluginAudioPort()
  41. {
  42. CARLA_ASSERT(port == nullptr);
  43. }
  44. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioPort)
  45. };
  46. struct PluginAudioData {
  47. uint32_t count;
  48. PluginAudioPort* ports;
  49. PluginAudioData()
  50. : count(0),
  51. ports(nullptr) {}
  52. ~PluginAudioData()
  53. {
  54. CARLA_ASSERT(ports == nullptr);
  55. }
  56. void createNew(const size_t count)
  57. {
  58. CARLA_ASSERT(ports == nullptr);
  59. if (ports == nullptr)
  60. ports = new PluginAudioPort[count];
  61. this->count = count;
  62. }
  63. void freePorts()
  64. {
  65. for (uint32_t i=0; i < count; i++)
  66. {
  67. if (ports[i].port != nullptr)
  68. {
  69. delete ports[i].port;
  70. ports[i].port = nullptr;
  71. }
  72. }
  73. }
  74. void clear()
  75. {
  76. freePorts();
  77. if (ports != nullptr)
  78. {
  79. delete[] ports;
  80. ports = nullptr;
  81. }
  82. count = 0;
  83. }
  84. void initBuffers(CarlaEngine* const engine)
  85. {
  86. for (uint32_t i=0; i < count; i++)
  87. {
  88. if (ports[i].port != nullptr)
  89. ports[i].port->initBuffer(engine);
  90. }
  91. }
  92. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioData)
  93. };
  94. // -----------------------------------------------------------------------
  95. struct PluginEventData {
  96. CarlaEngineEventPort* portIn;
  97. CarlaEngineEventPort* portOut;
  98. PluginEventData()
  99. : portIn(nullptr),
  100. portOut(nullptr) {}
  101. ~PluginEventData()
  102. {
  103. CARLA_ASSERT(portIn == nullptr);
  104. CARLA_ASSERT(portOut == nullptr);
  105. }
  106. void freePorts()
  107. {
  108. if (portIn != nullptr)
  109. {
  110. delete portIn;
  111. portIn = nullptr;
  112. }
  113. if (portOut != nullptr)
  114. {
  115. delete portOut;
  116. portOut = nullptr;
  117. }
  118. }
  119. void clear()
  120. {
  121. freePorts();
  122. }
  123. void initBuffers(CarlaEngine* const engine)
  124. {
  125. if (portIn != nullptr)
  126. portIn->initBuffer(engine);
  127. if (portOut != nullptr)
  128. portOut->initBuffer(engine);
  129. }
  130. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginEventData)
  131. };
  132. // -----------------------------------------------------------------------
  133. struct PluginParameterData {
  134. uint32_t count;
  135. ParameterData* data;
  136. ParameterRanges* ranges;
  137. PluginParameterData()
  138. : count(0),
  139. data(nullptr),
  140. ranges(nullptr) {}
  141. ~PluginParameterData()
  142. {
  143. CARLA_ASSERT(data == nullptr);
  144. CARLA_ASSERT(ranges == nullptr);
  145. }
  146. void createNew(const size_t count)
  147. {
  148. CARLA_ASSERT(data == nullptr);
  149. CARLA_ASSERT(ranges == nullptr);
  150. if (data == nullptr)
  151. data = new ParameterData[count];
  152. if (ranges == nullptr)
  153. ranges = new ParameterRanges[count];
  154. this->count = count;
  155. }
  156. void clear()
  157. {
  158. if (data != nullptr)
  159. {
  160. delete[] data;
  161. data = nullptr;
  162. }
  163. if (ranges != nullptr)
  164. {
  165. delete[] ranges;
  166. ranges = nullptr;
  167. }
  168. count = 0;
  169. }
  170. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginParameterData)
  171. };
  172. // -----------------------------------------------------------------------
  173. typedef const char* ProgramName;
  174. struct PluginProgramData {
  175. uint32_t count;
  176. int32_t current;
  177. ProgramName* names;
  178. PluginProgramData()
  179. : count(0),
  180. current(-1),
  181. names(nullptr) {}
  182. ~PluginProgramData()
  183. {
  184. CARLA_ASSERT(names == nullptr);
  185. }
  186. void createNew(const uint32_t count)
  187. {
  188. CARLA_ASSERT(names == nullptr);
  189. if (names == nullptr)
  190. names = new ProgramName[count];
  191. for (uint32_t i=0; i < count; i++)
  192. names[i] = nullptr;
  193. this->count = count;
  194. }
  195. void clear()
  196. {
  197. if (names != nullptr)
  198. {
  199. for (uint32_t i=0; i < count; i++)
  200. std::free((void*)names[i]);
  201. delete[] names;
  202. names = nullptr;
  203. }
  204. count = 0;
  205. current = -1;
  206. }
  207. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginProgramData)
  208. };
  209. // -----------------------------------------------------------------------
  210. struct PluginMidiProgramData {
  211. uint32_t count;
  212. int32_t current;
  213. MidiProgramData* data;
  214. PluginMidiProgramData()
  215. : count(0),
  216. current(-1),
  217. data(nullptr) {}
  218. ~PluginMidiProgramData()
  219. {
  220. CARLA_ASSERT(data == nullptr);
  221. }
  222. void createNew(const uint32_t count)
  223. {
  224. CARLA_ASSERT(data == nullptr);
  225. if (data == nullptr)
  226. data = new MidiProgramData[count];
  227. this->count = count;
  228. }
  229. void clear()
  230. {
  231. if (data != nullptr)
  232. {
  233. delete[] data;
  234. data = nullptr;
  235. }
  236. count = 0;
  237. current = -1;
  238. }
  239. const MidiProgramData& getCurrent() const
  240. {
  241. CARLA_ASSERT(current >= 0 && current < static_cast<int32_t>(count));
  242. return data[current];
  243. }
  244. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginMidiProgramData)
  245. };
  246. // -----------------------------------------------------------------------
  247. struct PluginPostRtEvent {
  248. PluginPostRtEventType type;
  249. int32_t value1;
  250. int32_t value2;
  251. double value3;
  252. PluginPostRtEvent()
  253. : type(kPluginPostRtEventNull),
  254. value1(-1),
  255. value2(-1),
  256. value3(0.0) {}
  257. CARLA_DECLARE_NON_COPY_STRUCT(PluginPostRtEvent)
  258. };
  259. // -----------------------------------------------------------------------
  260. struct ExternalMidiNote {
  261. int8_t channel; // invalid = -1
  262. uint8_t note;
  263. uint8_t velo;
  264. ExternalMidiNote()
  265. : channel(-1),
  266. note(0),
  267. velo(0) {}
  268. CARLA_DECLARE_NON_COPY_STRUCT(ExternalMidiNote)
  269. };
  270. // -----------------------------------------------------------------------
  271. class CarlaPluginGUI : public QMainWindow
  272. {
  273. public:
  274. CarlaPluginGUI(QWidget* const parent = nullptr);
  275. ~CarlaPluginGUI();
  276. private:
  277. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI)
  278. };
  279. // -----------------------------------------------------------------------
  280. const unsigned short MIN_RT_EVENTS = 152;
  281. const unsigned short MAX_RT_EVENTS = 512;
  282. const unsigned int PLUGIN_OPTION2_HAS_MIDI_IN = 0x1;
  283. const unsigned int PLUGIN_OPTION2_HAS_MIDI_OUT = 0x2;
  284. // -----------------------------------------------------------------------
  285. struct CarlaPluginProtectedData {
  286. unsigned int id;
  287. CarlaEngine* const engine;
  288. CarlaEngineClient* client;
  289. CarlaPluginGUI* gui;
  290. unsigned int hints;
  291. unsigned int options;
  292. unsigned int options2;
  293. bool active;
  294. bool activeBefore;
  295. bool enabled;
  296. void* lib;
  297. CarlaString name;
  298. CarlaString filename;
  299. // misc
  300. int8_t ctrlInChannel;
  301. #if 0
  302. uint32_t latency;
  303. float** latencyBuffers;
  304. #endif
  305. // data
  306. PluginAudioData audioIn;
  307. PluginAudioData audioOut;
  308. PluginEventData event;
  309. PluginParameterData param;
  310. PluginProgramData prog;
  311. PluginMidiProgramData midiprog;
  312. NonRtListNew<CustomData> custom;
  313. struct ExternalNotes {
  314. CarlaMutex mutex;
  315. RtList<ExternalMidiNote> data;
  316. ExternalNotes()
  317. : data(32, 512) {}
  318. void append(const ExternalMidiNote& note)
  319. {
  320. data.append_sleepy(note);
  321. }
  322. } extNotes;
  323. struct PostRtEvents {
  324. CarlaMutex mutex;
  325. RtList<PluginPostRtEvent> data;
  326. RtList<PluginPostRtEvent> dataPendingRT;
  327. PostRtEvents()
  328. : data(MIN_RT_EVENTS, MAX_RT_EVENTS),
  329. dataPendingRT(MIN_RT_EVENTS, MAX_RT_EVENTS) {}
  330. void appendRT(const PluginPostRtEvent& event)
  331. {
  332. dataPendingRT.append(event);
  333. if (mutex.tryLock())
  334. {
  335. dataPendingRT.splice(data, true);
  336. mutex.unlock();
  337. }
  338. }
  339. //void appendNonRT(const PluginPostRtEvent& event)
  340. //{
  341. // data.append_sleepy(event);
  342. //}
  343. } postRtEvents;
  344. struct PostProc {
  345. float dryWet;
  346. float volume;
  347. float balanceLeft;
  348. float balanceRight;
  349. float panning;
  350. PostProc()
  351. : dryWet(1.0f),
  352. volume(1.0f),
  353. balanceLeft(-1.0f),
  354. balanceRight(1.0f),
  355. panning(0.0f) {}
  356. } postProc;
  357. struct OSC {
  358. CarlaOscData data;
  359. CarlaPluginThread* thread;
  360. OSC()
  361. : thread(nullptr) {}
  362. } osc;
  363. CarlaPluginProtectedData(CarlaEngine* const engine_, const unsigned short id_)
  364. : id(id_),
  365. engine(engine_),
  366. client(nullptr),
  367. gui(nullptr),
  368. hints(0x0),
  369. options(0x0),
  370. options2(0x0),
  371. active(false),
  372. activeBefore(false),
  373. enabled(false),
  374. lib(nullptr),
  375. ctrlInChannel(-1) {}
  376. #if 0
  377. latency(0),
  378. latencyBuffers(nullptr) {}
  379. #endif
  380. CarlaPluginProtectedData() = delete;
  381. CARLA_LEAK_DETECTOR(CarlaPluginProtectedData)
  382. };
  383. // -----------------------------------------------------------------------
  384. CARLA_BACKEND_END_NAMESPACE
  385. #endif // __CARLA_PLUGIN_INTERNAL_HPP__
  386. // common includes
  387. //#include <cmath>
  388. //#include <vector>
  389. //#include <QtCore/QMutex>
  390. //#include <QtGui/QMainWindow>
  391. //#ifdef Q_WS_X11
  392. //# include <QtGui/QX11EmbedContainer>
  393. //typedef QX11EmbedContainer GuiContainer;
  394. //#else
  395. //# include <QtGui/QWidget>
  396. //typedef QWidget GuiContainer;
  397. //#endif
  398. #if 0
  399. // -------------------------------------------------------------------
  400. // Extra
  401. ExternalMidiNote extMidiNotes[MAX_MIDI_EVENTS];
  402. // -------------------------------------------------------------------
  403. // Utilities
  404. static double fixParameterValue(double& value, const ParameterRanges& ranges)
  405. {
  406. if (value < ranges.min)
  407. value = ranges.min;
  408. else if (value > ranges.max)
  409. value = ranges.max;
  410. return value;
  411. }
  412. static float fixParameterValue(float& value, const ParameterRanges& ranges)
  413. {
  414. if (value < ranges.min)
  415. value = ranges.min;
  416. else if (value > ranges.max)
  417. value = ranges.max;
  418. return value;
  419. }
  420. friend class CarlaEngine; // FIXME
  421. friend class CarlaEngineJack;
  422. #endif
  423. #if 0
  424. // -------------------------------------------------------------------
  425. /*!
  426. * \class ScopedDisabler
  427. *
  428. * \brief Carla plugin scoped disabler
  429. *
  430. * This is a handy class that temporarily disables a plugin during a function scope.\n
  431. * It should be used when the plugin needs reload or state change, something like this:
  432. * \code
  433. * {
  434. * const CarlaPlugin::ScopedDisabler m(plugin);
  435. * plugin->setChunkData(data);
  436. * }
  437. * \endcode
  438. */
  439. class ScopedDisabler
  440. {
  441. public:
  442. /*!
  443. * Disable plugin \a plugin if \a disable is true.
  444. * The plugin is re-enabled in the deconstructor of this class if \a disable is true.
  445. *
  446. * \param plugin The plugin to disable
  447. * \param disable Wherever to disable the plugin or not, true by default
  448. */
  449. ScopedDisabler(CarlaPlugin* const plugin, const bool disable = true)
  450. : m_plugin(plugin),
  451. m_disable(disable)
  452. {
  453. if (m_disable)
  454. {
  455. m_plugin->engineProcessLock();
  456. m_plugin->setEnabled(false);
  457. m_plugin->engineProcessUnlock();
  458. }
  459. }
  460. ~ScopedDisabler()
  461. {
  462. if (m_disable)
  463. {
  464. m_plugin->engineProcessLock();
  465. m_plugin->setEnabled(true);
  466. m_plugin->engineProcessUnlock();
  467. }
  468. }
  469. private:
  470. CarlaPlugin* const m_plugin;
  471. const bool m_disable;
  472. };
  473. /*!
  474. * \class CarlaPluginGUI
  475. *
  476. * \brief Carla Backend gui plugin class
  477. *
  478. * \see CarlaPlugin
  479. */
  480. class CarlaPluginGUI : public QMainWindow
  481. {
  482. public:
  483. /*!
  484. * \class Callback
  485. *
  486. * \brief Carla plugin GUI callback
  487. */
  488. class Callback
  489. {
  490. public:
  491. virtual ~Callback() {}
  492. virtual void guiClosedCallback() = 0;
  493. };
  494. // -------------------------------------------------------------------
  495. // Constructor and destructor
  496. /*!
  497. * TODO
  498. */
  499. CarlaPluginGUI(QWidget* const parent, Callback* const callback);
  500. /*!
  501. * TODO
  502. */
  503. ~CarlaPluginGUI();
  504. // -------------------------------------------------------------------
  505. // Get data
  506. /*!
  507. * TODO
  508. */
  509. GuiContainer* getContainer() const;
  510. /*!
  511. * TODO
  512. */
  513. WId getWinId() const;
  514. // -------------------------------------------------------------------
  515. // Set data
  516. /*!
  517. * TODO
  518. */
  519. void setNewSize(const int width, const int height);
  520. /*!
  521. * TODO
  522. */
  523. void setResizable(const bool resizable);
  524. /*!
  525. * TODO
  526. */
  527. void setTitle(const char* const title);
  528. /*!
  529. * TODO
  530. */
  531. void setVisible(const bool yesNo);
  532. // -------------------------------------------------------------------
  533. private:
  534. Callback* const m_callback;
  535. GuiContainer* m_container;
  536. QByteArray m_geometry;
  537. bool m_resizable;
  538. void hideEvent(QHideEvent* const event);
  539. void closeEvent(QCloseEvent* const event);
  540. };
  541. #endif