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 42KB

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