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

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