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.

1396 lines
49KB

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