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.

CarlaPluginJack.cpp 71KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082
  1. /*
  2. * Carla Plugin JACK
  3. * Copyright (C) 2016-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 "CarlaPluginInternal.hpp"
  18. #include "CarlaEngine.hpp"
  19. #if defined(CARLA_OS_LINUX) || defined(CARLA_OS_MAC)
  20. #include "CarlaLibJackHints.h"
  21. #include "CarlaBackendUtils.hpp"
  22. #include "CarlaBridgeUtils.hpp"
  23. #include "CarlaEngineUtils.hpp"
  24. #include "CarlaMathUtils.hpp"
  25. #include "CarlaPipeUtils.hpp"
  26. #include "CarlaScopeUtils.hpp"
  27. #include "CarlaShmUtils.hpp"
  28. #include "CarlaThread.hpp"
  29. #ifdef HAVE_LIBLO
  30. # include "CarlaOscUtils.hpp"
  31. #else
  32. # warning No liblo support, NSM (session state) will not be available
  33. #endif
  34. #include "water/files/File.h"
  35. #include "water/misc/Time.h"
  36. #include "water/text/StringArray.h"
  37. #include "water/threads/ChildProcess.h"
  38. #include "jackbridge/JackBridge.hpp"
  39. #include <ctime>
  40. #include <vector>
  41. // -------------------------------------------------------------------------------------------------------------------
  42. using water::ChildProcess;
  43. using water::File;
  44. using water::String;
  45. using water::StringArray;
  46. CARLA_BACKEND_START_NAMESPACE
  47. static size_t safe_rand(const size_t limit)
  48. {
  49. const int r = std::rand();
  50. CARLA_SAFE_ASSERT_RETURN(r >= 0, 0);
  51. return static_cast<uint>(r) % limit;
  52. }
  53. // -------------------------------------------------------------------------------------------------------------------
  54. // Fallback data
  55. static const ExternalMidiNote kExternalMidiNoteFallback = { -1, 0, 0 };
  56. // -------------------------------------------------------------------------------------------------------------------
  57. struct Announcer {
  58. virtual ~Announcer() {}
  59. virtual void nsmAnnounced(bool hasGui) = 0;
  60. };
  61. class CarlaPluginJackThread : public CarlaThread
  62. {
  63. public:
  64. CarlaPluginJackThread(Announcer* const ann, CarlaEngine* const engine, CarlaPlugin* const plugin) noexcept
  65. : CarlaThread("CarlaPluginJackThread"),
  66. kAnnouncer(ann),
  67. kEngine(engine),
  68. kPlugin(plugin),
  69. fShmIds(),
  70. fSetupLabel(),
  71. #ifdef HAVE_LIBLO
  72. fOscClientAddress(nullptr),
  73. fOscServer(nullptr),
  74. fHasOptionalGui(false),
  75. fProject(),
  76. #endif
  77. fProcess() {}
  78. void setData(const char* const shmIds, const char* const setupLabel) noexcept
  79. {
  80. CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && shmIds[0] != '\0',);
  81. CARLA_SAFE_ASSERT_RETURN(setupLabel != nullptr && setupLabel[0] != '\0',);
  82. CARLA_SAFE_ASSERT(! isThreadRunning());
  83. fShmIds = shmIds;
  84. fSetupLabel = setupLabel;
  85. }
  86. uintptr_t getProcessID() const noexcept
  87. {
  88. CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0);
  89. return (uintptr_t)fProcess->getPID();
  90. }
  91. #ifdef HAVE_LIBLO
  92. void nsmSave(const char* const setupLabel)
  93. {
  94. if (fOscClientAddress == nullptr)
  95. return;
  96. if (fSetupLabel != setupLabel)
  97. fSetupLabel = setupLabel;
  98. maybeOpenFirstTime(false);
  99. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/save", "");
  100. }
  101. bool nsmShowGui(const bool yesNo)
  102. {
  103. if (fOscClientAddress == nullptr || ! fHasOptionalGui)
  104. return false;
  105. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE,
  106. yesNo ? "/nsm/client/show_optional_gui"
  107. : "/nsm/client/hide_optional_gui", "");
  108. return true;
  109. }
  110. #endif
  111. char* getEnvVarsToExport()
  112. {
  113. const EngineOptions& options(kEngine->getOptions());
  114. CarlaString binaryDir(options.binaryDir);
  115. #ifdef HAVE_LIBLO
  116. const int sessionManager = fSetupLabel[4U] - '0';
  117. #endif
  118. CarlaString ret;
  119. #ifdef CARLA_OS_MAC
  120. ret += "export DYLD_LIBRARY_PATH=" + binaryDir + "/jack\n";
  121. ret += "export DYLD_INSERT_LIBRARIES=" + binaryDir + "/libcarla_interposer-jack-x11.dylib\n";
  122. ret += "export DYLD_FORCE_FLAT_NAMESPACE=1\n";
  123. #else
  124. ret += "export LD_LIBRARY_PATH=" + binaryDir + "/jack\n";
  125. ret += "export LD_PRELOAD=" + binaryDir + "/libcarla_interposer-jack-x11.so\n";
  126. #endif
  127. #ifdef HAVE_LIBLO
  128. if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
  129. {
  130. for (int i=50; fOscServer == nullptr && --i>=0;)
  131. carla_msleep(100);
  132. ret += "export NSM_URL=";
  133. ret += lo_server_get_url(fOscServer);
  134. ret += "\n";
  135. }
  136. #endif
  137. if (kPlugin->getHints() & PLUGIN_HAS_CUSTOM_UI)
  138. ret += "export CARLA_FRONTEND_WIN_ID=" + CarlaString(options.frontendWinId) + "\n";
  139. ret += "export CARLA_LIBJACK_SETUP=" + fSetupLabel + "\n";
  140. ret += "export CARLA_SHM_IDS=" + fShmIds + "\n";
  141. return ret.releaseBufferPointer();
  142. }
  143. protected:
  144. #ifdef HAVE_LIBLO
  145. static void _osc_error_handler(int num, const char* msg, const char* path)
  146. {
  147. carla_stderr2("CarlaPluginJackThread::_osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
  148. }
  149. static int _broadcast_handler(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* data)
  150. {
  151. CARLA_SAFE_ASSERT_RETURN(data != nullptr, 0);
  152. carla_stdout("CarlaPluginJackThread::_broadcast_handler(%s, %s, %p, %i)", path, types, argv, argc);
  153. return ((CarlaPluginJackThread*)data)->handleBroadcast(path, types, argv, msg);
  154. }
  155. void maybeOpenFirstTime(const bool announced)
  156. {
  157. if (fSetupLabel.length() <= 6)
  158. return;
  159. if ((announced || fProject.path.isEmpty()) && fProject.init(kPlugin->getName(),
  160. kEngine->getCurrentProjectFolder(),
  161. &fSetupLabel[6U]))
  162. {
  163. carla_stdout("Sending open signal %s %s %s",
  164. fProject.path.buffer(), fProject.display.buffer(), fProject.clientName.buffer());
  165. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/open", "sss",
  166. fProject.path.buffer(), fProject.display.buffer(), fProject.clientName.buffer());
  167. }
  168. }
  169. int handleBroadcast(const char* path, const char* types, lo_arg** argv, lo_message msg)
  170. {
  171. if (std::strcmp(path, "/nsm/server/announce") == 0)
  172. {
  173. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "sssiii") == 0, 0);
  174. const lo_address msgAddress(lo_message_get_source(msg));
  175. CARLA_SAFE_ASSERT_RETURN(msgAddress != nullptr, 0);
  176. char* const msgURL(lo_address_get_url(msgAddress));
  177. CARLA_SAFE_ASSERT_RETURN(msgURL != nullptr, 0);
  178. if (fOscClientAddress != nullptr)
  179. lo_address_free(fOscClientAddress);
  180. fOscClientAddress = lo_address_new_from_url(msgURL);
  181. CARLA_SAFE_ASSERT_RETURN(fOscClientAddress != nullptr, 0);
  182. fProject.appName = &argv[0]->s;
  183. fHasOptionalGui = std::strstr(&argv[1]->s, ":optional-gui:") != nullptr;
  184. kAnnouncer->nsmAnnounced(fHasOptionalGui);
  185. static const char* const featuresG = ":server-control:optional-gui:";
  186. static const char* const featuresN = ":server-control:";
  187. static const char* const method = "/nsm/server/announce";
  188. static const char* const message = "Howdy, what took you so long?";
  189. static const char* const smName = "Carla";
  190. const char* const features = ((fSetupLabel[5U] - '0') & LIBJACK_FLAG_CONTROL_WINDOW)
  191. ? featuresG : featuresN;
  192. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/reply", "ssss",
  193. method, message, smName, features);
  194. maybeOpenFirstTime(true);
  195. return 0;
  196. }
  197. CARLA_SAFE_ASSERT_RETURN(fOscClientAddress != nullptr, 0);
  198. if (std::strcmp(path, "/reply") == 0)
  199. {
  200. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "ss") == 0, 0);
  201. const char* const method = &argv[0]->s;
  202. const char* const message = &argv[1]->s;
  203. carla_stdout("Got reply of '%s' as '%s'", method, message);
  204. if (std::strcmp(method, "/nsm/client/open") == 0)
  205. {
  206. carla_stdout("Sending 'Session is loaded' to %s", fProject.appName.buffer());
  207. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/session_is_loaded", "");
  208. }
  209. }
  210. else if (std::strcmp(path, "/nsm/client/gui_is_shown") == 0)
  211. {
  212. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "") == 0, 0);
  213. kEngine->callback(true, true,
  214. ENGINE_CALLBACK_UI_STATE_CHANGED,
  215. kPlugin->getId(),
  216. 1,
  217. 0, 0, 0.0f, nullptr);
  218. }
  219. else if (std::strcmp(path, "/nsm/client/gui_is_hidden") == 0)
  220. {
  221. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "") == 0, 0);
  222. kEngine->callback(true, true,
  223. ENGINE_CALLBACK_UI_STATE_CHANGED,
  224. kPlugin->getId(),
  225. 0,
  226. 0, 0, 0.0f, nullptr);
  227. }
  228. // special messages
  229. else if (std::strcmp(path, "/nsm/gui/client/save") == 0)
  230. {
  231. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "s") == 0, 0);
  232. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/save", "");
  233. }
  234. else if (std::strcmp(path, "/nsm/server/stop") == 0)
  235. {
  236. CARLA_SAFE_ASSERT_RETURN(std::strcmp(types, "s") == 0, 0);
  237. lo_send_from(fOscClientAddress, fOscServer, LO_TT_IMMEDIATE, "/nsm/client/hide_optional_gui", "");
  238. kEngine->callback(true, true,
  239. ENGINE_CALLBACK_UI_STATE_CHANGED,
  240. kPlugin->getId(),
  241. 0,
  242. 0, 0, 0.0f, nullptr);
  243. }
  244. return 0;
  245. }
  246. #endif
  247. void run()
  248. {
  249. #ifdef HAVE_LIBLO
  250. if (fOscClientAddress != nullptr)
  251. {
  252. lo_address_free(fOscClientAddress);
  253. fOscClientAddress = nullptr;
  254. }
  255. const int sessionManager = fSetupLabel[4U] - '0';
  256. if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
  257. {
  258. // NSM support
  259. fOscServer = lo_server_new_with_proto(nullptr, LO_UDP, _osc_error_handler);
  260. CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr,);
  261. lo_server_add_method(fOscServer, nullptr, nullptr, _broadcast_handler, this);
  262. }
  263. #endif
  264. const bool externalProcess = ((fSetupLabel[5U] - '0') & LIBJACK_FLAG_EXTERNAL_START)
  265. && ! kEngine->isLoadingProject();
  266. if (! externalProcess)
  267. {
  268. if (fProcess == nullptr)
  269. {
  270. fProcess = new ChildProcess();
  271. }
  272. else if (fProcess->isRunning())
  273. {
  274. carla_stderr("CarlaPluginJackThread::run() - already running");
  275. }
  276. String name(kPlugin->getName());
  277. String filename(kPlugin->getFilename());
  278. if (name.isEmpty())
  279. name = "(none)";
  280. CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(),);
  281. StringArray arguments;
  282. // binary
  283. arguments.addTokens(filename, true);
  284. const EngineOptions& options(kEngine->getOptions());
  285. char winIdStr[STR_MAX+1];
  286. std::snprintf(winIdStr, STR_MAX, P_UINTPTR, options.frontendWinId);
  287. winIdStr[STR_MAX] = '\0';
  288. const CarlaString libjackdir(CarlaString(options.binaryDir) + "/jack");
  289. #ifdef CARLA_OS_MAC
  290. const CarlaString ldpreload(CarlaString(options.binaryDir) + "/libcarla_interposer-jack-x11.dylib");
  291. #else
  292. const CarlaString ldpreload(CarlaString(options.binaryDir) + "/libcarla_interposer-jack-x11.so");
  293. #endif
  294. const ScopedEngineEnvironmentLocker _seel(kEngine);
  295. #ifdef CARLA_OS_MAC
  296. const CarlaScopedEnvVar sev2("DYLD_LIBRARY_PATH", libjackdir.buffer());
  297. const CarlaScopedEnvVar sev1("DYLD_INSERT_LIBRARIES", ldpreload.isNotEmpty() ? ldpreload.buffer() : nullptr);
  298. const CarlaScopedEnvVar sev0("DYLD_FORCE_FLAT_NAMESPACE", "1");
  299. #else
  300. const CarlaScopedEnvVar sev2("LD_LIBRARY_PATH", libjackdir.buffer());
  301. const CarlaScopedEnvVar sev1("LD_PRELOAD", ldpreload.isNotEmpty() ? ldpreload.buffer() : nullptr);
  302. #endif
  303. #ifdef HAVE_LIBLO
  304. const CarlaScopedEnvVar sev3("NSM_URL", lo_server_get_url(fOscServer));
  305. #endif
  306. if (kPlugin->getHints() & PLUGIN_HAS_CUSTOM_UI)
  307. carla_setenv("CARLA_FRONTEND_WIN_ID", winIdStr);
  308. else
  309. carla_unsetenv("CARLA_FRONTEND_WIN_ID");
  310. carla_setenv("CARLA_LIBJACK_SETUP", fSetupLabel.buffer());
  311. carla_setenv("CARLA_SHM_IDS", fShmIds.buffer());
  312. if (! fProcess->start(arguments))
  313. {
  314. carla_stdout("failed!");
  315. fProcess = nullptr;
  316. return;
  317. }
  318. }
  319. for (; (externalProcess || fProcess->isRunning()) && ! shouldThreadExit();)
  320. {
  321. #ifdef HAVE_LIBLO
  322. if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
  323. {
  324. lo_server_recv_noblock(fOscServer, 50);
  325. }
  326. else
  327. #endif
  328. {
  329. carla_msleep(50);
  330. }
  331. }
  332. #ifdef HAVE_LIBLO
  333. if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
  334. {
  335. lo_server_free(fOscServer);
  336. fOscServer = nullptr;
  337. if (fOscClientAddress != nullptr)
  338. {
  339. lo_address_free(fOscClientAddress);
  340. fOscClientAddress = nullptr;
  341. }
  342. }
  343. #endif
  344. if (! externalProcess)
  345. {
  346. // we only get here if bridge crashed or thread asked to exit
  347. if (fProcess->isRunning() && shouldThreadExit())
  348. {
  349. fProcess->waitForProcessToFinish(2000);
  350. if (fProcess->isRunning())
  351. {
  352. carla_stdout("CarlaPluginJackThread::run() - application refused to close, force kill now");
  353. fProcess->kill();
  354. }
  355. }
  356. else
  357. {
  358. // forced quit, may have crashed
  359. if (fProcess->getExitCodeAndClearPID() != 0)
  360. {
  361. carla_stderr("CarlaPluginJackThread::run() - application crashed");
  362. CarlaString errorString("Plugin '" + CarlaString(kPlugin->getName()) + "' has crashed!\n"
  363. "Saving now will lose its current settings.\n"
  364. "Please remove this plugin, and not rely on it from this point.");
  365. kEngine->callback(true, true,
  366. ENGINE_CALLBACK_ERROR,
  367. kPlugin->getId(),
  368. 0, 0, 0, 0.0f,
  369. errorString);
  370. }
  371. }
  372. }
  373. fProcess = nullptr;
  374. }
  375. private:
  376. Announcer* const kAnnouncer;
  377. CarlaEngine* const kEngine;
  378. CarlaPlugin* const kPlugin;
  379. CarlaString fShmIds;
  380. CarlaString fSetupLabel;
  381. #ifdef HAVE_LIBLO
  382. lo_address fOscClientAddress;
  383. lo_server fOscServer;
  384. bool fHasOptionalGui;
  385. struct ProjectData {
  386. CarlaString appName;
  387. CarlaString path;
  388. CarlaString display;
  389. CarlaString clientName;
  390. ProjectData()
  391. : appName(),
  392. path(),
  393. display(),
  394. clientName() {}
  395. bool init(const char* const pluginName,
  396. const char* const engineProjectFolder,
  397. const char* const uniqueCodeID)
  398. {
  399. CARLA_SAFE_ASSERT_RETURN(engineProjectFolder != nullptr && engineProjectFolder[0] != '\0', false);
  400. CARLA_SAFE_ASSERT_RETURN(uniqueCodeID != nullptr && uniqueCodeID[0] != '\0', false);
  401. CARLA_SAFE_ASSERT_RETURN(appName.isNotEmpty(), false);
  402. String child(pluginName);
  403. child += ".";
  404. child += uniqueCodeID;
  405. const File file(File(engineProjectFolder).getChildFile(child));
  406. clientName = appName + "." + uniqueCodeID;
  407. path = file.getFullPathName().toRawUTF8();
  408. display = file.getFileNameWithoutExtension().toRawUTF8();
  409. return true;
  410. }
  411. CARLA_DECLARE_NON_COPYABLE(ProjectData)
  412. } fProject;
  413. #endif
  414. CarlaScopedPointer<ChildProcess> fProcess;
  415. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginJackThread)
  416. };
  417. // -------------------------------------------------------------------------------------------------------------------
  418. class CarlaPluginJack : public CarlaPlugin,
  419. public Announcer
  420. {
  421. public:
  422. CarlaPluginJack(CarlaEngine* const engine, const uint id)
  423. : CarlaPlugin(engine, id),
  424. fInitiated(false),
  425. fInitError(false),
  426. fTimedOut(false),
  427. fTimedError(false),
  428. fProcCanceled(false),
  429. fBufferSize(engine->getBufferSize()),
  430. fProcWaitTime(0),
  431. fSetupHints(0x0),
  432. fBridgeThread(this, engine, this),
  433. fShmAudioPool(),
  434. fShmRtClientControl(),
  435. fShmNonRtClientControl(),
  436. fShmNonRtServerControl(),
  437. fInfo()
  438. {
  439. carla_debug("CarlaPluginJack::CarlaPluginJack(%p, %i)", engine, id);
  440. pData->hints |= PLUGIN_IS_BRIDGE;
  441. }
  442. ~CarlaPluginJack() override
  443. {
  444. carla_debug("CarlaPluginJack::~CarlaPluginJack()");
  445. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  446. // close UI
  447. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  448. pData->transientTryCounter = 0;
  449. #endif
  450. pData->singleMutex.lock();
  451. pData->masterMutex.lock();
  452. if (pData->client != nullptr && pData->client->isActive())
  453. pData->client->deactivate(true);
  454. if (pData->active)
  455. {
  456. deactivate();
  457. pData->active = false;
  458. }
  459. if (fBridgeThread.isThreadRunning())
  460. {
  461. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientQuit);
  462. fShmRtClientControl.commitWrite();
  463. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientQuit);
  464. fShmNonRtClientControl.commitWrite();
  465. if (! fTimedOut)
  466. waitForClient("stopping", 3000);
  467. }
  468. fBridgeThread.stopThread(3000);
  469. fShmNonRtServerControl.clear();
  470. fShmNonRtClientControl.clear();
  471. fShmRtClientControl.clear();
  472. fShmAudioPool.clear();
  473. clearBuffers();
  474. fInfo.chunk.clear();
  475. }
  476. // -------------------------------------------------------------------
  477. void nsmAnnounced(bool hasGui) override
  478. {
  479. if (hasGui || (pData->hints & PLUGIN_HAS_CUSTOM_UI) == 0x0)
  480. return;
  481. {
  482. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  483. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientShowUI);
  484. fShmNonRtClientControl.commitWrite();
  485. }
  486. pData->engine->callback(true, true,
  487. ENGINE_CALLBACK_UI_STATE_CHANGED,
  488. pData->id,
  489. 1,
  490. 0, 0, 0.0f, nullptr);
  491. }
  492. // -------------------------------------------------------------------
  493. // Information (base)
  494. PluginType getType() const noexcept override
  495. {
  496. return PLUGIN_JACK;
  497. }
  498. PluginCategory getCategory() const noexcept override
  499. {
  500. return PLUGIN_CATEGORY_NONE;
  501. }
  502. // -------------------------------------------------------------------
  503. // Information (count)
  504. uint32_t getMidiInCount() const noexcept override
  505. {
  506. return fInfo.mIns;
  507. }
  508. uint32_t getMidiOutCount() const noexcept override
  509. {
  510. return fInfo.mOuts;
  511. }
  512. // -------------------------------------------------------------------
  513. // Information (current data)
  514. // -------------------------------------------------------------------
  515. // Information (per-plugin data)
  516. uint getOptionsAvailable() const noexcept override
  517. {
  518. uint options = 0x0;
  519. if (fInfo.mIns > 0)
  520. {
  521. options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  522. options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  523. options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  524. options |= PLUGIN_OPTION_SEND_PITCHBEND;
  525. options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  526. options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  527. options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  528. }
  529. return options;
  530. }
  531. bool getLabel(char* const strBuf) const noexcept override
  532. {
  533. std::strncpy(strBuf, fInfo.setupLabel, STR_MAX);
  534. return true;
  535. }
  536. bool getMaker(char* const) const noexcept override
  537. {
  538. return false;
  539. }
  540. bool getCopyright(char* const) const noexcept override
  541. {
  542. return false;
  543. }
  544. bool getRealName(char* const strBuf) const noexcept override
  545. {
  546. // FIXME
  547. std::strncpy(strBuf, "Carla's libjack", STR_MAX);
  548. return true;
  549. }
  550. // -------------------------------------------------------------------
  551. // Set data (state)
  552. void prepareForSave(bool) noexcept override
  553. {
  554. #ifdef HAVE_LIBLO
  555. if (fInfo.setupLabel.length() == 6)
  556. setupUniqueProjectID();
  557. #endif
  558. {
  559. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  560. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientPrepareForSave);
  561. fShmNonRtClientControl.commitWrite();
  562. }
  563. #ifdef HAVE_LIBLO
  564. fBridgeThread.nsmSave(fInfo.setupLabel);
  565. #endif
  566. }
  567. // -------------------------------------------------------------------
  568. // Set data (internal stuff)
  569. void setOption(const uint option, const bool yesNo, const bool sendCallback) override
  570. {
  571. {
  572. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  573. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetOption);
  574. fShmNonRtClientControl.writeUInt(option);
  575. fShmNonRtClientControl.writeBool(yesNo);
  576. fShmNonRtClientControl.commitWrite();
  577. }
  578. CarlaPlugin::setOption(option, yesNo, sendCallback);
  579. }
  580. void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override
  581. {
  582. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  583. {
  584. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  585. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetCtrlChannel);
  586. fShmNonRtClientControl.writeShort(channel);
  587. fShmNonRtClientControl.commitWrite();
  588. }
  589. CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback);
  590. }
  591. // -------------------------------------------------------------------
  592. // Set data (plugin-specific stuff)
  593. void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override
  594. {
  595. CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
  596. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  597. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  598. if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
  599. return CarlaPlugin::setCustomData(type, key, value, sendGui);
  600. if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0 && std::strcmp(key, "__CarlaPingOnOff__") == 0)
  601. {
  602. #if 0
  603. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  604. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientPingOnOff);
  605. fShmNonRtClientControl.writeBool(std::strcmp(value, "true") == 0);
  606. fShmNonRtClientControl.commitWrite();
  607. #endif
  608. return;
  609. }
  610. CarlaPlugin::setCustomData(type, key, value, sendGui);
  611. }
  612. // -------------------------------------------------------------------
  613. // Set ui stuff
  614. void showCustomUI(const bool yesNo) override
  615. {
  616. if (yesNo && ! fBridgeThread.isThreadRunning()) {
  617. CARLA_SAFE_ASSERT_RETURN(restartBridgeThread(),);
  618. }
  619. #ifdef HAVE_LIBLO
  620. if (! fBridgeThread.nsmShowGui(yesNo))
  621. #endif
  622. {
  623. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  624. fShmNonRtClientControl.writeOpcode(yesNo ? kPluginBridgeNonRtClientShowUI : kPluginBridgeNonRtClientHideUI);
  625. fShmNonRtClientControl.commitWrite();
  626. }
  627. }
  628. void idle() override
  629. {
  630. if (fBridgeThread.isThreadRunning())
  631. {
  632. if (fInitiated && fTimedOut && pData->active)
  633. setActive(false, true, true);
  634. {
  635. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  636. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientPing);
  637. fShmNonRtClientControl.commitWrite();
  638. }
  639. try {
  640. handleNonRtData();
  641. } CARLA_SAFE_EXCEPTION("handleNonRtData");
  642. }
  643. else if (fInitiated)
  644. {
  645. fTimedOut = true;
  646. fTimedError = true;
  647. fInitiated = false;
  648. handleProcessStopped();
  649. }
  650. else if (fProcCanceled)
  651. {
  652. handleProcessStopped();
  653. fProcCanceled = false;
  654. }
  655. CarlaPlugin::idle();
  656. }
  657. // -------------------------------------------------------------------
  658. // Plugin state
  659. void reload() override
  660. {
  661. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  662. carla_debug("CarlaPluginJack::reload() - start");
  663. const EngineProcessMode processMode(pData->engine->getProccessMode());
  664. // Safely disable plugin for reload
  665. const ScopedDisabler sd(this);
  666. // cleanup of previous data
  667. pData->audioIn.clear();
  668. pData->audioOut.clear();
  669. pData->event.clear();
  670. bool needsCtrlIn, needsCtrlOut;
  671. needsCtrlIn = needsCtrlOut = false;
  672. if (fInfo.aIns > 0)
  673. {
  674. pData->audioIn.createNew(fInfo.aIns);
  675. }
  676. if (fInfo.aOuts > 0)
  677. {
  678. pData->audioOut.createNew(fInfo.aOuts);
  679. needsCtrlIn = true;
  680. }
  681. if (fInfo.mIns > 0)
  682. needsCtrlIn = true;
  683. if (fInfo.mOuts > 0)
  684. needsCtrlOut = true;
  685. const uint portNameSize(pData->engine->getMaxPortNameSize());
  686. CarlaString portName;
  687. // Audio Ins
  688. for (uint8_t j=0; j < fInfo.aIns; ++j)
  689. {
  690. portName.clear();
  691. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  692. {
  693. portName = pData->name;
  694. portName += ":";
  695. }
  696. if (fInfo.aIns > 1)
  697. {
  698. portName += "audio_in_";
  699. portName += CarlaString(j+1);
  700. }
  701. else
  702. {
  703. portName += "audio_in";
  704. }
  705. portName.truncate(portNameSize);
  706. pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
  707. pData->audioIn.ports[j].rindex = j;
  708. }
  709. // Audio Outs
  710. for (uint8_t j=0; j < fInfo.aOuts; ++j)
  711. {
  712. portName.clear();
  713. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  714. {
  715. portName = pData->name;
  716. portName += ":";
  717. }
  718. if (fInfo.aOuts > 1)
  719. {
  720. portName += "audio_out_";
  721. portName += CarlaString(j+1);
  722. }
  723. else
  724. {
  725. portName += "audio_out";
  726. }
  727. portName.truncate(portNameSize);
  728. pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
  729. pData->audioOut.ports[j].rindex = j;
  730. }
  731. if (needsCtrlIn)
  732. {
  733. portName.clear();
  734. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  735. {
  736. portName = pData->name;
  737. portName += ":";
  738. }
  739. portName += "event-in";
  740. portName.truncate(portNameSize);
  741. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  742. }
  743. if (needsCtrlOut)
  744. {
  745. portName.clear();
  746. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  747. {
  748. portName = pData->name;
  749. portName += ":";
  750. }
  751. portName += "event-out";
  752. portName.truncate(portNameSize);
  753. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  754. }
  755. // extra plugin hints
  756. pData->extraHints = 0x0;
  757. if (fInfo.mIns > 0)
  758. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN;
  759. if (fInfo.mOuts > 0)
  760. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT;
  761. bufferSizeChanged(pData->engine->getBufferSize());
  762. reloadPrograms(true);
  763. carla_debug("CarlaPluginJack::reload() - end");
  764. }
  765. // -------------------------------------------------------------------
  766. // Plugin processing
  767. void activate() noexcept override
  768. {
  769. if (! fBridgeThread.isThreadRunning())
  770. {
  771. CARLA_SAFE_ASSERT_RETURN(restartBridgeThread(),);
  772. }
  773. CARLA_SAFE_ASSERT_RETURN(! fTimedError,);
  774. {
  775. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  776. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientActivate);
  777. fShmNonRtClientControl.commitWrite();
  778. }
  779. fTimedOut = false;
  780. try {
  781. waitForClient("activate", 2000);
  782. } CARLA_SAFE_EXCEPTION("activate - waitForClient");
  783. }
  784. void deactivate() noexcept override
  785. {
  786. if (! fBridgeThread.isThreadRunning())
  787. return;
  788. CARLA_SAFE_ASSERT_RETURN(! fTimedError,);
  789. {
  790. const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);
  791. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientDeactivate);
  792. fShmNonRtClientControl.commitWrite();
  793. }
  794. fTimedOut = false;
  795. try {
  796. waitForClient("deactivate", 2000);
  797. } CARLA_SAFE_EXCEPTION("deactivate - waitForClient");
  798. }
  799. void process(const float* const* const audioIn, float** const audioOut,
  800. const float* const*, float**, const uint32_t frames) override
  801. {
  802. // --------------------------------------------------------------------------------------------------------
  803. // Check if active
  804. if (fProcCanceled || fTimedOut || fTimedError || ! pData->active)
  805. {
  806. // disable any output sound
  807. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  808. carla_zeroFloats(audioOut[i], frames);
  809. return;
  810. }
  811. // --------------------------------------------------------------------------------------------------------
  812. // Check if needs reset
  813. if (pData->needsReset)
  814. {
  815. // TODO
  816. pData->needsReset = false;
  817. }
  818. // --------------------------------------------------------------------------------------------------------
  819. // Event Input
  820. if (pData->event.portIn != nullptr)
  821. {
  822. // ----------------------------------------------------------------------------------------------------
  823. // MIDI Input (External)
  824. if (pData->extNotes.mutex.tryLock())
  825. {
  826. for (RtLinkedList<ExternalMidiNote>::Itenerator it = pData->extNotes.data.begin2(); it.valid(); it.next())
  827. {
  828. const ExternalMidiNote& note(it.getValue(kExternalMidiNoteFallback));
  829. CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
  830. uint8_t data1, data2, data3;
  831. data1 = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
  832. data2 = note.note;
  833. data3 = note.velo;
  834. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientMidiEvent);
  835. fShmRtClientControl.writeUInt(0); // time
  836. fShmRtClientControl.writeByte(0); // port
  837. fShmRtClientControl.writeByte(3); // size
  838. fShmRtClientControl.writeByte(data1);
  839. fShmRtClientControl.writeByte(data2);
  840. fShmRtClientControl.writeByte(data3);
  841. fShmRtClientControl.commitWrite();
  842. }
  843. pData->extNotes.data.clear();
  844. pData->extNotes.mutex.unlock();
  845. } // End of MIDI Input (External)
  846. // ----------------------------------------------------------------------------------------------------
  847. // Event Input (System)
  848. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  849. bool allNotesOffSent = false;
  850. #endif
  851. for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
  852. {
  853. const EngineEvent& event(pData->event.portIn->getEvent(i));
  854. // Control change
  855. switch (event.type)
  856. {
  857. case kEngineEventTypeNull:
  858. break;
  859. case kEngineEventTypeControl: {
  860. const EngineControlEvent& ctrlEvent = event.ctrl;
  861. switch (ctrlEvent.type)
  862. {
  863. case kEngineControlEventTypeNull:
  864. break;
  865. case kEngineControlEventTypeParameter:
  866. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  867. // Control backend stuff
  868. if (event.channel == pData->ctrlChannel)
  869. {
  870. float value;
  871. if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) != 0)
  872. {
  873. value = ctrlEvent.normalizedValue;
  874. setDryWetRT(value, true);
  875. }
  876. if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) != 0)
  877. {
  878. value = ctrlEvent.normalizedValue*127.0f/100.0f;
  879. setVolumeRT(value, true);
  880. }
  881. if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) != 0)
  882. {
  883. float left, right;
  884. value = ctrlEvent.normalizedValue/0.5f - 1.0f;
  885. if (value < 0.0f)
  886. {
  887. left = -1.0f;
  888. right = (value*2.0f)+1.0f;
  889. }
  890. else if (value > 0.0f)
  891. {
  892. left = (value*2.0f)-1.0f;
  893. right = 1.0f;
  894. }
  895. else
  896. {
  897. left = -1.0f;
  898. right = 1.0f;
  899. }
  900. setBalanceLeftRT(left, true);
  901. setBalanceRightRT(right, true);
  902. }
  903. }
  904. #endif
  905. if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE)
  906. {
  907. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientMidiEvent);
  908. fShmRtClientControl.writeUInt(event.time);
  909. fShmRtClientControl.writeByte(0); // port
  910. fShmRtClientControl.writeByte(3); // size
  911. fShmRtClientControl.writeByte(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT)));
  912. fShmRtClientControl.writeByte(uint8_t(ctrlEvent.param));
  913. fShmRtClientControl.writeByte(uint8_t(ctrlEvent.normalizedValue*127.0f + 0.5f));
  914. }
  915. break;
  916. case kEngineControlEventTypeMidiBank:
  917. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  918. {
  919. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventMidiBank);
  920. fShmRtClientControl.writeUInt(event.time);
  921. fShmRtClientControl.writeByte(event.channel);
  922. fShmRtClientControl.writeUShort(event.ctrl.param);
  923. fShmRtClientControl.commitWrite();
  924. }
  925. break;
  926. case kEngineControlEventTypeMidiProgram:
  927. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  928. {
  929. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventMidiProgram);
  930. fShmRtClientControl.writeUInt(event.time);
  931. fShmRtClientControl.writeByte(event.channel);
  932. fShmRtClientControl.writeUShort(event.ctrl.param);
  933. fShmRtClientControl.commitWrite();
  934. }
  935. break;
  936. case kEngineControlEventTypeAllSoundOff:
  937. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  938. {
  939. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventAllSoundOff);
  940. fShmRtClientControl.writeUInt(event.time);
  941. fShmRtClientControl.writeByte(event.channel);
  942. fShmRtClientControl.commitWrite();
  943. }
  944. break;
  945. case kEngineControlEventTypeAllNotesOff:
  946. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  947. {
  948. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  949. if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
  950. {
  951. allNotesOffSent = true;
  952. postponeRtAllNotesOff();
  953. }
  954. #endif
  955. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventAllNotesOff);
  956. fShmRtClientControl.writeUInt(event.time);
  957. fShmRtClientControl.writeByte(event.channel);
  958. fShmRtClientControl.commitWrite();
  959. }
  960. break;
  961. } // switch (ctrlEvent.type)
  962. break;
  963. } // case kEngineEventTypeControl
  964. case kEngineEventTypeMidi: {
  965. const EngineMidiEvent& midiEvent(event.midi);
  966. if (midiEvent.size == 0 || midiEvent.size >= MAX_MIDI_VALUE)
  967. continue;
  968. const uint8_t* const midiData(midiEvent.size > EngineMidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data);
  969. uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiData));
  970. if ((status == MIDI_STATUS_NOTE_OFF || status == MIDI_STATUS_NOTE_ON) && (pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES))
  971. continue;
  972. if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
  973. continue;
  974. if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
  975. continue;
  976. if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
  977. continue;
  978. if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
  979. continue;
  980. // Fix bad note-off
  981. if (status == MIDI_STATUS_NOTE_ON && midiData[2] == 0)
  982. status = MIDI_STATUS_NOTE_OFF;
  983. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientMidiEvent);
  984. fShmRtClientControl.writeUInt(event.time);
  985. fShmRtClientControl.writeByte(midiEvent.port);
  986. fShmRtClientControl.writeByte(midiEvent.size);
  987. fShmRtClientControl.writeByte(uint8_t(midiData[0] | (event.channel & MIDI_CHANNEL_BIT)));
  988. for (uint8_t j=1; j < midiEvent.size; ++j)
  989. fShmRtClientControl.writeByte(midiData[j]);
  990. fShmRtClientControl.commitWrite();
  991. if (status == MIDI_STATUS_NOTE_ON)
  992. {
  993. pData->postponeNoteOnRtEvent(true, event.channel, midiData[1], midiData[2]);
  994. }
  995. else if (status == MIDI_STATUS_NOTE_OFF)
  996. {
  997. pData->postponeNoteOffRtEvent(true, event.channel, midiData[1]);
  998. }
  999. } break;
  1000. }
  1001. }
  1002. pData->postRtEvents.trySplice();
  1003. } // End of Event Input
  1004. if (! processSingle(audioIn, audioOut, frames))
  1005. return;
  1006. // --------------------------------------------------------------------------------------------------------
  1007. // MIDI Output
  1008. if (pData->event.portOut != nullptr)
  1009. {
  1010. uint32_t time;
  1011. uint8_t port, size;
  1012. const uint8_t* midiData(fShmRtClientControl.data->midiOut);
  1013. for (std::size_t read=0; read<kBridgeRtClientDataMidiOutSize-kBridgeBaseMidiOutHeaderSize;)
  1014. {
  1015. // get time
  1016. time = *(const uint32_t*)midiData;
  1017. midiData += 4;
  1018. // get port and size
  1019. port = *midiData++;
  1020. size = *midiData++;
  1021. if (size == 0)
  1022. break;
  1023. // store midi data advancing as needed
  1024. uint8_t data[size];
  1025. for (uint8_t j=0; j<size; ++j)
  1026. data[j] = *midiData++;
  1027. pData->event.portOut->writeMidiEvent(time, size, data);
  1028. read += kBridgeBaseMidiOutHeaderSize + size;
  1029. }
  1030. // TODO
  1031. (void)port;
  1032. } // End of Control and MIDI Output
  1033. }
  1034. bool processSingle(const float* const* const audioIn, float** const audioOut, const uint32_t frames)
  1035. {
  1036. CARLA_SAFE_ASSERT_RETURN(! fTimedError, false);
  1037. CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
  1038. CARLA_SAFE_ASSERT_RETURN(frames <= fBufferSize, false);
  1039. if (pData->audioIn.count > 0)
  1040. {
  1041. CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false);
  1042. }
  1043. if (pData->audioOut.count > 0)
  1044. {
  1045. CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false);
  1046. }
  1047. // --------------------------------------------------------------------------------------------------------
  1048. // Try lock, silence otherwise
  1049. #ifndef STOAT_TEST_BUILD
  1050. if (pData->engine->isOffline())
  1051. {
  1052. pData->singleMutex.lock();
  1053. }
  1054. else
  1055. #endif
  1056. if (! pData->singleMutex.tryLock())
  1057. {
  1058. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1059. carla_zeroFloats(audioOut[i], frames);
  1060. return false;
  1061. }
  1062. // --------------------------------------------------------------------------------------------------------
  1063. // Reset audio buffers
  1064. for (uint32_t i=0; i < fInfo.aIns; ++i)
  1065. carla_copyFloats(fShmAudioPool.data + (i * fBufferSize), audioIn[i], frames);
  1066. // --------------------------------------------------------------------------------------------------------
  1067. // TimeInfo
  1068. const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
  1069. BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);
  1070. bridgeTimeInfo.playing = timeInfo.playing;
  1071. bridgeTimeInfo.frame = timeInfo.frame;
  1072. bridgeTimeInfo.usecs = timeInfo.usecs;
  1073. bridgeTimeInfo.validFlags = timeInfo.bbt.valid ? kPluginBridgeTimeInfoValidBBT : 0x0;
  1074. if (timeInfo.bbt.valid)
  1075. {
  1076. bridgeTimeInfo.bar = timeInfo.bbt.bar;
  1077. bridgeTimeInfo.beat = timeInfo.bbt.beat;
  1078. bridgeTimeInfo.tick = timeInfo.bbt.tick;
  1079. bridgeTimeInfo.beatsPerBar = timeInfo.bbt.beatsPerBar;
  1080. bridgeTimeInfo.beatType = timeInfo.bbt.beatType;
  1081. bridgeTimeInfo.ticksPerBeat = timeInfo.bbt.ticksPerBeat;
  1082. bridgeTimeInfo.beatsPerMinute = timeInfo.bbt.beatsPerMinute;
  1083. bridgeTimeInfo.barStartTick = timeInfo.bbt.barStartTick;
  1084. }
  1085. // --------------------------------------------------------------------------------------------------------
  1086. // Run plugin
  1087. {
  1088. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientProcess);
  1089. fShmRtClientControl.writeUInt(frames);
  1090. fShmRtClientControl.commitWrite();
  1091. }
  1092. waitForClient("process", fProcWaitTime);
  1093. if (fTimedOut)
  1094. {
  1095. pData->singleMutex.unlock();
  1096. return false;
  1097. }
  1098. if (fShmRtClientControl.data->procFlags)
  1099. {
  1100. fInitiated = false;
  1101. fProcCanceled = true;
  1102. }
  1103. for (uint32_t i=0; i < fInfo.aOuts; ++i)
  1104. carla_copyFloats(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * fBufferSize), frames);
  1105. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1106. // --------------------------------------------------------------------------------------------------------
  1107. // Post-processing (dry/wet, volume and balance)
  1108. {
  1109. const bool doVolume = (pData->hints & PLUGIN_CAN_VOLUME) != 0 && carla_isNotEqual(pData->postProc.volume, 1.0f);
  1110. const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
  1111. const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
  1112. const bool isMono = (pData->audioIn.count == 1);
  1113. bool isPair;
  1114. float bufValue;
  1115. float* const oldBufLeft = pData->postProc.extraBuffer;
  1116. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1117. {
  1118. // Dry/Wet
  1119. if (doDryWet)
  1120. {
  1121. const uint32_t c = isMono ? 0 : i;
  1122. for (uint32_t k=0; k < frames; ++k)
  1123. {
  1124. bufValue = audioIn[c][k];
  1125. audioOut[i][k] = (audioOut[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
  1126. }
  1127. }
  1128. // Balance
  1129. if (doBalance)
  1130. {
  1131. isPair = (i % 2 == 0);
  1132. if (isPair)
  1133. {
  1134. CARLA_ASSERT(i+1 < pData->audioOut.count);
  1135. carla_copyFloats(oldBufLeft, audioOut[i], frames);
  1136. }
  1137. float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
  1138. float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
  1139. for (uint32_t k=0; k < frames; ++k)
  1140. {
  1141. if (isPair)
  1142. {
  1143. // left
  1144. audioOut[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
  1145. audioOut[i][k] += audioOut[i+1][k] * (1.0f - balRangeR);
  1146. }
  1147. else
  1148. {
  1149. // right
  1150. audioOut[i][k] = audioOut[i][k] * balRangeR;
  1151. audioOut[i][k] += oldBufLeft[k] * balRangeL;
  1152. }
  1153. }
  1154. }
  1155. // Volume
  1156. if (doVolume)
  1157. {
  1158. for (uint32_t k=0; k < frames; ++k)
  1159. audioOut[i][k] *= pData->postProc.volume;
  1160. }
  1161. }
  1162. } // End of Post-processing
  1163. #endif
  1164. // --------------------------------------------------------------------------------------------------------
  1165. pData->singleMutex.unlock();
  1166. return true;
  1167. }
  1168. void bufferSizeChanged(const uint32_t newBufferSize) override
  1169. {
  1170. fBufferSize = newBufferSize;
  1171. resizeAudioPool(newBufferSize);
  1172. {
  1173. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetBufferSize);
  1174. fShmRtClientControl.writeUInt(newBufferSize);
  1175. fShmRtClientControl.commitWrite();
  1176. }
  1177. //fProcWaitTime = newBufferSize*1000/pData->engine->getSampleRate();
  1178. fProcWaitTime = 1000;
  1179. waitForClient("buffersize", 1000);
  1180. }
  1181. void sampleRateChanged(const double newSampleRate) override
  1182. {
  1183. {
  1184. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetSampleRate);
  1185. fShmRtClientControl.writeDouble(newSampleRate);
  1186. fShmRtClientControl.commitWrite();
  1187. }
  1188. //fProcWaitTime = pData->engine->getBufferSize()*1000/newSampleRate;
  1189. fProcWaitTime = 1000;
  1190. waitForClient("samplerate", 1000);
  1191. }
  1192. void offlineModeChanged(const bool isOffline) override
  1193. {
  1194. {
  1195. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetOnline);
  1196. fShmRtClientControl.writeBool(isOffline);
  1197. fShmRtClientControl.commitWrite();
  1198. }
  1199. waitForClient("offline", 1000);
  1200. }
  1201. // -------------------------------------------------------------------
  1202. // Post-poned UI Stuff
  1203. // -------------------------------------------------------------------
  1204. void handleNonRtData()
  1205. {
  1206. for (; fShmNonRtServerControl.isDataAvailableForReading();)
  1207. {
  1208. const PluginBridgeNonRtServerOpcode opcode(fShmNonRtServerControl.readOpcode());
  1209. //#ifdef DEBUG
  1210. if (opcode != kPluginBridgeNonRtServerPong)
  1211. {
  1212. carla_debug("CarlaPluginJack::handleNonRtData() - got opcode: %s", PluginBridgeNonRtServerOpcode2str(opcode));
  1213. }
  1214. //#endif
  1215. switch (opcode)
  1216. {
  1217. case kPluginBridgeNonRtServerNull:
  1218. case kPluginBridgeNonRtServerPong:
  1219. case kPluginBridgeNonRtServerPluginInfo1:
  1220. case kPluginBridgeNonRtServerPluginInfo2:
  1221. case kPluginBridgeNonRtServerAudioCount:
  1222. case kPluginBridgeNonRtServerMidiCount:
  1223. case kPluginBridgeNonRtServerCvCount:
  1224. case kPluginBridgeNonRtServerParameterCount:
  1225. case kPluginBridgeNonRtServerProgramCount:
  1226. case kPluginBridgeNonRtServerMidiProgramCount:
  1227. case kPluginBridgeNonRtServerPortName:
  1228. case kPluginBridgeNonRtServerParameterData1:
  1229. case kPluginBridgeNonRtServerParameterData2:
  1230. case kPluginBridgeNonRtServerParameterRanges:
  1231. case kPluginBridgeNonRtServerParameterValue:
  1232. case kPluginBridgeNonRtServerParameterValue2:
  1233. case kPluginBridgeNonRtServerParameterTouch:
  1234. case kPluginBridgeNonRtServerDefaultValue:
  1235. case kPluginBridgeNonRtServerCurrentProgram:
  1236. case kPluginBridgeNonRtServerCurrentMidiProgram:
  1237. case kPluginBridgeNonRtServerProgramName:
  1238. case kPluginBridgeNonRtServerMidiProgramData:
  1239. case kPluginBridgeNonRtServerSetCustomData:
  1240. case kPluginBridgeNonRtServerVersion:
  1241. case kPluginBridgeNonRtServerRespEmbedUI:
  1242. case kPluginBridgeNonRtServerResizeEmbedUI:
  1243. break;
  1244. case kPluginBridgeNonRtServerSetChunkDataFile:
  1245. // uint/size, str[] (filename)
  1246. if (const uint32_t chunkFilePathSize = fShmNonRtServerControl.readUInt())
  1247. {
  1248. char chunkFilePath[chunkFilePathSize];
  1249. fShmNonRtServerControl.readCustomData(chunkFilePath, chunkFilePathSize);
  1250. }
  1251. break;
  1252. case kPluginBridgeNonRtServerSetLatency:
  1253. case kPluginBridgeNonRtServerSetParameterText:
  1254. break;
  1255. case kPluginBridgeNonRtServerReady:
  1256. fInitiated = true;
  1257. break;
  1258. case kPluginBridgeNonRtServerSaved:
  1259. break;
  1260. case kPluginBridgeNonRtServerUiClosed:
  1261. pData->engine->callback(true, true,
  1262. ENGINE_CALLBACK_UI_STATE_CHANGED,
  1263. pData->id,
  1264. 0,
  1265. 0, 0, 0.0f, nullptr);
  1266. break;
  1267. case kPluginBridgeNonRtServerError: {
  1268. // error
  1269. const uint32_t errorSize(fShmNonRtServerControl.readUInt());
  1270. char error[errorSize+1];
  1271. carla_zeroChars(error, errorSize+1);
  1272. fShmNonRtServerControl.readCustomData(error, errorSize);
  1273. if (fInitiated)
  1274. {
  1275. pData->engine->callback(true, true, ENGINE_CALLBACK_ERROR, pData->id, 0, 0, 0, 0.0f, error);
  1276. // just in case
  1277. pData->engine->setLastError(error);
  1278. fInitError = true;
  1279. }
  1280. else
  1281. {
  1282. pData->engine->setLastError(error);
  1283. fInitError = true;
  1284. fInitiated = true;
  1285. }
  1286. } break;
  1287. }
  1288. }
  1289. }
  1290. // -------------------------------------------------------------------
  1291. uintptr_t getUiBridgeProcessId() const noexcept override
  1292. {
  1293. return fBridgeThread.getProcessID();
  1294. }
  1295. // -------------------------------------------------------------------
  1296. bool init(const CarlaPluginPtr plugin,
  1297. const char* const filename, const char* const name, const char* const label, const uint options)
  1298. {
  1299. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  1300. // ---------------------------------------------------------------
  1301. // first checks
  1302. if (pData->client != nullptr)
  1303. {
  1304. pData->engine->setLastError("Plugin client is already registered");
  1305. return false;
  1306. }
  1307. if (filename == nullptr || filename[0] == '\0')
  1308. {
  1309. pData->engine->setLastError("null filename");
  1310. return false;
  1311. }
  1312. if (label == nullptr || label[0] == '\0')
  1313. {
  1314. pData->engine->setLastError("null label");
  1315. return false;
  1316. }
  1317. // ---------------------------------------------------------------
  1318. // check setup
  1319. if (std::strlen(label) < 6)
  1320. {
  1321. pData->engine->setLastError("invalid application setup received");
  1322. return false;
  1323. }
  1324. for (int i=4; --i >= 0;) {
  1325. CARLA_SAFE_ASSERT_INT2_RETURN(label[i] >= '0' && label[i] <= '0'+64, i, label[i], false);
  1326. }
  1327. CARLA_SAFE_ASSERT_INT2_RETURN(label[4] >= '0' && label[4] < '0'+0x4f, 4, label[4], false);
  1328. CARLA_SAFE_ASSERT_UINT2_RETURN(static_cast<uchar>(label[5]) >= '0' &&
  1329. static_cast<uchar>(label[5]) <= '0'+0x73,
  1330. static_cast<uchar>(label[5]),
  1331. static_cast<uchar>('0'+0x73),
  1332. false);
  1333. fInfo.aIns = static_cast<uint8_t>(label[0] - '0');
  1334. fInfo.aOuts = static_cast<uint8_t>(label[1] - '0');
  1335. fInfo.mIns = static_cast<uint8_t>(carla_minPositive(label[2] - '0', 1));
  1336. fInfo.mOuts = static_cast<uint8_t>(carla_minPositive(label[3] - '0', 1));
  1337. fInfo.setupLabel = label;
  1338. // ---------------------------------------------------------------
  1339. // set project unique id
  1340. if (label[6] == '\0')
  1341. setupUniqueProjectID();
  1342. // ---------------------------------------------------------------
  1343. // set icon
  1344. pData->iconName = carla_strdup_safe("application");
  1345. // ---------------------------------------------------------------
  1346. // set info
  1347. pData->filename = carla_strdup(filename);
  1348. if (name != nullptr && name[0] != '\0')
  1349. pData->name = pData->engine->getUniquePluginName(name);
  1350. else
  1351. pData->name = pData->engine->getUniquePluginName("Jack Application");
  1352. std::srand(static_cast<uint>(std::time(nullptr)));
  1353. // ---------------------------------------------------------------
  1354. // init sem/shm
  1355. if (! fShmAudioPool.initializeServer())
  1356. {
  1357. carla_stderr("Failed to initialize shared memory audio pool");
  1358. return false;
  1359. }
  1360. if (! fShmRtClientControl.initializeServer())
  1361. {
  1362. carla_stderr("Failed to initialize RT client control");
  1363. fShmAudioPool.clear();
  1364. return false;
  1365. }
  1366. if (! fShmNonRtClientControl.initializeServer())
  1367. {
  1368. carla_stderr("Failed to initialize Non-RT client control");
  1369. fShmRtClientControl.clear();
  1370. fShmAudioPool.clear();
  1371. return false;
  1372. }
  1373. if (! fShmNonRtServerControl.initializeServer())
  1374. {
  1375. carla_stderr("Failed to initialize Non-RT server control");
  1376. fShmNonRtClientControl.clear();
  1377. fShmRtClientControl.clear();
  1378. fShmAudioPool.clear();
  1379. return false;
  1380. }
  1381. // ---------------------------------------------------------------
  1382. // setup hints and options
  1383. fSetupHints = static_cast<uint>(static_cast<uchar>(label[5]) - '0');
  1384. // FIXME dryWet broken
  1385. pData->hints = PLUGIN_IS_BRIDGE;
  1386. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1387. pData->hints |= /*PLUGIN_CAN_DRYWET |*/ PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE;
  1388. #endif
  1389. if (fSetupHints & LIBJACK_FLAG_CONTROL_WINDOW)
  1390. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  1391. // ---------------------------------------------------------------
  1392. // init bridge thread
  1393. {
  1394. char shmIdsStr[6*4+1];
  1395. carla_zeroChars(shmIdsStr, 6*4+1);
  1396. std::strncpy(shmIdsStr+6*0, &fShmAudioPool.filename[fShmAudioPool.filename.length()-6], 6);
  1397. std::strncpy(shmIdsStr+6*1, &fShmRtClientControl.filename[fShmRtClientControl.filename.length()-6], 6);
  1398. std::strncpy(shmIdsStr+6*2, &fShmNonRtClientControl.filename[fShmNonRtClientControl.filename.length()-6], 6);
  1399. std::strncpy(shmIdsStr+6*3, &fShmNonRtServerControl.filename[fShmNonRtServerControl.filename.length()-6], 6);
  1400. fBridgeThread.setData(shmIdsStr, fInfo.setupLabel);
  1401. }
  1402. if (! restartBridgeThread())
  1403. return false;
  1404. // ---------------------------------------------------------------
  1405. // register client
  1406. if (pData->name == nullptr)
  1407. pData->name = pData->engine->getUniquePluginName("unknown");
  1408. pData->client = pData->engine->addClient(plugin);
  1409. if (pData->client == nullptr || ! pData->client->isOk())
  1410. {
  1411. pData->engine->setLastError("Failed to register plugin client");
  1412. return false;
  1413. }
  1414. // remove unprintable characters if needed
  1415. if (fSetupHints & LIBJACK_FLAG_EXTERNAL_START)
  1416. fInfo.setupLabel[5U] = static_cast<char>('0' + (fSetupHints ^ LIBJACK_FLAG_EXTERNAL_START));
  1417. // ---------------------------------------------------------------
  1418. // set options
  1419. pData->options = PLUGIN_OPTION_FIXED_BUFFERS;
  1420. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
  1421. pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  1422. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
  1423. pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  1424. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
  1425. pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  1426. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
  1427. pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
  1428. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
  1429. pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  1430. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PROGRAM_CHANGES))
  1431. pData->options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  1432. if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
  1433. pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  1434. return true;
  1435. }
  1436. private:
  1437. bool fInitiated;
  1438. bool fInitError;
  1439. bool fTimedOut;
  1440. bool fTimedError;
  1441. bool fProcCanceled;
  1442. uint fBufferSize;
  1443. uint fProcWaitTime;
  1444. uint fSetupHints;
  1445. CarlaPluginJackThread fBridgeThread;
  1446. BridgeAudioPool fShmAudioPool;
  1447. BridgeRtClientControl fShmRtClientControl;
  1448. BridgeNonRtClientControl fShmNonRtClientControl;
  1449. BridgeNonRtServerControl fShmNonRtServerControl;
  1450. struct Info {
  1451. uint8_t aIns, aOuts;
  1452. uint8_t mIns, mOuts;
  1453. CarlaString setupLabel;
  1454. std::vector<uint8_t> chunk;
  1455. Info()
  1456. : aIns(0),
  1457. aOuts(0),
  1458. mIns(0),
  1459. mOuts(0),
  1460. setupLabel(),
  1461. chunk() {}
  1462. CARLA_DECLARE_NON_COPYABLE(Info)
  1463. } fInfo;
  1464. void handleProcessStopped() noexcept
  1465. {
  1466. const bool wasActive = pData->active;
  1467. pData->active = false;
  1468. if (wasActive)
  1469. {
  1470. pData->engine->callback(true, true,
  1471. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1472. pData->id,
  1473. PARAMETER_ACTIVE,
  1474. 0, 0,
  1475. 0.0f,
  1476. nullptr);
  1477. }
  1478. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  1479. pData->engine->callback(true, true,
  1480. ENGINE_CALLBACK_UI_STATE_CHANGED,
  1481. pData->id,
  1482. 0,
  1483. 0, 0, 0.0f, nullptr);
  1484. }
  1485. void resizeAudioPool(const uint32_t bufferSize)
  1486. {
  1487. fShmAudioPool.resize(bufferSize, static_cast<uint32_t>(fInfo.aIns+fInfo.aOuts), 0);
  1488. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetAudioPool);
  1489. fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.dataSize));
  1490. fShmRtClientControl.commitWrite();
  1491. waitForClient("resize-pool", 5000);
  1492. }
  1493. void setupUniqueProjectID()
  1494. {
  1495. const char* const engineProjectFolder = pData->engine->getCurrentProjectFolder();
  1496. carla_stdout("setupUniqueProjectID %s", engineProjectFolder);
  1497. if (engineProjectFolder == nullptr || engineProjectFolder[0] == '\0')
  1498. return;
  1499. const File file(engineProjectFolder);
  1500. CARLA_SAFE_ASSERT_RETURN(file.exists(),);
  1501. char code[6];
  1502. code[5] = '\0';
  1503. String child;
  1504. for (;;)
  1505. {
  1506. static const char* const kValidChars =
  1507. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  1508. "abcdefghijklmnopqrstuvwxyz"
  1509. "0123456789";
  1510. static const size_t kValidCharsLen(std::strlen(kValidChars)-1U);
  1511. code[0] = kValidChars[safe_rand(kValidCharsLen)];
  1512. code[1] = kValidChars[safe_rand(kValidCharsLen)];
  1513. code[2] = kValidChars[safe_rand(kValidCharsLen)];
  1514. code[3] = kValidChars[safe_rand(kValidCharsLen)];
  1515. code[4] = kValidChars[safe_rand(kValidCharsLen)];
  1516. child = pData->name;
  1517. child += ".";
  1518. child += code;
  1519. const File newFile(file.getChildFile(child));
  1520. if (newFile.existsAsFile())
  1521. continue;
  1522. fInfo.setupLabel += code;
  1523. carla_stdout("new label %s", fInfo.setupLabel.buffer());
  1524. break;
  1525. }
  1526. }
  1527. bool restartBridgeThread()
  1528. {
  1529. fInitiated = false;
  1530. fInitError = false;
  1531. fTimedError = false;
  1532. // reset memory
  1533. fProcCanceled = false;
  1534. fShmRtClientControl.data->procFlags = 0;
  1535. carla_zeroStruct(fShmRtClientControl.data->timeInfo);
  1536. carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize);
  1537. fShmRtClientControl.clearData();
  1538. fShmNonRtClientControl.clearData();
  1539. fShmNonRtServerControl.clearData();
  1540. // initial values
  1541. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientVersion);
  1542. fShmNonRtClientControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION_CURRENT);
  1543. fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeRtClientData)));
  1544. fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtClientData)));
  1545. fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtServerData)));
  1546. fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientInitialSetup);
  1547. fShmNonRtClientControl.writeUInt(pData->engine->getBufferSize());
  1548. fShmNonRtClientControl.writeDouble(pData->engine->getSampleRate());
  1549. fShmNonRtClientControl.commitWrite();
  1550. if (fShmAudioPool.dataSize != 0)
  1551. {
  1552. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetAudioPool);
  1553. fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.dataSize));
  1554. fShmRtClientControl.commitWrite();
  1555. }
  1556. else
  1557. {
  1558. // testing dummy message
  1559. fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull);
  1560. fShmRtClientControl.commitWrite();
  1561. }
  1562. fBridgeThread.startThread();
  1563. const bool needsCancelableAction = ! pData->engine->isLoadingProject();
  1564. const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;
  1565. CarlaString actionName;
  1566. if (needsCancelableAction)
  1567. {
  1568. if (fSetupHints & LIBJACK_FLAG_EXTERNAL_START)
  1569. {
  1570. const EngineOptions& options(pData->engine->getOptions());
  1571. CarlaString binaryDir(options.binaryDir);
  1572. char* const hwVars = fBridgeThread.getEnvVarsToExport();
  1573. actionName = "Waiting for external JACK application start, please use the following environment variables:\n";
  1574. actionName += hwVars;
  1575. delete[] hwVars;
  1576. }
  1577. else
  1578. {
  1579. actionName = "Loading JACK application";
  1580. }
  1581. pData->engine->setActionCanceled(false);
  1582. pData->engine->callback(true, true,
  1583. ENGINE_CALLBACK_CANCELABLE_ACTION,
  1584. pData->id,
  1585. 1,
  1586. 0, 0, 0.0f,
  1587. actionName.buffer());
  1588. }
  1589. for (;fBridgeThread.isThreadRunning();)
  1590. {
  1591. pData->engine->callback(true, false, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
  1592. if (needsEngineIdle)
  1593. pData->engine->idle();
  1594. idle();
  1595. if (fInitiated)
  1596. break;
  1597. if (pData->engine->isAboutToClose() || pData->engine->wasActionCanceled())
  1598. break;
  1599. carla_msleep(5);
  1600. }
  1601. if (needsCancelableAction)
  1602. {
  1603. pData->engine->callback(true, true,
  1604. ENGINE_CALLBACK_CANCELABLE_ACTION,
  1605. pData->id,
  1606. 0,
  1607. 0, 0, 0.0f,
  1608. actionName.buffer());
  1609. }
  1610. if (fInitError || ! fInitiated)
  1611. {
  1612. fBridgeThread.stopThread(6000);
  1613. if (! fInitError)
  1614. pData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n"
  1615. "(or the plugin crashed on initialization?)");
  1616. return false;
  1617. }
  1618. return true;
  1619. }
  1620. void waitForClient(const char* const action, const uint msecs)
  1621. {
  1622. CARLA_SAFE_ASSERT_RETURN(! fTimedOut,);
  1623. CARLA_SAFE_ASSERT_RETURN(! fTimedError,);
  1624. if (fShmRtClientControl.waitForClient(msecs))
  1625. return;
  1626. fTimedOut = true;
  1627. carla_stderr2("waitForClient(%s) timed out", action);
  1628. }
  1629. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginJack)
  1630. };
  1631. CARLA_BACKEND_END_NAMESPACE
  1632. #endif // CARLA_OS_LINUX
  1633. // -------------------------------------------------------------------------------------------------------------------
  1634. CARLA_BACKEND_START_NAMESPACE
  1635. CarlaPluginPtr CarlaPlugin::newJackApp(const Initializer& init)
  1636. {
  1637. carla_debug("CarlaPlugin::newJackApp({%p, \"%s\", \"%s\", \"%s\"})",
  1638. init.engine, init.filename, init.name, init.label);
  1639. #if defined(CARLA_OS_LINUX) || defined(CARLA_OS_MAC)
  1640. std::shared_ptr<CarlaPluginJack> plugin(new CarlaPluginJack(init.engine, init.id));
  1641. if (! plugin->init(plugin, init.filename, init.name, init.label, init.options))
  1642. return nullptr;
  1643. return plugin;
  1644. #else
  1645. init.engine->setLastError("JACK Application support not available");
  1646. return nullptr;
  1647. #endif
  1648. }
  1649. CARLA_BACKEND_END_NAMESPACE
  1650. // -------------------------------------------------------------------------------------------------------------------