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.

1431 lines
50KB

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