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.

CarlaPluginDSSI.cpp 104KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
11 years ago
11 years ago
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
10 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
10 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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
10 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
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
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
11 years ago
11 years ago
11 years ago
10 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
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887
  1. /*
  2. * Carla Plugin, DSSI implementation
  3. * Copyright (C) 2011-2015 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 "CarlaEngineUtils.hpp"
  19. #include "CarlaDssiUtils.hpp"
  20. #include "CarlaMathUtils.hpp"
  21. #ifdef HAVE_LIBLO
  22. # include "CarlaOscUtils.hpp"
  23. # include "CarlaPipeUtils.hpp"
  24. # include "CarlaThread.hpp"
  25. #endif
  26. using juce::ChildProcess;
  27. using juce::ScopedPointer;
  28. using juce::String;
  29. using juce::StringArray;
  30. #define CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \
  31. /* check argument count */ \
  32. if (argc != argcToCompare) \
  33. { \
  34. carla_stderr("CarlaPluginDSSI::%s() - argument count mismatch: %i != %i", __FUNCTION__, argc, argcToCompare); \
  35. return; \
  36. } \
  37. if (argc > 0) \
  38. { \
  39. /* check for nullness */ \
  40. if (types == nullptr || typesToCompare == nullptr) \
  41. { \
  42. carla_stderr("CarlaPluginDSSI::%s() - argument types are null", __FUNCTION__); \
  43. return; \
  44. } \
  45. /* check argument types */ \
  46. if (std::strcmp(types, typesToCompare) != 0) \
  47. { \
  48. carla_stderr("CarlaPluginDSSI::%s() - argument types mismatch: '%s' != '%s'", __FUNCTION__, types, typesToCompare); \
  49. return; \
  50. } \
  51. }
  52. CARLA_BACKEND_START_NAMESPACE
  53. // -------------------------------------------------------------------
  54. // Fallback data
  55. static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
  56. #ifdef HAVE_LIBLO
  57. // -------------------------------------------------------------------
  58. class CarlaThreadDSSIUI : public CarlaThread
  59. {
  60. public:
  61. CarlaThreadDSSIUI(CarlaEngine* const engine, CarlaPlugin* const plugin, const CarlaOscData& oscData) noexcept
  62. : CarlaThread("CarlaThreadDSSIUI"),
  63. kEngine(engine),
  64. kPlugin(plugin),
  65. fBinary(),
  66. fLabel(),
  67. fOscData(oscData),
  68. fProcess(),
  69. leakDetector_CarlaThreadDSSIUI() {}
  70. void setData(const char* const binary, const char* const label) noexcept
  71. {
  72. CARLA_SAFE_ASSERT_RETURN(binary != nullptr && binary[0] != '\0',);
  73. CARLA_SAFE_ASSERT_RETURN(label != nullptr /*&& label[0] != '\0'*/,);
  74. CARLA_SAFE_ASSERT(! isThreadRunning());
  75. fBinary = binary;
  76. fLabel = label;
  77. if (fLabel.isEmpty())
  78. fLabel = "\"\"";
  79. }
  80. uintptr_t getProcessPID() const noexcept
  81. {
  82. CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0);
  83. return (uintptr_t)fProcess->getPID();
  84. }
  85. void run()
  86. {
  87. if (fProcess == nullptr)
  88. {
  89. fProcess = new ChildProcess();
  90. }
  91. else if (fProcess->isRunning())
  92. {
  93. carla_stderr("CarlaThreadDSSI::run() - already running, giving up...");
  94. kEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, kPlugin->getId(), 0, 0, 0.0f, nullptr);
  95. fProcess->kill();
  96. fProcess = nullptr;
  97. return;
  98. }
  99. String name(kPlugin->getName());
  100. String filename(kPlugin->getFilename());
  101. if (name.isEmpty())
  102. name = "(none)";
  103. if (filename.isEmpty())
  104. filename = "\"\"";
  105. StringArray arguments;
  106. // binary
  107. arguments.add(fBinary.buffer());
  108. // osc-url
  109. arguments.add(String(kEngine->getOscServerPathUDP()) + String("/") + String(kPlugin->getId()));
  110. // filename
  111. arguments.add(filename);
  112. // label
  113. arguments.add(fLabel.buffer());
  114. // ui-title
  115. arguments.add(name + String(" (GUI)"));
  116. bool started;
  117. {
  118. #ifdef CARLA_OS_LINUX
  119. /*
  120. * If the frontend uses winId parent, set LD_PRELOAD to auto-map the DSSI UI.
  121. * If not, unset LD_PRELOAD.
  122. */
  123. const uintptr_t winId(kEngine->getOptions().frontendWinId);
  124. // for CARLA_ENGINE_OPTION_FRONTEND_WIN_ID
  125. char winIdStr[STR_MAX+1];
  126. winIdStr[STR_MAX] = '\0';
  127. // for LD_PRELOAD
  128. CarlaString ldPreloadValue;
  129. if (winId != 0)
  130. {
  131. std::snprintf(winIdStr, STR_MAX, P_UINTPTR, kEngine->getOptions().frontendWinId);
  132. ldPreloadValue = (CarlaString(kEngine->getOptions().binaryDir) + CARLA_OS_SEP_STR "libcarla_interposer-x11.so");
  133. }
  134. const ScopedEngineEnvironmentLocker _seel(kEngine);
  135. const ScopedEnvVar _sev1("CARLA_ENGINE_OPTION_FRONTEND_WIN_ID", winIdStr[0] != '\0' ? winIdStr : nullptr);
  136. const ScopedEnvVar _sev2("LD_PRELOAD", ldPreloadValue.isNotEmpty() ? ldPreloadValue.buffer() : nullptr);
  137. #endif // CARLA_OS_LINUX
  138. // start the DSSI UI application
  139. carla_stdout("starting DSSI UI...");
  140. started = fProcess->start(arguments);
  141. }
  142. if (! started)
  143. {
  144. carla_stdout("failed!");
  145. fProcess = nullptr;
  146. return;
  147. }
  148. if (waitForOscGuiShow())
  149. {
  150. for (; fProcess->isRunning() && ! shouldThreadExit();)
  151. carla_sleep(1);
  152. // we only get here if UI was closed or thread asked to exit
  153. if (fProcess->isRunning() && shouldThreadExit())
  154. {
  155. fProcess->waitForProcessToFinish(static_cast<int>(kEngine->getOptions().uiBridgesTimeout));
  156. if (fProcess->isRunning())
  157. {
  158. carla_stdout("CarlaThreadDSSIUI::run() - UI refused to close, force kill now");
  159. fProcess->kill();
  160. }
  161. else
  162. {
  163. carla_stdout("CarlaThreadDSSIUI::run() - UI auto-closed successfully");
  164. }
  165. }
  166. else if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/)
  167. carla_stderr("CarlaThreadDSSIUI::run() - UI crashed while running");
  168. else
  169. carla_stdout("CarlaThreadDSSIUI::run() - UI closed cleanly");
  170. kEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, kPlugin->getId(), 0, 0, 0.0f, nullptr);
  171. }
  172. else
  173. {
  174. fProcess->kill();
  175. carla_stdout("CarlaThreadDSSIUI::run() - GUI timeout");
  176. kEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, kPlugin->getId(), 0, 0, 0.0f, nullptr);
  177. }
  178. carla_stdout("DSSI UI finished");
  179. fProcess = nullptr;
  180. }
  181. private:
  182. CarlaEngine* const kEngine;
  183. CarlaPlugin* const kPlugin;
  184. CarlaString fBinary;
  185. CarlaString fLabel;
  186. const CarlaOscData& fOscData;
  187. ScopedPointer<ChildProcess> fProcess;
  188. bool waitForOscGuiShow()
  189. {
  190. carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow()");
  191. uint i=0, oscUiTimeout = kEngine->getOptions().uiBridgesTimeout;
  192. // wait for UI 'update' call
  193. for (; i < oscUiTimeout/100; ++i)
  194. {
  195. if (fOscData.target != nullptr)
  196. {
  197. carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow() - got response, asking UI to show itself now");
  198. osc_send_show(fOscData);
  199. return true;
  200. }
  201. if (fProcess != nullptr && fProcess->isRunning())
  202. carla_msleep(100);
  203. else
  204. return false;
  205. }
  206. carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow() - Timeout while waiting for UI to respond (waited %u msecs)", oscUiTimeout);
  207. return false;
  208. }
  209. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThreadDSSIUI)
  210. };
  211. #endif
  212. // -----------------------------------------------------
  213. class CarlaPluginDSSI : public CarlaPlugin
  214. {
  215. public:
  216. CarlaPluginDSSI(CarlaEngine* const engine, const uint id) noexcept
  217. : CarlaPlugin(engine, id),
  218. fHandles(),
  219. fDescriptor(nullptr),
  220. fDssiDescriptor(nullptr),
  221. fAudioInBuffers(nullptr),
  222. fAudioOutBuffers(nullptr),
  223. fExtraStereoBuffer(),
  224. fParamBuffers(nullptr),
  225. fLatencyIndex(-1),
  226. fForcedStereoIn(false),
  227. fForcedStereoOut(false),
  228. fIsDssiVst(false),
  229. fUsesCustomData(false),
  230. #ifdef HAVE_LIBLO
  231. fOscData(),
  232. fThreadUI(engine, this, fOscData),
  233. fUiFilename(nullptr),
  234. #endif
  235. leakDetector_CarlaPluginDSSI()
  236. {
  237. carla_debug("CarlaPluginDSSI::CarlaPluginDSSI(%p, %i)", engine, id);
  238. carla_zeroPointers(fExtraStereoBuffer, 2);
  239. }
  240. ~CarlaPluginDSSI() noexcept override
  241. {
  242. carla_debug("CarlaPluginDSSI::~CarlaPluginDSSI()");
  243. #ifdef HAVE_LIBLO
  244. // close UI
  245. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  246. {
  247. showCustomUI(false);
  248. fThreadUI.stopThread(static_cast<int>(pData->engine->getOptions().uiBridgesTimeout * 2));
  249. }
  250. #endif
  251. pData->singleMutex.lock();
  252. pData->masterMutex.lock();
  253. if (pData->client != nullptr && pData->client->isActive())
  254. pData->client->deactivate();
  255. if (pData->active)
  256. {
  257. deactivate();
  258. pData->active = false;
  259. }
  260. if (fDescriptor != nullptr)
  261. {
  262. if (fDescriptor->cleanup != nullptr)
  263. {
  264. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  265. {
  266. LADSPA_Handle const handle(it.getValue(nullptr));
  267. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  268. try {
  269. fDescriptor->cleanup(handle);
  270. } CARLA_SAFE_EXCEPTION("LADSPA cleanup");
  271. }
  272. }
  273. fHandles.clear();
  274. fDescriptor = nullptr;
  275. fDssiDescriptor = nullptr;
  276. }
  277. #ifdef HAVE_LIBLO
  278. if (fUiFilename != nullptr)
  279. {
  280. delete[] fUiFilename;
  281. fUiFilename = nullptr;
  282. }
  283. #endif
  284. clearBuffers();
  285. }
  286. // -------------------------------------------------------------------
  287. // Information (base)
  288. PluginType getType() const noexcept override
  289. {
  290. return PLUGIN_DSSI;
  291. }
  292. PluginCategory getCategory() const noexcept override
  293. {
  294. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr, PLUGIN_CATEGORY_NONE);
  295. if (pData->audioIn.count == 0 && pData->audioOut.count > 0 && fDssiDescriptor->run_synth != nullptr)
  296. return PLUGIN_CATEGORY_SYNTH;
  297. return CarlaPlugin::getCategory();
  298. }
  299. int64_t getUniqueId() const noexcept override
  300. {
  301. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0);
  302. return static_cast<int64_t>(fDescriptor->UniqueID);
  303. }
  304. // -------------------------------------------------------------------
  305. // Information (count)
  306. // nothing
  307. // -------------------------------------------------------------------
  308. // Information (current data)
  309. std::size_t getChunkData(void** const dataPtr) noexcept override
  310. {
  311. CARLA_SAFE_ASSERT_RETURN(fUsesCustomData, 0);
  312. CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0);
  313. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr, 0);
  314. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->get_custom_data != nullptr, 0);
  315. CARLA_SAFE_ASSERT_RETURN(fHandles.count() > 0, 0);
  316. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
  317. *dataPtr = nullptr;
  318. int ret = 0;
  319. ulong dataSize = 0;
  320. try {
  321. ret = fDssiDescriptor->get_custom_data(fHandles.getFirst(nullptr), dataPtr, &dataSize);
  322. } CARLA_SAFE_EXCEPTION_RETURN("CarlaPluginDSSI::getChunkData", 0);
  323. return (ret != 0) ? dataSize : 0;
  324. }
  325. // -------------------------------------------------------------------
  326. // Information (per-plugin data)
  327. uint getOptionsAvailable() const noexcept override
  328. {
  329. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr, 0x0);
  330. uint options = 0x0;
  331. if (! fIsDssiVst)
  332. {
  333. // can't disable fixed buffers if using latency
  334. if (fLatencyIndex == -1)
  335. options |= PLUGIN_OPTION_FIXED_BUFFERS;
  336. // can't disable forced stereo if in rack mode
  337. if (pData->engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  338. pass();
  339. // if inputs or outputs are just 1, then yes we can force stereo
  340. else if (pData->audioIn.count == 1 || pData->audioOut.count == 1 || fForcedStereoIn || fForcedStereoOut)
  341. options |= PLUGIN_OPTION_FORCE_STEREO;
  342. }
  343. if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
  344. options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  345. if (fDssiDescriptor->run_synth != nullptr)
  346. {
  347. options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  348. options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  349. options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  350. options |= PLUGIN_OPTION_SEND_PITCHBEND;
  351. options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  352. }
  353. if (fUsesCustomData)
  354. options |= PLUGIN_OPTION_USE_CHUNKS;
  355. return options;
  356. }
  357. float getParameterValue(const uint32_t parameterId) const noexcept override
  358. {
  359. CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr, 0.0f);
  360. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
  361. // bad plugins might have set output values out of bounds
  362. if (pData->param.data[parameterId].type == PARAMETER_OUTPUT)
  363. return pData->param.ranges[parameterId].getFixedValue(fParamBuffers[parameterId]);
  364. // not output, should be fine
  365. return fParamBuffers[parameterId];
  366. }
  367. void getLabel(char* const strBuf) const noexcept override
  368. {
  369. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, nullStrBuf(strBuf));
  370. CARLA_SAFE_ASSERT_RETURN(fDescriptor->Label != nullptr, nullStrBuf(strBuf));
  371. std::strncpy(strBuf, fDescriptor->Label, STR_MAX);
  372. }
  373. void getMaker(char* const strBuf) const noexcept override
  374. {
  375. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, nullStrBuf(strBuf));
  376. CARLA_SAFE_ASSERT_RETURN(fDescriptor->Maker != nullptr, nullStrBuf(strBuf));
  377. std::strncpy(strBuf, fDescriptor->Maker, STR_MAX);
  378. }
  379. void getCopyright(char* const strBuf) const noexcept override
  380. {
  381. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, nullStrBuf(strBuf));
  382. CARLA_SAFE_ASSERT_RETURN(fDescriptor->Copyright != nullptr, nullStrBuf(strBuf));
  383. std::strncpy(strBuf, fDescriptor->Copyright, STR_MAX);
  384. }
  385. void getRealName(char* const strBuf) const noexcept override
  386. {
  387. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, nullStrBuf(strBuf));
  388. CARLA_SAFE_ASSERT_RETURN(fDescriptor->Name != nullptr, nullStrBuf(strBuf));
  389. std::strncpy(strBuf, fDescriptor->Name, STR_MAX);
  390. }
  391. void getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
  392. {
  393. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, nullStrBuf(strBuf));
  394. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf));
  395. const int32_t rindex(pData->param.data[parameterId].rindex);
  396. CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fDescriptor->PortCount), nullStrBuf(strBuf));
  397. CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames[rindex] != nullptr, nullStrBuf(strBuf));
  398. if (getSeparatedParameterNameOrUnit(fDescriptor->PortNames[rindex], strBuf, true))
  399. return;
  400. std::strncpy(strBuf, fDescriptor->PortNames[rindex], STR_MAX);
  401. }
  402. void getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override
  403. {
  404. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf));
  405. const int32_t rindex(pData->param.data[parameterId].rindex);
  406. CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fDescriptor->PortCount), nullStrBuf(strBuf));
  407. if (getSeparatedParameterNameOrUnit(fDescriptor->PortNames[rindex], strBuf, false))
  408. return;
  409. nullStrBuf(strBuf);
  410. }
  411. // -------------------------------------------------------------------
  412. // Set data (state)
  413. // nothing
  414. // -------------------------------------------------------------------
  415. // Set data (internal stuff)
  416. void setId(const uint newId) noexcept
  417. {
  418. CarlaPlugin::setId(newId);
  419. // UI osc-url uses Id, so we need to close it when it changes
  420. // FIXME - must be RT safe
  421. showCustomUI(false);
  422. }
  423. // -------------------------------------------------------------------
  424. // Set data (plugin-specific stuff)
  425. void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  426. {
  427. CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr,);
  428. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  429. const float fixedValue(pData->param.getFixedValue(parameterId, value));
  430. fParamBuffers[parameterId] = fixedValue;
  431. CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
  432. }
  433. void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override
  434. {
  435. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
  436. CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
  437. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  438. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  439. carla_debug("CarlaPluginDSSI::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui));
  440. if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
  441. return CarlaPlugin::setCustomData(type, key, value, sendGui);
  442. if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0)
  443. return carla_stderr2("CarlaPluginDSSI::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui));
  444. if (fDssiDescriptor->configure != nullptr && fHandles.count() > 0)
  445. {
  446. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  447. {
  448. LADSPA_Handle const handle(it.getValue(nullptr));
  449. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  450. try {
  451. fDssiDescriptor->configure(handle, key, value);
  452. } catch(...) {}
  453. }
  454. }
  455. #ifdef HAVE_LIBLO
  456. if (sendGui && fOscData.target != nullptr)
  457. osc_send_configure(fOscData, key, value);
  458. #endif
  459. if (std::strcmp(key, "reloadprograms") == 0 || std::strcmp(key, "load") == 0 || std::strncmp(key, "patches", 7) == 0)
  460. {
  461. const ScopedSingleProcessLocker spl(this, true);
  462. reloadPrograms(false);
  463. }
  464. CarlaPlugin::setCustomData(type, key, value, sendGui);
  465. }
  466. void setChunkData(const void* const data, const std::size_t dataSize) override
  467. {
  468. CARLA_SAFE_ASSERT_RETURN(fUsesCustomData,);
  469. CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS,);
  470. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
  471. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->set_custom_data != nullptr,);
  472. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  473. CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
  474. if (fHandles.count() > 0)
  475. {
  476. const ScopedSingleProcessLocker spl(this, true);
  477. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  478. {
  479. LADSPA_Handle const handle(it.getValue(nullptr));
  480. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  481. try {
  482. fDssiDescriptor->set_custom_data(handle, const_cast<void*>(data), static_cast<ulong>(dataSize));
  483. } CARLA_SAFE_EXCEPTION("CarlaPluginDSSI::setChunkData");
  484. }
  485. }
  486. #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
  487. const bool sendOsc(pData->engine->isOscControlRegistered());
  488. #else
  489. const bool sendOsc(false);
  490. #endif
  491. pData->updateParameterValues(this, sendOsc, true, false);
  492. }
  493. void setMidiProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  494. {
  495. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
  496. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->select_program != nullptr,);
  497. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
  498. if (index >= 0 && fHandles.count() > 0)
  499. {
  500. const uint32_t bank(pData->midiprog.data[index].bank);
  501. const uint32_t program(pData->midiprog.data[index].program);
  502. const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback));
  503. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  504. {
  505. LADSPA_Handle const handle(it.getValue(nullptr));
  506. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  507. try {
  508. fDssiDescriptor->select_program(handle, bank, program);
  509. } catch(...) {}
  510. }
  511. }
  512. CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback);
  513. }
  514. #ifdef HAVE_LIBLO
  515. // -------------------------------------------------------------------
  516. // Set ui stuff
  517. void showCustomUI(const bool yesNo) override
  518. {
  519. if (yesNo)
  520. {
  521. fOscData.clear();
  522. fThreadUI.startThread();
  523. }
  524. else
  525. {
  526. pData->transientTryCounter = 0;
  527. if (fOscData.target != nullptr)
  528. {
  529. osc_send_hide(fOscData);
  530. osc_send_quit(fOscData);
  531. fOscData.clear();
  532. }
  533. fThreadUI.stopThread(static_cast<int>(pData->engine->getOptions().uiBridgesTimeout * 2));
  534. }
  535. }
  536. #endif
  537. #if 0 // TODO
  538. void idle() override
  539. {
  540. if (fLatencyChanged && fLatencyIndex != -1)
  541. {
  542. fLatencyChanged = false;
  543. const int32_t latency(static_cast<int32_t>(fParamBuffers[fLatencyIndex]));
  544. if (latency >= 0)
  545. {
  546. const uint32_t ulatency(static_cast<uint32_t>(latency));
  547. if (pData->latency != ulatency)
  548. {
  549. carla_stdout("latency changed to %i", latency);
  550. const ScopedSingleProcessLocker sspl(this, true);
  551. pData->latency = ulatency;
  552. pData->client->setLatency(ulatency);
  553. #ifndef BUILD_BRIDGE
  554. pData->recreateLatencyBuffers();
  555. #endif
  556. }
  557. }
  558. else
  559. carla_safe_assert_int("latency >= 0", __FILE__, __LINE__, latency);
  560. }
  561. CarlaPlugin::idle();
  562. }
  563. #endif
  564. // -------------------------------------------------------------------
  565. // Plugin state
  566. void reload() override
  567. {
  568. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  569. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  570. CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
  571. CARLA_SAFE_ASSERT_RETURN(fHandles.count() > 0,);
  572. carla_debug("CarlaPluginDSSI::reload() - start");
  573. const EngineProcessMode processMode(pData->engine->getProccessMode());
  574. // Safely disable plugin for reload
  575. const ScopedDisabler sd(this);
  576. if (pData->active)
  577. deactivate();
  578. clearBuffers();
  579. const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
  580. const uint32_t portCount(getSafePortCount());
  581. uint32_t aIns, aOuts, mIns, params;
  582. aIns = aOuts = mIns = params = 0;
  583. bool forcedStereoIn, forcedStereoOut;
  584. forcedStereoIn = forcedStereoOut = false;
  585. bool needsCtrlIn, needsCtrlOut;
  586. needsCtrlIn = needsCtrlOut = false;
  587. for (uint32_t i=0; i < portCount; ++i)
  588. {
  589. const LADSPA_PortDescriptor portType(fDescriptor->PortDescriptors[i]);
  590. if (LADSPA_IS_PORT_AUDIO(portType))
  591. {
  592. if (LADSPA_IS_PORT_INPUT(portType))
  593. aIns += 1;
  594. else if (LADSPA_IS_PORT_OUTPUT(portType))
  595. aOuts += 1;
  596. }
  597. else if (LADSPA_IS_PORT_CONTROL(portType))
  598. params += 1;
  599. }
  600. if (pData->options & PLUGIN_OPTION_FORCE_STEREO)
  601. {
  602. if ((aIns == 1 || aOuts == 1) && fHandles.count() == 1 && addInstance())
  603. {
  604. if (aIns == 1)
  605. {
  606. aIns = 2;
  607. forcedStereoIn = true;
  608. }
  609. if (aOuts == 1)
  610. {
  611. aOuts = 2;
  612. forcedStereoOut = true;
  613. }
  614. }
  615. }
  616. if (fDssiDescriptor->run_synth != nullptr)
  617. {
  618. mIns = 1;
  619. needsCtrlIn = true;
  620. }
  621. if (aIns > 0)
  622. {
  623. pData->audioIn.createNew(aIns);
  624. fAudioInBuffers = new float*[aIns];
  625. for (uint32_t i=0; i < aIns; ++i)
  626. fAudioInBuffers[i] = nullptr;
  627. }
  628. if (aOuts > 0)
  629. {
  630. pData->audioOut.createNew(aOuts);
  631. fAudioOutBuffers = new float*[aOuts];
  632. needsCtrlIn = true;
  633. for (uint32_t i=0; i < aOuts; ++i)
  634. fAudioOutBuffers[i] = nullptr;
  635. }
  636. if (params > 0)
  637. {
  638. pData->param.createNew(params, true);
  639. fParamBuffers = new float[params];
  640. FloatVectorOperations::clear(fParamBuffers, static_cast<int>(params));
  641. }
  642. const uint portNameSize(pData->engine->getMaxPortNameSize());
  643. CarlaString portName;
  644. for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iCtrl=0; i < portCount; ++i)
  645. {
  646. const LADSPA_PortDescriptor portType = fDescriptor->PortDescriptors[i];
  647. const LADSPA_PortRangeHint portRangeHints = fDescriptor->PortRangeHints[i];
  648. if (LADSPA_IS_PORT_AUDIO(portType))
  649. {
  650. portName.clear();
  651. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  652. {
  653. portName = pData->name;
  654. portName += ":";
  655. }
  656. if (fDescriptor->PortNames[i] != nullptr && fDescriptor->PortNames[i][0] != '\0')
  657. {
  658. portName += fDescriptor->PortNames[i];
  659. }
  660. else
  661. {
  662. if (LADSPA_IS_PORT_INPUT(portType))
  663. {
  664. if (aIns > 1)
  665. {
  666. portName += "audio-in_";
  667. portName += CarlaString(iAudioIn+1);
  668. }
  669. else
  670. portName += "audio-in";
  671. }
  672. else
  673. {
  674. if (aOuts > 1)
  675. {
  676. portName += "audio-out_";
  677. portName += CarlaString(iAudioOut+1);
  678. }
  679. else
  680. portName += "audio-out";
  681. }
  682. }
  683. portName.truncate(portNameSize);
  684. if (LADSPA_IS_PORT_INPUT(portType))
  685. {
  686. const uint32_t j = iAudioIn++;
  687. pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
  688. pData->audioIn.ports[j].rindex = i;
  689. if (forcedStereoIn)
  690. {
  691. portName += "_2";
  692. pData->audioIn.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, 1);
  693. pData->audioIn.ports[1].rindex = i;
  694. }
  695. }
  696. else if (LADSPA_IS_PORT_OUTPUT(portType))
  697. {
  698. const uint32_t j = iAudioOut++;
  699. pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
  700. pData->audioOut.ports[j].rindex = i;
  701. if (forcedStereoOut)
  702. {
  703. portName += "_2";
  704. pData->audioOut.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, 1);
  705. pData->audioOut.ports[1].rindex = i;
  706. }
  707. }
  708. else
  709. carla_stderr2("WARNING - Got a broken Port (Audio, but not input or output)");
  710. }
  711. else if (LADSPA_IS_PORT_CONTROL(portType))
  712. {
  713. const uint32_t j = iCtrl++;
  714. pData->param.data[j].index = static_cast<int32_t>(j);
  715. pData->param.data[j].rindex = static_cast<int32_t>(i);
  716. const char* const paramName(fDescriptor->PortNames[i] != nullptr ? fDescriptor->PortNames[i] : "unknown");
  717. float min, max, def, step, stepSmall, stepLarge;
  718. // min value
  719. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  720. min = portRangeHints.LowerBound;
  721. else
  722. min = 0.0f;
  723. // max value
  724. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  725. max = portRangeHints.UpperBound;
  726. else
  727. max = 1.0f;
  728. if (min > max)
  729. {
  730. carla_stderr2("WARNING - Broken plugin parameter '%s': min > max", paramName);
  731. min = max - 0.1f;
  732. }
  733. else if (carla_isEqual(min, max))
  734. {
  735. carla_stderr2("WARNING - Broken plugin parameter '%s': min == max", paramName);
  736. max = min + 0.1f;
  737. }
  738. // default value
  739. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  740. if (def < min)
  741. def = min;
  742. else if (def > max)
  743. def = max;
  744. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  745. {
  746. min *= sampleRate;
  747. max *= sampleRate;
  748. def *= sampleRate;
  749. pData->param.data[j].hints |= PARAMETER_USES_SAMPLERATE;
  750. }
  751. if (LADSPA_IS_HINT_TOGGLED(portRangeHints.HintDescriptor))
  752. {
  753. step = max - min;
  754. stepSmall = step;
  755. stepLarge = step;
  756. pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
  757. }
  758. else if (LADSPA_IS_HINT_INTEGER(portRangeHints.HintDescriptor))
  759. {
  760. step = 1.0f;
  761. stepSmall = 1.0f;
  762. stepLarge = 10.0f;
  763. pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
  764. }
  765. else
  766. {
  767. const float range = max - min;
  768. step = range/100.0f;
  769. stepSmall = range/1000.0f;
  770. stepLarge = range/10.0f;
  771. }
  772. if (LADSPA_IS_PORT_INPUT(portType))
  773. {
  774. pData->param.data[j].type = PARAMETER_INPUT;
  775. pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
  776. pData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE;
  777. needsCtrlIn = true;
  778. // MIDI CC value
  779. if (fDssiDescriptor->get_midi_controller_for_port != nullptr)
  780. {
  781. int controller = fDssiDescriptor->get_midi_controller_for_port(fHandles.getFirst(nullptr), i);
  782. if (DSSI_CONTROLLER_IS_SET(controller) && DSSI_IS_CC(controller))
  783. {
  784. int16_t cc = DSSI_CC_NUMBER(controller);
  785. if (! MIDI_IS_CONTROL_BANK_SELECT(cc))
  786. pData->param.data[j].midiCC = cc;
  787. }
  788. }
  789. }
  790. else if (LADSPA_IS_PORT_OUTPUT(portType))
  791. {
  792. pData->param.data[j].type = PARAMETER_OUTPUT;
  793. if (std::strcmp(paramName, "latency") == 0 || std::strcmp(paramName, "_latency") == 0)
  794. {
  795. min = 0.0f;
  796. max = sampleRate;
  797. def = 0.0f;
  798. step = 1.0f;
  799. stepSmall = 1.0f;
  800. stepLarge = 1.0f;
  801. pData->param.special[j] = PARAMETER_SPECIAL_LATENCY;
  802. CARLA_SAFE_ASSERT(fLatencyIndex == -1);
  803. fLatencyIndex = static_cast<int32_t>(j);
  804. }
  805. else
  806. {
  807. pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
  808. pData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE;
  809. needsCtrlOut = true;
  810. }
  811. }
  812. else
  813. {
  814. carla_stderr2("WARNING - Got a broken Port (Control, but not input or output)");
  815. }
  816. // extra parameter hints
  817. if (LADSPA_IS_HINT_LOGARITHMIC(portRangeHints.HintDescriptor))
  818. pData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC;
  819. pData->param.ranges[j].min = min;
  820. pData->param.ranges[j].max = max;
  821. pData->param.ranges[j].def = def;
  822. pData->param.ranges[j].step = step;
  823. pData->param.ranges[j].stepSmall = stepSmall;
  824. pData->param.ranges[j].stepLarge = stepLarge;
  825. // Start parameters in their default values
  826. fParamBuffers[j] = def;
  827. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  828. {
  829. LADSPA_Handle const handle(it.getValue(nullptr));
  830. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  831. try {
  832. fDescriptor->connect_port(handle, i, &fParamBuffers[j]);
  833. } CARLA_SAFE_EXCEPTION("DSSI connect_port (parameter)");
  834. }
  835. }
  836. else
  837. {
  838. // Not Audio or Control
  839. carla_stderr2("ERROR - Got a broken Port (neither Audio or Control)");
  840. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  841. {
  842. LADSPA_Handle const handle(it.getValue(nullptr));
  843. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  844. try {
  845. fDescriptor->connect_port(handle, i, nullptr);
  846. } CARLA_SAFE_EXCEPTION("DSSI connect_port (null)");
  847. }
  848. }
  849. }
  850. if (needsCtrlIn)
  851. {
  852. portName.clear();
  853. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  854. {
  855. portName = pData->name;
  856. portName += ":";
  857. }
  858. portName += "events-in";
  859. portName.truncate(portNameSize);
  860. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  861. }
  862. if (needsCtrlOut)
  863. {
  864. portName.clear();
  865. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  866. {
  867. portName = pData->name;
  868. portName += ":";
  869. }
  870. portName += "events-out";
  871. portName.truncate(portNameSize);
  872. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  873. }
  874. if (forcedStereoIn || forcedStereoOut)
  875. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  876. else
  877. pData->options &= ~PLUGIN_OPTION_FORCE_STEREO;
  878. // plugin hints
  879. pData->hints = 0x0;
  880. if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties))
  881. pData->hints |= PLUGIN_IS_RTSAFE;
  882. #ifdef HAVE_LIBLO
  883. if (fUiFilename != nullptr)
  884. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  885. #endif
  886. #ifndef BUILD_BRIDGE
  887. if (aOuts > 0 && (aIns == aOuts || aIns == 1))
  888. pData->hints |= PLUGIN_CAN_DRYWET;
  889. if (aOuts > 0)
  890. pData->hints |= PLUGIN_CAN_VOLUME;
  891. if (aOuts >= 2 && aOuts % 2 == 0)
  892. pData->hints |= PLUGIN_CAN_BALANCE;
  893. #endif
  894. // extra plugin hints
  895. pData->extraHints = 0x0;
  896. if (mIns > 0)
  897. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN;
  898. if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0))
  899. pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK;
  900. #if 0 // TODO
  901. // check latency
  902. if (fLatencyIndex >= 0)
  903. {
  904. // we need to pre-run the plugin so it can update its latency control-port
  905. float tmpIn [(aIns > 0) ? aIns : 1][2];
  906. float tmpOut[(aOuts > 0) ? aOuts : 1][2];
  907. for (uint32_t j=0; j < aIns; ++j)
  908. {
  909. tmpIn[j][0] = 0.0f;
  910. tmpIn[j][1] = 0.0f;
  911. try {
  912. fDescriptor->connect_port(fHandle, pData->audioIn.ports[j].rindex, tmpIn[j]);
  913. } CARLA_SAFE_EXCEPTION("DSSI connect_port latency input");
  914. }
  915. for (uint32_t j=0; j < aOuts; ++j)
  916. {
  917. tmpOut[j][0] = 0.0f;
  918. tmpOut[j][1] = 0.0f;
  919. try {
  920. fDescriptor->connect_port(fHandle, pData->audioOut.ports[j].rindex, tmpOut[j]);
  921. } CARLA_SAFE_EXCEPTION("DSSI connect_port latency output");
  922. }
  923. if (fDescriptor->activate != nullptr)
  924. {
  925. try {
  926. fDescriptor->activate(fHandle);
  927. } CARLA_SAFE_EXCEPTION("DSSI latency activate");
  928. }
  929. try {
  930. fDescriptor->run(fHandle, 2);
  931. } CARLA_SAFE_EXCEPTION("DSSI latency run");
  932. if (fDescriptor->deactivate != nullptr)
  933. {
  934. try {
  935. fDescriptor->deactivate(fHandle);
  936. } CARLA_SAFE_EXCEPTION("DSSI latency deactivate");
  937. }
  938. const int32_t latency(static_cast<int32_t>(fParamBuffers[fLatencyIndex]));
  939. if (latency >= 0)
  940. {
  941. const uint32_t ulatency(static_cast<uint32_t>(latency));
  942. if (pData->latency != ulatency)
  943. {
  944. carla_stdout("latency = %i", latency);
  945. pData->latency = ulatency;
  946. pData->client->setLatency(ulatency);
  947. #ifndef BUILD_BRIDGE
  948. pData->recreateLatencyBuffers();
  949. #endif
  950. }
  951. }
  952. else
  953. carla_safe_assert_int("latency >= 0", __FILE__, __LINE__, latency);
  954. fLatencyChanged = false;
  955. }
  956. #endif
  957. bufferSizeChanged(pData->engine->getBufferSize());
  958. reloadPrograms(true);
  959. if (pData->active)
  960. activate();
  961. carla_debug("CarlaPluginDSSI::reload() - end");
  962. }
  963. void reloadPrograms(const bool doInit) override
  964. {
  965. carla_debug("CarlaPluginDSSI::reloadPrograms(%s)", bool2str(doInit));
  966. const LADSPA_Handle handle(fHandles.getFirst(nullptr));
  967. CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
  968. const uint32_t oldCount = pData->midiprog.count;
  969. const int32_t current = pData->midiprog.current;
  970. // Delete old programs
  971. pData->midiprog.clear();
  972. // Query new programs
  973. uint32_t newCount = 0;
  974. if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
  975. {
  976. for (; fDssiDescriptor->get_program(handle, newCount) != nullptr;)
  977. ++newCount;
  978. }
  979. if (newCount > 0)
  980. {
  981. pData->midiprog.createNew(newCount);
  982. // Update data
  983. for (uint32_t i=0; i < newCount; ++i)
  984. {
  985. const DSSI_Program_Descriptor* const pdesc(fDssiDescriptor->get_program(handle, i));
  986. CARLA_SAFE_ASSERT_CONTINUE(pdesc != nullptr);
  987. CARLA_SAFE_ASSERT(pdesc->Name != nullptr);
  988. pData->midiprog.data[i].bank = static_cast<uint32_t>(pdesc->Bank);
  989. pData->midiprog.data[i].program = static_cast<uint32_t>(pdesc->Program);
  990. pData->midiprog.data[i].name = carla_strdup(pdesc->Name);
  991. }
  992. }
  993. #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
  994. // Update OSC Names
  995. if (pData->engine->isOscControlRegistered() && pData->id < pData->engine->getCurrentPluginCount())
  996. {
  997. pData->engine->oscSend_control_set_midi_program_count(pData->id, newCount);
  998. for (uint32_t i=0; i < newCount; ++i)
  999. pData->engine->oscSend_control_set_midi_program_data(pData->id, i, pData->midiprog.data[i].bank, pData->midiprog.data[i].program, pData->midiprog.data[i].name);
  1000. }
  1001. #endif
  1002. if (doInit)
  1003. {
  1004. if (newCount > 0)
  1005. setMidiProgram(0, false, false, false);
  1006. }
  1007. else
  1008. {
  1009. // Check if current program is invalid
  1010. bool programChanged = false;
  1011. if (newCount == oldCount+1)
  1012. {
  1013. // one midi program added, probably created by user
  1014. pData->midiprog.current = static_cast<int32_t>(oldCount);
  1015. programChanged = true;
  1016. }
  1017. else if (current < 0 && newCount > 0)
  1018. {
  1019. // programs exist now, but not before
  1020. pData->midiprog.current = 0;
  1021. programChanged = true;
  1022. }
  1023. else if (current >= 0 && newCount == 0)
  1024. {
  1025. // programs existed before, but not anymore
  1026. pData->midiprog.current = -1;
  1027. programChanged = true;
  1028. }
  1029. else if (current >= static_cast<int32_t>(newCount))
  1030. {
  1031. // current midi program > count
  1032. pData->midiprog.current = 0;
  1033. programChanged = true;
  1034. }
  1035. else
  1036. {
  1037. // no change
  1038. pData->midiprog.current = current;
  1039. }
  1040. if (programChanged)
  1041. setMidiProgram(pData->midiprog.current, true, true, true);
  1042. pData->engine->callback(ENGINE_CALLBACK_RELOAD_PROGRAMS, pData->id, 0, 0, 0.0f, nullptr);
  1043. }
  1044. }
  1045. // -------------------------------------------------------------------
  1046. // Plugin processing
  1047. void activate() noexcept override
  1048. {
  1049. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  1050. if (fDescriptor->activate != nullptr)
  1051. {
  1052. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  1053. {
  1054. LADSPA_Handle const handle(it.getValue(nullptr));
  1055. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1056. try {
  1057. fDescriptor->activate(handle);
  1058. } CARLA_SAFE_EXCEPTION("DSSI activate");
  1059. }
  1060. }
  1061. }
  1062. void deactivate() noexcept override
  1063. {
  1064. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  1065. if (fDescriptor->deactivate != nullptr)
  1066. {
  1067. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  1068. {
  1069. LADSPA_Handle const handle(it.getValue(nullptr));
  1070. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1071. try {
  1072. fDescriptor->deactivate(handle);
  1073. } CARLA_SAFE_EXCEPTION("DSSI deactivate");
  1074. }
  1075. }
  1076. }
  1077. void process(const float** const audioIn, float** const audioOut, const float** const, float** const, const uint32_t frames) override
  1078. {
  1079. // --------------------------------------------------------------------------------------------------------
  1080. // Check if active
  1081. if (! pData->active)
  1082. {
  1083. // disable any output sound
  1084. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1085. FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames));
  1086. return;
  1087. }
  1088. ulong midiEventCount = 0;
  1089. carla_zeroStructs(fMidiEvents, kPluginMaxMidiEvents);
  1090. // --------------------------------------------------------------------------------------------------------
  1091. // Check if needs reset
  1092. if (pData->needsReset)
  1093. {
  1094. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1095. {
  1096. midiEventCount = MAX_MIDI_CHANNELS*2;
  1097. for (uchar i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i)
  1098. {
  1099. fMidiEvents[i].type = SND_SEQ_EVENT_CONTROLLER;
  1100. fMidiEvents[i].data.control.channel = i;
  1101. fMidiEvents[i].data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;
  1102. fMidiEvents[k+i].type = SND_SEQ_EVENT_CONTROLLER;
  1103. fMidiEvents[k+i].data.control.channel = i;
  1104. fMidiEvents[k+i].data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;
  1105. }
  1106. }
  1107. else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
  1108. {
  1109. midiEventCount = MAX_MIDI_NOTE;
  1110. for (uchar i=0; i < MAX_MIDI_NOTE; ++i)
  1111. {
  1112. fMidiEvents[i].type = SND_SEQ_EVENT_NOTEOFF;
  1113. fMidiEvents[i].data.note.channel = static_cast<uchar>(pData->ctrlChannel);
  1114. fMidiEvents[i].data.note.note = i;
  1115. }
  1116. }
  1117. #ifndef BUILD_BRIDGE
  1118. #if 0 // TODO
  1119. if (pData->latency > 0)
  1120. {
  1121. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1122. FloatVectorOperations::clear(pData->latencyBuffers[i], static_cast<int>(pData->latency));
  1123. }
  1124. #endif
  1125. #endif
  1126. pData->needsReset = false;
  1127. }
  1128. // --------------------------------------------------------------------------------------------------------
  1129. // Event Input and Processing
  1130. if (pData->event.portIn != nullptr)
  1131. {
  1132. // ----------------------------------------------------------------------------------------------------
  1133. // MIDI Input (External)
  1134. if (pData->extNotes.mutex.tryLock())
  1135. {
  1136. ExternalMidiNote note = { 0, 0, 0 };
  1137. for (; midiEventCount < kPluginMaxMidiEvents && ! pData->extNotes.data.isEmpty();)
  1138. {
  1139. note = pData->extNotes.data.getFirst(note, true);
  1140. CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
  1141. snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
  1142. seqEvent.type = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
  1143. seqEvent.data.note.channel = static_cast<uchar>(note.channel);
  1144. seqEvent.data.note.note = note.note;
  1145. seqEvent.data.note.velocity = note.velo;
  1146. }
  1147. pData->extNotes.mutex.unlock();
  1148. } // End of MIDI Input (External)
  1149. // ----------------------------------------------------------------------------------------------------
  1150. // Event Input (System)
  1151. #ifndef BUILD_BRIDGE
  1152. bool allNotesOffSent = false;
  1153. #endif
  1154. const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;
  1155. uint32_t startTime = 0;
  1156. uint32_t timeOffset = 0;
  1157. uint32_t nextBankId;
  1158. if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  1159. nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
  1160. else
  1161. nextBankId = 0;
  1162. for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
  1163. {
  1164. const EngineEvent& event(pData->event.portIn->getEvent(i));
  1165. if (event.time >= frames)
  1166. continue;
  1167. CARLA_ASSERT_INT2(event.time >= timeOffset, event.time, timeOffset);
  1168. if (isSampleAccurate && event.time > timeOffset)
  1169. {
  1170. if (processSingle(audioIn, audioOut, event.time - timeOffset, timeOffset, midiEventCount))
  1171. {
  1172. startTime = 0;
  1173. timeOffset = event.time;
  1174. midiEventCount = 0;
  1175. if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  1176. nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
  1177. else
  1178. nextBankId = 0;
  1179. }
  1180. else
  1181. startTime += timeOffset;
  1182. }
  1183. switch (event.type)
  1184. {
  1185. case kEngineEventTypeNull:
  1186. break;
  1187. case kEngineEventTypeControl: {
  1188. const EngineControlEvent& ctrlEvent(event.ctrl);
  1189. switch (ctrlEvent.type)
  1190. {
  1191. case kEngineControlEventTypeNull:
  1192. break;
  1193. case kEngineControlEventTypeParameter: {
  1194. #ifndef BUILD_BRIDGE
  1195. // Control backend stuff
  1196. if (event.channel == pData->ctrlChannel)
  1197. {
  1198. float value;
  1199. if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) != 0)
  1200. {
  1201. value = ctrlEvent.value;
  1202. setDryWet(value, false, false);
  1203. pData->postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_DRYWET, 0, value);
  1204. break;
  1205. }
  1206. if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) != 0)
  1207. {
  1208. value = ctrlEvent.value*127.0f/100.0f;
  1209. setVolume(value, false, false);
  1210. pData->postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_VOLUME, 0, value);
  1211. break;
  1212. }
  1213. if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) != 0)
  1214. {
  1215. float left, right;
  1216. value = ctrlEvent.value/0.5f - 1.0f;
  1217. if (value < 0.0f)
  1218. {
  1219. left = -1.0f;
  1220. right = (value*2.0f)+1.0f;
  1221. }
  1222. else if (value > 0.0f)
  1223. {
  1224. left = (value*2.0f)-1.0f;
  1225. right = 1.0f;
  1226. }
  1227. else
  1228. {
  1229. left = -1.0f;
  1230. right = 1.0f;
  1231. }
  1232. setBalanceLeft(left, false, false);
  1233. setBalanceRight(right, false, false);
  1234. pData->postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left);
  1235. pData->postponeRtEvent(kPluginPostRtEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right);
  1236. break;
  1237. }
  1238. }
  1239. #endif
  1240. // Control plugin parameters
  1241. uint32_t k;
  1242. for (k=0; k < pData->param.count; ++k)
  1243. {
  1244. if (pData->param.data[k].midiChannel != event.channel)
  1245. continue;
  1246. if (pData->param.data[k].midiCC != ctrlEvent.param)
  1247. continue;
  1248. if (pData->param.data[k].type != PARAMETER_INPUT)
  1249. continue;
  1250. if ((pData->param.data[k].hints & PARAMETER_IS_AUTOMABLE) == 0)
  1251. continue;
  1252. float value;
  1253. if (pData->param.data[k].hints & PARAMETER_IS_BOOLEAN)
  1254. {
  1255. value = (ctrlEvent.value < 0.5f) ? pData->param.ranges[k].min : pData->param.ranges[k].max;
  1256. }
  1257. else
  1258. {
  1259. value = pData->param.ranges[k].getUnnormalizedValue(ctrlEvent.value);
  1260. if (pData->param.data[k].hints & PARAMETER_IS_INTEGER)
  1261. value = std::rint(value);
  1262. }
  1263. setParameterValue(k, value, false, false, false);
  1264. pData->postponeRtEvent(kPluginPostRtEventParameterChange, static_cast<int32_t>(k), 0, value);
  1265. break;
  1266. }
  1267. // check if event is already handled
  1268. if (k != pData->param.count)
  1269. break;
  1270. if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_CONTROL)
  1271. {
  1272. if (midiEventCount >= kPluginMaxMidiEvents)
  1273. continue;
  1274. snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
  1275. seqEvent.time.tick = isSampleAccurate ? startTime : event.time;
  1276. seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
  1277. seqEvent.data.control.channel = event.channel;
  1278. seqEvent.data.control.param = ctrlEvent.param;
  1279. seqEvent.data.control.value = int8_t(ctrlEvent.value*127.0f);
  1280. }
  1281. break;
  1282. } // case kEngineControlEventTypeParameter
  1283. case kEngineControlEventTypeMidiBank:
  1284. if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
  1285. nextBankId = ctrlEvent.param;
  1286. break;
  1287. case kEngineControlEventTypeMidiProgram:
  1288. if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
  1289. {
  1290. const uint32_t nextProgramId = ctrlEvent.param;
  1291. for (uint32_t k=0; k < pData->midiprog.count; ++k)
  1292. {
  1293. if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId)
  1294. {
  1295. const int32_t index(static_cast<int32_t>(k));
  1296. setMidiProgram(index, false, false, false);
  1297. pData->postponeRtEvent(kPluginPostRtEventMidiProgramChange, index, 0, 0.0f);
  1298. break;
  1299. }
  1300. }
  1301. }
  1302. break;
  1303. case kEngineControlEventTypeAllSoundOff:
  1304. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1305. {
  1306. if (midiEventCount >= kPluginMaxMidiEvents)
  1307. continue;
  1308. snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
  1309. seqEvent.time.tick = isSampleAccurate ? startTime : event.time;
  1310. seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
  1311. seqEvent.data.control.channel = event.channel;
  1312. seqEvent.data.control.param = MIDI_CONTROL_ALL_SOUND_OFF;
  1313. }
  1314. break;
  1315. case kEngineControlEventTypeAllNotesOff:
  1316. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1317. {
  1318. #ifndef BUILD_BRIDGE
  1319. if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
  1320. {
  1321. allNotesOffSent = true;
  1322. sendMidiAllNotesOffToCallback();
  1323. }
  1324. #endif
  1325. if (midiEventCount >= kPluginMaxMidiEvents)
  1326. continue;
  1327. snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
  1328. seqEvent.time.tick = isSampleAccurate ? startTime : event.time;
  1329. seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
  1330. seqEvent.data.control.channel = event.channel;
  1331. seqEvent.data.control.param = MIDI_CONTROL_ALL_NOTES_OFF;
  1332. }
  1333. break;
  1334. } // switch (ctrlEvent.type)
  1335. break;
  1336. } // case kEngineEventTypeControl
  1337. case kEngineEventTypeMidi: {
  1338. if (midiEventCount >= kPluginMaxMidiEvents)
  1339. continue;
  1340. const EngineMidiEvent& midiEvent(event.midi);
  1341. if (midiEvent.size > EngineMidiEvent::kDataSize)
  1342. continue;
  1343. uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
  1344. // Fix bad note-off (per DSSI spec)
  1345. if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
  1346. status = MIDI_STATUS_NOTE_OFF;
  1347. snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
  1348. seqEvent.time.tick = isSampleAccurate ? startTime : event.time;
  1349. switch (status)
  1350. {
  1351. case MIDI_STATUS_NOTE_OFF: {
  1352. const uint8_t note = midiEvent.data[1];
  1353. seqEvent.type = SND_SEQ_EVENT_NOTEOFF;
  1354. seqEvent.data.note.channel = event.channel;
  1355. seqEvent.data.note.note = note;
  1356. pData->postponeRtEvent(kPluginPostRtEventNoteOff, event.channel, note, 0.0f);
  1357. break;
  1358. }
  1359. case MIDI_STATUS_NOTE_ON: {
  1360. const uint8_t note = midiEvent.data[1];
  1361. const uint8_t velo = midiEvent.data[2];
  1362. seqEvent.type = SND_SEQ_EVENT_NOTEON;
  1363. seqEvent.data.note.channel = event.channel;
  1364. seqEvent.data.note.note = note;
  1365. seqEvent.data.note.velocity = velo;
  1366. pData->postponeRtEvent(kPluginPostRtEventNoteOn, event.channel, note, velo);
  1367. break;
  1368. }
  1369. case MIDI_STATUS_POLYPHONIC_AFTERTOUCH:
  1370. if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH)
  1371. {
  1372. const uint8_t note = midiEvent.data[1];
  1373. const uint8_t pressure = midiEvent.data[2];
  1374. seqEvent.type = SND_SEQ_EVENT_KEYPRESS;
  1375. seqEvent.data.note.channel = event.channel;
  1376. seqEvent.data.note.note = note;
  1377. seqEvent.data.note.velocity = pressure;
  1378. }
  1379. break;
  1380. case MIDI_STATUS_CONTROL_CHANGE:
  1381. if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES)
  1382. {
  1383. const uint8_t control = midiEvent.data[1];
  1384. const uint8_t value = midiEvent.data[2];
  1385. seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
  1386. seqEvent.data.control.channel = event.channel;
  1387. seqEvent.data.control.param = control;
  1388. seqEvent.data.control.value = value;
  1389. }
  1390. break;
  1391. case MIDI_STATUS_CHANNEL_PRESSURE:
  1392. if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE)
  1393. {
  1394. const uint8_t pressure = midiEvent.data[1];
  1395. seqEvent.type = SND_SEQ_EVENT_CHANPRESS;
  1396. seqEvent.data.control.channel = event.channel;
  1397. seqEvent.data.control.value = pressure;
  1398. }
  1399. break;
  1400. case MIDI_STATUS_PITCH_WHEEL_CONTROL:
  1401. if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND)
  1402. {
  1403. const uint8_t lsb = midiEvent.data[1];
  1404. const uint8_t msb = midiEvent.data[2];
  1405. seqEvent.type = SND_SEQ_EVENT_PITCHBEND;
  1406. seqEvent.data.control.channel = event.channel;
  1407. seqEvent.data.control.value = ((msb << 7) | lsb) - 8192;
  1408. }
  1409. break;
  1410. default:
  1411. --midiEventCount;
  1412. break;
  1413. } // switch (status)
  1414. } break;
  1415. } // switch (event.type)
  1416. }
  1417. pData->postRtEvents.trySplice();
  1418. if (frames > timeOffset)
  1419. processSingle(audioIn, audioOut, frames - timeOffset, timeOffset, midiEventCount);
  1420. } // End of Event Input and Processing
  1421. // --------------------------------------------------------------------------------------------------------
  1422. // Plugin processing (no events)
  1423. else
  1424. {
  1425. processSingle(audioIn, audioOut, frames, 0, midiEventCount);
  1426. } // End of Plugin processing (no events)
  1427. #ifndef BUILD_BRIDGE
  1428. #if 0 // TODO
  1429. // --------------------------------------------------------------------------------------------------------
  1430. // Latency, save values for next callback
  1431. if (fLatencyIndex != -1)
  1432. {
  1433. if (pData->latency != static_cast<uint32_t>(fParamBuffers[fLatencyIndex]))
  1434. {
  1435. fLatencyChanged = true;
  1436. }
  1437. else if (pData->latency > 0)
  1438. {
  1439. if (pData->latency <= frames)
  1440. {
  1441. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1442. FloatVectorOperations::copy(pData->latencyBuffers[i], audioIn[i]+(frames-pData->latency), static_cast<int>(pData->latency));
  1443. }
  1444. else
  1445. {
  1446. for (uint32_t i=0, j, k; i < pData->audioIn.count; ++i)
  1447. {
  1448. for (k=0; k < pData->latency-frames; ++k)
  1449. pData->latencyBuffers[i][k] = pData->latencyBuffers[i][k+frames];
  1450. for (j=0; k < pData->latency; ++j, ++k)
  1451. pData->latencyBuffers[i][k] = audioIn[i][j];
  1452. }
  1453. }
  1454. }
  1455. }
  1456. #endif
  1457. // --------------------------------------------------------------------------------------------------------
  1458. // Control Output
  1459. if (pData->event.portOut != nullptr)
  1460. {
  1461. uint8_t channel;
  1462. uint16_t param;
  1463. float value;
  1464. for (uint32_t k=0; k < pData->param.count; ++k)
  1465. {
  1466. if (pData->param.data[k].type != PARAMETER_OUTPUT)
  1467. continue;
  1468. pData->param.ranges[k].fixValue(fParamBuffers[k]);
  1469. if (pData->param.data[k].midiCC > 0)
  1470. {
  1471. channel = pData->param.data[k].midiChannel;
  1472. param = static_cast<uint16_t>(pData->param.data[k].midiCC);
  1473. value = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]);
  1474. pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter, param, value);
  1475. }
  1476. }
  1477. } // End of Control Output
  1478. #endif
  1479. }
  1480. bool processSingle(const float** const audioIn, float** const audioOut, const uint32_t frames,
  1481. const uint32_t timeOffset, const ulong midiEventCount)
  1482. {
  1483. CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
  1484. if (pData->audioIn.count > 0)
  1485. {
  1486. CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false);
  1487. }
  1488. if (pData->audioOut.count > 0)
  1489. {
  1490. CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false);
  1491. }
  1492. // --------------------------------------------------------------------------------------------------------
  1493. // Try lock, silence otherwise
  1494. if (pData->engine->isOffline())
  1495. {
  1496. pData->singleMutex.lock();
  1497. }
  1498. else if (! pData->singleMutex.tryLock())
  1499. {
  1500. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1501. {
  1502. for (uint32_t k=0; k < frames; ++k)
  1503. audioOut[i][k+timeOffset] = 0.0f;
  1504. }
  1505. return false;
  1506. }
  1507. const int iframes(static_cast<int>(frames));
  1508. // --------------------------------------------------------------------------------------------------------
  1509. // Handle needsReset
  1510. if (pData->needsReset)
  1511. {
  1512. if (pData->latency.frames > 0)
  1513. {
  1514. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1515. FloatVectorOperations::clear(pData->latency.buffers[i], static_cast<int>(pData->latency.frames));
  1516. }
  1517. pData->needsReset = false;
  1518. }
  1519. // --------------------------------------------------------------------------------------------------------
  1520. // Set audio buffers
  1521. const bool customMonoOut = pData->audioOut.count == 2 && fForcedStereoOut && ! fForcedStereoIn;
  1522. const bool customStereoOut = pData->audioOut.count == 2 && fForcedStereoIn && ! fForcedStereoOut;
  1523. if (! customMonoOut)
  1524. {
  1525. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1526. FloatVectorOperations::clear(fAudioOutBuffers[i], iframes);
  1527. }
  1528. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1529. FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, iframes);
  1530. // --------------------------------------------------------------------------------------------------------
  1531. // Run plugin
  1532. uint instn = 0;
  1533. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next(), ++instn)
  1534. {
  1535. LADSPA_Handle const handle(it.getValue(nullptr));
  1536. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1537. // ----------------------------------------------------------------------------------------------------
  1538. // Mixdown for forced stereo
  1539. if (customMonoOut)
  1540. FloatVectorOperations::clear(fAudioOutBuffers[instn], iframes);
  1541. // ----------------------------------------------------------------------------------------------------
  1542. // Run it
  1543. if (fDssiDescriptor->run_synth != nullptr)
  1544. {
  1545. try {
  1546. fDssiDescriptor->run_synth(handle, frames, fMidiEvents, midiEventCount);
  1547. } CARLA_SAFE_EXCEPTION("DSSI run_synth");
  1548. }
  1549. else
  1550. {
  1551. try {
  1552. fDescriptor->run(handle, frames);
  1553. } CARLA_SAFE_EXCEPTION("DSSI run");
  1554. }
  1555. // ----------------------------------------------------------------------------------------------------
  1556. // Mixdown for forced stereo
  1557. if (customMonoOut)
  1558. FloatVectorOperations::multiply(fAudioOutBuffers[instn], 0.5f, iframes);
  1559. else if (customStereoOut)
  1560. FloatVectorOperations::copy(fExtraStereoBuffer[instn], fAudioOutBuffers[instn], iframes);
  1561. }
  1562. // --------------------------------------------------------------------------------------------------------
  1563. // Run plugin
  1564. #ifndef BUILD_BRIDGE
  1565. // --------------------------------------------------------------------------------------------------------
  1566. // Post-processing (dry/wet, volume and balance)
  1567. {
  1568. const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
  1569. const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
  1570. const bool isMono = (pData->audioIn.count == 1);
  1571. bool isPair;
  1572. float bufValue, oldBufLeft[doBalance ? frames : 1];
  1573. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1574. {
  1575. // Dry/Wet
  1576. if (doDryWet)
  1577. {
  1578. for (uint32_t k=0; k < frames; ++k)
  1579. {
  1580. #if 0 // TODO
  1581. if (k < pData->latency)
  1582. bufValue = pData->latencyBuffers[isMono ? 0 : i][k];
  1583. else if (pData->latency < frames)
  1584. bufValue = fAudioInBuffers[isMono ? 0 : i][k-pData->latency];
  1585. else
  1586. #endif
  1587. bufValue = fAudioInBuffers[isMono ? 0 : i][k];
  1588. fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
  1589. }
  1590. }
  1591. // Balance
  1592. if (doBalance)
  1593. {
  1594. isPair = (i % 2 == 0);
  1595. if (isPair)
  1596. {
  1597. CARLA_ASSERT(i+1 < pData->audioOut.count);
  1598. FloatVectorOperations::copy(oldBufLeft, fAudioOutBuffers[i], static_cast<int>(frames));
  1599. }
  1600. float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
  1601. float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
  1602. for (uint32_t k=0; k < frames; ++k)
  1603. {
  1604. if (isPair)
  1605. {
  1606. // left
  1607. fAudioOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
  1608. fAudioOutBuffers[i][k] += fAudioOutBuffers[i+1][k] * (1.0f - balRangeR);
  1609. }
  1610. else
  1611. {
  1612. // right
  1613. fAudioOutBuffers[i][k] = fAudioOutBuffers[i][k] * balRangeR;
  1614. fAudioOutBuffers[i][k] += oldBufLeft[k] * balRangeL;
  1615. }
  1616. }
  1617. }
  1618. // Volume (and buffer copy)
  1619. {
  1620. for (uint32_t k=0; k < frames; ++k)
  1621. audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume;
  1622. }
  1623. }
  1624. } // End of Post-processing
  1625. #else // BUILD_BRIDGE
  1626. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1627. {
  1628. for (uint32_t k=0; k < frames; ++k)
  1629. audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k];
  1630. }
  1631. #endif
  1632. #if 0
  1633. for (uint32_t i=0; i < pData->cvOut.count; ++i)
  1634. {
  1635. for (uint32_t k=0; k < frames; ++k)
  1636. cvOut[i][k+timeOffset] = fCvOutBuffers[i][k];
  1637. }
  1638. #endif
  1639. // --------------------------------------------------------------------------------------------------------
  1640. pData->singleMutex.unlock();
  1641. return true;
  1642. }
  1643. void bufferSizeChanged(const uint32_t newBufferSize) override
  1644. {
  1645. CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
  1646. carla_debug("CarlaPluginDSSI::bufferSizeChanged(%i) - start", newBufferSize);
  1647. const int iBufferSize(static_cast<int>(newBufferSize));
  1648. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1649. {
  1650. if (fAudioInBuffers[i] != nullptr)
  1651. delete[] fAudioInBuffers[i];
  1652. fAudioInBuffers[i] = new float[newBufferSize];
  1653. FloatVectorOperations::clear(fAudioInBuffers[i], iBufferSize);
  1654. }
  1655. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1656. {
  1657. if (fAudioOutBuffers[i] != nullptr)
  1658. delete[] fAudioOutBuffers[i];
  1659. fAudioOutBuffers[i] = new float[newBufferSize];
  1660. FloatVectorOperations::clear(fAudioOutBuffers[i], iBufferSize);
  1661. }
  1662. if (fExtraStereoBuffer[0] != nullptr)
  1663. {
  1664. delete[] fExtraStereoBuffer[0];
  1665. fExtraStereoBuffer[0] = nullptr;
  1666. }
  1667. if (fExtraStereoBuffer[1] != nullptr)
  1668. {
  1669. delete[] fExtraStereoBuffer[1];
  1670. fExtraStereoBuffer[1] = nullptr;
  1671. }
  1672. if (fForcedStereoIn && pData->audioOut.count == 2)
  1673. {
  1674. fExtraStereoBuffer[0] = new float[newBufferSize];
  1675. fExtraStereoBuffer[1] = new float[newBufferSize];
  1676. FloatVectorOperations::clear(fExtraStereoBuffer[0], iBufferSize);
  1677. FloatVectorOperations::clear(fExtraStereoBuffer[1], iBufferSize);
  1678. }
  1679. reconnectAudioPorts();
  1680. carla_debug("CarlaPluginDSSI::bufferSizeChanged(%i) - end", newBufferSize);
  1681. }
  1682. void sampleRateChanged(const double newSampleRate) override
  1683. {
  1684. CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate);
  1685. carla_debug("CarlaPluginDSSI::sampleRateChanged(%g) - start", newSampleRate);
  1686. // TODO - handle UI stuff
  1687. if (pData->active)
  1688. deactivate();
  1689. const std::size_t instanceCount(fHandles.count());
  1690. if (fDescriptor->cleanup == nullptr)
  1691. {
  1692. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  1693. {
  1694. LADSPA_Handle const handle(it.getValue(nullptr));
  1695. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1696. try {
  1697. fDescriptor->cleanup(handle);
  1698. } CARLA_SAFE_EXCEPTION("LADSPA cleanup");
  1699. }
  1700. }
  1701. fHandles.clear();
  1702. for (std::size_t i=0; i<instanceCount; ++i)
  1703. addInstance();
  1704. reconnectAudioPorts();
  1705. if (pData->active)
  1706. activate();
  1707. carla_debug("CarlaPluginDSSI::sampleRateChanged(%g) - end", newSampleRate);
  1708. }
  1709. void reconnectAudioPorts() const noexcept
  1710. {
  1711. if (fForcedStereoIn)
  1712. {
  1713. if (LADSPA_Handle const handle = fHandles.getAt(0, nullptr))
  1714. {
  1715. try {
  1716. fDescriptor->connect_port(handle, pData->audioIn.ports[0].rindex, fAudioInBuffers[0]);
  1717. } CARLA_SAFE_EXCEPTION("DSSI connect_port (forced stereo input)");
  1718. }
  1719. if (LADSPA_Handle const handle = fHandles.getAt(1, nullptr))
  1720. {
  1721. try {
  1722. fDescriptor->connect_port(handle, pData->audioIn.ports[1].rindex, fAudioInBuffers[1]);
  1723. } CARLA_SAFE_EXCEPTION("DSSI connect_port (forced stereo input)");
  1724. }
  1725. }
  1726. else
  1727. {
  1728. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  1729. {
  1730. LADSPA_Handle const handle(it.getValue(nullptr));
  1731. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1732. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1733. {
  1734. try {
  1735. fDescriptor->connect_port(handle, pData->audioIn.ports[i].rindex, fAudioInBuffers[i]);
  1736. } CARLA_SAFE_EXCEPTION("DSSI connect_port (audio input)");
  1737. }
  1738. }
  1739. }
  1740. if (fForcedStereoOut)
  1741. {
  1742. if (LADSPA_Handle const handle = fHandles.getAt(0, nullptr))
  1743. {
  1744. try {
  1745. fDescriptor->connect_port(handle, pData->audioOut.ports[0].rindex, fAudioOutBuffers[0]);
  1746. } CARLA_SAFE_EXCEPTION("DSSI connect_port (forced stereo output)");
  1747. }
  1748. if (LADSPA_Handle const handle = fHandles.getAt(1, nullptr))
  1749. {
  1750. try {
  1751. fDescriptor->connect_port(handle, pData->audioOut.ports[1].rindex, fAudioOutBuffers[1]);
  1752. } CARLA_SAFE_EXCEPTION("DSSI connect_port (forced stereo output)");
  1753. }
  1754. }
  1755. else
  1756. {
  1757. for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
  1758. {
  1759. LADSPA_Handle const handle(it.getValue(nullptr));
  1760. CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
  1761. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1762. {
  1763. try {
  1764. fDescriptor->connect_port(handle, pData->audioOut.ports[i].rindex, fAudioOutBuffers[i]);
  1765. } CARLA_SAFE_EXCEPTION("DSSI connect_port (audio output)");
  1766. }
  1767. }
  1768. }
  1769. }
  1770. // -------------------------------------------------------------------
  1771. // Plugin buffers
  1772. void clearBuffers() noexcept override
  1773. {
  1774. carla_debug("CarlaPluginDSSI::clearBuffers() - start");
  1775. if (fAudioInBuffers != nullptr)
  1776. {
  1777. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1778. {
  1779. if (fAudioInBuffers[i] != nullptr)
  1780. {
  1781. delete[] fAudioInBuffers[i];
  1782. fAudioInBuffers[i] = nullptr;
  1783. }
  1784. }
  1785. delete[] fAudioInBuffers;
  1786. fAudioInBuffers = nullptr;
  1787. }
  1788. if (fAudioOutBuffers != nullptr)
  1789. {
  1790. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1791. {
  1792. if (fAudioOutBuffers[i] != nullptr)
  1793. {
  1794. delete[] fAudioOutBuffers[i];
  1795. fAudioOutBuffers[i] = nullptr;
  1796. }
  1797. }
  1798. delete[] fAudioOutBuffers;
  1799. fAudioOutBuffers = nullptr;
  1800. }
  1801. if (fExtraStereoBuffer[0] != nullptr)
  1802. {
  1803. delete[] fExtraStereoBuffer[0];
  1804. fExtraStereoBuffer[0] = nullptr;
  1805. }
  1806. if (fExtraStereoBuffer[1] != nullptr)
  1807. {
  1808. delete[] fExtraStereoBuffer[1];
  1809. fExtraStereoBuffer[1] = nullptr;
  1810. }
  1811. if (fParamBuffers != nullptr)
  1812. {
  1813. delete[] fParamBuffers;
  1814. fParamBuffers = nullptr;
  1815. }
  1816. CarlaPlugin::clearBuffers();
  1817. carla_debug("CarlaPluginDSSI::clearBuffers() - end");
  1818. }
  1819. #ifdef HAVE_LIBLO
  1820. // -------------------------------------------------------------------
  1821. // OSC stuff
  1822. void handleOscMessage(const char* const method, const int argc, const void* const argvx, const char* const types, const lo_message msg) override
  1823. {
  1824. const lo_address source(lo_message_get_source(msg));
  1825. CARLA_SAFE_ASSERT_RETURN(source != nullptr,);
  1826. // protocol for DSSI UIs *must* be UDP
  1827. CARLA_SAFE_ASSERT_RETURN(lo_address_get_protocol(source) == LO_UDP,);
  1828. if (fOscData.source == nullptr)
  1829. {
  1830. // if no UI is registered yet only "update" message is valid
  1831. CARLA_SAFE_ASSERT_RETURN(std::strcmp(method, "update") == 0,)
  1832. }
  1833. else
  1834. {
  1835. // make sure message source is the DSSI UI
  1836. const char* const msghost = lo_address_get_hostname(source);
  1837. const char* const msgport = lo_address_get_port(source);
  1838. const char* const ourhost = lo_address_get_hostname(fOscData.source);
  1839. const char* const ourport = lo_address_get_port(fOscData.source);
  1840. CARLA_SAFE_ASSERT_RETURN(std::strcmp(msghost, ourhost) == 0,);
  1841. CARLA_SAFE_ASSERT_RETURN(std::strcmp(msgport, ourport) == 0,);
  1842. }
  1843. const lo_arg* const* const argv(static_cast<const lo_arg* const* const>(argvx));
  1844. if (std::strcmp(method, "configure") == 0)
  1845. return handleOscMessageConfigure(argc, argv, types);
  1846. if (std::strcmp(method, "control") == 0)
  1847. return handleOscMessageControl(argc, argv, types);
  1848. if (std::strcmp(method, "program") == 0)
  1849. return handleOscMessageProgram(argc, argv, types);
  1850. if (std::strcmp(method, "midi") == 0)
  1851. return handleOscMessageMIDI(argc, argv, types);
  1852. if (std::strcmp(method, "update") == 0)
  1853. return handleOscMessageUpdate(argc, argv, types, lo_message_get_source(msg));
  1854. if (std::strcmp(method, "exiting") == 0)
  1855. return handleOscMessageExiting();
  1856. carla_stdout("CarlaPluginDSSI::handleOscMessage() - unknown method '%s'", method);
  1857. }
  1858. void handleOscMessageConfigure(const int argc, const lo_arg* const* const argv, const char* const types)
  1859. {
  1860. carla_debug("CarlaPluginDSSI::handleMsgConfigure()");
  1861. CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "ss");
  1862. const char* const key = (const char*)&argv[0]->s;
  1863. const char* const value = (const char*)&argv[1]->s;
  1864. setCustomData(CUSTOM_DATA_TYPE_STRING, key, value, false);
  1865. }
  1866. void handleOscMessageControl(const int argc, const lo_arg* const* const argv, const char* const types)
  1867. {
  1868. carla_debug("CarlaPluginDSSI::handleMsgControl()");
  1869. CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "if");
  1870. const int32_t rindex = argv[0]->i;
  1871. const float value = argv[1]->f;
  1872. setParameterValueByRealIndex(rindex, value, false, true, true);
  1873. }
  1874. void handleOscMessageProgram(const int argc, const lo_arg* const* const argv, const char* const types)
  1875. {
  1876. carla_debug("CarlaPluginDSSI::handleMsgProgram()");
  1877. CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "ii");
  1878. const int32_t bank = argv[0]->i;
  1879. const int32_t program = argv[1]->i;
  1880. CARLA_SAFE_ASSERT_RETURN(bank >= 0,);
  1881. CARLA_SAFE_ASSERT_RETURN(program >= 0,);
  1882. setMidiProgramById(static_cast<uint32_t>(bank), static_cast<uint32_t>(program), false, true, true);
  1883. }
  1884. void handleOscMessageMIDI(const int argc, const lo_arg* const* const argv, const char* const types)
  1885. {
  1886. carla_debug("CarlaPluginDSSI::handleMsgMidi()");
  1887. CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(1, "m");
  1888. if (getMidiInCount() == 0)
  1889. {
  1890. carla_stderr("CarlaPluginDSSI::handleMsgMidi() - received midi when plugin has no midi inputs");
  1891. return;
  1892. }
  1893. const uint8_t* const data = argv[0]->m;
  1894. uint8_t status = data[1];
  1895. uint8_t channel = status & 0x0F;
  1896. // Fix bad note-off
  1897. if (MIDI_IS_STATUS_NOTE_ON(status) && data[3] == 0)
  1898. status = MIDI_STATUS_NOTE_OFF;
  1899. if (MIDI_IS_STATUS_NOTE_OFF(status))
  1900. {
  1901. const uint8_t note = data[2];
  1902. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1903. sendMidiSingleNote(channel, note, 0, false, true, true);
  1904. }
  1905. else if (MIDI_IS_STATUS_NOTE_ON(status))
  1906. {
  1907. const uint8_t note = data[2];
  1908. const uint8_t velo = data[3];
  1909. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1910. CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
  1911. sendMidiSingleNote(channel, note, velo, false, true, true);
  1912. }
  1913. }
  1914. void handleOscMessageUpdate(const int argc, const lo_arg* const* const argv, const char* const types, const lo_address source)
  1915. {
  1916. carla_debug("CarlaPluginDSSI::handleMsgUpdate()");
  1917. CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(1, "s");
  1918. const char* const url = (const char*)&argv[0]->s;
  1919. // FIXME - remove debug prints later
  1920. carla_stdout("CarlaPluginDSSI::updateOscData(%p, \"%s\")", source, url);
  1921. fOscData.clear();
  1922. const int proto = lo_address_get_protocol(source);
  1923. {
  1924. const char* host = lo_address_get_hostname(source);
  1925. const char* port = lo_address_get_port(source);
  1926. fOscData.source = lo_address_new_with_proto(proto, host, port);
  1927. carla_stdout("CarlaPlugin::updateOscData() - source: host \"%s\", port \"%s\"", host, port);
  1928. }
  1929. {
  1930. char* host = lo_url_get_hostname(url);
  1931. char* port = lo_url_get_port(url);
  1932. fOscData.path = carla_strdup_free(lo_url_get_path(url));
  1933. fOscData.target = lo_address_new_with_proto(proto, host, port);
  1934. carla_stdout("CarlaPlugin::updateOscData() - target: host \"%s\", port \"%s\", path \"%s\"", host, port, fOscData.path);
  1935. std::free(host);
  1936. std::free(port);
  1937. }
  1938. osc_send_sample_rate(fOscData, static_cast<float>(pData->engine->getSampleRate()));
  1939. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  1940. {
  1941. const CustomData& customData(it.getValue(kCustomDataFallback));
  1942. CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
  1943. if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_STRING) == 0)
  1944. osc_send_configure(fOscData, customData.key, customData.value);
  1945. }
  1946. if (pData->prog.current >= 0)
  1947. osc_send_program(fOscData, static_cast<uint32_t>(pData->prog.current));
  1948. if (pData->midiprog.current >= 0)
  1949. {
  1950. const MidiProgramData& curMidiProg(pData->midiprog.getCurrent());
  1951. if (getType() == PLUGIN_DSSI)
  1952. osc_send_program(fOscData, curMidiProg.bank, curMidiProg.program);
  1953. else
  1954. osc_send_midi_program(fOscData, curMidiProg.bank, curMidiProg.program);
  1955. }
  1956. for (uint32_t i=0; i < pData->param.count; ++i)
  1957. osc_send_control(fOscData, pData->param.data[i].rindex, getParameterValue(i));
  1958. if ((pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0 && pData->engine->getOptions().frontendWinId != 0)
  1959. pData->transientTryCounter = 1;
  1960. carla_stdout("CarlaPluginDSSI::updateOscData() - done");
  1961. }
  1962. void handleOscMessageExiting()
  1963. {
  1964. carla_debug("CarlaPluginDSSI::handleMsgExiting()");
  1965. // hide UI
  1966. showCustomUI(false);
  1967. // tell frontend
  1968. pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr);
  1969. }
  1970. // -------------------------------------------------------------------
  1971. // Post-poned UI Stuff
  1972. void uiParameterChange(const uint32_t index, const float value) noexcept override
  1973. {
  1974. CARLA_SAFE_ASSERT_RETURN(index < pData->param.count,);
  1975. if (fOscData.target == nullptr)
  1976. return;
  1977. osc_send_control(fOscData, pData->param.data[index].rindex, value);
  1978. }
  1979. void uiMidiProgramChange(const uint32_t index) noexcept override
  1980. {
  1981. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
  1982. if (fOscData.target == nullptr)
  1983. return;
  1984. osc_send_program(fOscData, pData->midiprog.data[index].bank, pData->midiprog.data[index].program);
  1985. }
  1986. void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept override
  1987. {
  1988. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1989. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1990. CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
  1991. if (fOscData.target == nullptr)
  1992. return;
  1993. #if 0
  1994. uint8_t midiData[4];
  1995. midiData[0] = 0;
  1996. midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
  1997. midiData[2] = note;
  1998. midiData[3] = velo;
  1999. osc_send_midi(fOscData, midiData);
  2000. #endif
  2001. }
  2002. void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept override
  2003. {
  2004. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  2005. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  2006. if (fOscData.target == nullptr)
  2007. return;
  2008. #if 0
  2009. uint8_t midiData[4];
  2010. midiData[0] = 0;
  2011. midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
  2012. midiData[2] = note;
  2013. midiData[3] = 0;
  2014. osc_send_midi(fOscData, midiData);
  2015. #endif
  2016. }
  2017. #endif // HAVE_LIBLO
  2018. // -------------------------------------------------------------------
  2019. const void* getNativeDescriptor() const noexcept override
  2020. {
  2021. return fDssiDescriptor;
  2022. }
  2023. #ifdef HAVE_LIBLO
  2024. uintptr_t getUiBridgeProcessId() const noexcept override
  2025. {
  2026. return fThreadUI.getProcessPID();
  2027. }
  2028. const void* getExtraStuff() const noexcept override
  2029. {
  2030. return fUiFilename;
  2031. }
  2032. #endif
  2033. // -------------------------------------------------------------------
  2034. bool init(const char* const filename, const char* const name, const char* const label, const uint options)
  2035. {
  2036. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  2037. // ---------------------------------------------------------------
  2038. // first checks
  2039. if (pData->client != nullptr)
  2040. {
  2041. pData->engine->setLastError("Plugin client is already registered");
  2042. return false;
  2043. }
  2044. if (filename == nullptr || filename[0] == '\0')
  2045. {
  2046. pData->engine->setLastError("null filename");
  2047. return false;
  2048. }
  2049. if (label == nullptr || label[0] == '\0')
  2050. {
  2051. pData->engine->setLastError("null label");
  2052. return false;
  2053. }
  2054. // ---------------------------------------------------------------
  2055. // open DLL
  2056. if (! pData->libOpen(filename))
  2057. {
  2058. pData->engine->setLastError(pData->libError(filename));
  2059. return false;
  2060. }
  2061. // ---------------------------------------------------------------
  2062. // get DLL main entry
  2063. const DSSI_Descriptor_Function descFn = pData->libSymbol<DSSI_Descriptor_Function>("dssi_descriptor");
  2064. if (descFn == nullptr)
  2065. {
  2066. pData->engine->setLastError("Could not find the DSSI Descriptor in the plugin library");
  2067. return false;
  2068. }
  2069. // ---------------------------------------------------------------
  2070. // get descriptor that matches label
  2071. for (ulong d=0;; ++d)
  2072. {
  2073. try {
  2074. fDssiDescriptor = descFn(d);
  2075. }
  2076. catch(...) {
  2077. carla_stderr2("Caught exception when trying to get DSSI descriptor");
  2078. fDescriptor = nullptr;
  2079. fDssiDescriptor = nullptr;
  2080. break;
  2081. }
  2082. if (fDssiDescriptor == nullptr)
  2083. break;
  2084. fDescriptor = fDssiDescriptor->LADSPA_Plugin;
  2085. if (fDescriptor == nullptr)
  2086. {
  2087. carla_stderr2("WARNING - Missing LADSPA interface, will not use this plugin");
  2088. fDssiDescriptor = nullptr;
  2089. break;
  2090. }
  2091. if (fDescriptor->Label == nullptr || fDescriptor->Label[0] == '\0')
  2092. {
  2093. carla_stderr2("WARNING - Got an invalid label, will not use this plugin");
  2094. fDescriptor = nullptr;
  2095. fDssiDescriptor = nullptr;
  2096. break;
  2097. }
  2098. if (fDescriptor->run == nullptr)
  2099. {
  2100. carla_stderr2("WARNING - Plugin has no run, cannot use it");
  2101. fDescriptor = nullptr;
  2102. fDssiDescriptor = nullptr;
  2103. break;
  2104. }
  2105. if (std::strcmp(fDescriptor->Label, label) == 0)
  2106. break;
  2107. }
  2108. if (fDescriptor == nullptr || fDssiDescriptor == nullptr)
  2109. {
  2110. pData->engine->setLastError("Could not find the requested plugin label in the plugin library");
  2111. return false;
  2112. }
  2113. // ---------------------------------------------------------------
  2114. // check if uses global instance
  2115. if (fDssiDescriptor->run_synth == nullptr && fDssiDescriptor->run_multiple_synths != nullptr)
  2116. {
  2117. pData->engine->setLastError("This plugin requires run_multiple_synths which is not supported");
  2118. return false;
  2119. }
  2120. // ---------------------------------------------------------------
  2121. // get info
  2122. if (name != nullptr && name[0] != '\0')
  2123. pData->name = pData->engine->getUniquePluginName(name);
  2124. else if (fDescriptor->Name != nullptr && fDescriptor->Name[0] != '\0')
  2125. pData->name = pData->engine->getUniquePluginName(fDescriptor->Name);
  2126. else
  2127. pData->name = pData->engine->getUniquePluginName(fDescriptor->Label);
  2128. pData->filename = carla_strdup(filename);
  2129. // ---------------------------------------------------------------
  2130. // register client
  2131. pData->client = pData->engine->addClient(this);
  2132. if (pData->client == nullptr || ! pData->client->isOk())
  2133. {
  2134. pData->engine->setLastError("Failed to register plugin client");
  2135. return false;
  2136. }
  2137. // ---------------------------------------------------------------
  2138. // initialize plugin
  2139. if (! addInstance())
  2140. return false;
  2141. // ---------------------------------------------------------------
  2142. // find latency port index
  2143. for (uint32_t i=0, iCtrl=0, count=getSafePortCount(); i<count; ++i)
  2144. {
  2145. const int portType(fDescriptor->PortDescriptors[i]);
  2146. if (! LADSPA_IS_PORT_CONTROL(portType))
  2147. continue;
  2148. const uint32_t index(iCtrl++);
  2149. if (! LADSPA_IS_PORT_OUTPUT(portType))
  2150. continue;
  2151. const char* const portName(fDescriptor->PortNames[i]);
  2152. CARLA_SAFE_ASSERT_BREAK(portName != nullptr);
  2153. if (std::strcmp(portName, "latency") == 0 ||
  2154. std::strcmp(portName, "_latency") == 0)
  2155. {
  2156. fLatencyIndex = static_cast<int32_t>(index);
  2157. break;
  2158. }
  2159. }
  2160. // ---------------------------------------------------------------
  2161. // check for custom data extension
  2162. if (fDssiDescriptor->configure != nullptr)
  2163. {
  2164. if (char* const error = fDssiDescriptor->configure(fHandles.getFirst(nullptr), DSSI_CUSTOMDATA_EXTENSION_KEY, ""))
  2165. {
  2166. if (std::strcmp(error, "true") == 0 && fDssiDescriptor->get_custom_data != nullptr
  2167. && fDssiDescriptor->set_custom_data != nullptr)
  2168. fUsesCustomData = true;
  2169. std::free(error);
  2170. }
  2171. }
  2172. // ---------------------------------------------------------------
  2173. // check if this is dssi-vst
  2174. fIsDssiVst = CarlaString(filename).contains("dssi-vst", true);
  2175. #ifdef HAVE_LIBLO
  2176. // ---------------------------------------------------------------
  2177. // check for gui
  2178. if (const char* const guiFilename = find_dssi_ui(filename, fDescriptor->Label))
  2179. {
  2180. fUiFilename = guiFilename;
  2181. fThreadUI.setData(guiFilename, fDescriptor->Label);
  2182. }
  2183. #endif
  2184. // ---------------------------------------------------------------
  2185. // set default options
  2186. pData->options = 0x0;
  2187. /**/ if (fLatencyIndex >= 0 || fIsDssiVst)
  2188. pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
  2189. else if (options & PLUGIN_OPTION_FIXED_BUFFERS)
  2190. pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
  2191. /**/ if (pData->engine->getOptions().forceStereo)
  2192. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  2193. else if (options & PLUGIN_OPTION_FORCE_STEREO)
  2194. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  2195. if (fUsesCustomData)
  2196. pData->options |= PLUGIN_OPTION_USE_CHUNKS;
  2197. if (fDssiDescriptor->run_synth != nullptr)
  2198. {
  2199. pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  2200. pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  2201. pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
  2202. pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  2203. if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
  2204. pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  2205. }
  2206. return true;
  2207. }
  2208. // -------------------------------------------------------------------
  2209. private:
  2210. LinkedList<LADSPA_Handle> fHandles;
  2211. const LADSPA_Descriptor* fDescriptor;
  2212. const DSSI_Descriptor* fDssiDescriptor;
  2213. float** fAudioInBuffers;
  2214. float** fAudioOutBuffers;
  2215. float* fExtraStereoBuffer[2]; // used only if forcedStereoIn and audioOut == 2
  2216. float* fParamBuffers;
  2217. snd_seq_event_t fMidiEvents[kPluginMaxMidiEvents];
  2218. int32_t fLatencyIndex; // -1 if invalid
  2219. bool fForcedStereoIn;
  2220. bool fForcedStereoOut;
  2221. bool fIsDssiVst;
  2222. bool fUsesCustomData;
  2223. #ifdef HAVE_LIBLO
  2224. CarlaOscData fOscData;
  2225. CarlaThreadDSSIUI fThreadUI;
  2226. const char* fUiFilename;
  2227. #endif
  2228. // -------------------------------------------------------------------
  2229. bool addInstance()
  2230. {
  2231. LADSPA_Handle handle;
  2232. try {
  2233. handle = fDescriptor->instantiate(fDescriptor, static_cast<ulong>(pData->engine->getSampleRate()));
  2234. } CARLA_SAFE_EXCEPTION_RETURN_ERR("LADSPA instantiate", "Plugin failed to initialize");
  2235. for (uint32_t i=0, count=pData->param.count; i<count; ++i)
  2236. {
  2237. const int32_t rindex(pData->param.data[i].rindex);
  2238. CARLA_SAFE_ASSERT_CONTINUE(rindex >= 0);
  2239. try {
  2240. fDescriptor->connect_port(handle, static_cast<ulong>(rindex), &fParamBuffers[i]);
  2241. } CARLA_SAFE_EXCEPTION("LADSPA connect_port");
  2242. }
  2243. if (fHandles.append(handle))
  2244. return true;
  2245. try {
  2246. fDescriptor->cleanup(handle);
  2247. } CARLA_SAFE_EXCEPTION("LADSPA cleanup");
  2248. pData->engine->setLastError("Out of memory");
  2249. return false;
  2250. }
  2251. uint32_t getSafePortCount() const noexcept
  2252. {
  2253. if (fDescriptor->PortCount == 0)
  2254. return 0;
  2255. CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortDescriptors != nullptr, 0);
  2256. CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortRangeHints != nullptr, 0);
  2257. CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames != nullptr, 0);
  2258. return static_cast<uint32_t>(fDescriptor->PortCount);
  2259. }
  2260. bool getSeparatedParameterNameOrUnit(const char* const paramName, char* const strBuf, const bool wantName) const noexcept
  2261. {
  2262. if (_getSeparatedParameterNameOrUnitImpl(paramName, strBuf, wantName, true))
  2263. return true;
  2264. if (_getSeparatedParameterNameOrUnitImpl(paramName, strBuf, wantName, false))
  2265. return true;
  2266. return false;
  2267. }
  2268. static bool _getSeparatedParameterNameOrUnitImpl(const char* const paramName, char* const strBuf,
  2269. const bool wantName, const bool useBracket) noexcept
  2270. {
  2271. const char* const sepBracketStart(std::strstr(paramName, useBracket ? " [" : " ("));
  2272. if (sepBracketStart == nullptr)
  2273. return false;
  2274. const char* const sepBracketEnd(std::strstr(sepBracketStart, useBracket ? "]" : ")"));
  2275. if (sepBracketEnd == nullptr)
  2276. return false;
  2277. const std::size_t unitSize(static_cast<std::size_t>(sepBracketEnd-sepBracketStart-2));
  2278. if (unitSize > 7) // very unlikely to have such big unit
  2279. return false;
  2280. const std::size_t sepIndex(std::strlen(paramName)-unitSize-3);
  2281. // just in case
  2282. if (sepIndex+2 >= STR_MAX)
  2283. return false;
  2284. if (wantName)
  2285. {
  2286. std::strncpy(strBuf, paramName, sepIndex);
  2287. strBuf[sepIndex] = '\0';
  2288. }
  2289. else
  2290. {
  2291. std::strncpy(strBuf, paramName+(sepIndex+2), unitSize);
  2292. strBuf[unitSize] = '\0';
  2293. }
  2294. return true;
  2295. }
  2296. // -------------------------------------------------------------------
  2297. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginDSSI)
  2298. };
  2299. // -------------------------------------------------------------------------------------------------------------------
  2300. CarlaPlugin* CarlaPlugin::newDSSI(const Initializer& init)
  2301. {
  2302. carla_debug("CarlaPlugin::newDSSI({%p, \"%s\", \"%s\", \"%s\", " P_INT64 ", %x})",
  2303. init.engine, init.filename, init.name, init.label, init.uniqueId, init.options);
  2304. CarlaPluginDSSI* const plugin(new CarlaPluginDSSI(init.engine, init.id));
  2305. if (! plugin->init(init.filename, init.name, init.label, init.options))
  2306. {
  2307. delete plugin;
  2308. return nullptr;
  2309. }
  2310. return plugin;
  2311. }
  2312. // -------------------------------------------------------------------------------------------------------------------
  2313. CARLA_BACKEND_END_NAMESPACE