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.

1550 lines
54KB

  1. /*
  2. * Carla Bridge UI
  3. * Copyright (C) 2011-2019 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 "CarlaBridgeFormat.hpp"
  18. #include "CarlaBridgeToolkit.hpp"
  19. #include "CarlaLibUtils.hpp"
  20. #include "CarlaLv2Utils.hpp"
  21. #include "CarlaMIDI.h"
  22. #include "LinkedList.hpp"
  23. #include "water/files/File.h"
  24. #ifdef CARLA_OS_MAC
  25. # include "CarlaMacUtils.hpp"
  26. #endif
  27. #include <string>
  28. #include <vector>
  29. #define URI_CARLA_ATOM_WORKER_IN "http://kxstudio.sf.net/ns/carla/atomWorkerIn"
  30. #define URI_CARLA_ATOM_WORKER_RESP "http://kxstudio.sf.net/ns/carla/atomWorkerResp"
  31. using water::File;
  32. CARLA_BRIDGE_UI_START_NAMESPACE
  33. // --------------------------------------------------------------------------------------------------------------------
  34. static double gInitialSampleRate = 44100.0;
  35. static const char* const kNullWindowTitle = "TestUI";
  36. static const uint32_t kNullWindowTitleSize = 6;
  37. static const char* const kUnmapFallback = "urn:null";
  38. // LV2 URI Map Ids
  39. enum CarlaLv2URIDs {
  40. kUridNull = 0,
  41. kUridAtomBlank,
  42. kUridAtomBool,
  43. kUridAtomChunk,
  44. kUridAtomDouble,
  45. kUridAtomEvent,
  46. kUridAtomFloat,
  47. kUridAtomInt,
  48. kUridAtomLiteral,
  49. kUridAtomLong,
  50. kUridAtomNumber,
  51. kUridAtomObject,
  52. kUridAtomPath,
  53. kUridAtomProperty,
  54. kUridAtomResource,
  55. kUridAtomSequence,
  56. kUridAtomSound,
  57. kUridAtomString,
  58. kUridAtomTuple,
  59. kUridAtomURI,
  60. kUridAtomURID,
  61. kUridAtomVector,
  62. kUridAtomTransferAtom,
  63. kUridAtomTransferEvent,
  64. kUridBufMaxLength,
  65. kUridBufMinLength,
  66. kUridBufNominalLength,
  67. kUridBufSequenceSize,
  68. kUridLogError,
  69. kUridLogNote,
  70. kUridLogTrace,
  71. kUridLogWarning,
  72. kUridPatchSet,
  73. kUridPatchProperty,
  74. kUridPatchValue,
  75. // time base type
  76. kUridTimePosition,
  77. // time values
  78. kUridTimeBar,
  79. kUridTimeBarBeat,
  80. kUridTimeBeat,
  81. kUridTimeBeatUnit,
  82. kUridTimeBeatsPerBar,
  83. kUridTimeBeatsPerMinute,
  84. kUridTimeFrame,
  85. kUridTimeFramesPerSecond,
  86. kUridTimeSpeed,
  87. kUridTimeTicksPerBeat,
  88. kUridMidiEvent,
  89. kUridParamSampleRate,
  90. // ui stuff
  91. kUridBackgroundColor,
  92. kUridForegroundColor,
  93. kUridScaleFactor,
  94. kUridWindowTitle,
  95. // custom carla props
  96. kUridCarlaAtomWorkerIn,
  97. kUridCarlaAtomWorkerResp,
  98. kUridCarlaTransientWindowId,
  99. // count
  100. kUridCount
  101. };
  102. // LV2 Feature Ids
  103. enum CarlaLv2Features {
  104. // DSP features
  105. kFeatureIdLogs = 0,
  106. kFeatureIdOptions,
  107. kFeatureIdPrograms,
  108. kFeatureIdStateFreePath,
  109. kFeatureIdStateMakePath,
  110. kFeatureIdStateMapPath,
  111. kFeatureIdUriMap,
  112. kFeatureIdUridMap,
  113. kFeatureIdUridUnmap,
  114. kFeatureIdUiIdleInterface,
  115. kFeatureIdUiFixedSize,
  116. kFeatureIdUiMakeResident,
  117. kFeatureIdUiMakeResident2,
  118. kFeatureIdUiNoUserResize,
  119. kFeatureIdUiParent,
  120. kFeatureIdUiPortMap,
  121. kFeatureIdUiPortSubscribe,
  122. kFeatureIdUiRequestValue,
  123. kFeatureIdUiResize,
  124. kFeatureIdUiTouch,
  125. kFeatureCount
  126. };
  127. // --------------------------------------------------------------------------------------------------------------------
  128. struct Lv2PluginOptions {
  129. enum OptIndex {
  130. SampleRate,
  131. TransientWinId,
  132. BackgroundColor,
  133. ForegroundColor,
  134. ScaleFactor,
  135. WindowTitle,
  136. Null,
  137. Count
  138. };
  139. float sampleRate;
  140. int64_t transientWinId;
  141. uint32_t bgColor;
  142. uint32_t fgColor;
  143. float uiScale;
  144. LV2_Options_Option opts[Count];
  145. Lv2PluginOptions() noexcept
  146. : sampleRate(static_cast<float>(gInitialSampleRate)),
  147. transientWinId(0),
  148. bgColor(0x000000ff),
  149. fgColor(0xffffffff),
  150. uiScale(1.0f)
  151. {
  152. LV2_Options_Option& optSampleRate(opts[SampleRate]);
  153. optSampleRate.context = LV2_OPTIONS_INSTANCE;
  154. optSampleRate.subject = 0;
  155. optSampleRate.key = kUridParamSampleRate;
  156. optSampleRate.size = sizeof(float);
  157. optSampleRate.type = kUridAtomFloat;
  158. optSampleRate.value = &sampleRate;
  159. LV2_Options_Option& optBackgroundColor(opts[BackgroundColor]);
  160. optBackgroundColor.context = LV2_OPTIONS_INSTANCE;
  161. optBackgroundColor.subject = 0;
  162. optBackgroundColor.key = kUridBackgroundColor;
  163. optBackgroundColor.size = sizeof(int32_t);
  164. optBackgroundColor.type = kUridAtomInt;
  165. optBackgroundColor.value = &bgColor;
  166. LV2_Options_Option& optForegroundColor(opts[ForegroundColor]);
  167. optForegroundColor.context = LV2_OPTIONS_INSTANCE;
  168. optForegroundColor.subject = 0;
  169. optForegroundColor.key = kUridForegroundColor;
  170. optForegroundColor.size = sizeof(int32_t);
  171. optForegroundColor.type = kUridAtomInt;
  172. optForegroundColor.value = &fgColor;
  173. LV2_Options_Option& optScaleFactor(opts[ScaleFactor]);
  174. optScaleFactor.context = LV2_OPTIONS_INSTANCE;
  175. optScaleFactor.subject = 0;
  176. optScaleFactor.key = kUridScaleFactor;
  177. optScaleFactor.size = sizeof(float);
  178. optScaleFactor.type = kUridAtomFloat;
  179. optScaleFactor.value = &uiScale;
  180. LV2_Options_Option& optTransientWinId(opts[TransientWinId]);
  181. optTransientWinId.context = LV2_OPTIONS_INSTANCE;
  182. optTransientWinId.subject = 0;
  183. optTransientWinId.key = kUridCarlaTransientWindowId;
  184. optTransientWinId.size = sizeof(int64_t);
  185. optTransientWinId.type = kUridAtomLong;
  186. optTransientWinId.value = &transientWinId;
  187. LV2_Options_Option& optWindowTitle(opts[WindowTitle]);
  188. optWindowTitle.context = LV2_OPTIONS_INSTANCE;
  189. optWindowTitle.subject = 0;
  190. optWindowTitle.key = kUridWindowTitle;
  191. optWindowTitle.size = kNullWindowTitleSize;
  192. optWindowTitle.type = kUridAtomString;
  193. optWindowTitle.value = kNullWindowTitle;
  194. LV2_Options_Option& optNull(opts[Null]);
  195. optNull.context = LV2_OPTIONS_INSTANCE;
  196. optNull.subject = 0;
  197. optNull.key = kUridNull;
  198. optNull.size = 0;
  199. optNull.type = kUridNull;
  200. optNull.value = nullptr;
  201. }
  202. };
  203. // -------------------------------------------------------------------------------------------------------------------
  204. static void initAtomForge(LV2_Atom_Forge& atomForge) noexcept
  205. {
  206. carla_zeroStruct(atomForge);
  207. atomForge.Bool = kUridAtomBool;
  208. atomForge.Chunk = kUridAtomChunk;
  209. atomForge.Double = kUridAtomDouble;
  210. atomForge.Float = kUridAtomFloat;
  211. atomForge.Int = kUridAtomInt;
  212. atomForge.Literal = kUridAtomLiteral;
  213. atomForge.Long = kUridAtomLong;
  214. atomForge.Object = kUridAtomObject;
  215. atomForge.Path = kUridAtomPath;
  216. atomForge.Property = kUridAtomProperty;
  217. atomForge.Sequence = kUridAtomSequence;
  218. atomForge.String = kUridAtomString;
  219. atomForge.Tuple = kUridAtomTuple;
  220. atomForge.URI = kUridAtomURI;
  221. atomForge.URID = kUridAtomURID;
  222. atomForge.Vector = kUridAtomVector;
  223. #if defined(__clang__)
  224. # pragma clang diagnostic push
  225. # pragma clang diagnostic ignored "-Wdeprecated-declarations"
  226. #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  227. # pragma GCC diagnostic push
  228. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  229. #endif
  230. atomForge.Blank = kUridAtomBlank;
  231. atomForge.Resource = kUridAtomResource;
  232. #if defined(__clang__)
  233. # pragma clang diagnostic pop
  234. #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  235. # pragma GCC diagnostic pop
  236. #endif
  237. }
  238. // --------------------------------------------------------------------------------------------------------------------
  239. class CarlaLv2Client : public CarlaBridgeFormat
  240. {
  241. public:
  242. CarlaLv2Client()
  243. : CarlaBridgeFormat(),
  244. fHandle(nullptr),
  245. fWidget(nullptr),
  246. fDescriptor(nullptr),
  247. fRdfDescriptor(nullptr),
  248. fRdfUiDescriptor(nullptr),
  249. fControlDesignatedPort(0),
  250. fLv2Options(),
  251. fUiOptions(),
  252. fCustomURIDs(kUridCount, std::string("urn:null")),
  253. fExt()
  254. {
  255. CARLA_SAFE_ASSERT(fCustomURIDs.size() == kUridCount);
  256. carla_zeroPointers(fFeatures, kFeatureCount+1);
  257. // ------------------------------------------------------------------------------------------------------------
  258. // initialize features (part 1)
  259. LV2_Log_Log* const logFt = new LV2_Log_Log;
  260. logFt->handle = this;
  261. logFt->printf = carla_lv2_log_printf;
  262. logFt->vprintf = carla_lv2_log_vprintf;
  263. LV2_State_Free_Path* const stateFreePathFt = new LV2_State_Free_Path;
  264. stateFreePathFt->handle = this;
  265. stateFreePathFt->free_path = carla_lv2_state_free_path;
  266. LV2_State_Make_Path* const stateMakePathFt = new LV2_State_Make_Path;
  267. stateMakePathFt->handle = this;
  268. stateMakePathFt->path = carla_lv2_state_make_path_tmp;
  269. LV2_State_Map_Path* const stateMapPathFt = new LV2_State_Map_Path;
  270. stateMapPathFt->handle = this;
  271. stateMapPathFt->abstract_path = carla_lv2_state_map_abstract_path_tmp;
  272. stateMapPathFt->absolute_path = carla_lv2_state_map_absolute_path_tmp;
  273. LV2_Programs_Host* const programsFt = new LV2_Programs_Host;
  274. programsFt->handle = this;
  275. programsFt->program_changed = carla_lv2_program_changed;
  276. LV2_URI_Map_Feature* const uriMapFt = new LV2_URI_Map_Feature;
  277. uriMapFt->callback_data = this;
  278. uriMapFt->uri_to_id = carla_lv2_uri_to_id;
  279. LV2_URID_Map* const uridMapFt = new LV2_URID_Map;
  280. uridMapFt->handle = this;
  281. uridMapFt->map = carla_lv2_urid_map;
  282. LV2_URID_Unmap* const uridUnmapFt = new LV2_URID_Unmap;
  283. uridUnmapFt->handle = this;
  284. uridUnmapFt->unmap = carla_lv2_urid_unmap;
  285. LV2UI_Port_Map* const uiPortMapFt = new LV2UI_Port_Map;
  286. uiPortMapFt->handle = this;
  287. uiPortMapFt->port_index = carla_lv2_ui_port_map;
  288. LV2UI_Request_Value* const uiRequestValueFt = new LV2UI_Request_Value;
  289. uiRequestValueFt->handle = this;
  290. uiRequestValueFt->request = carla_lv2_ui_request_value;
  291. LV2UI_Resize* const uiResizeFt = new LV2UI_Resize;
  292. uiResizeFt->handle = this;
  293. uiResizeFt->ui_resize = carla_lv2_ui_resize;
  294. // ------------------------------------------------------------------------------------------------------------
  295. // initialize features (part 2)
  296. for (uint32_t i=0; i < kFeatureCount; ++i)
  297. fFeatures[i] = new LV2_Feature;
  298. fFeatures[kFeatureIdLogs]->URI = LV2_LOG__log;
  299. fFeatures[kFeatureIdLogs]->data = logFt;
  300. fFeatures[kFeatureIdOptions]->URI = LV2_OPTIONS__options;
  301. fFeatures[kFeatureIdOptions]->data = fLv2Options.opts;
  302. fFeatures[kFeatureIdPrograms]->URI = LV2_PROGRAMS__Host;
  303. fFeatures[kFeatureIdPrograms]->data = programsFt;
  304. fFeatures[kFeatureIdStateFreePath]->URI = LV2_STATE__freePath;
  305. fFeatures[kFeatureIdStateFreePath]->data = stateFreePathFt;
  306. fFeatures[kFeatureIdStateMakePath]->URI = LV2_STATE__makePath;
  307. fFeatures[kFeatureIdStateMakePath]->data = stateMakePathFt;
  308. fFeatures[kFeatureIdStateMapPath]->URI = LV2_STATE__mapPath;
  309. fFeatures[kFeatureIdStateMapPath]->data = stateMapPathFt;
  310. fFeatures[kFeatureIdUriMap]->URI = LV2_URI_MAP_URI;
  311. fFeatures[kFeatureIdUriMap]->data = uriMapFt;
  312. fFeatures[kFeatureIdUridMap]->URI = LV2_URID__map;
  313. fFeatures[kFeatureIdUridMap]->data = uridMapFt;
  314. fFeatures[kFeatureIdUridUnmap]->URI = LV2_URID__unmap;
  315. fFeatures[kFeatureIdUridUnmap]->data = uridUnmapFt;
  316. fFeatures[kFeatureIdUiIdleInterface]->URI = LV2_UI__idleInterface;
  317. fFeatures[kFeatureIdUiIdleInterface]->data = nullptr;
  318. fFeatures[kFeatureIdUiFixedSize]->URI = LV2_UI__fixedSize;
  319. fFeatures[kFeatureIdUiFixedSize]->data = nullptr;
  320. fFeatures[kFeatureIdUiMakeResident]->URI = LV2_UI__makeResident;
  321. fFeatures[kFeatureIdUiMakeResident]->data = nullptr;
  322. fFeatures[kFeatureIdUiMakeResident2]->URI = LV2_UI__makeSONameResident;
  323. fFeatures[kFeatureIdUiMakeResident2]->data = nullptr;
  324. fFeatures[kFeatureIdUiNoUserResize]->URI = LV2_UI__noUserResize;
  325. fFeatures[kFeatureIdUiNoUserResize]->data = nullptr;
  326. fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent;
  327. fFeatures[kFeatureIdUiParent]->data = nullptr;
  328. fFeatures[kFeatureIdUiPortMap]->URI = LV2_UI__portMap;
  329. fFeatures[kFeatureIdUiPortMap]->data = uiPortMapFt;
  330. fFeatures[kFeatureIdUiPortSubscribe]->URI = LV2_UI__portSubscribe;
  331. fFeatures[kFeatureIdUiPortSubscribe]->data = nullptr;
  332. fFeatures[kFeatureIdUiRequestValue]->URI = LV2_UI__requestValue;
  333. fFeatures[kFeatureIdUiRequestValue]->data = uiRequestValueFt;
  334. fFeatures[kFeatureIdUiResize]->URI = LV2_UI__resize;
  335. fFeatures[kFeatureIdUiResize]->data = uiResizeFt;
  336. fFeatures[kFeatureIdUiTouch]->URI = LV2_UI__touch;
  337. fFeatures[kFeatureIdUiTouch]->data = nullptr;
  338. }
  339. ~CarlaLv2Client() override
  340. {
  341. if (fHandle != nullptr && fDescriptor != nullptr && fDescriptor->cleanup != nullptr)
  342. {
  343. fDescriptor->cleanup(fHandle);
  344. fHandle = nullptr;
  345. }
  346. if (fRdfDescriptor != nullptr)
  347. {
  348. delete fRdfDescriptor;
  349. fRdfDescriptor = nullptr;
  350. }
  351. fRdfUiDescriptor = nullptr;
  352. delete (LV2_Log_Log*)fFeatures[kFeatureIdLogs]->data;
  353. delete (LV2_State_Free_Path*)fFeatures[kFeatureIdStateFreePath]->data;
  354. delete (LV2_State_Make_Path*)fFeatures[kFeatureIdStateMakePath]->data;
  355. delete (LV2_State_Map_Path*)fFeatures[kFeatureIdStateMapPath]->data;
  356. delete (LV2_Programs_Host*)fFeatures[kFeatureIdPrograms]->data;
  357. delete (LV2_URI_Map_Feature*)fFeatures[kFeatureIdUriMap]->data;
  358. delete (LV2_URID_Map*)fFeatures[kFeatureIdUridMap]->data;
  359. delete (LV2_URID_Unmap*)fFeatures[kFeatureIdUridUnmap]->data;
  360. delete (LV2UI_Port_Map*)fFeatures[kFeatureIdUiPortMap]->data;
  361. delete (LV2UI_Request_Value*)fFeatures[kFeatureIdUiRequestValue]->data;
  362. delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data;
  363. for (uint32_t i=0; i < kFeatureCount; ++i)
  364. {
  365. if (fFeatures[i] != nullptr)
  366. {
  367. delete fFeatures[i];
  368. fFeatures[i] = nullptr;
  369. }
  370. }
  371. }
  372. // ----------------------------------------------------------------------------------------------------------------
  373. // UI initialization
  374. bool init(const int argc, const char* argv[]) override
  375. {
  376. const char* pluginURI = argv[1];
  377. const char* uiURI = argc > 2 ? argv[2] : nullptr;
  378. // ------------------------------------------------------------------------------------------------------------
  379. // load plugin
  380. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  381. lv2World.initIfNeeded(std::getenv("LV2_PATH"));
  382. #if 0
  383. Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, uiBundle));
  384. CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(), false);
  385. CarlaString sBundle(bundleNode.as_uri());
  386. if (! sBundle.endsWith("/"))
  387. sBundle += "/";
  388. lv2World.load_bundle(sBundle);
  389. #endif
  390. // ------------------------------------------------------------------------------------------------------------
  391. // get plugin from lv2_rdf (lilv)
  392. fRdfDescriptor = lv2_rdf_new(pluginURI, false);
  393. CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr, false);
  394. // ------------------------------------------------------------------------------------------------------------
  395. // find requested UI
  396. if (uiURI == nullptr)
  397. {
  398. CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor->UICount > 0, false);
  399. fRdfUiDescriptor = &fRdfDescriptor->UIs[0];
  400. uiURI = fRdfUiDescriptor->URI;
  401. }
  402. else
  403. {
  404. for (uint32_t i=0; i < fRdfDescriptor->UICount; ++i)
  405. {
  406. if (std::strcmp(fRdfDescriptor->UIs[i].URI, uiURI) == 0)
  407. {
  408. fRdfUiDescriptor = &fRdfDescriptor->UIs[i];
  409. break;
  410. }
  411. }
  412. }
  413. CARLA_SAFE_ASSERT_RETURN(fRdfUiDescriptor != nullptr, false);
  414. // ------------------------------------------------------------------------------------------------------------
  415. // check if not resizable
  416. for (uint32_t i=0; i < fRdfUiDescriptor->FeatureCount; ++i)
  417. {
  418. if (std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__fixedSize ) == 0 ||
  419. std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__noUserResize) == 0)
  420. {
  421. fUiOptions.isResizable = false;
  422. break;
  423. }
  424. }
  425. // ------------------------------------------------------------------------------------------------------------
  426. // init UI
  427. if (! CarlaBridgeFormat::init(argc, argv))
  428. return false;
  429. // ------------------------------------------------------------------------------------------------------------
  430. // open DLL
  431. #ifdef CARLA_OS_MAC
  432. // Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
  433. CarlaBackend::removeFileFromQuarantine(fRdfUiDescriptor->Binary);
  434. #endif
  435. if (! libOpen(fRdfUiDescriptor->Binary))
  436. {
  437. carla_stderr("Failed to load UI binary, error was:\n%s", libError());
  438. return false;
  439. }
  440. // ------------------------------------------------------------------------------------------------------------
  441. // get DLL main entry
  442. const LV2UI_DescriptorFunction ui_descFn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor");
  443. if (ui_descFn == nullptr)
  444. return false;
  445. // ------------------------------------------------------------------------------------------------------------
  446. // get descriptor that matches URI
  447. for (uint32_t i=0; (fDescriptor = ui_descFn(i++)) != nullptr;)
  448. {
  449. if (std::strcmp(fDescriptor->URI, uiURI) == 0)
  450. break;
  451. }
  452. if (fDescriptor == nullptr)
  453. {
  454. carla_stderr("Failed to find UI descriptor");
  455. return false;
  456. }
  457. // ------------------------------------------------------------------------------------------------------------
  458. // initialize UI
  459. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  460. fFeatures[kFeatureIdUiParent]->data = fToolkit->getContainerId();
  461. #endif
  462. fHandle = fDescriptor->instantiate(fDescriptor, fRdfDescriptor->URI, fRdfUiDescriptor->Bundle,
  463. carla_lv2_ui_write_function, this, &fWidget, fFeatures);
  464. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  465. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  466. if (fWidget != nullptr)
  467. fToolkit->setChildWindow(fWidget);
  468. #endif
  469. // ------------------------------------------------------------------------------------------------------------
  470. // check for known extensions
  471. if (fDescriptor->extension_data != nullptr)
  472. {
  473. fExt.options = (const LV2_Options_Interface*)fDescriptor->extension_data(LV2_OPTIONS__interface);
  474. fExt.programs = (const LV2_Programs_UI_Interface*)fDescriptor->extension_data(LV2_PROGRAMS__UIInterface);
  475. fExt.idle = (const LV2UI_Idle_Interface*)fDescriptor->extension_data(LV2_UI__idleInterface);
  476. fExt.resize = (const LV2UI_Resize*)fDescriptor->extension_data(LV2_UI__resize);
  477. // check if invalid
  478. if (fExt.programs != nullptr && fExt.programs->select_program == nullptr)
  479. fExt.programs = nullptr;
  480. if (fExt.idle != nullptr && fExt.idle->idle == nullptr)
  481. fExt.idle = nullptr;
  482. if (fExt.resize != nullptr && fExt.resize->ui_resize == nullptr)
  483. fExt.resize = nullptr;
  484. }
  485. for (uint32_t i=0; i<fRdfDescriptor->PortCount; ++i)
  486. {
  487. if (LV2_IS_PORT_DESIGNATION_CONTROL(fRdfDescriptor->Ports[i].Designation))
  488. {
  489. fControlDesignatedPort = i;
  490. break;
  491. }
  492. }
  493. return true;
  494. }
  495. void idleUI() override
  496. {
  497. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  498. if (fHandle != nullptr && fExt.idle != nullptr && fExt.idle->idle(fHandle) != 0)
  499. {
  500. if (isPipeRunning() && ! fQuitReceived)
  501. writeExitingMessageAndWait();
  502. }
  503. #endif
  504. }
  505. // ----------------------------------------------------------------------------------------------------------------
  506. // UI management
  507. void* getWidget() const noexcept override
  508. {
  509. return fWidget;
  510. }
  511. const Options& getOptions() const noexcept override
  512. {
  513. return fUiOptions;
  514. }
  515. // ----------------------------------------------------------------------------------------------------------------
  516. // DSP Callbacks
  517. void dspParameterChanged(const uint32_t index, const float value) override
  518. {
  519. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  520. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  521. if (fDescriptor->port_event == nullptr)
  522. return;
  523. fDescriptor->port_event(fHandle, index, sizeof(float), kUridNull, &value);
  524. }
  525. void dspParameterChanged(const char* const uri, const float value) override
  526. {
  527. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  528. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  529. if (fDescriptor->port_event == nullptr)
  530. return;
  531. uint32_t parameterId = UINT32_MAX;
  532. for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
  533. {
  534. const LV2_RDF_Parameter& rdfParam(fRdfDescriptor->Parameters[i]);
  535. if (std::strcmp(rdfParam.URI, uri) == 0)
  536. {
  537. parameterId = i;
  538. break;
  539. }
  540. }
  541. if (parameterId == UINT32_MAX)
  542. return;
  543. uint8_t atomBuf[256];
  544. LV2_Atom_Forge atomForge;
  545. initAtomForge(atomForge);
  546. lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
  547. LV2_Atom_Forge_Frame forgeFrame;
  548. lv2_atom_forge_object(&atomForge, &forgeFrame, kUridNull, kUridPatchSet);
  549. lv2_atom_forge_key(&atomForge, kUridPatchProperty);
  550. lv2_atom_forge_urid(&atomForge, getCustomURID(uri));
  551. lv2_atom_forge_key(&atomForge, kUridPatchValue);
  552. switch (fRdfDescriptor->Parameters[parameterId].Type)
  553. {
  554. case LV2_PARAMETER_BOOL:
  555. lv2_atom_forge_bool(&atomForge, value > 0.5f);
  556. break;
  557. case LV2_PARAMETER_INT:
  558. lv2_atom_forge_int(&atomForge, static_cast<int32_t>(value + 0.5f));
  559. break;
  560. case LV2_PARAMETER_LONG:
  561. lv2_atom_forge_long(&atomForge, static_cast<int64_t>(value + 0.5f));
  562. break;
  563. case LV2_PARAMETER_FLOAT:
  564. lv2_atom_forge_float(&atomForge, value);
  565. break;
  566. case LV2_PARAMETER_DOUBLE:
  567. lv2_atom_forge_double(&atomForge, value);
  568. break;
  569. default:
  570. carla_stderr2("dspParameterChanged called for invalid parameter, abort!");
  571. return;
  572. }
  573. lv2_atom_forge_pop(&atomForge, &forgeFrame);
  574. LV2_Atom* const atom((LV2_Atom*)atomBuf);
  575. CARLA_SAFE_ASSERT(atom->size < sizeof(atomBuf));
  576. fDescriptor->port_event(fHandle,
  577. fControlDesignatedPort,
  578. lv2_atom_total_size(atom),
  579. kUridAtomTransferEvent,
  580. atom);
  581. }
  582. void dspProgramChanged(const uint32_t index) override
  583. {
  584. carla_stderr2("dspProgramChanged(%i) - not handled", index);
  585. }
  586. void dspMidiProgramChanged(const uint32_t bank, const uint32_t program) override
  587. {
  588. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  589. if (fExt.programs == nullptr)
  590. return;
  591. fExt.programs->select_program(fHandle, bank, program);
  592. }
  593. void dspStateChanged(const char* const, const char* const) override
  594. {
  595. }
  596. void dspNoteReceived(const bool onOff, const uint8_t channel, const uint8_t note, const uint8_t velocity) override
  597. {
  598. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
  599. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  600. if (fDescriptor->port_event == nullptr)
  601. return;
  602. LV2_Atom_MidiEvent midiEv;
  603. midiEv.atom.type = kUridMidiEvent;
  604. midiEv.atom.size = 3;
  605. midiEv.data[0] = uint8_t((onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (channel & MIDI_CHANNEL_BIT));
  606. midiEv.data[1] = note;
  607. midiEv.data[2] = velocity;
  608. fDescriptor->port_event(fHandle, fControlDesignatedPort, lv2_atom_total_size(midiEv), kUridAtomTransferEvent, &midiEv);
  609. }
  610. void dspAtomReceived(const uint32_t portIndex, const LV2_Atom* const atom) override
  611. {
  612. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  613. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  614. CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
  615. if (fDescriptor->port_event == nullptr)
  616. return;
  617. fDescriptor->port_event(fHandle, portIndex, lv2_atom_total_size(atom), kUridAtomTransferEvent, atom);
  618. }
  619. void dspURIDReceived(const LV2_URID urid, const char* const uri) override
  620. {
  621. CARLA_SAFE_ASSERT_RETURN(urid == fCustomURIDs.size(),);
  622. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0',);
  623. fCustomURIDs.push_back(uri);
  624. }
  625. void uiOptionsChanged(const BridgeFormatOptions& opts) override
  626. {
  627. carla_debug("CarlaLv2Client::uiOptionsChanged()");
  628. // ------------------------------------------------------------------------------------------------------------
  629. // sample rate
  630. const float sampleRatef = static_cast<float>(opts.sampleRate);
  631. if (carla_isNotEqual(fLv2Options.sampleRate, sampleRatef))
  632. {
  633. fLv2Options.sampleRate = sampleRatef;
  634. if (fExt.options != nullptr && fExt.options->set != nullptr)
  635. {
  636. LV2_Options_Option options[2];
  637. carla_zeroStructs(options, 2);
  638. LV2_Options_Option& optSampleRate(options[0]);
  639. optSampleRate.context = LV2_OPTIONS_INSTANCE;
  640. optSampleRate.subject = 0;
  641. optSampleRate.key = kUridParamSampleRate;
  642. optSampleRate.size = sizeof(float);
  643. optSampleRate.type = kUridAtomFloat;
  644. optSampleRate.value = &fLv2Options.sampleRate;
  645. fExt.options->set(fHandle, options);
  646. }
  647. }
  648. // ------------------------------------------------------------------------------------------------------------
  649. // ui colors and scale
  650. fLv2Options.bgColor = opts.bgColor;
  651. fLv2Options.fgColor = opts.fgColor;
  652. fLv2Options.uiScale = opts.uiScale;
  653. // ------------------------------------------------------------------------------------------------------------
  654. // window title
  655. if (opts.windowTitle != nullptr)
  656. fUiOptions.windowTitle = opts.windowTitle;
  657. else
  658. fUiOptions.windowTitle.clear();
  659. fLv2Options.opts[Lv2PluginOptions::WindowTitle].size = static_cast<uint32_t>(fUiOptions.windowTitle.length());
  660. fLv2Options.opts[Lv2PluginOptions::WindowTitle].value = fUiOptions.windowTitle.buffer();
  661. // ------------------------------------------------------------------------------------------------------------
  662. // transient win id
  663. fLv2Options.transientWinId = static_cast<int64_t>(opts.transientWindowId);
  664. fUiOptions.transientWindowId = opts.transientWindowId;
  665. // ------------------------------------------------------------------------------------------------------------
  666. // other
  667. fUiOptions.useTheme = opts.useTheme;
  668. fUiOptions.useThemeColors = opts.useThemeColors;
  669. }
  670. void uiResized(const uint width, const uint height) override
  671. {
  672. if (fHandle != nullptr && fExt.resize != nullptr)
  673. fExt.resize->ui_resize(fHandle, static_cast<int>(width), static_cast<int>(height));
  674. }
  675. // ----------------------------------------------------------------------------------------------------------------
  676. LV2_URID getCustomURID(const char* const uri)
  677. {
  678. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
  679. carla_debug("CarlaLv2Client::getCustomURID(\"%s\")", uri);
  680. const std::string s_uri(uri);
  681. const std::ptrdiff_t s_pos(std::find(fCustomURIDs.begin(), fCustomURIDs.end(), s_uri) - fCustomURIDs.begin());
  682. if (s_pos <= 0 || s_pos >= INT32_MAX)
  683. return kUridNull;
  684. const LV2_URID urid = static_cast<LV2_URID>(s_pos);
  685. const LV2_URID uriCount = static_cast<LV2_URID>(fCustomURIDs.size());
  686. if (urid < uriCount)
  687. return urid;
  688. CARLA_SAFE_ASSERT(urid == uriCount);
  689. fCustomURIDs.push_back(uri);
  690. if (isPipeRunning())
  691. writeLv2UridMessage(urid, uri);
  692. return urid;
  693. }
  694. const char* getCustomURIDString(const LV2_URID urid) const noexcept
  695. {
  696. CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, kUnmapFallback);
  697. CARLA_SAFE_ASSERT_RETURN(urid < fCustomURIDs.size(), kUnmapFallback);
  698. carla_debug("CarlaLv2Client::getCustomURIDString(%i)", urid);
  699. return fCustomURIDs[urid].c_str();
  700. }
  701. // ----------------------------------------------------------------------------------------------------------------
  702. void handleProgramChanged(const int32_t index)
  703. {
  704. if (isPipeRunning())
  705. writeReloadProgramsMessage(index);
  706. }
  707. uint32_t handleUiPortMap(const char* const symbol)
  708. {
  709. CARLA_SAFE_ASSERT_RETURN(symbol != nullptr && symbol[0] != '\0', LV2UI_INVALID_PORT_INDEX);
  710. carla_debug("CarlaLv2Client::handleUiPortMap(\"%s\")", symbol);
  711. for (uint32_t i=0; i < fRdfDescriptor->PortCount; ++i)
  712. {
  713. if (std::strcmp(fRdfDescriptor->Ports[i].Symbol, symbol) == 0)
  714. return i;
  715. }
  716. return LV2UI_INVALID_PORT_INDEX;
  717. }
  718. // ----------------------------------------------------------------------------------------------------------------
  719. char* handleStateMapToAbstractPath(const char* const absolutePath)
  720. {
  721. // may already be an abstract path
  722. if (! File::isAbsolutePath(absolutePath))
  723. return strdup(absolutePath);
  724. return strdup(File(absolutePath).getRelativePathFrom(File::getCurrentWorkingDirectory()).toRawUTF8());
  725. }
  726. char* handleStateMapToAbsolutePath(const bool createDir, const char* const abstractPath)
  727. {
  728. File target;
  729. if (File::isAbsolutePath(abstractPath))
  730. {
  731. target = abstractPath;
  732. }
  733. else
  734. {
  735. target = File::getCurrentWorkingDirectory().getChildFile(abstractPath);
  736. }
  737. if (createDir)
  738. {
  739. File dir(target.getParentDirectory());
  740. if (! dir.exists())
  741. dir.createDirectory();
  742. }
  743. return strdup(target.getFullPathName().toRawUTF8());
  744. }
  745. // ----------------------------------------------------------------------------------------------------------------
  746. LV2UI_Request_Value_Status handleUiRequestValue(const LV2_URID key,
  747. const LV2_URID type,
  748. const LV2_Feature* const* features)
  749. {
  750. CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
  751. carla_debug("CarlaLv2Client::handleUIRequestValue(%u, %u, %p)", key, type, features);
  752. if (type != kUridAtomPath)
  753. return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
  754. const char* const uri = getCustomURIDString(key);
  755. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri != kUnmapFallback, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
  756. // TODO check if a file browser is already open
  757. for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
  758. {
  759. if (fRdfDescriptor->Parameters[i].Type != LV2_PARAMETER_PATH)
  760. continue;
  761. if (std::strcmp(fRdfDescriptor->Parameters[i].URI, uri) != 0)
  762. continue;
  763. // TODO file browser filters, also label for title
  764. if (isPipeRunning())
  765. {
  766. char tmpBuf[0xff];
  767. const CarlaMutexLocker cml(getPipeLock());
  768. writeMessage("requestvalue\n", 13);
  769. std::snprintf(tmpBuf, 0xff-1, "%u\n", key);
  770. tmpBuf[0xff-1] = '\0';
  771. writeMessage(tmpBuf);
  772. std::snprintf(tmpBuf, 0xff-1, "%u\n", type);
  773. tmpBuf[0xff-1] = '\0';
  774. writeMessage(tmpBuf);
  775. }
  776. return LV2UI_REQUEST_VALUE_SUCCESS;
  777. }
  778. return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
  779. // may be unused
  780. (void)features;
  781. }
  782. int handleUiResize(const int width, const int height)
  783. {
  784. CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, 1);
  785. CARLA_SAFE_ASSERT_RETURN(width > 0, 1);
  786. CARLA_SAFE_ASSERT_RETURN(height > 0, 1);
  787. carla_debug("CarlaLv2Client::handleUiResize(%i, %i)", width, height);
  788. fToolkit->setSize(static_cast<uint>(width), static_cast<uint>(height));
  789. return 0;
  790. }
  791. void handleUiWrite(uint32_t rindex, uint32_t bufferSize, uint32_t format, const void* buffer)
  792. {
  793. CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,);
  794. CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);
  795. carla_debug("CarlaLv2Client::handleUiWrite(%i, %i, %i, %p)", rindex, bufferSize, format, buffer);
  796. switch (format)
  797. {
  798. case kUridNull:
  799. CARLA_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),);
  800. if (isPipeRunning())
  801. {
  802. const float value(*(const float*)buffer);
  803. writeControlMessage(rindex, value);
  804. }
  805. break;
  806. case kUridAtomTransferAtom:
  807. case kUridAtomTransferEvent:
  808. CARLA_SAFE_ASSERT_RETURN(bufferSize >= sizeof(LV2_Atom),);
  809. if (isPipeRunning())
  810. {
  811. const LV2_Atom* const atom((const LV2_Atom*)buffer);
  812. // plugins sometimes fail on this, not good...
  813. const uint32_t totalSize = lv2_atom_total_size(atom);
  814. const uint32_t paddedSize = lv2_atom_pad_size(totalSize);
  815. if (bufferSize != totalSize && bufferSize != paddedSize)
  816. carla_stderr2("Warning: LV2 UI sending atom with invalid size %u! size: %u, padded-size: %u",
  817. bufferSize, totalSize, paddedSize);
  818. writeLv2AtomMessage(rindex, atom);
  819. }
  820. break;
  821. default:
  822. carla_stderr("CarlaLv2Client::handleUiWrite(%i, %i, %i:\"%s\", %p) - unknown format",
  823. rindex, bufferSize, format, carla_lv2_urid_unmap(this, format), buffer);
  824. break;
  825. }
  826. }
  827. // ----------------------------------------------------------------------------------------------------------------
  828. private:
  829. LV2UI_Handle fHandle;
  830. LV2UI_Widget fWidget;
  831. LV2_Feature* fFeatures[kFeatureCount+1];
  832. const LV2UI_Descriptor* fDescriptor;
  833. const LV2_RDF_Descriptor* fRdfDescriptor;
  834. const LV2_RDF_UI* fRdfUiDescriptor;
  835. uint32_t fControlDesignatedPort;
  836. Lv2PluginOptions fLv2Options;
  837. Options fUiOptions;
  838. std::vector<std::string> fCustomURIDs;
  839. struct Extensions {
  840. const LV2_Options_Interface* options;
  841. const LV2_Programs_UI_Interface* programs;
  842. const LV2UI_Idle_Interface* idle;
  843. const LV2UI_Resize* resize;
  844. Extensions()
  845. : options(nullptr),
  846. programs(nullptr),
  847. idle(nullptr),
  848. resize(nullptr) {}
  849. } fExt;
  850. // ----------------------------------------------------------------------------------------------------------------
  851. // Logs Feature
  852. static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
  853. {
  854. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
  855. CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
  856. CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
  857. #ifndef DEBUG
  858. if (type == kUridLogTrace)
  859. return 0;
  860. #endif
  861. va_list args;
  862. va_start(args, fmt);
  863. const int ret(carla_lv2_log_vprintf(handle, type, fmt, args));
  864. va_end(args);
  865. return ret;
  866. }
  867. static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
  868. {
  869. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
  870. CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
  871. CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
  872. int ret = 0;
  873. switch (type)
  874. {
  875. case kUridLogError:
  876. std::fprintf(stderr, "\x1b[31m");
  877. ret = std::vfprintf(stderr, fmt, ap);
  878. std::fprintf(stderr, "\x1b[0m");
  879. break;
  880. case kUridLogNote:
  881. ret = std::vfprintf(stdout, fmt, ap);
  882. break;
  883. case kUridLogTrace:
  884. #ifdef DEBUG
  885. std::fprintf(stdout, "\x1b[30;1m");
  886. ret = std::vfprintf(stdout, fmt, ap);
  887. std::fprintf(stdout, "\x1b[0m");
  888. #endif
  889. break;
  890. case kUridLogWarning:
  891. ret = std::vfprintf(stderr, fmt, ap);
  892. break;
  893. default:
  894. break;
  895. }
  896. return ret;
  897. }
  898. // ----------------------------------------------------------------------------------------------------------------
  899. // Programs Feature
  900. static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
  901. {
  902. CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
  903. carla_debug("carla_lv2_program_changed(%p, %i)", handle, index);
  904. ((CarlaLv2Client*)handle)->handleProgramChanged(index);
  905. }
  906. // ----------------------------------------------------------------------------------------------------------------
  907. // State Feature
  908. static void carla_lv2_state_free_path(LV2_State_Free_Path_Handle handle, char* path)
  909. {
  910. CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
  911. carla_debug("carla_lv2_state_free_path(%p, \"%s\")", handle, path);
  912. std::free(path);
  913. }
  914. static char* carla_lv2_state_make_path_tmp(LV2_State_Make_Path_Handle handle, const char* path)
  915. {
  916. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  917. CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr);
  918. carla_debug("carla_lv2_state_make_path_tmp(%p, \"%s\")", handle, path);
  919. return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(true, path);
  920. }
  921. static char* carla_lv2_state_map_abstract_path_tmp(LV2_State_Map_Path_Handle handle, const char* absolute_path)
  922. {
  923. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  924. CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr);
  925. carla_debug("carla_lv2_state_map_abstract_path_tmp(%p, \"%s\")", handle, absolute_path);
  926. return ((CarlaLv2Client*)handle)->handleStateMapToAbstractPath(absolute_path);
  927. }
  928. static char* carla_lv2_state_map_absolute_path_tmp(LV2_State_Map_Path_Handle handle, const char* abstract_path)
  929. {
  930. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  931. CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr);
  932. carla_debug("carla_lv2_state_map_absolute_path_tmp(%p, \"%s\")", handle, abstract_path);
  933. return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(false, abstract_path);
  934. }
  935. // ----------------------------------------------------------------------------------------------------------------
  936. // URI-Map Feature
  937. static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
  938. {
  939. carla_debug("carla_lv2_uri_to_id(%p, \"%s\", \"%s\")", data, map, uri);
  940. return carla_lv2_urid_map((LV2_URID_Map_Handle*)data, uri);
  941. // unused
  942. (void)map;
  943. }
  944. // ----------------------------------------------------------------------------------------------------------------
  945. // URID Feature
  946. static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri)
  947. {
  948. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, kUridNull);
  949. CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
  950. carla_debug("carla_lv2_urid_map(%p, \"%s\")", handle, uri);
  951. // Atom types
  952. if (std::strcmp(uri, LV2_ATOM__Blank) == 0)
  953. return kUridAtomBlank;
  954. if (std::strcmp(uri, LV2_ATOM__Bool) == 0)
  955. return kUridAtomBool;
  956. if (std::strcmp(uri, LV2_ATOM__Chunk) == 0)
  957. return kUridAtomChunk;
  958. if (std::strcmp(uri, LV2_ATOM__Double) == 0)
  959. return kUridAtomDouble;
  960. if (std::strcmp(uri, LV2_ATOM__Event) == 0)
  961. return kUridAtomEvent;
  962. if (std::strcmp(uri, LV2_ATOM__Float) == 0)
  963. return kUridAtomFloat;
  964. if (std::strcmp(uri, LV2_ATOM__Int) == 0)
  965. return kUridAtomInt;
  966. if (std::strcmp(uri, LV2_ATOM__Literal) == 0)
  967. return kUridAtomLiteral;
  968. if (std::strcmp(uri, LV2_ATOM__Long) == 0)
  969. return kUridAtomLong;
  970. if (std::strcmp(uri, LV2_ATOM__Number) == 0)
  971. return kUridAtomNumber;
  972. if (std::strcmp(uri, LV2_ATOM__Object) == 0)
  973. return kUridAtomObject;
  974. if (std::strcmp(uri, LV2_ATOM__Path) == 0)
  975. return kUridAtomPath;
  976. if (std::strcmp(uri, LV2_ATOM__Property) == 0)
  977. return kUridAtomProperty;
  978. if (std::strcmp(uri, LV2_ATOM__Resource) == 0)
  979. return kUridAtomResource;
  980. if (std::strcmp(uri, LV2_ATOM__Sequence) == 0)
  981. return kUridAtomSequence;
  982. if (std::strcmp(uri, LV2_ATOM__Sound) == 0)
  983. return kUridAtomSound;
  984. if (std::strcmp(uri, LV2_ATOM__String) == 0)
  985. return kUridAtomString;
  986. if (std::strcmp(uri, LV2_ATOM__Tuple) == 0)
  987. return kUridAtomTuple;
  988. if (std::strcmp(uri, LV2_ATOM__URI) == 0)
  989. return kUridAtomURI;
  990. if (std::strcmp(uri, LV2_ATOM__URID) == 0)
  991. return kUridAtomURID;
  992. if (std::strcmp(uri, LV2_ATOM__Vector) == 0)
  993. return kUridAtomVector;
  994. if (std::strcmp(uri, LV2_ATOM__atomTransfer) == 0)
  995. return kUridAtomTransferAtom;
  996. if (std::strcmp(uri, LV2_ATOM__eventTransfer) == 0)
  997. return kUridAtomTransferEvent;
  998. // BufSize types
  999. if (std::strcmp(uri, LV2_BUF_SIZE__maxBlockLength) == 0)
  1000. return kUridBufMaxLength;
  1001. if (std::strcmp(uri, LV2_BUF_SIZE__minBlockLength) == 0)
  1002. return kUridBufMinLength;
  1003. if (std::strcmp(uri, LV2_BUF_SIZE__nominalBlockLength) == 0)
  1004. return kUridBufNominalLength;
  1005. if (std::strcmp(uri, LV2_BUF_SIZE__sequenceSize) == 0)
  1006. return kUridBufSequenceSize;
  1007. // Log types
  1008. if (std::strcmp(uri, LV2_LOG__Error) == 0)
  1009. return kUridLogError;
  1010. if (std::strcmp(uri, LV2_LOG__Note) == 0)
  1011. return kUridLogNote;
  1012. if (std::strcmp(uri, LV2_LOG__Trace) == 0)
  1013. return kUridLogTrace;
  1014. if (std::strcmp(uri, LV2_LOG__Warning) == 0)
  1015. return kUridLogWarning;
  1016. // Patch types
  1017. if (std::strcmp(uri, LV2_PATCH__Set) == 0)
  1018. return kUridPatchSet;
  1019. if (std::strcmp(uri, LV2_PATCH__property) == 0)
  1020. return kUridPatchProperty;
  1021. if (std::strcmp(uri, LV2_PATCH__value) == 0)
  1022. return kUridPatchValue;
  1023. // Time types
  1024. if (std::strcmp(uri, LV2_TIME__Position) == 0)
  1025. return kUridTimePosition;
  1026. if (std::strcmp(uri, LV2_TIME__bar) == 0)
  1027. return kUridTimeBar;
  1028. if (std::strcmp(uri, LV2_TIME__barBeat) == 0)
  1029. return kUridTimeBarBeat;
  1030. if (std::strcmp(uri, LV2_TIME__beat) == 0)
  1031. return kUridTimeBeat;
  1032. if (std::strcmp(uri, LV2_TIME__beatUnit) == 0)
  1033. return kUridTimeBeatUnit;
  1034. if (std::strcmp(uri, LV2_TIME__beatsPerBar) == 0)
  1035. return kUridTimeBeatsPerBar;
  1036. if (std::strcmp(uri, LV2_TIME__beatsPerMinute) == 0)
  1037. return kUridTimeBeatsPerMinute;
  1038. if (std::strcmp(uri, LV2_TIME__frame) == 0)
  1039. return kUridTimeFrame;
  1040. if (std::strcmp(uri, LV2_TIME__framesPerSecond) == 0)
  1041. return kUridTimeFramesPerSecond;
  1042. if (std::strcmp(uri, LV2_TIME__speed) == 0)
  1043. return kUridTimeSpeed;
  1044. if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
  1045. return kUridTimeTicksPerBeat;
  1046. // Others
  1047. if (std::strcmp(uri, LV2_MIDI__MidiEvent) == 0)
  1048. return kUridMidiEvent;
  1049. if (std::strcmp(uri, LV2_PARAMETERS__sampleRate) == 0)
  1050. return kUridParamSampleRate;
  1051. if (std::strcmp(uri, LV2_UI__backgroundColor) == 0)
  1052. return kUridBackgroundColor;
  1053. if (std::strcmp(uri, LV2_UI__foregroundColor) == 0)
  1054. return kUridForegroundColor;
  1055. if (std::strcmp(uri, LV2_UI__scaleFactor) == 0)
  1056. return kUridScaleFactor;
  1057. if (std::strcmp(uri, LV2_UI__windowTitle) == 0)
  1058. return kUridWindowTitle;
  1059. // Custom Carla types
  1060. if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_IN) == 0)
  1061. return kUridCarlaAtomWorkerIn;
  1062. if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_RESP) == 0)
  1063. return kUridCarlaAtomWorkerResp;
  1064. if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TransientWindowId) == 0)
  1065. return kUridCarlaTransientWindowId;
  1066. // Custom plugin types
  1067. return ((CarlaLv2Client*)handle)->getCustomURID(uri);
  1068. }
  1069. static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
  1070. {
  1071. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  1072. CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, nullptr);
  1073. carla_debug("carla_lv2_urid_unmap(%p, %i)", handle, urid);
  1074. switch (urid)
  1075. {
  1076. // Atom types
  1077. case kUridAtomBlank:
  1078. return LV2_ATOM__Blank;
  1079. case kUridAtomBool:
  1080. return LV2_ATOM__Bool;
  1081. case kUridAtomChunk:
  1082. return LV2_ATOM__Chunk;
  1083. case kUridAtomDouble:
  1084. return LV2_ATOM__Double;
  1085. case kUridAtomEvent:
  1086. return LV2_ATOM__Event;
  1087. case kUridAtomFloat:
  1088. return LV2_ATOM__Float;
  1089. case kUridAtomInt:
  1090. return LV2_ATOM__Int;
  1091. case kUridAtomLiteral:
  1092. return LV2_ATOM__Literal;
  1093. case kUridAtomLong:
  1094. return LV2_ATOM__Long;
  1095. case kUridAtomNumber:
  1096. return LV2_ATOM__Number;
  1097. case kUridAtomObject:
  1098. return LV2_ATOM__Object;
  1099. case kUridAtomPath:
  1100. return LV2_ATOM__Path;
  1101. case kUridAtomProperty:
  1102. return LV2_ATOM__Property;
  1103. case kUridAtomResource:
  1104. return LV2_ATOM__Resource;
  1105. case kUridAtomSequence:
  1106. return LV2_ATOM__Sequence;
  1107. case kUridAtomSound:
  1108. return LV2_ATOM__Sound;
  1109. case kUridAtomString:
  1110. return LV2_ATOM__String;
  1111. case kUridAtomTuple:
  1112. return LV2_ATOM__Tuple;
  1113. case kUridAtomURI:
  1114. return LV2_ATOM__URI;
  1115. case kUridAtomURID:
  1116. return LV2_ATOM__URID;
  1117. case kUridAtomVector:
  1118. return LV2_ATOM__Vector;
  1119. case kUridAtomTransferAtom:
  1120. return LV2_ATOM__atomTransfer;
  1121. case kUridAtomTransferEvent:
  1122. return LV2_ATOM__eventTransfer;
  1123. // BufSize types
  1124. case kUridBufMaxLength:
  1125. return LV2_BUF_SIZE__maxBlockLength;
  1126. case kUridBufMinLength:
  1127. return LV2_BUF_SIZE__minBlockLength;
  1128. case kUridBufNominalLength:
  1129. return LV2_BUF_SIZE__nominalBlockLength;
  1130. case kUridBufSequenceSize:
  1131. return LV2_BUF_SIZE__sequenceSize;
  1132. // Log types
  1133. case kUridLogError:
  1134. return LV2_LOG__Error;
  1135. case kUridLogNote:
  1136. return LV2_LOG__Note;
  1137. case kUridLogTrace:
  1138. return LV2_LOG__Trace;
  1139. case kUridLogWarning:
  1140. return LV2_LOG__Warning;
  1141. // Patch types
  1142. case kUridPatchSet:
  1143. return LV2_PATCH__Set;
  1144. case kUridPatchProperty:
  1145. return LV2_PATCH__property;
  1146. case kUridPatchValue:
  1147. return LV2_PATCH__value;
  1148. // Time types
  1149. case kUridTimePosition:
  1150. return LV2_TIME__Position;
  1151. case kUridTimeBar:
  1152. return LV2_TIME__bar;
  1153. case kUridTimeBarBeat:
  1154. return LV2_TIME__barBeat;
  1155. case kUridTimeBeat:
  1156. return LV2_TIME__beat;
  1157. case kUridTimeBeatUnit:
  1158. return LV2_TIME__beatUnit;
  1159. case kUridTimeBeatsPerBar:
  1160. return LV2_TIME__beatsPerBar;
  1161. case kUridTimeBeatsPerMinute:
  1162. return LV2_TIME__beatsPerMinute;
  1163. case kUridTimeFrame:
  1164. return LV2_TIME__frame;
  1165. case kUridTimeFramesPerSecond:
  1166. return LV2_TIME__framesPerSecond;
  1167. case kUridTimeSpeed:
  1168. return LV2_TIME__speed;
  1169. case kUridTimeTicksPerBeat:
  1170. return LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat;
  1171. // Others
  1172. case kUridMidiEvent:
  1173. return LV2_MIDI__MidiEvent;
  1174. case kUridParamSampleRate:
  1175. return LV2_PARAMETERS__sampleRate;
  1176. case kUridBackgroundColor:
  1177. return LV2_UI__backgroundColor;
  1178. case kUridForegroundColor:
  1179. return LV2_UI__foregroundColor;
  1180. case kUridScaleFactor:
  1181. return LV2_UI__scaleFactor;
  1182. case kUridWindowTitle:
  1183. return LV2_UI__windowTitle;
  1184. // Custom Carla types
  1185. case kUridCarlaAtomWorkerIn:
  1186. return URI_CARLA_ATOM_WORKER_IN;
  1187. case kUridCarlaAtomWorkerResp:
  1188. return URI_CARLA_ATOM_WORKER_RESP;
  1189. case kUridCarlaTransientWindowId:
  1190. return LV2_KXSTUDIO_PROPERTIES__TransientWindowId;
  1191. }
  1192. // Custom types
  1193. return ((CarlaLv2Client*)handle)->getCustomURIDString(urid);
  1194. }
  1195. // ----------------------------------------------------------------------------------------------------------------
  1196. // UI Port-Map Feature
  1197. static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
  1198. {
  1199. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_INVALID_PORT_INDEX);
  1200. carla_debug("carla_lv2_ui_port_map(%p, \"%s\")", handle, symbol);
  1201. return ((CarlaLv2Client*)handle)->handleUiPortMap(symbol);
  1202. }
  1203. // ----------------------------------------------------------------------------------------------------------------
  1204. // UI Request Parameter Feature
  1205. static LV2UI_Request_Value_Status carla_lv2_ui_request_value(LV2UI_Feature_Handle handle,
  1206. LV2_URID key,
  1207. LV2_URID type,
  1208. const LV2_Feature* const* features)
  1209. {
  1210. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
  1211. carla_debug("carla_lv2_ui_request_value(%p, %u, %u, %p)", handle, key, type, features);
  1212. return ((CarlaLv2Client*)handle)->handleUiRequestValue(key, type, features);
  1213. }
  1214. // ----------------------------------------------------------------------------------------------------------------
  1215. // UI Resize Feature
  1216. static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
  1217. {
  1218. CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1);
  1219. carla_debug("carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);
  1220. return ((CarlaLv2Client*)handle)->handleUiResize(width, height);
  1221. }
  1222. // ----------------------------------------------------------------------------------------------------------------
  1223. // UI Extension
  1224. static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
  1225. {
  1226. CARLA_SAFE_ASSERT_RETURN(controller != nullptr,);
  1227. carla_debug("carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer);
  1228. ((CarlaLv2Client*)controller)->handleUiWrite(port_index, buffer_size, format, buffer);
  1229. }
  1230. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaLv2Client)
  1231. };
  1232. // --------------------------------------------------------------------------------------------------------------------
  1233. CARLA_BRIDGE_UI_END_NAMESPACE
  1234. // --------------------------------------------------------------------------------------------------------------------
  1235. int main(int argc, const char* argv[])
  1236. {
  1237. CARLA_BRIDGE_UI_USE_NAMESPACE
  1238. if (argc < 2)
  1239. {
  1240. carla_stderr("usage: %s <plugin-uri> [ui-uri]", argv[0]);
  1241. return 1;
  1242. }
  1243. const bool testingModeOnly = (argc != 7);
  1244. // try to get sampleRate value
  1245. if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
  1246. {
  1247. const CarlaScopedLocale csl;
  1248. gInitialSampleRate = std::atof(sampleRateStr);
  1249. }
  1250. // Init LV2 client
  1251. CarlaLv2Client client;
  1252. // Load UI
  1253. int ret;
  1254. if (client.init(argc, argv))
  1255. {
  1256. client.exec(testingModeOnly);
  1257. ret = 0;
  1258. }
  1259. else
  1260. {
  1261. ret = 1;
  1262. }
  1263. return ret;
  1264. }
  1265. // --------------------------------------------------------------------------------------------------------------------