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.

658 lines
14KB

  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_state_utils.hpp"
  24. #include "carla_midi.h"
  25. #include "rt_list.hpp"
  26. #include <QtGui/QMainWindow>
  27. #define CARLA_DECLARE_NON_COPY_STRUCT(structName) \
  28. structName(const structName&) = delete;
  29. #define CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(structName) \
  30. CARLA_DECLARE_NON_COPY_STRUCT(structName) \
  31. CARLA_LEAK_DETECTOR(structName)
  32. #define CARLA_PROCESS_CONTINUE_CHECK if (! fEnabled) { kData->engine->callback(CALLBACK_DEBUG, fId, 0, 0, 0.0, nullptr); return; }
  33. CARLA_BACKEND_START_NAMESPACE
  34. // -----------------------------------------------------------------------
  35. #ifndef BUILD_BRIDGE
  36. enum PluginBridgeInfoType {
  37. kPluginBridgeAudioCount,
  38. kPluginBridgeMidiCount,
  39. kPluginBridgeParameterCount,
  40. kPluginBridgeProgramCount,
  41. kPluginBridgeMidiProgramCount,
  42. kPluginBridgePluginInfo,
  43. kPluginBridgeParameterInfo,
  44. kPluginBridgeParameterData,
  45. kPluginBridgeParameterRanges,
  46. kPluginBridgeProgramInfo,
  47. kPluginBridgeMidiProgramInfo,
  48. kPluginBridgeConfigure,
  49. kPluginBridgeSetParameterValue,
  50. kPluginBridgeSetDefaultValue,
  51. kPluginBridgeSetProgram,
  52. kPluginBridgeSetMidiProgram,
  53. kPluginBridgeSetCustomData,
  54. kPluginBridgeSetChunkData,
  55. kPluginBridgeUpdateNow,
  56. kPluginBridgeError
  57. };
  58. #endif
  59. // -----------------------------------------------------------------------
  60. const unsigned short MAX_RT_EVENTS = 128;
  61. const unsigned short MAX_MIDI_EVENTS = 512;
  62. const unsigned int PLUGIN_HINT_HAS_MIDI_IN = 0x1;
  63. const unsigned int PLUGIN_HINT_HAS_MIDI_OUT = 0x2;
  64. // -----------------------------------------------------------------------
  65. struct PluginAudioPort {
  66. uint32_t rindex;
  67. CarlaEngineAudioPort* port;
  68. PluginAudioPort()
  69. : rindex(0),
  70. port(nullptr) {}
  71. ~PluginAudioPort()
  72. {
  73. CARLA_ASSERT(port == nullptr);
  74. }
  75. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioPort)
  76. };
  77. struct PluginAudioData {
  78. uint32_t count;
  79. PluginAudioPort* ports;
  80. PluginAudioData()
  81. : count(0),
  82. ports(nullptr) {}
  83. ~PluginAudioData()
  84. {
  85. CARLA_ASSERT(ports == nullptr);
  86. }
  87. void createNew(const uint32_t count)
  88. {
  89. CARLA_ASSERT(ports == nullptr);
  90. if (ports == nullptr)
  91. ports = new PluginAudioPort[count];
  92. this->count = count;
  93. }
  94. void clear()
  95. {
  96. if (ports != nullptr)
  97. {
  98. for (uint32_t i=0; i < count; i++)
  99. {
  100. if (ports[i].port != nullptr)
  101. {
  102. delete ports[i].port;
  103. ports[i].port = nullptr;
  104. }
  105. }
  106. delete[] ports;
  107. ports = nullptr;
  108. }
  109. count = 0;
  110. }
  111. void initBuffers(CarlaEngine* const engine)
  112. {
  113. for (uint32_t i=0; i < count; i++)
  114. {
  115. if (ports[i].port != nullptr)
  116. ports[i].port->initBuffer(engine);
  117. }
  118. }
  119. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioData)
  120. };
  121. // -----------------------------------------------------------------------
  122. struct PluginEventData {
  123. CarlaEngineEventPort* portIn;
  124. CarlaEngineEventPort* portOut;
  125. PluginEventData()
  126. : portIn(nullptr),
  127. portOut(nullptr) {}
  128. ~PluginEventData()
  129. {
  130. CARLA_ASSERT(portIn == nullptr);
  131. CARLA_ASSERT(portOut == nullptr);
  132. }
  133. void clear()
  134. {
  135. if (portIn != nullptr)
  136. {
  137. delete portIn;
  138. portIn = nullptr;
  139. }
  140. if (portOut != nullptr)
  141. {
  142. delete portOut;
  143. portOut = nullptr;
  144. }
  145. }
  146. void initBuffers(CarlaEngine* const engine)
  147. {
  148. if (portIn != nullptr)
  149. portIn->initBuffer(engine);
  150. if (portOut != nullptr)
  151. portOut->initBuffer(engine);
  152. }
  153. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginEventData)
  154. };
  155. // -----------------------------------------------------------------------
  156. struct PluginParameterData {
  157. uint32_t count;
  158. ParameterData* data;
  159. ParameterRanges* ranges;
  160. PluginParameterData()
  161. : count(0),
  162. data(nullptr),
  163. ranges(nullptr) {}
  164. ~PluginParameterData()
  165. {
  166. CARLA_ASSERT(data == nullptr);
  167. CARLA_ASSERT(ranges == nullptr);
  168. }
  169. void createNew(const uint32_t count)
  170. {
  171. CARLA_ASSERT(data == nullptr);
  172. CARLA_ASSERT(ranges == nullptr);
  173. if (data == nullptr)
  174. data = new ParameterData[count];
  175. if (ranges == nullptr)
  176. ranges = new ParameterRanges[count];
  177. this->count = count;
  178. }
  179. void clear()
  180. {
  181. if (data != nullptr)
  182. {
  183. delete[] data;
  184. data = nullptr;
  185. }
  186. if (ranges != nullptr)
  187. {
  188. delete[] ranges;
  189. ranges = nullptr;
  190. }
  191. count = 0;
  192. }
  193. float fixValue(const uint32_t parameterId, const float& value)
  194. {
  195. return ranges[parameterId].fixValue(value);
  196. }
  197. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginParameterData)
  198. };
  199. // -----------------------------------------------------------------------
  200. typedef const char* ProgramName;
  201. struct PluginProgramData {
  202. uint32_t count;
  203. int32_t current;
  204. ProgramName* names;
  205. PluginProgramData()
  206. : count(0),
  207. current(-1),
  208. names(nullptr) {}
  209. ~PluginProgramData()
  210. {
  211. CARLA_ASSERT(names == nullptr);
  212. }
  213. void createNew(const uint32_t count)
  214. {
  215. CARLA_ASSERT(names == nullptr);
  216. if (names == nullptr)
  217. names = new ProgramName[count];
  218. for (uint32_t i=0; i < count; i++)
  219. names[i] = nullptr;
  220. this->count = count;
  221. }
  222. void clear()
  223. {
  224. if (names != nullptr)
  225. {
  226. for (uint32_t i=0; i < count; i++)
  227. {
  228. if (names[i] != nullptr)
  229. delete[] names[i];
  230. }
  231. delete[] names;
  232. names = nullptr;
  233. }
  234. count = 0;
  235. current = -1;
  236. }
  237. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginProgramData)
  238. };
  239. // -----------------------------------------------------------------------
  240. struct PluginMidiProgramData {
  241. uint32_t count;
  242. int32_t current;
  243. MidiProgramData* data;
  244. PluginMidiProgramData()
  245. : count(0),
  246. current(-1),
  247. data(nullptr) {}
  248. ~PluginMidiProgramData()
  249. {
  250. CARLA_ASSERT(data == nullptr);
  251. }
  252. void createNew(const uint32_t count)
  253. {
  254. CARLA_ASSERT(data == nullptr);
  255. if (data == nullptr)
  256. data = new MidiProgramData[count];
  257. this->count = count;
  258. }
  259. void clear()
  260. {
  261. if (data != nullptr)
  262. {
  263. delete[] data;
  264. data = nullptr;
  265. }
  266. count = 0;
  267. current = -1;
  268. }
  269. const MidiProgramData& getCurrent() const
  270. {
  271. CARLA_ASSERT(current >= 0 && current < static_cast<int32_t>(count));
  272. return data[current];
  273. }
  274. CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginMidiProgramData)
  275. };
  276. // -----------------------------------------------------------------------
  277. struct PluginPostRtEvent {
  278. PluginPostRtEventType type;
  279. int32_t value1;
  280. int32_t value2;
  281. double value3;
  282. PluginPostRtEvent()
  283. : type(kPluginPostRtEventNull),
  284. value1(-1),
  285. value2(-1),
  286. value3(0.0) {}
  287. CARLA_DECLARE_NON_COPY_STRUCT(PluginPostRtEvent)
  288. };
  289. // -----------------------------------------------------------------------
  290. struct ExternalMidiNote {
  291. int8_t channel; // invalid = -1
  292. uint8_t note;
  293. uint8_t velo;
  294. ExternalMidiNote()
  295. : channel(-1),
  296. note(0),
  297. velo(0) {}
  298. CARLA_DECLARE_NON_COPY_STRUCT(ExternalMidiNote)
  299. };
  300. // -----------------------------------------------------------------------
  301. class CarlaPluginGUI : public QMainWindow
  302. {
  303. public:
  304. class Callback
  305. {
  306. public:
  307. virtual ~Callback() {}
  308. virtual void guiClosedCallback() = 0;
  309. };
  310. CarlaPluginGUI(QWidget* const parent, Callback* const callback);
  311. ~CarlaPluginGUI();
  312. private:
  313. Callback* const kCallback;
  314. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI)
  315. };
  316. // -----------------------------------------------------------------------
  317. struct CarlaPluginProtectedData {
  318. CarlaEngine* const engine;
  319. CarlaEngineClient* client;
  320. CarlaPluginGUI* gui;
  321. bool active;
  322. bool activeBefore;
  323. void* lib;
  324. // misc
  325. int8_t ctrlInChannel;
  326. unsigned int extraHints;
  327. uint32_t latency;
  328. float** latencyBuffers;
  329. // data
  330. PluginAudioData audioIn;
  331. PluginAudioData audioOut;
  332. PluginEventData event;
  333. PluginParameterData param;
  334. PluginProgramData prog;
  335. PluginMidiProgramData midiprog;
  336. NonRtListNew<CustomData> custom;
  337. struct ExternalNotes {
  338. CarlaMutex mutex;
  339. RtList<ExternalMidiNote>::Pool dataPool;
  340. RtList<ExternalMidiNote> data;
  341. ExternalNotes()
  342. : dataPool(152, 512),
  343. data(&dataPool) {}
  344. ~ExternalNotes()
  345. {
  346. data.clear();
  347. }
  348. void append(const ExternalMidiNote& note)
  349. {
  350. data.append_sleepy(note);
  351. }
  352. } extNotes;
  353. struct PostRtEvents {
  354. CarlaMutex mutex;
  355. RtList<PluginPostRtEvent>::Pool dataPool;
  356. RtList<PluginPostRtEvent> data;
  357. RtList<PluginPostRtEvent> dataPendingRT;
  358. PostRtEvents()
  359. : dataPool(MAX_RT_EVENTS, MAX_RT_EVENTS),
  360. data(&dataPool),
  361. dataPendingRT(&dataPool) {}
  362. ~PostRtEvents()
  363. {
  364. clear();
  365. }
  366. void appendRT(const PluginPostRtEvent& event)
  367. {
  368. dataPendingRT.append(event);
  369. }
  370. void trySplice()
  371. {
  372. if (mutex.tryLock())
  373. {
  374. dataPendingRT.splice(data, true);
  375. mutex.unlock();
  376. }
  377. }
  378. void clear()
  379. {
  380. mutex.lock();
  381. data.clear();
  382. dataPendingRT.clear();
  383. mutex.unlock();
  384. }
  385. } postRtEvents;
  386. struct PostProc {
  387. float dryWet;
  388. float volume;
  389. float balanceLeft;
  390. float balanceRight;
  391. float panning;
  392. PostProc()
  393. : dryWet(1.0f),
  394. volume(1.0f),
  395. balanceLeft(-1.0f),
  396. balanceRight(1.0f),
  397. panning(0.0f) {}
  398. } postProc;
  399. struct OSC {
  400. CarlaOscData data;
  401. CarlaPluginThread* thread;
  402. OSC()
  403. : thread(nullptr) {}
  404. } osc;
  405. CarlaPluginProtectedData(CarlaEngine* const engine_)
  406. : engine(engine_),
  407. client(nullptr),
  408. gui(nullptr),
  409. active(false),
  410. activeBefore(false),
  411. lib(nullptr),
  412. ctrlInChannel(-1),
  413. extraHints(0x0),
  414. latency(0),
  415. latencyBuffers(nullptr) {}
  416. CarlaPluginProtectedData() = delete;
  417. CarlaPluginProtectedData(CarlaPluginProtectedData&) = delete;
  418. CarlaPluginProtectedData(const CarlaPluginProtectedData&) = delete;
  419. static CarlaEngine* getEngine(CarlaPlugin* const plugin)
  420. {
  421. return plugin->kData->engine;
  422. }
  423. static CarlaEngineAudioPort* getAudioInPort(CarlaPlugin* const plugin, uint32_t index)
  424. {
  425. return plugin->kData->audioIn.ports[index].port;
  426. }
  427. static CarlaEngineAudioPort* getAudioOutPort(CarlaPlugin* const plugin, uint32_t index)
  428. {
  429. return plugin->kData->audioOut.ports[index].port;
  430. }
  431. CARLA_LEAK_DETECTOR(CarlaPluginProtectedData)
  432. };
  433. // -----------------------------------------------------------------------
  434. CARLA_BACKEND_END_NAMESPACE
  435. #endif // __CARLA_PLUGIN_INTERNAL_HPP__
  436. // common includes
  437. //#include <cmath>
  438. //#include <vector>
  439. //#include <QtCore/QMutex>
  440. //#include <QtGui/QMainWindow>
  441. //#ifdef Q_WS_X11
  442. //# include <QtGui/QX11EmbedContainer>
  443. //typedef QX11EmbedContainer GuiContainer;
  444. //#else
  445. //# include <QtGui/QWidget>
  446. //typedef QWidget GuiContainer;
  447. //#endif
  448. #if 0
  449. /*!
  450. * \class CarlaPluginGUI
  451. *
  452. * \brief Carla Backend gui plugin class
  453. *
  454. * \see CarlaPlugin
  455. */
  456. class CarlaPluginGUI : public QMainWindow
  457. {
  458. public:
  459. /*!
  460. * \class Callback
  461. *
  462. * \brief Carla plugin GUI callback
  463. */
  464. class Callback
  465. {
  466. public:
  467. virtual ~Callback() {}
  468. virtual void guiClosedCallback() = 0;
  469. };
  470. // -------------------------------------------------------------------
  471. // Constructor and destructor
  472. /*!
  473. * TODO
  474. */
  475. CarlaPluginGUI(QWidget* const parent, Callback* const callback);
  476. /*!
  477. * TODO
  478. */
  479. ~CarlaPluginGUI();
  480. // -------------------------------------------------------------------
  481. // Get data
  482. /*!
  483. * TODO
  484. */
  485. GuiContainer* getContainer() const;
  486. /*!
  487. * TODO
  488. */
  489. WId getWinId() const;
  490. // -------------------------------------------------------------------
  491. // Set data
  492. /*!
  493. * TODO
  494. */
  495. void setNewSize(const int width, const int height);
  496. /*!
  497. * TODO
  498. */
  499. void setResizable(const bool resizable);
  500. /*!
  501. * TODO
  502. */
  503. void setTitle(const char* const title);
  504. /*!
  505. * TODO
  506. */
  507. void setVisible(const bool yesNo);
  508. // -------------------------------------------------------------------
  509. private:
  510. Callback* const m_callback;
  511. GuiContainer* m_container;
  512. QByteArray m_geometry;
  513. bool m_resizable;
  514. void hideEvent(QHideEvent* const event);
  515. void closeEvent(QCloseEvent* const event);
  516. };
  517. #endif