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

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