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.

1260 lines
44KB

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