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.

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