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.

1186 lines
44KB

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