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.

CarlaBridgeFormatLV2.cpp 43KB

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