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.

1221 lines
46KB

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