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.

1212 lines
45KB

  1. /*
  2. * Carla Bridge UI, LV2 version
  3. * Copyright (C) 2011-2014 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 doc/GPL.txt file.
  16. */
  17. #include "CarlaBridgeUI.hpp"
  18. #include "CarlaLibUtils.hpp"
  19. #include "CarlaLv2Utils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "LinkedList.hpp"
  22. #include "juce_core.h"
  23. #define URI_CARLA_ATOM_WORKER "http://kxstudio.sf.net/ns/carla/atomWorker"
  24. using juce::File;
  25. CARLA_BRIDGE_START_NAMESPACE
  26. // -----------------------------------------------------
  27. static int gBufferSize = 1024;
  28. static double gSampleRate = 44100.0;
  29. // Maximum default buffer size
  30. const unsigned int MAX_DEFAULT_BUFFER_SIZE = 8192; // 0x2000
  31. // LV2 URI Map Ids
  32. const uint32_t CARLA_URI_MAP_ID_NULL = 0;
  33. const uint32_t CARLA_URI_MAP_ID_ATOM_BLANK = 1;
  34. const uint32_t CARLA_URI_MAP_ID_ATOM_BOOL = 2;
  35. const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 3;
  36. const uint32_t CARLA_URI_MAP_ID_ATOM_DOUBLE = 4;
  37. const uint32_t CARLA_URI_MAP_ID_ATOM_EVENT = 5;
  38. const uint32_t CARLA_URI_MAP_ID_ATOM_FLOAT = 6;
  39. const uint32_t CARLA_URI_MAP_ID_ATOM_INT = 7;
  40. const uint32_t CARLA_URI_MAP_ID_ATOM_LITERAL = 8;
  41. const uint32_t CARLA_URI_MAP_ID_ATOM_LONG = 9;
  42. const uint32_t CARLA_URI_MAP_ID_ATOM_NUMBER = 10;
  43. const uint32_t CARLA_URI_MAP_ID_ATOM_OBJECT = 11;
  44. const uint32_t CARLA_URI_MAP_ID_ATOM_PATH = 12;
  45. const uint32_t CARLA_URI_MAP_ID_ATOM_PROPERTY = 13;
  46. const uint32_t CARLA_URI_MAP_ID_ATOM_RESOURCE = 14;
  47. const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 15;
  48. const uint32_t CARLA_URI_MAP_ID_ATOM_SOUND = 16;
  49. const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 17;
  50. const uint32_t CARLA_URI_MAP_ID_ATOM_TUPLE = 18;
  51. const uint32_t CARLA_URI_MAP_ID_ATOM_URI = 19;
  52. const uint32_t CARLA_URI_MAP_ID_ATOM_URID = 20;
  53. const uint32_t CARLA_URI_MAP_ID_ATOM_VECTOR = 21;
  54. const uint32_t CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM = 22;
  55. const uint32_t CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT = 23;
  56. const uint32_t CARLA_URI_MAP_ID_BUF_MAX_LENGTH = 24;
  57. const uint32_t CARLA_URI_MAP_ID_BUF_MIN_LENGTH = 25;
  58. const uint32_t CARLA_URI_MAP_ID_BUF_SEQUENCE_SIZE = 26;
  59. const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 27;
  60. const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 28;
  61. const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 29;
  62. const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 30;
  63. const uint32_t CARLA_URI_MAP_ID_TIME_POSITION = 31; // base type
  64. const uint32_t CARLA_URI_MAP_ID_TIME_BAR = 32; // values
  65. const uint32_t CARLA_URI_MAP_ID_TIME_BAR_BEAT = 33;
  66. const uint32_t CARLA_URI_MAP_ID_TIME_BEAT = 34;
  67. const uint32_t CARLA_URI_MAP_ID_TIME_BEAT_UNIT = 35;
  68. const uint32_t CARLA_URI_MAP_ID_TIME_BEATS_PER_BAR = 36;
  69. const uint32_t CARLA_URI_MAP_ID_TIME_BEATS_PER_MINUTE = 37;
  70. const uint32_t CARLA_URI_MAP_ID_TIME_FRAME = 38;
  71. const uint32_t CARLA_URI_MAP_ID_TIME_FRAMES_PER_SECOND = 39;
  72. const uint32_t CARLA_URI_MAP_ID_TIME_SPEED = 40;
  73. const uint32_t CARLA_URI_MAP_ID_TIME_TICKS_PER_BEAT = 41;
  74. const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 42;
  75. const uint32_t CARLA_URI_MAP_ID_PARAM_SAMPLE_RATE = 43;
  76. const uint32_t CARLA_URI_MAP_ID_UI_WINDOW_TITLE = 44;
  77. const uint32_t CARLA_URI_MAP_ID_CARLA_ATOM_WORKER = 45;
  78. const uint32_t CARLA_URI_MAP_ID_CARLA_TRANSIENT_WIN_ID = 46;
  79. const uint32_t CARLA_URI_MAP_ID_COUNT = 47;
  80. // LV2 Feature Ids
  81. const uint32_t kFeatureIdLogs = 0;
  82. const uint32_t kFeatureIdOptions = 1;
  83. const uint32_t kFeatureIdPrograms = 2;
  84. const uint32_t kFeatureIdStateMakePath = 3;
  85. const uint32_t kFeatureIdStateMapPath = 4;
  86. const uint32_t kFeatureIdUriMap = 5;
  87. const uint32_t kFeatureIdUridMap = 6;
  88. const uint32_t kFeatureIdUridUnmap = 7;
  89. const uint32_t kFeatureIdUiIdleInterface = 8;
  90. const uint32_t kFeatureIdUiFixedSize = 9;
  91. const uint32_t kFeatureIdUiMakeResident = 10;
  92. const uint32_t kFeatureIdUiNoUserResize = 11;
  93. const uint32_t kFeatureIdUiParent = 12;
  94. const uint32_t kFeatureIdUiPortMap = 13;
  95. const uint32_t kFeatureIdUiPortSubscribe = 14;
  96. const uint32_t kFeatureIdUiResize = 15;
  97. const uint32_t kFeatureIdUiTouch = 16;
  98. const uint32_t kFeatureCount = 17;
  99. // -------------------------------------------------------------------------
  100. struct Lv2PluginOptions {
  101. enum OptIndex {
  102. MaxBlockLenth = 0,
  103. MinBlockLenth,
  104. SequenceSize,
  105. SampleRate,
  106. FrontendWinId,
  107. //WindowTitle,
  108. Null,
  109. Count
  110. };
  111. int maxBufferSize;
  112. int minBufferSize;
  113. int sequenceSize;
  114. double sampleRate;
  115. int64_t frontendWinId;
  116. const char* windowTitle;
  117. LV2_Options_Option opts[Count];
  118. Lv2PluginOptions() noexcept
  119. : maxBufferSize(0),
  120. minBufferSize(0),
  121. sequenceSize(MAX_DEFAULT_BUFFER_SIZE),
  122. sampleRate(0.0),
  123. frontendWinId(0),
  124. windowTitle(nullptr)
  125. {
  126. LV2_Options_Option& optMaxBlockLenth(opts[MaxBlockLenth]);
  127. optMaxBlockLenth.context = LV2_OPTIONS_INSTANCE;
  128. optMaxBlockLenth.subject = 0;
  129. optMaxBlockLenth.key = CARLA_URI_MAP_ID_BUF_MAX_LENGTH;
  130. optMaxBlockLenth.size = sizeof(int);
  131. optMaxBlockLenth.type = CARLA_URI_MAP_ID_ATOM_INT;
  132. optMaxBlockLenth.value = &maxBufferSize;
  133. LV2_Options_Option& optMinBlockLenth(opts[MinBlockLenth]);
  134. optMinBlockLenth.context = LV2_OPTIONS_INSTANCE;
  135. optMinBlockLenth.subject = 0;
  136. optMinBlockLenth.key = CARLA_URI_MAP_ID_BUF_MIN_LENGTH;
  137. optMinBlockLenth.size = sizeof(int);
  138. optMinBlockLenth.type = CARLA_URI_MAP_ID_ATOM_INT;
  139. optMinBlockLenth.value = &minBufferSize;
  140. LV2_Options_Option& optSequenceSize(opts[SequenceSize]);
  141. optSequenceSize.context = LV2_OPTIONS_INSTANCE;
  142. optSequenceSize.subject = 0;
  143. optSequenceSize.key = CARLA_URI_MAP_ID_BUF_SEQUENCE_SIZE;
  144. optSequenceSize.size = sizeof(int);
  145. optSequenceSize.type = CARLA_URI_MAP_ID_ATOM_INT;
  146. optSequenceSize.value = &sequenceSize;
  147. LV2_Options_Option& optSampleRate(opts[SampleRate]);
  148. optSampleRate.context = LV2_OPTIONS_INSTANCE;
  149. optSampleRate.subject = 0;
  150. optSampleRate.key = CARLA_URI_MAP_ID_PARAM_SAMPLE_RATE;
  151. optSampleRate.size = sizeof(double);
  152. optSampleRate.type = CARLA_URI_MAP_ID_ATOM_DOUBLE;
  153. optSampleRate.value = &sampleRate;
  154. LV2_Options_Option& optFrontendWinId(opts[FrontendWinId]);
  155. optFrontendWinId.context = LV2_OPTIONS_INSTANCE;
  156. optFrontendWinId.subject = 0;
  157. optFrontendWinId.key = CARLA_URI_MAP_ID_CARLA_TRANSIENT_WIN_ID;
  158. optFrontendWinId.size = sizeof(int64_t);
  159. optFrontendWinId.type = CARLA_URI_MAP_ID_ATOM_LONG;
  160. optFrontendWinId.value = &frontendWinId;
  161. /*
  162. LV2_Options_Option& optWindowTitle(opts[WindowTitle]);
  163. optWindowTitle.context = LV2_OPTIONS_INSTANCE;
  164. optWindowTitle.subject = 0;
  165. optWindowTitle.key = CARLA_URI_MAP_ID_UI_WINDOW_TITLE;
  166. optWindowTitle.size = 0;
  167. optWindowTitle.type = CARLA_URI_MAP_ID_ATOM_STRING;
  168. optWindowTitle.value = nullptr;
  169. */
  170. LV2_Options_Option& optNull(opts[Null]);
  171. optNull.context = LV2_OPTIONS_INSTANCE;
  172. optNull.subject = 0;
  173. optNull.key = CARLA_URI_MAP_ID_NULL;
  174. optNull.size = 0;
  175. optNull.type = CARLA_URI_MAP_ID_NULL;
  176. optNull.value = nullptr;
  177. }
  178. };
  179. // -------------------------------------------------------------------------
  180. class CarlaLv2Client : public CarlaBridgeUI
  181. {
  182. public:
  183. CarlaLv2Client()
  184. : CarlaBridgeUI(),
  185. fHandle(nullptr),
  186. fWidget(nullptr),
  187. fDescriptor(nullptr),
  188. fRdfDescriptor(nullptr),
  189. fRdfUiDescriptor(nullptr),
  190. fLv2Options(),
  191. fUiOptions(),
  192. fCustomURIDs(),
  193. fExt(),
  194. leakDetector_CarlaLv2Client()
  195. {
  196. carla_zeroPointers(fFeatures, kFeatureCount+1);
  197. for (uint32_t i=0; i < CARLA_URI_MAP_ID_COUNT; ++i)
  198. fCustomURIDs.append(nullptr);
  199. // ---------------------------------------------------------------
  200. // initialize options
  201. fLv2Options.minBufferSize = gBufferSize;
  202. fLv2Options.maxBufferSize = gBufferSize;
  203. fLv2Options.sampleRate = gSampleRate;
  204. // ---------------------------------------------------------------
  205. // initialize features (part 1)
  206. LV2_Log_Log* const logFt = new LV2_Log_Log;
  207. logFt->handle = this;
  208. logFt->printf = carla_lv2_log_printf;
  209. logFt->vprintf = carla_lv2_log_vprintf;
  210. LV2_State_Make_Path* const stateMakePathFt = new LV2_State_Make_Path;
  211. stateMakePathFt->handle = this;
  212. stateMakePathFt->path = carla_lv2_state_make_path;
  213. LV2_State_Map_Path* const stateMapPathFt = new LV2_State_Map_Path;
  214. stateMapPathFt->handle = this;
  215. stateMapPathFt->abstract_path = carla_lv2_state_map_abstract_path;
  216. stateMapPathFt->absolute_path = carla_lv2_state_map_absolute_path;
  217. LV2_Programs_Host* const programsFt = new LV2_Programs_Host;
  218. programsFt->handle = this;
  219. programsFt->program_changed = carla_lv2_program_changed;
  220. LV2_URI_Map_Feature* const uriMapFt = new LV2_URI_Map_Feature;
  221. uriMapFt->callback_data = this;
  222. uriMapFt->uri_to_id = carla_lv2_uri_to_id;
  223. LV2_URID_Map* const uridMapFt = new LV2_URID_Map;
  224. uridMapFt->handle = this;
  225. uridMapFt->map = carla_lv2_urid_map;
  226. LV2_URID_Unmap* const uridUnmapFt = new LV2_URID_Unmap;
  227. uridUnmapFt->handle = this;
  228. uridUnmapFt->unmap = carla_lv2_urid_unmap;
  229. LV2UI_Port_Map* const uiPortMapFt = new LV2UI_Port_Map;
  230. uiPortMapFt->handle = this;
  231. uiPortMapFt->port_index = carla_lv2_ui_port_map;
  232. LV2UI_Resize* const uiResizeFt = new LV2UI_Resize;
  233. uiResizeFt->handle = this;
  234. uiResizeFt->ui_resize = carla_lv2_ui_resize;
  235. // ---------------------------------------------------------------
  236. // initialize features (part 2)
  237. for (uint32_t i=0; i < kFeatureCount; ++i)
  238. fFeatures[i] = new LV2_Feature;
  239. fFeatures[kFeatureIdLogs]->URI = LV2_LOG__log;
  240. fFeatures[kFeatureIdLogs]->data = logFt;
  241. fFeatures[kFeatureIdOptions]->URI = LV2_OPTIONS__options;
  242. fFeatures[kFeatureIdOptions]->data = fLv2Options.opts;
  243. fFeatures[kFeatureIdPrograms]->URI = LV2_PROGRAMS__Host;
  244. fFeatures[kFeatureIdPrograms]->data = programsFt;
  245. fFeatures[kFeatureIdStateMakePath]->URI = LV2_STATE__makePath;
  246. fFeatures[kFeatureIdStateMakePath]->data = stateMakePathFt;
  247. fFeatures[kFeatureIdStateMapPath]->URI = LV2_STATE__mapPath;
  248. fFeatures[kFeatureIdStateMapPath]->data = stateMapPathFt;
  249. fFeatures[kFeatureIdUriMap]->URI = LV2_URI_MAP_URI;
  250. fFeatures[kFeatureIdUriMap]->data = uriMapFt;
  251. fFeatures[kFeatureIdUridMap]->URI = LV2_URID__map;
  252. fFeatures[kFeatureIdUridMap]->data = uridMapFt;
  253. fFeatures[kFeatureIdUridUnmap]->URI = LV2_URID__unmap;
  254. fFeatures[kFeatureIdUridUnmap]->data = uridUnmapFt;
  255. fFeatures[kFeatureIdUiIdleInterface]->URI = LV2_UI__idleInterface;
  256. fFeatures[kFeatureIdUiIdleInterface]->data = nullptr;
  257. fFeatures[kFeatureIdUiFixedSize]->URI = LV2_UI__fixedSize;
  258. fFeatures[kFeatureIdUiFixedSize]->data = nullptr;
  259. fFeatures[kFeatureIdUiMakeResident]->URI = LV2_UI__makeResident;
  260. fFeatures[kFeatureIdUiMakeResident]->data = nullptr;
  261. fFeatures[kFeatureIdUiNoUserResize]->URI = LV2_UI__noUserResize;
  262. fFeatures[kFeatureIdUiNoUserResize]->data = nullptr;
  263. fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent;
  264. fFeatures[kFeatureIdUiParent]->data = nullptr;
  265. fFeatures[kFeatureIdUiPortMap]->URI = LV2_UI__portMap;
  266. fFeatures[kFeatureIdUiPortMap]->data = uiPortMapFt;
  267. fFeatures[kFeatureIdUiPortSubscribe]->URI = LV2_UI__portSubscribe;
  268. fFeatures[kFeatureIdUiPortSubscribe]->data = nullptr;
  269. fFeatures[kFeatureIdUiResize]->URI = LV2_UI__resize;
  270. fFeatures[kFeatureIdUiResize]->data = uiResizeFt;
  271. fFeatures[kFeatureIdUiTouch]->URI = LV2_UI__touch;
  272. fFeatures[kFeatureIdUiTouch]->data = nullptr;
  273. }
  274. ~CarlaLv2Client() override
  275. {
  276. if (fHandle != nullptr && fDescriptor != nullptr && fDescriptor->cleanup != nullptr)
  277. {
  278. fDescriptor->cleanup(fHandle);
  279. fHandle = nullptr;
  280. }
  281. if (fRdfDescriptor != nullptr)
  282. {
  283. delete fRdfDescriptor;
  284. fRdfDescriptor = nullptr;
  285. }
  286. fRdfUiDescriptor = nullptr;
  287. delete (LV2_Log_Log*)fFeatures[kFeatureIdLogs]->data;
  288. delete (LV2_State_Make_Path*)fFeatures[kFeatureIdStateMakePath]->data;
  289. delete (LV2_State_Map_Path*)fFeatures[kFeatureIdStateMapPath]->data;
  290. delete (LV2_Programs_Host*)fFeatures[kFeatureIdPrograms]->data;
  291. delete (LV2_URI_Map_Feature*)fFeatures[kFeatureIdUriMap]->data;
  292. delete (LV2_URID_Map*)fFeatures[kFeatureIdUridMap]->data;
  293. delete (LV2_URID_Unmap*)fFeatures[kFeatureIdUridUnmap]->data;
  294. delete (LV2UI_Port_Map*)fFeatures[kFeatureIdUiPortMap]->data;
  295. delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data;
  296. for (uint32_t i=0; i < kFeatureCount; ++i)
  297. {
  298. if (fFeatures[i] != nullptr)
  299. {
  300. delete fFeatures[i];
  301. fFeatures[i] = nullptr;
  302. }
  303. }
  304. for (LinkedList<const char*>::Itenerator it = fCustomURIDs.begin(); it.valid(); it.next())
  305. {
  306. const char* const uri(it.getValue(nullptr));
  307. if (uri != nullptr)
  308. delete[] uri;
  309. }
  310. fCustomURIDs.clear();
  311. }
  312. // ---------------------------------------------------------------------
  313. // UI initialization
  314. bool init(const int argc, const char* argv[]) override
  315. {
  316. const char* pluginURI = argv[1];
  317. const char* uiURI = argv[2];
  318. // -----------------------------------------------------------------
  319. // load plugin
  320. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  321. lv2World.initIfNeeded(std::getenv("LV2_PATH"));
  322. //Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, uiBundle));
  323. //CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(), false);
  324. //CarlaString sBundle(bundleNode.as_uri());
  325. //if (! sBundle.endsWith("/"))
  326. // sBundle += "/";
  327. //lv2World.load_bundle(sBundle);
  328. // -----------------------------------------------------------------
  329. // get plugin from lv2_rdf (lilv)
  330. fRdfDescriptor = lv2_rdf_new(pluginURI, true);
  331. CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr, false);
  332. // -----------------------------------------------------------------
  333. // find requested UI
  334. for (uint32_t i=0; i < fRdfDescriptor->UICount; ++i)
  335. {
  336. if (std::strcmp(fRdfDescriptor->UIs[i].URI, uiURI) == 0)
  337. {
  338. fRdfUiDescriptor = &fRdfDescriptor->UIs[i];
  339. break;
  340. }
  341. }
  342. CARLA_SAFE_ASSERT_RETURN(fRdfUiDescriptor != nullptr, false);
  343. // -----------------------------------------------------------
  344. // check if not resizable
  345. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  346. // embed UIs can only be resizable if they provide resize extension
  347. fUiOptions.isResizable = false;
  348. // TODO: put this trick into main carla
  349. for (uint32_t i=0; i < fRdfUiDescriptor->ExtensionCount; ++i)
  350. {
  351. carla_stdout("Test UI extension %s", fRdfUiDescriptor->Extensions[i]);
  352. if (std::strcmp(fRdfUiDescriptor->Extensions[i], LV2_UI__resize) == 0)
  353. {
  354. fUiOptions.isResizable = true;
  355. break;
  356. }
  357. }
  358. #endif
  359. for (uint32_t i=0; i < fRdfUiDescriptor->FeatureCount; ++i)
  360. {
  361. carla_stdout("Test UI feature %s", fRdfUiDescriptor->Features[i].URI);
  362. if (std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__fixedSize ) == 0 ||
  363. std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__noUserResize) == 0)
  364. {
  365. fUiOptions.isResizable = false;
  366. break;
  367. }
  368. }
  369. carla_stdout("Is resizable => %s", bool2str(fUiOptions.isResizable));
  370. // -----------------------------------------------------------------
  371. // init UI
  372. if (! CarlaBridgeUI::init(argc, argv))
  373. return false;
  374. // -----------------------------------------------------------------
  375. // open DLL
  376. if (! libOpen(fRdfUiDescriptor->Binary))
  377. {
  378. carla_stderr("Failed to load UI binary, error was:\n%s", libError());
  379. return false;
  380. }
  381. // -----------------------------------------------------------------
  382. // get DLL main entry
  383. const LV2UI_DescriptorFunction ui_descFn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor");
  384. if (ui_descFn == nullptr)
  385. return false;
  386. // -----------------------------------------------------------
  387. // get descriptor that matches URI
  388. uint32_t i = 0;
  389. while ((fDescriptor = ui_descFn(i++)))
  390. {
  391. if (std::strcmp(fDescriptor->URI, uiURI) == 0)
  392. break;
  393. }
  394. if (fDescriptor == nullptr)
  395. {
  396. carla_stderr("Failed to find UI descriptor");
  397. return false;
  398. }
  399. // -----------------------------------------------------------
  400. // initialize UI
  401. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  402. fFeatures[kFeatureIdUiParent]->data = fToolkit->getContainerId();
  403. #endif
  404. fHandle = fDescriptor->instantiate(fDescriptor, fRdfDescriptor->URI, fRdfUiDescriptor->Bundle, carla_lv2_ui_write_function, this, &fWidget, fFeatures);
  405. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  406. // -----------------------------------------------------------
  407. // check for known extensions
  408. if (fDescriptor->extension_data != nullptr)
  409. {
  410. fExt.options = (const LV2_Options_Interface*)fDescriptor->extension_data(LV2_OPTIONS__interface);
  411. fExt.programs = (const LV2_Programs_UI_Interface*)fDescriptor->extension_data(LV2_PROGRAMS__UIInterface);
  412. fExt.idle = (const LV2UI_Idle_Interface*)fDescriptor->extension_data(LV2_UI__idleInterface);
  413. fExt.resize = (const LV2UI_Resize*)fDescriptor->extension_data(LV2_UI__resize);
  414. // check if invalid
  415. if (fExt.programs != nullptr && fExt.programs->select_program == nullptr)
  416. fExt.programs = nullptr;
  417. if (fExt.idle != nullptr && fExt.idle->idle == nullptr)
  418. fExt.idle = nullptr;
  419. if (fExt.resize != nullptr && fExt.resize->ui_resize == nullptr)
  420. fExt.resize = nullptr;
  421. }
  422. return true;
  423. }
  424. void idleUI() override
  425. {
  426. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  427. if (fHandle != nullptr && fExt.idle != nullptr)
  428. fExt.idle->idle(fHandle);
  429. #endif
  430. }
  431. // ---------------------------------------------------------------------
  432. // UI management
  433. void* getWidget() const noexcept override
  434. {
  435. return fWidget;
  436. }
  437. const Options& getOptions() const noexcept override
  438. {
  439. return fUiOptions;
  440. }
  441. // ---------------------------------------------------------------------
  442. // DSP Callbacks
  443. void dspParameterChanged(const uint32_t index, const float value) override
  444. {
  445. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  446. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  447. if (fDescriptor->port_event == nullptr)
  448. return;
  449. fDescriptor->port_event(fHandle, index, sizeof(float), CARLA_URI_MAP_ID_NULL, &value);
  450. }
  451. void dspProgramChanged(const uint32_t) override
  452. {
  453. }
  454. void dspMidiProgramChanged(const uint32_t bank, const uint32_t program) override
  455. {
  456. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  457. if (fExt.programs == nullptr)
  458. return;
  459. fExt.programs->select_program(fHandle, bank, program);
  460. }
  461. void dspStateChanged(const char* const, const char* const) override
  462. {
  463. }
  464. void dspNoteReceived(const bool onOff, const uint8_t channel, const uint8_t note, const uint8_t velocity) override
  465. {
  466. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  467. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  468. if (fDescriptor->port_event == nullptr)
  469. return;
  470. LV2_Atom_MidiEvent midiEv;
  471. midiEv.atom.type = CARLA_URI_MAP_ID_MIDI_EVENT;
  472. midiEv.atom.size = 3;
  473. midiEv.data[0] = uint8_t((onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (channel & MIDI_CHANNEL_BIT));
  474. midiEv.data[1] = note;
  475. midiEv.data[2] = velocity;
  476. fDescriptor->port_event(fHandle, /* TODO */ 0, lv2_atom_total_size(midiEv), CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM, &midiEv);
  477. }
  478. void dspAtomReceived(const uint32_t portIndex, const LV2_Atom* const atom) override
  479. {
  480. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  481. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  482. CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
  483. if (fDescriptor->port_event == nullptr)
  484. return;
  485. fDescriptor->port_event(fHandle, portIndex, lv2_atom_total_size(atom), CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
  486. }
  487. void dspURIDReceived(const LV2_URID urid, const char* const uri)
  488. {
  489. CARLA_SAFE_ASSERT_RETURN(urid == fCustomURIDs.count(),);
  490. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0',);
  491. fCustomURIDs.append(carla_strdup(uri));
  492. }
  493. void uiOptionsChanged(const double sampleRate, const bool useTheme, const bool useThemeColors, const char* const windowTitle, uintptr_t transientWindowId) override
  494. {
  495. carla_debug("CarlaLv2Client::uiOptionsChanged(%g, %s, %s, \"%s\", " P_UINTPTR ")", sampleRate, bool2str(useTheme), bool2str(useThemeColors), windowTitle, transientWindowId);
  496. fLv2Options.sampleRate = gSampleRate = sampleRate;
  497. fUiOptions.useTheme = useTheme;
  498. fUiOptions.useThemeColors = useThemeColors;
  499. fUiOptions.windowTitle = windowTitle;
  500. fUiOptions.transientWindowId = transientWindowId;
  501. }
  502. void uiResized(const uint width, const uint height) override
  503. {
  504. if (fHandle != nullptr && fExt.resize != nullptr)
  505. fExt.resize->ui_resize(fHandle, static_cast<int>(width), static_cast<int>(height));
  506. }
  507. // ---------------------------------------------------------------------
  508. LV2_URID getCustomURID(const char* const uri)
  509. {
  510. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', CARLA_URI_MAP_ID_NULL);
  511. carla_debug("CarlaLv2Client::getCustomURID(\"%s\")", uri);
  512. LV2_URID urid = CARLA_URI_MAP_ID_NULL;
  513. for (uint32_t i=0, count=static_cast<uint32_t>(fCustomURIDs.count()); i<count; ++i)
  514. {
  515. const char* const thisUri(fCustomURIDs.getAt(i, nullptr));
  516. if (thisUri != nullptr && std::strcmp(thisUri, uri) == 0)
  517. {
  518. urid = i;
  519. break;
  520. }
  521. }
  522. if (urid == CARLA_URI_MAP_ID_NULL)
  523. {
  524. urid = static_cast<LV2_URID>(fCustomURIDs.count());
  525. fCustomURIDs.append(carla_strdup(uri));
  526. }
  527. if (isPipeRunning())
  528. writeLv2UridMessage(urid, uri);
  529. return urid;
  530. }
  531. const char* getCustomURIDString(const LV2_URID urid) const noexcept
  532. {
  533. static const char* const sFallback = "urn:null";
  534. CARLA_SAFE_ASSERT_RETURN(urid != CARLA_URI_MAP_ID_NULL, sFallback);
  535. CARLA_SAFE_ASSERT_RETURN(urid < fCustomURIDs.count(), sFallback);
  536. carla_debug("CarlaLv2Client::getCustomURIDString(%i)", urid);
  537. return fCustomURIDs.getAt(urid, sFallback);
  538. }
  539. // ---------------------------------------------------------------------
  540. void handleProgramChanged(const int32_t /*index*/)
  541. {
  542. if (isPipeRunning())
  543. writeConfigureMessage("reloadprograms", "");
  544. }
  545. uint32_t handleUiPortMap(const char* const symbol)
  546. {
  547. CARLA_SAFE_ASSERT_RETURN(symbol != nullptr && symbol[0] != '\0', LV2UI_INVALID_PORT_INDEX);
  548. carla_debug("CarlaLv2Client::handleUiPortMap(\"%s\")", symbol);
  549. for (uint32_t i=0; i < fRdfDescriptor->PortCount; ++i)
  550. {
  551. if (std::strcmp(fRdfDescriptor->Ports[i].Symbol, symbol) == 0)
  552. return i;
  553. }
  554. return LV2UI_INVALID_PORT_INDEX;
  555. }
  556. int handleUiResize(const int width, const int height)
  557. {
  558. CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, 1);
  559. CARLA_SAFE_ASSERT_RETURN(width > 0, 1);
  560. CARLA_SAFE_ASSERT_RETURN(height > 0, 1);
  561. carla_debug("CarlaLv2Client::handleUiResize(%i, %i)", width, height);
  562. fToolkit->setSize(static_cast<uint>(width), static_cast<uint>(height));
  563. return 0;
  564. }
  565. void handleUiWrite(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
  566. {
  567. CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,);
  568. CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);
  569. carla_debug("CarlaLv2Client::handleUiWrite(%i, %i, %i, %p)", portIndex, bufferSize, format, buffer);
  570. if (format == 0)
  571. {
  572. CARLA_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),);
  573. const float value(*(const float*)buffer);
  574. if (isPipeRunning())
  575. writeControlMessage(portIndex, value);
  576. }
  577. else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM || CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
  578. {
  579. CARLA_SAFE_ASSERT_RETURN(bufferSize >= sizeof(LV2_Atom),);
  580. const LV2_Atom* const atom((const LV2_Atom*)buffer);
  581. if (isPipeRunning())
  582. writeLv2AtomMessage(portIndex, atom);
  583. }
  584. else
  585. {
  586. carla_stdout("CarlaLv2Client::handleUiWrite(%i, %i, %i:\"%s\", %p) - unknown format", portIndex, bufferSize, format, carla_lv2_urid_unmap(this, format), buffer);
  587. }
  588. }
  589. // ---------------------------------------------------------------------
  590. private:
  591. LV2UI_Handle fHandle;
  592. LV2UI_Widget fWidget;
  593. LV2_Feature* fFeatures[kFeatureCount+1];
  594. const LV2UI_Descriptor* fDescriptor;
  595. const LV2_RDF_Descriptor* fRdfDescriptor;
  596. const LV2_RDF_UI* fRdfUiDescriptor;
  597. Lv2PluginOptions fLv2Options;
  598. Options fUiOptions;
  599. LinkedList<const char*> fCustomURIDs;
  600. struct Extensions {
  601. const LV2_Options_Interface* options;
  602. const LV2_Programs_UI_Interface* programs;
  603. const LV2UI_Idle_Interface* idle;
  604. const LV2UI_Resize* resize;
  605. Extensions()
  606. : options(nullptr),
  607. programs(nullptr),
  608. idle(nullptr),
  609. resize(nullptr) {}
  610. } fExt;
  611. // -------------------------------------------------------------------
  612. // Logs Feature
  613. static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
  614. {
  615. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
  616. CARLA_SAFE_ASSERT_RETURN(type != CARLA_URI_MAP_ID_NULL, 0);
  617. CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
  618. #ifndef DEBUG
  619. if (type == CARLA_URI_MAP_ID_LOG_TRACE)
  620. return 0;
  621. #endif
  622. va_list args;
  623. va_start(args, fmt);
  624. const int ret(carla_lv2_log_vprintf(handle, type, fmt, args));
  625. va_end(args);
  626. return ret;
  627. }
  628. static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
  629. {
  630. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
  631. CARLA_SAFE_ASSERT_RETURN(type != CARLA_URI_MAP_ID_NULL, 0);
  632. CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
  633. #ifndef DEBUG
  634. if (type == CARLA_URI_MAP_ID_LOG_TRACE)
  635. return 0;
  636. #endif
  637. int ret = 0;
  638. switch (type)
  639. {
  640. case CARLA_URI_MAP_ID_LOG_ERROR:
  641. std::fprintf(stderr, "\x1b[31m");
  642. ret = std::vfprintf(stderr, fmt, ap);
  643. std::fprintf(stderr, "\x1b[0m");
  644. break;
  645. case CARLA_URI_MAP_ID_LOG_NOTE:
  646. ret = std::vfprintf(stdout, fmt, ap);
  647. break;
  648. case CARLA_URI_MAP_ID_LOG_TRACE:
  649. #ifdef DEBUG
  650. std::fprintf(stdout, "\x1b[30;1m");
  651. ret = std::vfprintf(stdout, fmt, ap);
  652. std::fprintf(stdout, "\x1b[0m");
  653. #endif
  654. break;
  655. case CARLA_URI_MAP_ID_LOG_WARNING:
  656. ret = std::vfprintf(stderr, fmt, ap);
  657. break;
  658. default:
  659. break;
  660. }
  661. return ret;
  662. }
  663. // -------------------------------------------------------------------
  664. // Programs Feature
  665. static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
  666. {
  667. CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
  668. carla_debug("carla_lv2_program_changed(%p, %i)", handle, index);
  669. ((CarlaLv2Client*)handle)->handleProgramChanged(index);
  670. }
  671. // -------------------------------------------------------------------
  672. // State Feature
  673. static char* carla_lv2_state_make_path(LV2_State_Make_Path_Handle handle, const char* path)
  674. {
  675. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  676. CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr);
  677. carla_debug("carla_lv2_state_make_path(%p, \"%s\")", handle, path);
  678. File file;
  679. if (File::isAbsolutePath(path))
  680. file = File(path);
  681. else
  682. file = File::getCurrentWorkingDirectory().getChildFile(path);
  683. file.getParentDirectory().createDirectory();
  684. return strdup(file.getFullPathName().toRawUTF8());
  685. }
  686. static char* carla_lv2_state_map_abstract_path(LV2_State_Map_Path_Handle handle, const char* absolute_path)
  687. {
  688. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  689. CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr);
  690. carla_debug("carla_lv2_state_map_abstract_path(%p, \"%s\")", handle, absolute_path);
  691. // may already be an abstract path
  692. if (! File::isAbsolutePath(absolute_path))
  693. return strdup(absolute_path);
  694. return strdup(File(absolute_path).getRelativePathFrom(File::getCurrentWorkingDirectory()).toRawUTF8());
  695. }
  696. static char* carla_lv2_state_map_absolute_path(LV2_State_Map_Path_Handle handle, const char* abstract_path)
  697. {
  698. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  699. CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr);
  700. carla_debug("carla_lv2_state_map_absolute_path(%p, \"%s\")", handle, abstract_path);
  701. // may already be an absolute path
  702. if (File::isAbsolutePath(abstract_path))
  703. return strdup(abstract_path);
  704. return strdup(File::getCurrentWorkingDirectory().getChildFile(abstract_path).getFullPathName().toRawUTF8());
  705. }
  706. // -------------------------------------------------------------------
  707. // URI-Map Feature
  708. static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
  709. {
  710. carla_debug("carla_lv2_uri_to_id(%p, \"%s\", \"%s\")", data, map, uri);
  711. return carla_lv2_urid_map((LV2_URID_Map_Handle*)data, uri);
  712. // unused
  713. (void)map;
  714. }
  715. // -------------------------------------------------------------------
  716. // URID Feature
  717. static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri)
  718. {
  719. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, CARLA_URI_MAP_ID_NULL);
  720. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', CARLA_URI_MAP_ID_NULL);
  721. carla_debug("carla_lv2_urid_map(%p, \"%s\")", handle, uri);
  722. // Atom types
  723. if (std::strcmp(uri, LV2_ATOM__Blank) == 0)
  724. return CARLA_URI_MAP_ID_ATOM_BLANK;
  725. if (std::strcmp(uri, LV2_ATOM__Bool) == 0)
  726. return CARLA_URI_MAP_ID_ATOM_BOOL;
  727. if (std::strcmp(uri, LV2_ATOM__Chunk) == 0)
  728. return CARLA_URI_MAP_ID_ATOM_CHUNK;
  729. if (std::strcmp(uri, LV2_ATOM__Double) == 0)
  730. return CARLA_URI_MAP_ID_ATOM_DOUBLE;
  731. if (std::strcmp(uri, LV2_ATOM__Event) == 0)
  732. return CARLA_URI_MAP_ID_ATOM_EVENT;
  733. if (std::strcmp(uri, LV2_ATOM__Float) == 0)
  734. return CARLA_URI_MAP_ID_ATOM_FLOAT;
  735. if (std::strcmp(uri, LV2_ATOM__Int) == 0)
  736. return CARLA_URI_MAP_ID_ATOM_INT;
  737. if (std::strcmp(uri, LV2_ATOM__Literal) == 0)
  738. return CARLA_URI_MAP_ID_ATOM_LITERAL;
  739. if (std::strcmp(uri, LV2_ATOM__Long) == 0)
  740. return CARLA_URI_MAP_ID_ATOM_LONG;
  741. if (std::strcmp(uri, LV2_ATOM__Number) == 0)
  742. return CARLA_URI_MAP_ID_ATOM_NUMBER;
  743. if (std::strcmp(uri, LV2_ATOM__Object) == 0)
  744. return CARLA_URI_MAP_ID_ATOM_OBJECT;
  745. if (std::strcmp(uri, LV2_ATOM__Path) == 0)
  746. return CARLA_URI_MAP_ID_ATOM_PATH;
  747. if (std::strcmp(uri, LV2_ATOM__Property) == 0)
  748. return CARLA_URI_MAP_ID_ATOM_PROPERTY;
  749. if (std::strcmp(uri, LV2_ATOM__Resource) == 0)
  750. return CARLA_URI_MAP_ID_ATOM_RESOURCE;
  751. if (std::strcmp(uri, LV2_ATOM__Sequence) == 0)
  752. return CARLA_URI_MAP_ID_ATOM_SEQUENCE;
  753. if (std::strcmp(uri, LV2_ATOM__Sound) == 0)
  754. return CARLA_URI_MAP_ID_ATOM_SOUND;
  755. if (std::strcmp(uri, LV2_ATOM__String) == 0)
  756. return CARLA_URI_MAP_ID_ATOM_STRING;
  757. if (std::strcmp(uri, LV2_ATOM__Tuple) == 0)
  758. return CARLA_URI_MAP_ID_ATOM_TUPLE;
  759. if (std::strcmp(uri, LV2_ATOM__URI) == 0)
  760. return CARLA_URI_MAP_ID_ATOM_URI;
  761. if (std::strcmp(uri, LV2_ATOM__URID) == 0)
  762. return CARLA_URI_MAP_ID_ATOM_URID;
  763. if (std::strcmp(uri, LV2_ATOM__Vector) == 0)
  764. return CARLA_URI_MAP_ID_ATOM_VECTOR;
  765. if (std::strcmp(uri, LV2_ATOM__atomTransfer) == 0)
  766. return CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM;
  767. if (std::strcmp(uri, LV2_ATOM__eventTransfer) == 0)
  768. return CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT;
  769. // BufSize types
  770. if (std::strcmp(uri, LV2_BUF_SIZE__maxBlockLength) == 0)
  771. return CARLA_URI_MAP_ID_BUF_MAX_LENGTH;
  772. if (std::strcmp(uri, LV2_BUF_SIZE__minBlockLength) == 0)
  773. return CARLA_URI_MAP_ID_BUF_MIN_LENGTH;
  774. if (std::strcmp(uri, LV2_BUF_SIZE__sequenceSize) == 0)
  775. return CARLA_URI_MAP_ID_BUF_SEQUENCE_SIZE;
  776. // Log types
  777. if (std::strcmp(uri, LV2_LOG__Error) == 0)
  778. return CARLA_URI_MAP_ID_LOG_ERROR;
  779. if (std::strcmp(uri, LV2_LOG__Note) == 0)
  780. return CARLA_URI_MAP_ID_LOG_NOTE;
  781. if (std::strcmp(uri, LV2_LOG__Trace) == 0)
  782. return CARLA_URI_MAP_ID_LOG_TRACE;
  783. if (std::strcmp(uri, LV2_LOG__Warning) == 0)
  784. return CARLA_URI_MAP_ID_LOG_WARNING;
  785. // Time types
  786. if (std::strcmp(uri, LV2_TIME__Position) == 0)
  787. return CARLA_URI_MAP_ID_TIME_POSITION;
  788. if (std::strcmp(uri, LV2_TIME__bar) == 0)
  789. return CARLA_URI_MAP_ID_TIME_BAR;
  790. if (std::strcmp(uri, LV2_TIME__barBeat) == 0)
  791. return CARLA_URI_MAP_ID_TIME_BAR_BEAT;
  792. if (std::strcmp(uri, LV2_TIME__beat) == 0)
  793. return CARLA_URI_MAP_ID_TIME_BEAT;
  794. if (std::strcmp(uri, LV2_TIME__beatUnit) == 0)
  795. return CARLA_URI_MAP_ID_TIME_BEAT_UNIT;
  796. if (std::strcmp(uri, LV2_TIME__beatsPerBar) == 0)
  797. return CARLA_URI_MAP_ID_TIME_BEATS_PER_BAR;
  798. if (std::strcmp(uri, LV2_TIME__beatsPerMinute) == 0)
  799. return CARLA_URI_MAP_ID_TIME_BEATS_PER_MINUTE;
  800. if (std::strcmp(uri, LV2_TIME__frame) == 0)
  801. return CARLA_URI_MAP_ID_TIME_FRAME;
  802. if (std::strcmp(uri, LV2_TIME__framesPerSecond) == 0)
  803. return CARLA_URI_MAP_ID_TIME_FRAMES_PER_SECOND;
  804. if (std::strcmp(uri, LV2_TIME__speed) == 0)
  805. return CARLA_URI_MAP_ID_TIME_SPEED;
  806. if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
  807. return CARLA_URI_MAP_ID_TIME_TICKS_PER_BEAT;
  808. // Others
  809. if (std::strcmp(uri, LV2_MIDI__MidiEvent) == 0)
  810. return CARLA_URI_MAP_ID_MIDI_EVENT;
  811. if (std::strcmp(uri, LV2_PARAMETERS__sampleRate) == 0)
  812. return CARLA_URI_MAP_ID_PARAM_SAMPLE_RATE;
  813. if (std::strcmp(uri, LV2_UI__windowTitle) == 0)
  814. return CARLA_URI_MAP_ID_UI_WINDOW_TITLE;
  815. // Custom
  816. if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TransientWindowId) == 0)
  817. return CARLA_URI_MAP_ID_CARLA_TRANSIENT_WIN_ID;
  818. if (std::strcmp(uri, URI_CARLA_ATOM_WORKER) == 0)
  819. return CARLA_URI_MAP_ID_CARLA_ATOM_WORKER;
  820. // Custom types
  821. return ((CarlaLv2Client*)handle)->getCustomURID(uri);
  822. }
  823. static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
  824. {
  825. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  826. CARLA_SAFE_ASSERT_RETURN(urid != CARLA_URI_MAP_ID_NULL, nullptr);
  827. carla_debug("carla_lv2_urid_unmap(%p, %i)", handle, urid);
  828. // Atom types
  829. if (urid == CARLA_URI_MAP_ID_ATOM_BLANK)
  830. return LV2_ATOM__Blank;
  831. if (urid == CARLA_URI_MAP_ID_ATOM_BOOL)
  832. return LV2_ATOM__Bool;
  833. if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK)
  834. return LV2_ATOM__Chunk;
  835. if (urid == CARLA_URI_MAP_ID_ATOM_DOUBLE)
  836. return LV2_ATOM__Double;
  837. if (urid == CARLA_URI_MAP_ID_ATOM_EVENT)
  838. return LV2_ATOM__Event;
  839. if (urid == CARLA_URI_MAP_ID_ATOM_FLOAT)
  840. return LV2_ATOM__Float;
  841. if (urid == CARLA_URI_MAP_ID_ATOM_INT)
  842. return LV2_ATOM__Int;
  843. if (urid == CARLA_URI_MAP_ID_ATOM_LITERAL)
  844. return LV2_ATOM__Literal;
  845. if (urid == CARLA_URI_MAP_ID_ATOM_LONG)
  846. return LV2_ATOM__Long;
  847. if (urid == CARLA_URI_MAP_ID_ATOM_NUMBER)
  848. return LV2_ATOM__Number;
  849. if (urid == CARLA_URI_MAP_ID_ATOM_OBJECT)
  850. return LV2_ATOM__Object;
  851. if (urid == CARLA_URI_MAP_ID_ATOM_PATH)
  852. return LV2_ATOM__Path;
  853. if (urid == CARLA_URI_MAP_ID_ATOM_PROPERTY)
  854. return LV2_ATOM__Property;
  855. if (urid == CARLA_URI_MAP_ID_ATOM_RESOURCE)
  856. return LV2_ATOM__Resource;
  857. if (urid == CARLA_URI_MAP_ID_ATOM_SEQUENCE)
  858. return LV2_ATOM__Sequence;
  859. if (urid == CARLA_URI_MAP_ID_ATOM_SOUND)
  860. return LV2_ATOM__Sound;
  861. if (urid == CARLA_URI_MAP_ID_ATOM_STRING)
  862. return LV2_ATOM__String;
  863. if (urid == CARLA_URI_MAP_ID_ATOM_TUPLE)
  864. return LV2_ATOM__Tuple;
  865. if (urid == CARLA_URI_MAP_ID_ATOM_URI)
  866. return LV2_ATOM__URI;
  867. if (urid == CARLA_URI_MAP_ID_ATOM_URID)
  868. return LV2_ATOM__URID;
  869. if (urid == CARLA_URI_MAP_ID_ATOM_VECTOR)
  870. return LV2_ATOM__Vector;
  871. if (urid == CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM)
  872. return LV2_ATOM__atomTransfer;
  873. if (urid == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
  874. return LV2_ATOM__eventTransfer;
  875. // BufSize types
  876. if (urid == CARLA_URI_MAP_ID_BUF_MAX_LENGTH)
  877. return LV2_BUF_SIZE__maxBlockLength;
  878. if (urid == CARLA_URI_MAP_ID_BUF_MIN_LENGTH)
  879. return LV2_BUF_SIZE__minBlockLength;
  880. if (urid == CARLA_URI_MAP_ID_BUF_SEQUENCE_SIZE)
  881. return LV2_BUF_SIZE__sequenceSize;
  882. // Log types
  883. if (urid == CARLA_URI_MAP_ID_LOG_ERROR)
  884. return LV2_LOG__Error;
  885. if (urid == CARLA_URI_MAP_ID_LOG_NOTE)
  886. return LV2_LOG__Note;
  887. if (urid == CARLA_URI_MAP_ID_LOG_TRACE)
  888. return LV2_LOG__Trace;
  889. if (urid == CARLA_URI_MAP_ID_LOG_WARNING)
  890. return LV2_LOG__Warning;
  891. // Time types
  892. if (urid == CARLA_URI_MAP_ID_TIME_POSITION)
  893. return LV2_TIME__Position;
  894. if (urid == CARLA_URI_MAP_ID_TIME_BAR)
  895. return LV2_TIME__bar;
  896. if (urid == CARLA_URI_MAP_ID_TIME_BAR_BEAT)
  897. return LV2_TIME__barBeat;
  898. if (urid == CARLA_URI_MAP_ID_TIME_BEAT)
  899. return LV2_TIME__beat;
  900. if (urid == CARLA_URI_MAP_ID_TIME_BEAT_UNIT)
  901. return LV2_TIME__beatUnit;
  902. if (urid == CARLA_URI_MAP_ID_TIME_BEATS_PER_BAR)
  903. return LV2_TIME__beatsPerBar;
  904. if (urid == CARLA_URI_MAP_ID_TIME_BEATS_PER_MINUTE)
  905. return LV2_TIME__beatsPerMinute;
  906. if (urid == CARLA_URI_MAP_ID_TIME_FRAME)
  907. return LV2_TIME__frame;
  908. if (urid == CARLA_URI_MAP_ID_TIME_FRAMES_PER_SECOND)
  909. return LV2_TIME__framesPerSecond;
  910. if (urid == CARLA_URI_MAP_ID_TIME_SPEED)
  911. return LV2_TIME__speed;
  912. if (urid == CARLA_URI_MAP_ID_TIME_TICKS_PER_BEAT)
  913. return LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat;
  914. // Others
  915. if (urid == CARLA_URI_MAP_ID_MIDI_EVENT)
  916. return LV2_MIDI__MidiEvent;
  917. if (urid == CARLA_URI_MAP_ID_PARAM_SAMPLE_RATE)
  918. return LV2_PARAMETERS__sampleRate;
  919. if (urid == CARLA_URI_MAP_ID_UI_WINDOW_TITLE)
  920. return LV2_UI__windowTitle;
  921. // Custom
  922. if (urid == CARLA_URI_MAP_ID_CARLA_ATOM_WORKER)
  923. return URI_CARLA_ATOM_WORKER;
  924. if (urid == CARLA_URI_MAP_ID_CARLA_TRANSIENT_WIN_ID)
  925. return LV2_KXSTUDIO_PROPERTIES__TransientWindowId;
  926. // Custom types
  927. return ((CarlaLv2Client*)handle)->getCustomURIDString(urid);
  928. }
  929. // -------------------------------------------------------------------
  930. // UI Port-Map Feature
  931. static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
  932. {
  933. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_INVALID_PORT_INDEX);
  934. carla_debug("carla_lv2_ui_port_map(%p, \"%s\")", handle, symbol);
  935. return ((CarlaLv2Client*)handle)->handleUiPortMap(symbol);
  936. }
  937. // -------------------------------------------------------------------
  938. // UI Resize Feature
  939. static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
  940. {
  941. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1);
  942. carla_debug("carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);
  943. return ((CarlaLv2Client*)handle)->handleUiResize(width, height);
  944. }
  945. // -------------------------------------------------------------------
  946. // UI Extension
  947. static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
  948. {
  949. CARLA_SAFE_ASSERT_RETURN(controller != nullptr,);
  950. carla_debug("carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer);
  951. ((CarlaLv2Client*)controller)->handleUiWrite(port_index, buffer_size, format, buffer);
  952. }
  953. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaLv2Client)
  954. };
  955. // -----------------------------------------------------------------------
  956. CARLA_BRIDGE_END_NAMESPACE
  957. // -----------------------------------------------------------------------
  958. int main(int argc, const char* argv[])
  959. {
  960. CARLA_BRIDGE_USE_NAMESPACE
  961. if (argc < 3)
  962. {
  963. carla_stderr("usage: %s <plugin-uri> <ui-uri>", argv[0]);
  964. return 1;
  965. }
  966. const bool testingModeOnly = (argc != 7);
  967. // try to get sampleRate value
  968. if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
  969. gSampleRate = std::atof(sampleRateStr);
  970. // Init LV2 client
  971. CarlaLv2Client client;
  972. // Load UI
  973. int ret;
  974. if (client.init(argc, argv))
  975. {
  976. client.exec(testingModeOnly);
  977. ret = 0;
  978. }
  979. else
  980. {
  981. ret = 1;
  982. }
  983. return ret;
  984. }
  985. // -----------------------------------------------------------------------