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

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