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.

1574 lines
55KB

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