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.

1324 lines
46KB

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