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.

CarlaPluginNative.cpp 114KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 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
10 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
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
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
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
10 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
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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
6 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 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
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
10 years ago
10 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195
  1. /*
  2. * Carla Native Plugin
  3. * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaPluginInternal.hpp"
  18. #include "CarlaEngine.hpp"
  19. #include "CarlaBackendUtils.hpp"
  20. #include "CarlaMathUtils.hpp"
  21. #include "CarlaNative.h"
  22. #include "water/misc/Time.h"
  23. #include "water/text/StringArray.h"
  24. using water::String;
  25. using water::StringArray;
  26. // -----------------------------------------------------------------------
  27. // used in carla-base.cpp
  28. std::size_t carla_getNativePluginCount() noexcept;
  29. const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) noexcept;
  30. // -----------------------------------------------------------------------
  31. static LinkedList<const NativePluginDescriptor*> gPluginDescriptors;
  32. void carla_register_native_plugin(const NativePluginDescriptor* desc)
  33. {
  34. gPluginDescriptors.append(desc);
  35. }
  36. // -----------------------------------------------------------------------
  37. static
  38. class NativePluginInitializer
  39. {
  40. public:
  41. NativePluginInitializer() noexcept
  42. : fNeedsInit(true) {}
  43. ~NativePluginInitializer() noexcept
  44. {
  45. gPluginDescriptors.clear();
  46. }
  47. void initIfNeeded() noexcept
  48. {
  49. if (! fNeedsInit)
  50. return;
  51. fNeedsInit = false;
  52. try {
  53. carla_register_all_native_plugins();
  54. } CARLA_SAFE_EXCEPTION("carla_register_all_native_plugins")
  55. }
  56. private:
  57. bool fNeedsInit;
  58. } sPluginInitializer;
  59. // -----------------------------------------------------------------------
  60. std::size_t carla_getNativePluginCount() noexcept
  61. {
  62. sPluginInitializer.initIfNeeded();
  63. return gPluginDescriptors.count();
  64. }
  65. const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) noexcept
  66. {
  67. sPluginInitializer.initIfNeeded();
  68. return gPluginDescriptors.getAt(index, nullptr);
  69. }
  70. // -----------------------------------------------------------------------
  71. CARLA_BACKEND_START_NAMESPACE
  72. // -------------------------------------------------------------------
  73. // Fallback data
  74. static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
  75. static EngineEvent kNullEngineEvent = {
  76. kEngineEventTypeNull, 0, 0, {{ kEngineControlEventTypeNull, 0, -1, 0.0f, true }}
  77. };
  78. // -----------------------------------------------------------------------
  79. struct NativePluginMidiOutData {
  80. uint32_t count;
  81. uint32_t* indexes;
  82. CarlaEngineEventPort** ports;
  83. NativePluginMidiOutData() noexcept
  84. : count(0),
  85. indexes(nullptr),
  86. ports(nullptr) {}
  87. ~NativePluginMidiOutData() noexcept
  88. {
  89. CARLA_SAFE_ASSERT_INT(count == 0, count);
  90. CARLA_SAFE_ASSERT(indexes == nullptr);
  91. CARLA_SAFE_ASSERT(ports == nullptr);
  92. }
  93. bool createNew(const uint32_t newCount)
  94. {
  95. CARLA_SAFE_ASSERT_INT(count == 0, count);
  96. CARLA_SAFE_ASSERT_RETURN(indexes == nullptr, false);
  97. CARLA_SAFE_ASSERT_RETURN(ports == nullptr, false);
  98. CARLA_SAFE_ASSERT_RETURN(newCount > 0, false);
  99. indexes = new uint32_t[newCount];
  100. ports = new CarlaEngineEventPort*[newCount];
  101. count = newCount;
  102. carla_zeroStructs(indexes, newCount);
  103. carla_zeroStructs(ports, newCount);
  104. return true;
  105. }
  106. void clear() noexcept
  107. {
  108. if (ports != nullptr)
  109. {
  110. for (uint32_t i=0; i < count; ++i)
  111. {
  112. if (ports[i] != nullptr)
  113. {
  114. delete ports[i];
  115. ports[i] = nullptr;
  116. }
  117. }
  118. delete[] ports;
  119. ports = nullptr;
  120. }
  121. if (indexes != nullptr)
  122. {
  123. delete[] indexes;
  124. indexes = nullptr;
  125. }
  126. count = 0;
  127. }
  128. void initBuffers() const noexcept
  129. {
  130. for (uint32_t i=0; i < count; ++i)
  131. {
  132. if (ports[i] != nullptr)
  133. ports[i]->initBuffer();
  134. }
  135. }
  136. CARLA_DECLARE_NON_COPYABLE(NativePluginMidiOutData)
  137. };
  138. struct NativePluginMidiInData : NativePluginMidiOutData {
  139. struct MultiPortData {
  140. uint32_t cachedEventCount;
  141. uint32_t usedIndex;
  142. };
  143. MultiPortData* multiportData;
  144. NativePluginMidiInData() noexcept
  145. : NativePluginMidiOutData(),
  146. multiportData(nullptr) {}
  147. ~NativePluginMidiInData() noexcept
  148. {
  149. CARLA_SAFE_ASSERT(multiportData == nullptr);
  150. }
  151. bool createNew(const uint32_t newCount)
  152. {
  153. if (! NativePluginMidiOutData::createNew(newCount))
  154. return false;
  155. multiportData = new MultiPortData[newCount];
  156. carla_zeroStructs(multiportData, newCount);
  157. return true;
  158. }
  159. void clear() noexcept
  160. {
  161. if (multiportData != nullptr)
  162. {
  163. delete[] multiportData;
  164. multiportData = nullptr;
  165. }
  166. NativePluginMidiOutData::clear();
  167. }
  168. void initBuffers(CarlaEngineEventPort* const port) const noexcept
  169. {
  170. if (count == 1)
  171. {
  172. CARLA_SAFE_ASSERT_RETURN(port != nullptr,);
  173. carla_zeroStruct(multiportData[0]);
  174. multiportData[0].cachedEventCount = port->getEventCount();
  175. return;
  176. }
  177. for (uint32_t i=0; i < count; ++i)
  178. {
  179. carla_zeroStruct(multiportData[i]);
  180. if (ports[i] != nullptr)
  181. {
  182. ports[i]->initBuffer();
  183. multiportData[i].cachedEventCount = ports[i]->getEventCount();
  184. }
  185. }
  186. }
  187. CARLA_DECLARE_NON_COPYABLE(NativePluginMidiInData)
  188. };
  189. // -----------------------------------------------------
  190. class CarlaPluginNative : public CarlaPlugin
  191. {
  192. public:
  193. CarlaPluginNative(CarlaEngine* const engine, const uint id)
  194. : CarlaPlugin(engine, id),
  195. fHandle(nullptr),
  196. fHandle2(nullptr),
  197. fHost(),
  198. fDescriptor(nullptr),
  199. fIsProcessing(false),
  200. fIsOffline(engine->isOffline()),
  201. fIsUiAvailable(false),
  202. fIsUiVisible(false),
  203. fNeedsIdle(false),
  204. fInlineDisplayNeedsRedraw(false),
  205. fInlineDisplayLastRedrawTime(0),
  206. fLastProjectFilename(),
  207. fLastProjectFolder(),
  208. fAudioAndCvInBuffers(nullptr),
  209. fAudioAndCvOutBuffers(nullptr),
  210. fMidiEventInCount(0),
  211. fMidiEventOutCount(0),
  212. fCurBufferSize(engine->getBufferSize()),
  213. fCurSampleRate(engine->getSampleRate()),
  214. fMidiIn(),
  215. fMidiOut(),
  216. fTimeInfo()
  217. {
  218. carla_debug("CarlaPluginNative::CarlaPluginNative(%p, %i)", engine, id);
  219. carla_fill(fCurMidiProgs, 0, MAX_MIDI_CHANNELS);
  220. carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents);
  221. carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents);
  222. carla_zeroStruct(fTimeInfo);
  223. fHost.handle = this;
  224. fHost.resourceDir = carla_strdup(engine->getOptions().resourceDir);
  225. fHost.uiName = nullptr;
  226. fHost.uiParentId = engine->getOptions().frontendWinId;
  227. fHost.get_buffer_size = carla_host_get_buffer_size;
  228. fHost.get_sample_rate = carla_host_get_sample_rate;
  229. fHost.is_offline = carla_host_is_offline;
  230. fHost.get_time_info = carla_host_get_time_info;
  231. fHost.write_midi_event = carla_host_write_midi_event;
  232. fHost.ui_parameter_changed = carla_host_ui_parameter_changed;
  233. fHost.ui_custom_data_changed = carla_host_ui_custom_data_changed;
  234. fHost.ui_closed = carla_host_ui_closed;
  235. fHost.ui_open_file = carla_host_ui_open_file;
  236. fHost.ui_save_file = carla_host_ui_save_file;
  237. fHost.dispatcher = carla_host_dispatcher;
  238. }
  239. ~CarlaPluginNative() override
  240. {
  241. carla_debug("CarlaPluginNative::~CarlaPluginNative()");
  242. fInlineDisplayNeedsRedraw = false;
  243. // close UI
  244. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  245. {
  246. if (fIsUiVisible && fDescriptor != nullptr && fDescriptor->ui_show != nullptr && fHandle != nullptr)
  247. fDescriptor->ui_show(fHandle, false);
  248. #ifndef BUILD_BRIDGE
  249. pData->transientTryCounter = 0;
  250. #endif
  251. }
  252. pData->singleMutex.lock();
  253. pData->masterMutex.lock();
  254. if (pData->client != nullptr && pData->client->isActive())
  255. pData->client->deactivate(true);
  256. CARLA_ASSERT(! fIsProcessing);
  257. if (pData->active)
  258. {
  259. deactivate();
  260. pData->active = false;
  261. }
  262. if (fDescriptor != nullptr)
  263. {
  264. if (fDescriptor->cleanup != nullptr)
  265. {
  266. if (fHandle != nullptr)
  267. fDescriptor->cleanup(fHandle);
  268. if (fHandle2 != nullptr)
  269. fDescriptor->cleanup(fHandle2);
  270. }
  271. fHandle = nullptr;
  272. fHandle2 = nullptr;
  273. fDescriptor = nullptr;
  274. }
  275. if (fHost.resourceDir != nullptr)
  276. {
  277. delete[] fHost.resourceDir;
  278. fHost.resourceDir = nullptr;
  279. }
  280. if (fHost.uiName != nullptr)
  281. {
  282. std::free(const_cast<char*>(fHost.uiName));
  283. fHost.uiName = nullptr;
  284. }
  285. clearBuffers();
  286. }
  287. // -------------------------------------------------------------------
  288. // Information (base)
  289. PluginType getType() const noexcept override
  290. {
  291. return PLUGIN_INTERNAL;
  292. }
  293. PluginCategory getCategory() const noexcept override
  294. {
  295. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, PLUGIN_CATEGORY_NONE);
  296. return static_cast<PluginCategory>(fDescriptor->category);
  297. }
  298. // -------------------------------------------------------------------
  299. // Information (count)
  300. uint32_t getMidiInCount() const noexcept override
  301. {
  302. return fMidiIn.count;
  303. }
  304. uint32_t getMidiOutCount() const noexcept override
  305. {
  306. return fMidiOut.count;
  307. }
  308. uint32_t getParameterScalePointCount(const uint32_t parameterId) const noexcept override
  309. {
  310. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0);
  311. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, 0);
  312. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0);
  313. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
  314. // FIXME - try
  315. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  316. return param->scalePointCount;
  317. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  318. return 0;
  319. }
  320. // -------------------------------------------------------------------
  321. // Information (current data)
  322. // nothing
  323. // -------------------------------------------------------------------
  324. // Information (per-plugin data)
  325. uint getOptionsAvailable() const noexcept override
  326. {
  327. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0x0);
  328. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0x0);
  329. bool hasMidiProgs = false;
  330. if (fDescriptor->get_midi_program_count != nullptr)
  331. {
  332. try {
  333. hasMidiProgs = fDescriptor->get_midi_program_count(fHandle) > 0;
  334. } catch (...) {}
  335. }
  336. uint options = 0x0;
  337. // can't disable fixed buffers if required by the plugin
  338. if ((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) == 0x0)
  339. options |= PLUGIN_OPTION_FIXED_BUFFERS;
  340. // can't disable forced stereo if enabled in the engine, or using CV
  341. if (pData->engine->getOptions().forceStereo || pData->cvIn.count != 0 || pData->cvOut.count != 0)
  342. pass();
  343. // if inputs or outputs are just 1, then yes we can force stereo
  344. else if (pData->audioIn.count == 1 || pData->audioOut.count == 1 || fHandle2 != nullptr)
  345. options |= PLUGIN_OPTION_FORCE_STEREO;
  346. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES)
  347. options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  348. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE)
  349. options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  350. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH)
  351. options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  352. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PITCHBEND)
  353. options |= PLUGIN_OPTION_SEND_PITCHBEND;
  354. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF)
  355. options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  356. if (fDescriptor->midiIns > 0)
  357. options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  358. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES)
  359. options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  360. else if (hasMidiProgs)
  361. options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  362. return options;
  363. }
  364. float getParameterValue(const uint32_t parameterId) const noexcept override
  365. {
  366. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0.0f);
  367. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_value != nullptr, 0.0f);
  368. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0.0f);
  369. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
  370. // FIXME - try
  371. return fDescriptor->get_parameter_value(fHandle, parameterId);
  372. }
  373. float getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept override
  374. {
  375. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0.0f);
  376. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, 0.0f);
  377. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, 0.0f);
  378. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
  379. // FIXME - try
  380. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  381. {
  382. CARLA_SAFE_ASSERT_RETURN(scalePointId < param->scalePointCount, 0.0f);
  383. const NativeParameterScalePoint* scalePoint(&param->scalePoints[scalePointId]);
  384. return scalePoint->value;
  385. }
  386. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  387. return 0.0f;
  388. }
  389. bool getLabel(char* const strBuf) const noexcept override
  390. {
  391. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  392. if (fDescriptor->label != nullptr)
  393. {
  394. std::strncpy(strBuf, fDescriptor->label, STR_MAX);
  395. return true;
  396. }
  397. return CarlaPlugin::getLabel(strBuf);
  398. }
  399. bool getMaker(char* const strBuf) const noexcept override
  400. {
  401. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  402. if (fDescriptor->maker != nullptr)
  403. {
  404. std::strncpy(strBuf, fDescriptor->maker, STR_MAX);
  405. return true;
  406. }
  407. return CarlaPlugin::getMaker(strBuf);
  408. }
  409. bool getCopyright(char* const strBuf) const noexcept override
  410. {
  411. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  412. if (fDescriptor->copyright != nullptr)
  413. {
  414. std::strncpy(strBuf, fDescriptor->copyright, STR_MAX);
  415. return true;
  416. }
  417. return CarlaPlugin::getCopyright(strBuf);
  418. }
  419. bool getRealName(char* const strBuf) const noexcept override
  420. {
  421. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  422. if (fDescriptor->name != nullptr)
  423. {
  424. std::strncpy(strBuf, fDescriptor->name, STR_MAX);
  425. return true;
  426. }
  427. return CarlaPlugin::getRealName(strBuf);
  428. }
  429. bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
  430. {
  431. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  432. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
  433. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  434. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  435. // FIXME - try
  436. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  437. {
  438. if (param->name != nullptr)
  439. {
  440. std::strncpy(strBuf, param->name, STR_MAX);
  441. return true;
  442. }
  443. carla_safe_assert("param->name != nullptr", __FILE__, __LINE__);
  444. return CarlaPlugin::getParameterName(parameterId, strBuf);
  445. }
  446. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  447. return CarlaPlugin::getParameterName(parameterId, strBuf);
  448. }
  449. bool getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override
  450. {
  451. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  452. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
  453. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  454. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  455. // FIXME - try
  456. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  457. {
  458. if (param->unit != nullptr)
  459. {
  460. std::strncpy(strBuf, param->unit, STR_MAX);
  461. return true;
  462. }
  463. return CarlaPlugin::getParameterUnit(parameterId, strBuf);
  464. }
  465. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  466. return CarlaPlugin::getParameterUnit(parameterId, strBuf);
  467. }
  468. bool getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept override
  469. {
  470. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  471. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
  472. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  473. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  474. // FIXME - try
  475. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  476. {
  477. if (param->comment != nullptr)
  478. {
  479. std::strncpy(strBuf, param->comment, STR_MAX);
  480. return true;
  481. }
  482. return CarlaPlugin::getParameterComment(parameterId, strBuf);
  483. }
  484. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  485. return CarlaPlugin::getParameterComment(parameterId, strBuf);
  486. }
  487. bool getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept override
  488. {
  489. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  490. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
  491. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  492. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  493. // FIXME - try
  494. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  495. {
  496. if (param->groupName != nullptr)
  497. {
  498. std::strncpy(strBuf, param->groupName, STR_MAX);
  499. return true;
  500. }
  501. return CarlaPlugin::getParameterGroupName(parameterId, strBuf);
  502. }
  503. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  504. return CarlaPlugin::getParameterGroupName(parameterId, strBuf);
  505. }
  506. bool getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept override
  507. {
  508. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
  509. CARLA_SAFE_ASSERT_RETURN(fDescriptor->get_parameter_info != nullptr, false);
  510. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
  511. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  512. // FIXME - try
  513. if (const NativeParameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId))
  514. {
  515. CARLA_SAFE_ASSERT_RETURN(scalePointId < param->scalePointCount, false);
  516. const NativeParameterScalePoint* scalePoint(&param->scalePoints[scalePointId]);
  517. if (scalePoint->label != nullptr)
  518. {
  519. std::strncpy(strBuf, scalePoint->label, STR_MAX);
  520. return true;
  521. }
  522. carla_safe_assert("scalePoint->label != nullptr", __FILE__, __LINE__);
  523. return CarlaPlugin::getParameterScalePointLabel(parameterId, scalePointId, strBuf);
  524. }
  525. carla_safe_assert("const Parameter* const param = fDescriptor->get_parameter_info(fHandle, parameterId)", __FILE__, __LINE__);
  526. return CarlaPlugin::getParameterScalePointLabel(parameterId, scalePointId, strBuf);
  527. }
  528. // -------------------------------------------------------------------
  529. // Set data (state)
  530. void prepareForSave(bool) override
  531. {
  532. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  533. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  534. if (pData->midiprog.count > 0 && fDescriptor->category == NATIVE_PLUGIN_CATEGORY_SYNTH)
  535. {
  536. char strBuf[STR_MAX+1];
  537. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i:%i",
  538. fCurMidiProgs[0], fCurMidiProgs[1], fCurMidiProgs[2], fCurMidiProgs[3],
  539. fCurMidiProgs[4], fCurMidiProgs[5], fCurMidiProgs[6], fCurMidiProgs[7],
  540. fCurMidiProgs[8], fCurMidiProgs[9], fCurMidiProgs[10], fCurMidiProgs[11],
  541. fCurMidiProgs[12], fCurMidiProgs[13], fCurMidiProgs[14], fCurMidiProgs[15]);
  542. strBuf[STR_MAX] = '\0';
  543. CarlaPlugin::setCustomData(CUSTOM_DATA_TYPE_STRING, "midiPrograms", strBuf, false);
  544. }
  545. if (fDescriptor == nullptr || fDescriptor->get_state == nullptr || (fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0)
  546. return;
  547. if (char* data = fDescriptor->get_state(fHandle))
  548. {
  549. CarlaPlugin::setCustomData(CUSTOM_DATA_TYPE_CHUNK, "State", data, false);
  550. std::free(data);
  551. }
  552. }
  553. // -------------------------------------------------------------------
  554. // Set data (internal stuff)
  555. void setName(const char* const newName) override
  556. {
  557. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  558. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  559. CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
  560. CarlaPlugin::setName(newName);
  561. if (pData->uiTitle.isEmpty())
  562. setWindowTitle(nullptr);
  563. }
  564. void setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept override
  565. {
  566. if (channel >= 0 && channel < MAX_MIDI_CHANNELS && pData->midiprog.count > 0)
  567. pData->midiprog.current = fCurMidiProgs[channel];
  568. CarlaPlugin::setCtrlChannel(channel, sendOsc, sendCallback);
  569. }
  570. void setWindowTitle(const char* const title) noexcept
  571. {
  572. CarlaString uiName;
  573. if (title != nullptr)
  574. {
  575. uiName = title;
  576. }
  577. else
  578. {
  579. uiName = pData->name;
  580. uiName += " (GUI)";
  581. }
  582. std::free(const_cast<char*>(fHost.uiName));
  583. fHost.uiName = uiName.releaseBufferPointer();
  584. if (fDescriptor->dispatcher != nullptr && fIsUiVisible)
  585. {
  586. try {
  587. fDescriptor->dispatcher(fHandle,
  588. NATIVE_PLUGIN_OPCODE_UI_NAME_CHANGED,
  589. 0, 0,
  590. const_cast<char*>(fHost.uiName),
  591. 0.0f);
  592. } CARLA_SAFE_EXCEPTION("set custom ui title");
  593. }
  594. }
  595. // -------------------------------------------------------------------
  596. // Set data (plugin-specific stuff)
  597. void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  598. {
  599. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  600. CARLA_SAFE_ASSERT_RETURN(fDescriptor->set_parameter_value != nullptr,);
  601. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  602. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  603. const float fixedValue(pData->param.getFixedValue(parameterId, value));
  604. // FIXME - try
  605. fDescriptor->set_parameter_value(fHandle, parameterId, fixedValue);
  606. if (fHandle2 != nullptr)
  607. fDescriptor->set_parameter_value(fHandle2, parameterId, fixedValue);
  608. CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
  609. }
  610. void setParameterValueRT(const uint32_t parameterId, const float value, const uint32_t frameOffset, const bool sendCallbackLater) noexcept override
  611. {
  612. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  613. CARLA_SAFE_ASSERT_RETURN(fDescriptor->set_parameter_value != nullptr,);
  614. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  615. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  616. const float fixedValue(pData->param.getFixedValue(parameterId, value));
  617. // FIXME - try
  618. fDescriptor->set_parameter_value(fHandle, parameterId, fixedValue);
  619. if (fHandle2 != nullptr)
  620. fDescriptor->set_parameter_value(fHandle2, parameterId, fixedValue);
  621. CarlaPlugin::setParameterValueRT(parameterId, fixedValue, frameOffset, sendCallbackLater);
  622. }
  623. void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override
  624. {
  625. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  626. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  627. CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
  628. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  629. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  630. carla_debug("CarlaPluginNative::setCustomData(\"%s\", \"%s\", ..., %s)", type, key, bool2str(sendGui));
  631. if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
  632. return CarlaPlugin::setCustomData(type, key, value, sendGui);
  633. if (std::strcmp(type, CUSTOM_DATA_TYPE_PATH) == 0)
  634. {
  635. CARLA_SAFE_ASSERT_RETURN(std::strcmp(key, "file") == 0,);
  636. CARLA_SAFE_ASSERT_RETURN(value[0] != '\0',);
  637. }
  638. else if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0 && std::strcmp(type, CUSTOM_DATA_TYPE_CHUNK) != 0)
  639. {
  640. return carla_stderr2("CarlaPluginNative::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is invalid",
  641. type, key, value, bool2str(sendGui));
  642. }
  643. if (std::strcmp(type, CUSTOM_DATA_TYPE_CHUNK) == 0)
  644. {
  645. if (fDescriptor->set_state != nullptr && (fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) != 0)
  646. {
  647. const ScopedSingleProcessLocker spl(this, true);
  648. fDescriptor->set_state(fHandle, value);
  649. if (fHandle2 != nullptr)
  650. fDescriptor->set_state(fHandle2, value);
  651. }
  652. }
  653. else if (std::strcmp(key, "midiPrograms") == 0 && fDescriptor->set_midi_program != nullptr)
  654. {
  655. StringArray midiProgramList(StringArray::fromTokens(value, ":", ""));
  656. if (midiProgramList.size() == MAX_MIDI_CHANNELS)
  657. {
  658. uint8_t channel = 0;
  659. for (String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
  660. {
  661. const int index(it->getIntValue());
  662. if (index >= 0 && index < static_cast<int>(pData->midiprog.count))
  663. {
  664. const uint32_t bank = pData->midiprog.data[index].bank;
  665. const uint32_t program = pData->midiprog.data[index].program;
  666. fDescriptor->set_midi_program(fHandle, channel, bank, program);
  667. if (fHandle2 != nullptr)
  668. fDescriptor->set_midi_program(fHandle2, channel, bank, program);
  669. fCurMidiProgs[channel] = index;
  670. if (pData->ctrlChannel == static_cast<int32_t>(channel))
  671. {
  672. pData->midiprog.current = index;
  673. pData->engine->callback(true, true,
  674. ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
  675. pData->id,
  676. index,
  677. 0, 0, 0.0f, nullptr);
  678. }
  679. }
  680. ++channel;
  681. }
  682. CARLA_SAFE_ASSERT(channel == MAX_MIDI_CHANNELS);
  683. }
  684. }
  685. else
  686. {
  687. if (fDescriptor->set_custom_data != nullptr)
  688. {
  689. fDescriptor->set_custom_data(fHandle, key, value);
  690. if (fHandle2 != nullptr)
  691. fDescriptor->set_custom_data(fHandle2, key, value);
  692. }
  693. if (sendGui && fIsUiVisible && fDescriptor->ui_set_custom_data != nullptr)
  694. fDescriptor->ui_set_custom_data(fHandle, key, value);
  695. }
  696. CarlaPlugin::setCustomData(type, key, value, sendGui);
  697. }
  698. void setMidiProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool doingInit) noexcept override
  699. {
  700. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  701. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  702. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
  703. CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback || doingInit,);
  704. // TODO, put into check below
  705. if ((pData->hints & PLUGIN_IS_SYNTH) != 0 && (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS))
  706. return CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, doingInit);
  707. if (index >= 0)
  708. {
  709. const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
  710. const uint32_t bank = pData->midiprog.data[index].bank;
  711. const uint32_t program = pData->midiprog.data[index].program;
  712. const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback));
  713. try {
  714. fDescriptor->set_midi_program(fHandle, channel, bank, program);
  715. } catch(...) {}
  716. if (fHandle2 != nullptr)
  717. {
  718. try {
  719. fDescriptor->set_midi_program(fHandle2, channel, bank, program);
  720. } catch(...) {}
  721. }
  722. fCurMidiProgs[channel] = index;
  723. }
  724. CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, doingInit);
  725. }
  726. // FIXME: this is never used
  727. void setMidiProgramRT(const uint32_t index, const bool sendCallbackLater) noexcept override
  728. {
  729. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  730. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  731. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
  732. // TODO, put into check below
  733. if ((pData->hints & PLUGIN_IS_SYNTH) != 0 && (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS))
  734. return CarlaPlugin::setMidiProgramRT(index, sendCallbackLater);
  735. const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
  736. const uint32_t bank = pData->midiprog.data[index].bank;
  737. const uint32_t program = pData->midiprog.data[index].program;
  738. try {
  739. fDescriptor->set_midi_program(fHandle, channel, bank, program);
  740. } catch(...) {}
  741. if (fHandle2 != nullptr)
  742. {
  743. try {
  744. fDescriptor->set_midi_program(fHandle2, channel, bank, program);
  745. } catch(...) {}
  746. }
  747. fCurMidiProgs[channel] = static_cast<int32_t>(index);
  748. CarlaPlugin::setMidiProgramRT(index, sendCallbackLater);
  749. }
  750. // -------------------------------------------------------------------
  751. // Set ui stuff
  752. void setCustomUITitle(const char* const title) noexcept override
  753. {
  754. setWindowTitle(title);
  755. CarlaPlugin::setCustomUITitle(title);
  756. }
  757. void showCustomUI(const bool yesNo) override
  758. {
  759. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  760. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  761. if (fDescriptor->ui_show == nullptr)
  762. return;
  763. fIsUiAvailable = true;
  764. fDescriptor->ui_show(fHandle, yesNo);
  765. // UI might not be available, see NATIVE_HOST_OPCODE_UI_UNAVAILABLE
  766. if (yesNo && ! fIsUiAvailable)
  767. return;
  768. fIsUiVisible = yesNo;
  769. if (! yesNo)
  770. {
  771. #ifndef BUILD_BRIDGE
  772. pData->transientTryCounter = 0;
  773. #endif
  774. return;
  775. }
  776. #ifndef BUILD_BRIDGE
  777. if ((fDescriptor->hints & NATIVE_PLUGIN_USES_PARENT_ID) == 0 && std::strstr(fDescriptor->label, "file") == nullptr)
  778. pData->tryTransient();
  779. #endif
  780. if (fDescriptor->ui_set_custom_data != nullptr)
  781. {
  782. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  783. {
  784. const CustomData& cData(it.getValue(kCustomDataFallback));
  785. CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
  786. if (std::strcmp(cData.type, CUSTOM_DATA_TYPE_STRING) == 0 && std::strcmp(cData.key, "midiPrograms") != 0)
  787. fDescriptor->ui_set_custom_data(fHandle, cData.key, cData.value);
  788. }
  789. }
  790. if (fDescriptor->ui_set_midi_program != nullptr && pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  791. {
  792. const int32_t index = pData->midiprog.current;
  793. const uint8_t channel = uint8_t((pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) ? pData->ctrlChannel : 0);
  794. const uint32_t bank = pData->midiprog.data[index].bank;
  795. const uint32_t program = pData->midiprog.data[index].program;
  796. fDescriptor->ui_set_midi_program(fHandle, channel, bank, program);
  797. }
  798. if (fDescriptor->ui_set_parameter_value != nullptr)
  799. {
  800. for (uint32_t i=0; i < pData->param.count; ++i)
  801. fDescriptor->ui_set_parameter_value(fHandle, i, fDescriptor->get_parameter_value(fHandle, i));
  802. }
  803. }
  804. void idle() override
  805. {
  806. if (fNeedsIdle)
  807. {
  808. fNeedsIdle = false;
  809. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f);
  810. }
  811. if (fInlineDisplayNeedsRedraw)
  812. {
  813. // TESTING
  814. CARLA_SAFE_ASSERT(pData->enabled)
  815. CARLA_SAFE_ASSERT(!pData->engine->isAboutToClose());
  816. CARLA_SAFE_ASSERT(pData->client->isActive());
  817. if (pData->enabled && !pData->engine->isAboutToClose() && pData->client->isActive())
  818. {
  819. const int64_t timeNow = water::Time::currentTimeMillis();
  820. if (timeNow - fInlineDisplayLastRedrawTime > (1000 / 30))
  821. {
  822. fInlineDisplayNeedsRedraw = false;
  823. fInlineDisplayLastRedrawTime = timeNow;
  824. pData->engine->callback(true, true,
  825. ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW,
  826. pData->id,
  827. 0, 0, 0, 0.0f, nullptr);
  828. }
  829. }
  830. else
  831. {
  832. fInlineDisplayNeedsRedraw = false;
  833. }
  834. }
  835. CarlaPlugin::idle();
  836. }
  837. void uiIdle() override
  838. {
  839. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  840. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  841. if (fIsUiVisible && fDescriptor->ui_idle != nullptr)
  842. fDescriptor->ui_idle(fHandle);
  843. CarlaPlugin::uiIdle();
  844. }
  845. // -------------------------------------------------------------------
  846. // Plugin state
  847. void reload() override
  848. {
  849. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  850. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  851. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  852. carla_debug("CarlaPluginNative::reload() - start");
  853. const EngineProcessMode processMode(pData->engine->getProccessMode());
  854. // Safely disable plugin for reload
  855. const ScopedDisabler sd(this);
  856. if (pData->active)
  857. deactivate();
  858. clearBuffers();
  859. uint32_t aIns, aOuts, cvIns, cvOuts, mIns, mOuts, j;
  860. bool forcedStereoIn, forcedStereoOut;
  861. forcedStereoIn = forcedStereoOut = false;
  862. bool needsCtrlIn, needsCtrlOut;
  863. needsCtrlIn = needsCtrlOut = false;
  864. aIns = fDescriptor->audioIns;
  865. aOuts = fDescriptor->audioOuts;
  866. cvIns = fDescriptor->cvIns;
  867. cvOuts = fDescriptor->cvOuts;
  868. mIns = fDescriptor->midiIns;
  869. mOuts = fDescriptor->midiOuts;
  870. if ((pData->options & PLUGIN_OPTION_FORCE_STEREO) != 0 && (aIns == 1 || aOuts == 1) && mIns <= 1 && mOuts <= 1)
  871. {
  872. if (fHandle2 == nullptr)
  873. fHandle2 = fDescriptor->instantiate(&fHost);
  874. if (fHandle2 != nullptr)
  875. {
  876. if (aIns == 1)
  877. {
  878. aIns = 2;
  879. forcedStereoIn = true;
  880. }
  881. if (aOuts == 1)
  882. {
  883. aOuts = 2;
  884. forcedStereoOut = true;
  885. }
  886. }
  887. }
  888. if (aIns > 0)
  889. {
  890. pData->audioIn.createNew(aIns);
  891. }
  892. if (aOuts > 0)
  893. {
  894. pData->audioOut.createNew(aOuts);
  895. needsCtrlIn = true;
  896. }
  897. if (cvIns > 0)
  898. {
  899. pData->cvIn.createNew(cvIns);
  900. }
  901. if (cvOuts > 0)
  902. {
  903. pData->cvOut.createNew(cvOuts);
  904. }
  905. if (const uint32_t acIns = aIns + cvIns)
  906. {
  907. fAudioAndCvInBuffers = new float*[acIns];
  908. carla_zeroPointers(fAudioAndCvInBuffers, acIns);
  909. }
  910. if (const uint32_t acOuts = aOuts + cvOuts)
  911. {
  912. fAudioAndCvOutBuffers = new float*[acOuts];
  913. carla_zeroPointers(fAudioAndCvOutBuffers, acOuts);
  914. }
  915. if (mIns > 0)
  916. {
  917. fMidiIn.createNew(mIns);
  918. needsCtrlIn = (mIns == 1);
  919. }
  920. if (mOuts > 0)
  921. {
  922. fMidiOut.createNew(mOuts);
  923. needsCtrlOut = (mOuts == 1);
  924. }
  925. const uint portNameSize(pData->engine->getMaxPortNameSize());
  926. CarlaString portName;
  927. // Audio Ins
  928. for (j=0; j < aIns; ++j)
  929. {
  930. portName.clear();
  931. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  932. {
  933. portName = pData->name;
  934. portName += ":";
  935. }
  936. if (fDescriptor->get_buffer_port_name != nullptr)
  937. {
  938. portName += fDescriptor->get_buffer_port_name(fHandle, forcedStereoIn ? 0 : j, false);
  939. }
  940. else if (aIns > 1 && ! forcedStereoIn)
  941. {
  942. portName += "input_";
  943. portName += CarlaString(j+1);
  944. }
  945. else
  946. portName += "input";
  947. portName.truncate(portNameSize);
  948. pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
  949. pData->audioIn.ports[j].rindex = j;
  950. if (forcedStereoIn)
  951. {
  952. portName += "_2";
  953. pData->audioIn.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, 1);
  954. pData->audioIn.ports[1].rindex = j;
  955. break;
  956. }
  957. }
  958. // Audio Outs
  959. for (j=0; j < aOuts; ++j)
  960. {
  961. portName.clear();
  962. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  963. {
  964. portName = pData->name;
  965. portName += ":";
  966. }
  967. if (fDescriptor->get_buffer_port_name != nullptr)
  968. {
  969. portName += fDescriptor->get_buffer_port_name(fHandle, forcedStereoOut ? 0 : j, true);
  970. }
  971. else if (aOuts > 1 && ! forcedStereoOut)
  972. {
  973. portName += "output_";
  974. portName += CarlaString(j+1);
  975. }
  976. else
  977. portName += "output";
  978. portName.truncate(portNameSize);
  979. pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
  980. pData->audioOut.ports[j].rindex = j;
  981. if (forcedStereoOut)
  982. {
  983. portName += "_2";
  984. pData->audioOut.ports[1].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, 1);
  985. pData->audioOut.ports[1].rindex = j;
  986. break;
  987. }
  988. }
  989. // CV Ins
  990. for (j=0; j < cvIns; ++j)
  991. {
  992. portName.clear();
  993. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  994. {
  995. portName = pData->name;
  996. portName += ":";
  997. }
  998. if (fDescriptor->get_buffer_port_name != nullptr)
  999. {
  1000. portName += fDescriptor->get_buffer_port_name(fHandle, fDescriptor->audioIns + j, false);
  1001. }
  1002. else if (cvIns > 1)
  1003. {
  1004. portName += "cv_input_";
  1005. portName += CarlaString(j+1);
  1006. }
  1007. else
  1008. portName += "cv_input";
  1009. portName.truncate(portNameSize);
  1010. float min = -1.0f, max = 1.0f;
  1011. if (fDescriptor->get_buffer_port_range != nullptr)
  1012. {
  1013. if (const NativePortRange* const range = fDescriptor->get_buffer_port_range(fHandle,
  1014. fDescriptor->audioIns + j,
  1015. false))
  1016. {
  1017. min = range->minimum;
  1018. max = range->maximum;
  1019. }
  1020. }
  1021. pData->cvIn.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, true, j);
  1022. pData->cvIn.ports[j].rindex = j;
  1023. pData->cvIn.ports[j].port->setRange(min, max);
  1024. }
  1025. // CV Outs
  1026. for (j=0; j < cvOuts; ++j)
  1027. {
  1028. portName.clear();
  1029. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1030. {
  1031. portName = pData->name;
  1032. portName += ":";
  1033. }
  1034. if (fDescriptor->get_buffer_port_name != nullptr)
  1035. {
  1036. portName += fDescriptor->get_buffer_port_name(fHandle, fDescriptor->audioOuts + j, true);
  1037. }
  1038. else if (cvOuts > 1)
  1039. {
  1040. portName += "cv_output_";
  1041. portName += CarlaString(j+1);
  1042. }
  1043. else
  1044. portName += "cv_output";
  1045. portName.truncate(portNameSize);
  1046. float min = -1.0f, max = 1.0f;
  1047. if (fDescriptor->get_buffer_port_range != nullptr)
  1048. {
  1049. if (const NativePortRange* const range = fDescriptor->get_buffer_port_range(fHandle,
  1050. fDescriptor->audioOuts + j,
  1051. true))
  1052. {
  1053. min = range->minimum;
  1054. max = range->maximum;
  1055. }
  1056. }
  1057. pData->cvOut.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, false, j);
  1058. pData->cvOut.ports[j].rindex = j;
  1059. pData->cvOut.ports[j].port->setRange(min, max);
  1060. }
  1061. // MIDI Input (only if multiple)
  1062. if (mIns > 1)
  1063. {
  1064. for (j=0; j < mIns; ++j)
  1065. {
  1066. portName.clear();
  1067. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1068. {
  1069. portName = pData->name;
  1070. portName += ":";
  1071. }
  1072. portName += "midi-in_";
  1073. portName += CarlaString(j+1);
  1074. portName.truncate(portNameSize);
  1075. fMidiIn.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, j);
  1076. fMidiIn.indexes[j] = j;
  1077. }
  1078. pData->event.portIn = fMidiIn.ports[0];
  1079. }
  1080. // MIDI Output (only if multiple)
  1081. if (mOuts > 1)
  1082. {
  1083. for (j=0; j < mOuts; ++j)
  1084. {
  1085. portName.clear();
  1086. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1087. {
  1088. portName = pData->name;
  1089. portName += ":";
  1090. }
  1091. portName += "midi-out_";
  1092. portName += CarlaString(j+1);
  1093. portName.truncate(portNameSize);
  1094. fMidiOut.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, j);
  1095. fMidiOut.indexes[j] = j;
  1096. }
  1097. pData->event.portOut = fMidiOut.ports[0];
  1098. }
  1099. reloadParameters(&needsCtrlIn, &needsCtrlOut);
  1100. if (needsCtrlIn || mIns == 1)
  1101. {
  1102. portName.clear();
  1103. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1104. {
  1105. portName = pData->name;
  1106. portName += ":";
  1107. }
  1108. portName += "events-in";
  1109. portName.truncate(portNameSize);
  1110. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  1111. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1112. pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
  1113. #endif
  1114. }
  1115. if (needsCtrlOut || mOuts == 1)
  1116. {
  1117. portName.clear();
  1118. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1119. {
  1120. portName = pData->name;
  1121. portName += ":";
  1122. }
  1123. portName += "events-out";
  1124. portName.truncate(portNameSize);
  1125. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  1126. }
  1127. if (forcedStereoIn || forcedStereoOut)
  1128. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  1129. else
  1130. pData->options &= ~PLUGIN_OPTION_FORCE_STEREO;
  1131. // plugin hints
  1132. pData->hints = 0x0;
  1133. if (aOuts > 0 && (aIns == aOuts || aIns == 1))
  1134. pData->hints |= PLUGIN_CAN_DRYWET;
  1135. if (aOuts > 0)
  1136. pData->hints |= PLUGIN_CAN_VOLUME;
  1137. if (aOuts >= 2 && aOuts % 2 == 0)
  1138. pData->hints |= PLUGIN_CAN_BALANCE;
  1139. // native plugin hints
  1140. if (fDescriptor->hints & NATIVE_PLUGIN_IS_RTSAFE)
  1141. pData->hints |= PLUGIN_IS_RTSAFE;
  1142. if (fDescriptor->hints & NATIVE_PLUGIN_IS_SYNTH)
  1143. pData->hints |= PLUGIN_IS_SYNTH;
  1144. if (fDescriptor->hints & NATIVE_PLUGIN_HAS_UI)
  1145. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  1146. if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
  1147. pData->hints |= PLUGIN_NEEDS_FIXED_BUFFERS;
  1148. if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD)
  1149. pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
  1150. if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
  1151. pData->hints |= PLUGIN_HAS_CUSTOM_UI_USING_FILE_OPEN;
  1152. if (fDescriptor->hints & NATIVE_PLUGIN_USES_MULTI_PROGS)
  1153. pData->hints |= PLUGIN_USES_MULTI_PROGS;
  1154. if (fDescriptor->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY)
  1155. pData->hints |= PLUGIN_HAS_INLINE_DISPLAY;
  1156. // extra plugin hints
  1157. pData->extraHints = 0x0;
  1158. bufferSizeChanged(pData->engine->getBufferSize());
  1159. reloadPrograms(true);
  1160. if (pData->active)
  1161. activate();
  1162. carla_debug("CarlaPluginNative::reload() - end");
  1163. }
  1164. void reloadParameters(bool* const needsCtrlIn, bool* const needsCtrlOut)
  1165. {
  1166. carla_debug("CarlaPluginNative::reloadParameters() - start");
  1167. const float sampleRate = static_cast<float>(pData->engine->getSampleRate());
  1168. const uint32_t params = (fDescriptor->get_parameter_count != nullptr && fDescriptor->get_parameter_info != nullptr)
  1169. ? fDescriptor->get_parameter_count(fHandle)
  1170. : 0;
  1171. pData->param.clear();
  1172. if (params > 0)
  1173. {
  1174. pData->param.createNew(params, true);
  1175. }
  1176. for (uint32_t j=0; j < params; ++j)
  1177. {
  1178. const NativeParameter* const paramInfo(fDescriptor->get_parameter_info(fHandle, j));
  1179. CARLA_SAFE_ASSERT_CONTINUE(paramInfo != nullptr);
  1180. pData->param.data[j].type = PARAMETER_UNKNOWN;
  1181. pData->param.data[j].index = static_cast<int32_t>(j);
  1182. pData->param.data[j].rindex = static_cast<int32_t>(j);
  1183. float min, max, def, step, stepSmall, stepLarge;
  1184. // min value
  1185. min = paramInfo->ranges.min;
  1186. // max value
  1187. max = paramInfo->ranges.max;
  1188. if (min > max)
  1189. max = min;
  1190. if (carla_isEqual(min, max))
  1191. {
  1192. carla_stderr2("WARNING - Broken plugin parameter '%s': max == min", paramInfo->name);
  1193. max = min + 0.1f;
  1194. }
  1195. // default value
  1196. def = paramInfo->ranges.def;
  1197. if (def < min)
  1198. def = min;
  1199. else if (def > max)
  1200. def = max;
  1201. if (paramInfo->hints & NATIVE_PARAMETER_USES_SAMPLE_RATE)
  1202. {
  1203. min *= sampleRate;
  1204. max *= sampleRate;
  1205. def *= sampleRate;
  1206. pData->param.data[j].hints |= PARAMETER_USES_SAMPLERATE;
  1207. }
  1208. if (paramInfo->hints & NATIVE_PARAMETER_IS_BOOLEAN)
  1209. {
  1210. step = max - min;
  1211. stepSmall = step;
  1212. stepLarge = step;
  1213. pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
  1214. }
  1215. else if (paramInfo->hints & NATIVE_PARAMETER_IS_INTEGER)
  1216. {
  1217. step = 1.0f;
  1218. stepSmall = 1.0f;
  1219. stepLarge = 10.0f;
  1220. pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
  1221. }
  1222. else
  1223. {
  1224. float range = max - min;
  1225. step = range/100.0f;
  1226. stepSmall = range/1000.0f;
  1227. stepLarge = range/10.0f;
  1228. }
  1229. if (paramInfo->hints & NATIVE_PARAMETER_IS_OUTPUT)
  1230. {
  1231. pData->param.data[j].type = PARAMETER_OUTPUT;
  1232. if (needsCtrlOut != nullptr)
  1233. *needsCtrlOut = true;
  1234. }
  1235. else
  1236. {
  1237. pData->param.data[j].type = PARAMETER_INPUT;
  1238. if (needsCtrlIn != nullptr)
  1239. *needsCtrlIn = true;
  1240. }
  1241. // extra parameter hints
  1242. if (paramInfo->hints & NATIVE_PARAMETER_IS_ENABLED)
  1243. {
  1244. pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
  1245. if (paramInfo->hints & NATIVE_PARAMETER_IS_AUTOMATABLE)
  1246. {
  1247. pData->param.data[j].hints |= PARAMETER_IS_AUTOMATABLE;
  1248. pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
  1249. }
  1250. }
  1251. if (paramInfo->hints & NATIVE_PARAMETER_IS_LOGARITHMIC)
  1252. pData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC;
  1253. if (paramInfo->hints & NATIVE_PARAMETER_USES_SCALEPOINTS)
  1254. pData->param.data[j].hints |= PARAMETER_USES_SCALEPOINTS;
  1255. pData->param.ranges[j].min = min;
  1256. pData->param.ranges[j].max = max;
  1257. pData->param.ranges[j].def = def;
  1258. pData->param.ranges[j].step = step;
  1259. pData->param.ranges[j].stepSmall = stepSmall;
  1260. pData->param.ranges[j].stepLarge = stepLarge;
  1261. }
  1262. carla_debug("CarlaPluginNative::reloadParameters() - end");
  1263. }
  1264. void reloadPrograms(const bool doInit) override
  1265. {
  1266. carla_debug("CarlaPluginNative::reloadPrograms(%s)", bool2str(doInit));
  1267. uint32_t i, oldCount = pData->midiprog.count;
  1268. const int32_t current = pData->midiprog.current;
  1269. // Delete old programs
  1270. pData->midiprog.clear();
  1271. // Query new programs
  1272. uint32_t count = 0;
  1273. if (fDescriptor->get_midi_program_count != nullptr && fDescriptor->get_midi_program_info != nullptr && fDescriptor->set_midi_program != nullptr)
  1274. count = fDescriptor->get_midi_program_count(fHandle);
  1275. if (count > 0)
  1276. {
  1277. pData->midiprog.createNew(count);
  1278. // Update data
  1279. for (i=0; i < count; ++i)
  1280. {
  1281. const NativeMidiProgram* const mpDesc(fDescriptor->get_midi_program_info(fHandle, i));
  1282. CARLA_SAFE_ASSERT_CONTINUE(mpDesc != nullptr);
  1283. pData->midiprog.data[i].bank = mpDesc->bank;
  1284. pData->midiprog.data[i].program = mpDesc->program;
  1285. pData->midiprog.data[i].name = carla_strdup(mpDesc->name);
  1286. }
  1287. }
  1288. if (doInit)
  1289. {
  1290. if (count > 0)
  1291. setMidiProgram(0, false, false, false, true);
  1292. }
  1293. else
  1294. {
  1295. // Check if current program is invalid
  1296. bool programChanged = false;
  1297. if (count == oldCount+1)
  1298. {
  1299. // one midi program added, probably created by user
  1300. pData->midiprog.current = static_cast<int32_t>(oldCount);
  1301. programChanged = true;
  1302. }
  1303. else if (current < 0 && count > 0)
  1304. {
  1305. // programs exist now, but not before
  1306. pData->midiprog.current = 0;
  1307. programChanged = true;
  1308. }
  1309. else if (current >= 0 && count == 0)
  1310. {
  1311. // programs existed before, but not anymore
  1312. pData->midiprog.current = -1;
  1313. programChanged = true;
  1314. }
  1315. else if (current >= static_cast<int32_t>(count))
  1316. {
  1317. // current midi program > count
  1318. pData->midiprog.current = 0;
  1319. programChanged = true;
  1320. }
  1321. else
  1322. {
  1323. // no change
  1324. pData->midiprog.current = current;
  1325. }
  1326. if (programChanged)
  1327. setMidiProgram(pData->midiprog.current, true, true, true, false);
  1328. pData->engine->callback(true, true,
  1329. ENGINE_CALLBACK_RELOAD_PROGRAMS,
  1330. pData->id,
  1331. 0, 0, 0, 0.0f, nullptr);
  1332. }
  1333. }
  1334. // -------------------------------------------------------------------
  1335. // Plugin processing
  1336. void activate() noexcept override
  1337. {
  1338. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  1339. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  1340. if (fDescriptor->activate != nullptr)
  1341. {
  1342. try {
  1343. fDescriptor->activate(fHandle);
  1344. } catch(...) {}
  1345. if (fHandle2 != nullptr)
  1346. {
  1347. try {
  1348. fDescriptor->activate(fHandle2);
  1349. } catch(...) {}
  1350. }
  1351. }
  1352. }
  1353. void deactivate() noexcept override
  1354. {
  1355. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  1356. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  1357. if (fDescriptor->deactivate != nullptr)
  1358. {
  1359. try {
  1360. fDescriptor->deactivate(fHandle);
  1361. } catch(...) {}
  1362. if (fHandle2 != nullptr)
  1363. {
  1364. try {
  1365. fDescriptor->deactivate(fHandle2);
  1366. } catch(...) {}
  1367. }
  1368. }
  1369. }
  1370. EngineEvent& findNextEvent()
  1371. {
  1372. if (fMidiIn.count == 1)
  1373. {
  1374. NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[0]);
  1375. if (multiportData.usedIndex == multiportData.cachedEventCount)
  1376. {
  1377. const uint32_t eventCount = pData->event.portIn->getEventCount();
  1378. CARLA_SAFE_ASSERT_INT2(eventCount == multiportData.cachedEventCount,
  1379. eventCount, multiportData.cachedEventCount);
  1380. return kNullEngineEvent;
  1381. }
  1382. return pData->event.portIn->getEvent(multiportData.usedIndex++);
  1383. }
  1384. uint32_t lowestSampleTime = 9999999;
  1385. uint32_t portMatching = 0;
  1386. bool found = false;
  1387. // process events in order for multiple ports
  1388. for (uint32_t m=0; m < fMidiIn.count; ++m)
  1389. {
  1390. CarlaEngineEventPort* const eventPort(fMidiIn.ports[m]);
  1391. NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[m]);
  1392. if (multiportData.usedIndex == multiportData.cachedEventCount)
  1393. continue;
  1394. const EngineEvent& event(eventPort->getEventUnchecked(multiportData.usedIndex));
  1395. if (event.time < lowestSampleTime)
  1396. {
  1397. lowestSampleTime = event.time;
  1398. portMatching = m;
  1399. found = true;
  1400. }
  1401. }
  1402. if (found)
  1403. {
  1404. CarlaEngineEventPort* const eventPort(fMidiIn.ports[portMatching]);
  1405. NativePluginMidiInData::MultiPortData& multiportData(fMidiIn.multiportData[portMatching]);
  1406. return eventPort->getEvent(multiportData.usedIndex++);
  1407. }
  1408. return kNullEngineEvent;
  1409. }
  1410. void process(const float* const* const audioIn, float** const audioOut,
  1411. const float* const* const cvIn, float** const cvOut, const uint32_t frames) override
  1412. {
  1413. // --------------------------------------------------------------------------------------------------------
  1414. // Check if active
  1415. if (! pData->active)
  1416. {
  1417. // disable any output sound
  1418. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1419. carla_zeroFloats(audioOut[i], frames);
  1420. for (uint32_t i=0; i < pData->cvOut.count; ++i)
  1421. carla_zeroFloats(cvOut[i], frames);
  1422. return;
  1423. }
  1424. fMidiEventInCount = fMidiEventOutCount = 0;
  1425. carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents);
  1426. carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents);
  1427. // --------------------------------------------------------------------------------------------------------
  1428. // Check if needs reset
  1429. if (pData->needsReset)
  1430. {
  1431. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1432. {
  1433. fMidiEventInCount = MAX_MIDI_CHANNELS*2;
  1434. for (uint8_t k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; ++k)
  1435. {
  1436. fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
  1437. fMidiInEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
  1438. fMidiInEvents[k].data[2] = 0;
  1439. fMidiInEvents[k].size = 3;
  1440. fMidiInEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT));
  1441. fMidiInEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
  1442. fMidiInEvents[k+i].data[2] = 0;
  1443. fMidiInEvents[k+i].size = 3;
  1444. }
  1445. }
  1446. else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
  1447. {
  1448. fMidiEventInCount = MAX_MIDI_NOTE;
  1449. for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k)
  1450. {
  1451. fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT));
  1452. fMidiInEvents[k].data[1] = k;
  1453. fMidiInEvents[k].data[2] = 0;
  1454. fMidiInEvents[k].size = 3;
  1455. }
  1456. }
  1457. pData->needsReset = false;
  1458. }
  1459. // --------------------------------------------------------------------------------------------------------
  1460. // Set TimeInfo
  1461. const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
  1462. fTimeInfo.playing = timeInfo.playing;
  1463. fTimeInfo.frame = timeInfo.frame;
  1464. fTimeInfo.usecs = timeInfo.usecs;
  1465. if (timeInfo.bbt.valid)
  1466. {
  1467. fTimeInfo.bbt.valid = true;
  1468. fTimeInfo.bbt.bar = timeInfo.bbt.bar;
  1469. fTimeInfo.bbt.beat = timeInfo.bbt.beat;
  1470. fTimeInfo.bbt.tick = timeInfo.bbt.tick;
  1471. fTimeInfo.bbt.barStartTick = timeInfo.bbt.barStartTick;
  1472. fTimeInfo.bbt.beatsPerBar = timeInfo.bbt.beatsPerBar;
  1473. fTimeInfo.bbt.beatType = timeInfo.bbt.beatType;
  1474. fTimeInfo.bbt.ticksPerBeat = timeInfo.bbt.ticksPerBeat;
  1475. fTimeInfo.bbt.beatsPerMinute = timeInfo.bbt.beatsPerMinute;
  1476. }
  1477. else
  1478. {
  1479. fTimeInfo.bbt.valid = false;
  1480. }
  1481. #if 0
  1482. // This test code has proven to be quite useful
  1483. // So I am leaving it behind, I might need it again..
  1484. if (pData->id == 1)
  1485. {
  1486. static int64_t last_frame = timeInfo.frame;
  1487. static int64_t last_dev_frame = 0;
  1488. static double last_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick;
  1489. static double last_dev_val = 0.0;
  1490. int64_t cur_frame = timeInfo.frame;
  1491. int64_t cur_dev_frame = cur_frame - last_frame;
  1492. double cur_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick;
  1493. double cur_dev_val = cur_val - last_val;
  1494. if (std::abs(last_dev_val - cur_dev_val) >= 0.0001 || last_dev_frame != cur_dev_frame)
  1495. {
  1496. carla_stdout("currently %u at %u => %f : DEV1: %li : DEV2: %f",
  1497. frames,
  1498. timeInfo.frame,
  1499. cur_val,
  1500. cur_dev_frame,
  1501. cur_dev_val);
  1502. }
  1503. last_val = cur_val;
  1504. last_dev_val = cur_dev_val;
  1505. last_frame = cur_frame;
  1506. last_dev_frame = cur_dev_frame;
  1507. }
  1508. #endif
  1509. // --------------------------------------------------------------------------------------------------------
  1510. // Event Input and Processing
  1511. if (pData->event.portIn != nullptr)
  1512. {
  1513. // ----------------------------------------------------------------------------------------------------
  1514. // MIDI Input (External)
  1515. if (pData->extNotes.mutex.tryLock())
  1516. {
  1517. ExternalMidiNote note = { 0, 0, 0 };
  1518. for (; fMidiEventInCount < kPluginMaxMidiEvents && ! pData->extNotes.data.isEmpty();)
  1519. {
  1520. note = pData->extNotes.data.getFirst(note, true);
  1521. CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
  1522. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1523. nativeEvent.data[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT));
  1524. nativeEvent.data[1] = note.note;
  1525. nativeEvent.data[2] = note.velo;
  1526. nativeEvent.size = 3;
  1527. }
  1528. pData->extNotes.mutex.unlock();
  1529. } // End of MIDI Input (External)
  1530. // ----------------------------------------------------------------------------------------------------
  1531. // Event Input (System)
  1532. #ifndef BUILD_BRIDGE
  1533. bool allNotesOffSent = false;
  1534. #endif
  1535. const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;
  1536. uint32_t startTime = 0;
  1537. uint32_t timeOffset = 0;
  1538. uint32_t nextBankId;
  1539. if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  1540. nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
  1541. else
  1542. nextBankId = 0;
  1543. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1544. if (cvIn != nullptr && pData->event.cvSourcePorts != nullptr)
  1545. pData->event.cvSourcePorts->initPortBuffers(cvIn + pData->cvIn.count, frames, isSampleAccurate, pData->event.portIn);
  1546. #endif
  1547. for (;;)
  1548. {
  1549. EngineEvent& event(findNextEvent());
  1550. if (event.type == kEngineEventTypeNull)
  1551. break;
  1552. uint32_t eventTime = event.time;
  1553. CARLA_SAFE_ASSERT_UINT2_CONTINUE(eventTime < frames, eventTime, frames);
  1554. if (eventTime < timeOffset)
  1555. {
  1556. carla_stderr2("Timing error, eventTime:%u < timeOffset:%u for '%s'",
  1557. eventTime, timeOffset, pData->name);
  1558. eventTime = timeOffset;
  1559. }
  1560. if (isSampleAccurate && eventTime > timeOffset)
  1561. {
  1562. if (processSingle(audioIn, audioOut, cvIn, cvOut, eventTime - timeOffset, timeOffset))
  1563. {
  1564. startTime = 0;
  1565. timeOffset = eventTime;
  1566. if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  1567. nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
  1568. else
  1569. nextBankId = 0;
  1570. if (fMidiEventInCount > 0)
  1571. {
  1572. carla_zeroStructs(fMidiInEvents, fMidiEventInCount);
  1573. fMidiEventInCount = 0;
  1574. }
  1575. if (fMidiEventOutCount > 0)
  1576. {
  1577. carla_zeroStructs(fMidiOutEvents, fMidiEventOutCount);
  1578. fMidiEventOutCount = 0;
  1579. }
  1580. }
  1581. else
  1582. startTime += timeOffset;
  1583. }
  1584. // Control change
  1585. switch (event.type)
  1586. {
  1587. case kEngineEventTypeNull:
  1588. break;
  1589. case kEngineEventTypeControl: {
  1590. EngineControlEvent& ctrlEvent(event.ctrl);
  1591. switch (ctrlEvent.type)
  1592. {
  1593. case kEngineControlEventTypeNull:
  1594. break;
  1595. case kEngineControlEventTypeParameter: {
  1596. float value;
  1597. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1598. // non-midi
  1599. if (event.channel == kEngineEventNonMidiChannel)
  1600. {
  1601. const uint32_t k = ctrlEvent.param;
  1602. CARLA_SAFE_ASSERT_CONTINUE(k < pData->param.count);
  1603. ctrlEvent.handled = true;
  1604. value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
  1605. setParameterValueRT(k, value, event.time, true);
  1606. continue;
  1607. }
  1608. // Control backend stuff
  1609. if (event.channel == pData->ctrlChannel)
  1610. {
  1611. if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) > 0)
  1612. {
  1613. ctrlEvent.handled = true;
  1614. value = ctrlEvent.normalizedValue;
  1615. setDryWetRT(value, true);
  1616. }
  1617. else if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) > 0)
  1618. {
  1619. ctrlEvent.handled = true;
  1620. value = ctrlEvent.normalizedValue*127.0f/100.0f;
  1621. setVolumeRT(value, true);
  1622. }
  1623. else if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) > 0)
  1624. {
  1625. float left, right;
  1626. value = ctrlEvent.normalizedValue/0.5f - 1.0f;
  1627. if (value < 0.0f)
  1628. {
  1629. left = -1.0f;
  1630. right = (value*2.0f)+1.0f;
  1631. }
  1632. else if (value > 0.0f)
  1633. {
  1634. left = (value*2.0f)-1.0f;
  1635. right = 1.0f;
  1636. }
  1637. else
  1638. {
  1639. left = -1.0f;
  1640. right = 1.0f;
  1641. }
  1642. ctrlEvent.handled = true;
  1643. setBalanceLeftRT(left, true);
  1644. setBalanceRightRT(right, true);
  1645. }
  1646. }
  1647. #endif
  1648. // Control plugin parameters
  1649. for (uint32_t k=0; k < pData->param.count; ++k)
  1650. {
  1651. if (pData->param.data[k].midiChannel != event.channel)
  1652. continue;
  1653. if (pData->param.data[k].mappedControlIndex != ctrlEvent.param)
  1654. continue;
  1655. if (pData->param.data[k].type != PARAMETER_INPUT)
  1656. continue;
  1657. if ((pData->param.data[k].hints & PARAMETER_IS_AUTOMATABLE) == 0)
  1658. continue;
  1659. ctrlEvent.handled = true;
  1660. value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
  1661. setParameterValueRT(k, value, event.time, true);
  1662. }
  1663. if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE)
  1664. {
  1665. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1666. continue;
  1667. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1668. carla_zeroStruct(nativeEvent);
  1669. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1670. nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1671. nativeEvent.data[1] = uint8_t(ctrlEvent.param);
  1672. nativeEvent.data[2] = uint8_t(ctrlEvent.normalizedValue*127.0f + 0.5f);
  1673. nativeEvent.size = 3;
  1674. }
  1675. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1676. if (! ctrlEvent.handled)
  1677. checkForMidiLearn(event);
  1678. #endif
  1679. break;
  1680. } // case kEngineControlEventTypeParameter
  1681. case kEngineControlEventTypeMidiBank:
  1682. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  1683. {
  1684. if (event.channel == pData->ctrlChannel)
  1685. nextBankId = ctrlEvent.param;
  1686. }
  1687. else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
  1688. {
  1689. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1690. continue;
  1691. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1692. carla_zeroStruct(nativeEvent);
  1693. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1694. nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1695. nativeEvent.data[1] = MIDI_CONTROL_BANK_SELECT;
  1696. nativeEvent.data[2] = uint8_t(ctrlEvent.param);
  1697. nativeEvent.size = 3;
  1698. }
  1699. break;
  1700. case kEngineControlEventTypeMidiProgram:
  1701. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  1702. {
  1703. if (event.channel < MAX_MIDI_CHANNELS)
  1704. {
  1705. const uint32_t nextProgramId(ctrlEvent.param);
  1706. for (uint32_t k=0; k < pData->midiprog.count; ++k)
  1707. {
  1708. if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId)
  1709. {
  1710. fDescriptor->set_midi_program(fHandle, event.channel, nextBankId, nextProgramId);
  1711. if (fHandle2 != nullptr)
  1712. fDescriptor->set_midi_program(fHandle2, event.channel, nextBankId, nextProgramId);
  1713. fCurMidiProgs[event.channel] = static_cast<int32_t>(k);
  1714. if (event.channel == pData->ctrlChannel)
  1715. {
  1716. pData->postponeMidiProgramChangeRtEvent(true, k);
  1717. }
  1718. break;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
  1724. {
  1725. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1726. continue;
  1727. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1728. carla_zeroStruct(nativeEvent);
  1729. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1730. nativeEvent.data[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1731. nativeEvent.data[1] = uint8_t(ctrlEvent.param);
  1732. nativeEvent.size = 2;
  1733. }
  1734. break;
  1735. case kEngineControlEventTypeAllSoundOff:
  1736. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1737. {
  1738. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1739. continue;
  1740. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1741. carla_zeroStruct(nativeEvent);
  1742. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1743. nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1744. nativeEvent.data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
  1745. nativeEvent.data[2] = 0;
  1746. nativeEvent.size = 3;
  1747. }
  1748. break;
  1749. case kEngineControlEventTypeAllNotesOff:
  1750. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1751. {
  1752. #ifndef BUILD_BRIDGE
  1753. if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
  1754. {
  1755. allNotesOffSent = true;
  1756. postponeRtAllNotesOff();
  1757. }
  1758. #endif
  1759. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1760. continue;
  1761. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1762. carla_zeroStruct(nativeEvent);
  1763. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1764. nativeEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1765. nativeEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
  1766. nativeEvent.data[2] = 0;
  1767. nativeEvent.size = 3;
  1768. }
  1769. break;
  1770. }
  1771. break;
  1772. }
  1773. case kEngineEventTypeMidi: {
  1774. if (fMidiEventInCount >= kPluginMaxMidiEvents)
  1775. continue;
  1776. const EngineMidiEvent& midiEvent(event.midi);
  1777. if (midiEvent.size > 4)
  1778. continue;
  1779. #ifdef CARLA_PROPER_CPP11_SUPPORT
  1780. static_assert(4 <= EngineMidiEvent::kDataSize, "Incorrect data");
  1781. #endif
  1782. uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
  1783. if ((status == MIDI_STATUS_NOTE_OFF || status == MIDI_STATUS_NOTE_ON) && (pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES))
  1784. continue;
  1785. if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
  1786. continue;
  1787. if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
  1788. continue;
  1789. if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
  1790. continue;
  1791. if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
  1792. continue;
  1793. // Fix bad note-off
  1794. if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
  1795. status = MIDI_STATUS_NOTE_OFF;
  1796. NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]);
  1797. carla_zeroStruct(nativeEvent);
  1798. nativeEvent.port = midiEvent.port;
  1799. nativeEvent.time = isSampleAccurate ? startTime : eventTime;
  1800. nativeEvent.size = midiEvent.size;
  1801. nativeEvent.data[0] = uint8_t(status | (event.channel & MIDI_CHANNEL_BIT));
  1802. nativeEvent.data[1] = midiEvent.size >= 2 ? midiEvent.data[1] : 0;
  1803. nativeEvent.data[2] = midiEvent.size >= 3 ? midiEvent.data[2] : 0;
  1804. nativeEvent.data[3] = midiEvent.size == 4 ? midiEvent.data[3] : 0;
  1805. if (status == MIDI_STATUS_NOTE_ON)
  1806. {
  1807. pData->postponeNoteOnRtEvent(true, event.channel, midiEvent.data[1], midiEvent.data[2]);
  1808. }
  1809. else if (status == MIDI_STATUS_NOTE_OFF)
  1810. {
  1811. pData->postponeNoteOffRtEvent(true, event.channel, midiEvent.data[1]);
  1812. }
  1813. } break;
  1814. } // switch (event.type)
  1815. }
  1816. pData->postRtEvents.trySplice();
  1817. if (frames > timeOffset)
  1818. processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset);
  1819. } // End of Event Input and Processing
  1820. // --------------------------------------------------------------------------------------------------------
  1821. // Plugin processing (no events)
  1822. else
  1823. {
  1824. processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0);
  1825. } // End of Plugin processing (no events)
  1826. #ifndef BUILD_BRIDGE
  1827. // --------------------------------------------------------------------------------------------------------
  1828. // Control Output
  1829. if (pData->event.portOut != nullptr)
  1830. {
  1831. float value, curValue;
  1832. for (uint32_t k=0; k < pData->param.count; ++k)
  1833. {
  1834. if (pData->param.data[k].type != PARAMETER_OUTPUT)
  1835. continue;
  1836. curValue = fDescriptor->get_parameter_value(fHandle, k);
  1837. pData->param.ranges[k].fixValue(curValue);
  1838. if (pData->param.data[k].mappedControlIndex > 0)
  1839. {
  1840. value = pData->param.ranges[k].getNormalizedValue(curValue);
  1841. pData->event.portOut->writeControlEvent(0,
  1842. pData->param.data[k].midiChannel,
  1843. kEngineControlEventTypeParameter,
  1844. static_cast<uint16_t>(pData->param.data[k].mappedControlIndex),
  1845. -1,
  1846. value);
  1847. }
  1848. }
  1849. } // End of Control Output
  1850. #endif
  1851. }
  1852. bool processSingle(const float* const* const audioIn, float** const audioOut,
  1853. const float* const* const cvIn, float** const cvOut,
  1854. const uint32_t frames, const uint32_t timeOffset)
  1855. {
  1856. CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
  1857. if (pData->audioIn.count > 0) {
  1858. CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false);
  1859. }
  1860. if (pData->audioOut.count > 0) {
  1861. CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false);
  1862. }
  1863. if (pData->cvIn.count > 0) {
  1864. CARLA_SAFE_ASSERT_RETURN(cvIn != nullptr, false);
  1865. }
  1866. if (pData->cvOut.count > 0) {
  1867. CARLA_SAFE_ASSERT_RETURN(cvOut != nullptr, false);
  1868. }
  1869. // --------------------------------------------------------------------------------------------------------
  1870. // Try lock, silence otherwise
  1871. if (fIsOffline)
  1872. {
  1873. pData->singleMutex.lock();
  1874. }
  1875. else if (! pData->singleMutex.tryLock())
  1876. {
  1877. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1878. {
  1879. for (uint32_t k=0; k < frames; ++k)
  1880. audioOut[i][k+timeOffset] = 0.0f;
  1881. }
  1882. for (uint32_t i=0; i < pData->cvOut.count; ++i)
  1883. {
  1884. for (uint32_t k=0; k < frames; ++k)
  1885. cvOut[i][k+timeOffset] = 0.0f;
  1886. }
  1887. return false;
  1888. }
  1889. // --------------------------------------------------------------------------------------------------------
  1890. // Set audio buffers
  1891. {
  1892. for (uint32_t i=0; i < pData->audioIn.count; ++i)
  1893. carla_copyFloats(fAudioAndCvInBuffers[i], audioIn[i]+timeOffset, frames);
  1894. for (uint32_t i=0; i < pData->cvIn.count; ++i)
  1895. carla_copyFloats(fAudioAndCvInBuffers[pData->audioIn.count+i], cvIn[i]+timeOffset, frames);
  1896. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1897. carla_zeroFloats(fAudioAndCvOutBuffers[i], frames);
  1898. for (uint32_t i=0; i < pData->cvOut.count; ++i)
  1899. carla_zeroFloats(fAudioAndCvOutBuffers[pData->audioOut.count+i], frames);
  1900. }
  1901. // --------------------------------------------------------------------------------------------------------
  1902. // Run plugin
  1903. fIsProcessing = true;
  1904. if (fHandle2 == nullptr)
  1905. {
  1906. fDescriptor->process(fHandle,
  1907. fAudioAndCvInBuffers, fAudioAndCvOutBuffers, frames,
  1908. fMidiInEvents, fMidiEventInCount);
  1909. }
  1910. else
  1911. {
  1912. fDescriptor->process(fHandle,
  1913. (fAudioAndCvInBuffers != nullptr) ? &fAudioAndCvInBuffers[0] : nullptr,
  1914. (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[0] : nullptr,
  1915. frames, fMidiInEvents, fMidiEventInCount);
  1916. fDescriptor->process(fHandle2,
  1917. (fAudioAndCvInBuffers != nullptr) ? &fAudioAndCvInBuffers[1] : nullptr,
  1918. (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[1] : nullptr,
  1919. frames, fMidiInEvents, fMidiEventInCount);
  1920. }
  1921. fIsProcessing = false;
  1922. if (fTimeInfo.playing)
  1923. fTimeInfo.frame += frames;
  1924. uint32_t i=0;
  1925. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1926. // --------------------------------------------------------------------------------------------------------
  1927. // Post-processing (dry/wet, volume and balance)
  1928. {
  1929. const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
  1930. const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
  1931. bool isPair;
  1932. float bufValue, oldBufLeft[doBalance ? frames : 1];
  1933. for (; i < pData->audioOut.count; ++i)
  1934. {
  1935. // Dry/Wet
  1936. if (doDryWet)
  1937. {
  1938. for (uint32_t k=0; k < frames; ++k)
  1939. {
  1940. bufValue = fAudioAndCvInBuffers[(pData->audioIn.count == 1) ? 0 : i][k];
  1941. fAudioAndCvOutBuffers[i][k] = (fAudioAndCvOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
  1942. }
  1943. }
  1944. // Balance
  1945. if (doBalance)
  1946. {
  1947. isPair = (i % 2 == 0);
  1948. if (isPair)
  1949. {
  1950. CARLA_ASSERT(i+1 < pData->audioOut.count);
  1951. carla_copyFloats(oldBufLeft, fAudioAndCvOutBuffers[i], frames);
  1952. }
  1953. float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
  1954. float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
  1955. for (uint32_t k=0; k < frames; ++k)
  1956. {
  1957. if (isPair)
  1958. {
  1959. // left
  1960. fAudioAndCvOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
  1961. fAudioAndCvOutBuffers[i][k] += fAudioAndCvOutBuffers[i+1][k] * (1.0f - balRangeR);
  1962. }
  1963. else
  1964. {
  1965. // right
  1966. fAudioAndCvOutBuffers[i][k] = fAudioAndCvOutBuffers[i][k] * balRangeR;
  1967. fAudioAndCvOutBuffers[i][k] += oldBufLeft[k] * balRangeL;
  1968. }
  1969. }
  1970. }
  1971. // Volume (and buffer copy)
  1972. {
  1973. for (uint32_t k=0; k < frames; ++k)
  1974. audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k] * pData->postProc.volume;
  1975. }
  1976. }
  1977. } // End of Post-processing
  1978. #else
  1979. for (; i < pData->audioOut.count; ++i)
  1980. {
  1981. for (uint32_t k=0; k < frames; ++k)
  1982. audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k];
  1983. }
  1984. #endif
  1985. // CV stuff too
  1986. for (; i < pData->cvOut.count; ++i)
  1987. {
  1988. for (uint32_t k=0; k < frames; ++k)
  1989. cvOut[i][k+timeOffset] = fAudioAndCvOutBuffers[pData->audioOut.count+i][k];
  1990. }
  1991. // --------------------------------------------------------------------------------------------------------
  1992. // MIDI Output
  1993. if (pData->event.portOut != nullptr)
  1994. {
  1995. for (uint32_t k = 0; k < fMidiEventOutCount; ++k)
  1996. {
  1997. const uint8_t channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(fMidiOutEvents[k].data));
  1998. const uint8_t port = fMidiOutEvents[k].port;
  1999. if (fMidiOut.count > 1 && port < fMidiOut.count)
  2000. fMidiOut.ports[port]->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data);
  2001. else
  2002. pData->event.portOut->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data);
  2003. }
  2004. }
  2005. // --------------------------------------------------------------------------------------------------------
  2006. pData->singleMutex.unlock();
  2007. return true;
  2008. }
  2009. void bufferSizeChanged(const uint32_t newBufferSize) override
  2010. {
  2011. CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
  2012. carla_debug("CarlaPluginNative::bufferSizeChanged(%i)", newBufferSize);
  2013. for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i)
  2014. {
  2015. if (fAudioAndCvInBuffers[i] != nullptr)
  2016. delete[] fAudioAndCvInBuffers[i];
  2017. fAudioAndCvInBuffers[i] = new float[newBufferSize];
  2018. }
  2019. for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i)
  2020. {
  2021. if (fAudioAndCvOutBuffers[i] != nullptr)
  2022. delete[] fAudioAndCvOutBuffers[i];
  2023. fAudioAndCvOutBuffers[i] = new float[newBufferSize];
  2024. }
  2025. if (fCurBufferSize == newBufferSize)
  2026. return;
  2027. fCurBufferSize = newBufferSize;
  2028. if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
  2029. {
  2030. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, static_cast<intptr_t>(newBufferSize), nullptr, 0.0f);
  2031. if (fHandle2 != nullptr)
  2032. fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, static_cast<intptr_t>(newBufferSize), nullptr, 0.0f);
  2033. }
  2034. }
  2035. void sampleRateChanged(const double newSampleRate) override
  2036. {
  2037. CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate);
  2038. carla_debug("CarlaPluginNative::sampleRateChanged(%g)", newSampleRate);
  2039. if (carla_isEqual(fCurSampleRate, newSampleRate))
  2040. return;
  2041. fCurSampleRate = newSampleRate;
  2042. if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
  2043. {
  2044. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, float(newSampleRate));
  2045. if (fHandle2 != nullptr)
  2046. fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, float(newSampleRate));
  2047. }
  2048. }
  2049. void offlineModeChanged(const bool isOffline) override
  2050. {
  2051. if (fIsOffline == isOffline)
  2052. return;
  2053. fIsOffline = isOffline;
  2054. if (fDescriptor != nullptr && fDescriptor->dispatcher != nullptr)
  2055. {
  2056. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED, 0, isOffline ? 1 : 0, nullptr, 0.0f);
  2057. if (fHandle2 != nullptr)
  2058. fDescriptor->dispatcher(fHandle2, NATIVE_PLUGIN_OPCODE_OFFLINE_CHANGED, 0, isOffline ? 1 : 0, nullptr, 0.0f);
  2059. }
  2060. }
  2061. // -------------------------------------------------------------------
  2062. // Plugin buffers
  2063. void initBuffers() const noexcept override
  2064. {
  2065. CarlaPlugin::initBuffers();
  2066. fMidiIn.initBuffers(pData->event.portIn);
  2067. fMidiOut.initBuffers();
  2068. }
  2069. void clearBuffers() noexcept override
  2070. {
  2071. carla_debug("CarlaPluginNative::clearBuffers() - start");
  2072. if (fAudioAndCvInBuffers != nullptr)
  2073. {
  2074. for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i)
  2075. {
  2076. if (fAudioAndCvInBuffers[i] != nullptr)
  2077. {
  2078. delete[] fAudioAndCvInBuffers[i];
  2079. fAudioAndCvInBuffers[i] = nullptr;
  2080. }
  2081. }
  2082. delete[] fAudioAndCvInBuffers;
  2083. fAudioAndCvInBuffers = nullptr;
  2084. }
  2085. if (fAudioAndCvOutBuffers != nullptr)
  2086. {
  2087. for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i)
  2088. {
  2089. if (fAudioAndCvOutBuffers[i] != nullptr)
  2090. {
  2091. delete[] fAudioAndCvOutBuffers[i];
  2092. fAudioAndCvOutBuffers[i] = nullptr;
  2093. }
  2094. }
  2095. delete[] fAudioAndCvOutBuffers;
  2096. fAudioAndCvOutBuffers = nullptr;
  2097. }
  2098. if (fMidiIn.count > 1)
  2099. pData->event.portIn = nullptr;
  2100. if (fMidiOut.count > 1)
  2101. pData->event.portOut = nullptr;
  2102. fMidiIn.clear();
  2103. fMidiOut.clear();
  2104. CarlaPlugin::clearBuffers();
  2105. carla_debug("CarlaPluginNative::clearBuffers() - end");
  2106. }
  2107. // -------------------------------------------------------------------
  2108. // Post-poned UI Stuff
  2109. void uiParameterChange(const uint32_t index, const float value) noexcept override
  2110. {
  2111. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  2112. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  2113. CARLA_SAFE_ASSERT_RETURN(index < pData->param.count,);
  2114. if (! fIsUiVisible)
  2115. return;
  2116. if (fDescriptor->ui_set_parameter_value != nullptr)
  2117. fDescriptor->ui_set_parameter_value(fHandle, index, value);
  2118. }
  2119. void uiMidiProgramChange(const uint32_t index) noexcept override
  2120. {
  2121. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  2122. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  2123. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
  2124. if (! fIsUiVisible)
  2125. return;
  2126. if (index >= pData->midiprog.count)
  2127. return;
  2128. if (fDescriptor->ui_set_midi_program != nullptr)
  2129. fDescriptor->ui_set_midi_program(fHandle, 0, pData->midiprog.data[index].bank, pData->midiprog.data[index].program);
  2130. }
  2131. void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept override
  2132. {
  2133. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  2134. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  2135. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  2136. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  2137. CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
  2138. if (! fIsUiVisible)
  2139. return;
  2140. if (fDescriptor->dispatcher != nullptr)
  2141. {
  2142. uint8_t data[3] = {
  2143. uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT)),
  2144. note,
  2145. velo
  2146. };
  2147. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_UI_MIDI_EVENT,
  2148. 3, 0,
  2149. data,
  2150. 0.0f);
  2151. }
  2152. }
  2153. void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept override
  2154. {
  2155. CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
  2156. CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
  2157. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  2158. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  2159. if (! fIsUiVisible)
  2160. return;
  2161. if (fDescriptor == nullptr || fHandle == nullptr)
  2162. return;
  2163. if (fDescriptor->dispatcher != nullptr)
  2164. {
  2165. uint8_t data[3] = {
  2166. uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT)),
  2167. note,
  2168. 0
  2169. };
  2170. fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_UI_MIDI_EVENT,
  2171. 3, 0,
  2172. data,
  2173. 0.0f);
  2174. }
  2175. }
  2176. // -------------------------------------------------------------------
  2177. const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t width, const uint32_t height) const
  2178. {
  2179. CARLA_SAFE_ASSERT_RETURN(fDescriptor->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY, nullptr);
  2180. CARLA_SAFE_ASSERT_RETURN(fDescriptor->render_inline_display, nullptr);
  2181. CARLA_SAFE_ASSERT_RETURN(width > 0, nullptr);
  2182. CARLA_SAFE_ASSERT_RETURN(height > 0, nullptr);
  2183. return fDescriptor->render_inline_display(fHandle, width, height);
  2184. }
  2185. // -------------------------------------------------------------------
  2186. protected:
  2187. const NativeTimeInfo* handleGetTimeInfo() const noexcept
  2188. {
  2189. CARLA_SAFE_ASSERT_RETURN(fIsProcessing, nullptr);
  2190. return &fTimeInfo;
  2191. }
  2192. bool handleWriteMidiEvent(const NativeMidiEvent* const event)
  2193. {
  2194. CARLA_SAFE_ASSERT_RETURN(pData->enabled, false);
  2195. CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false);
  2196. CARLA_SAFE_ASSERT_RETURN(fMidiOut.count > 0 || pData->event.portOut != nullptr, false);
  2197. CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
  2198. CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);
  2199. if (fMidiEventOutCount == kPluginMaxMidiEvents)
  2200. {
  2201. carla_stdout("CarlaPluginNative::handleWriteMidiEvent(%p) - buffer full", event);
  2202. return false;
  2203. }
  2204. std::memcpy(&fMidiOutEvents[fMidiEventOutCount++], event, sizeof(NativeMidiEvent));
  2205. return true;
  2206. }
  2207. void handleUiParameterChanged(const uint32_t index, const float value)
  2208. {
  2209. setParameterValue(index, value, false, true, true);
  2210. }
  2211. void handleUiCustomDataChanged(const char* const key, const char* const value)
  2212. {
  2213. setCustomData(CUSTOM_DATA_TYPE_STRING, key, value, false);
  2214. }
  2215. void handleUiClosed()
  2216. {
  2217. pData->engine->callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0, 0.0f, nullptr);
  2218. fIsUiVisible = false;
  2219. }
  2220. const char* handleUiOpenFile(const bool isDir, const char* const title, const char* const filter)
  2221. {
  2222. return pData->engine->runFileCallback(FILE_CALLBACK_OPEN, isDir, title, filter);
  2223. }
  2224. const char* handleUiSaveFile(const bool isDir, const char* const title, const char* const filter)
  2225. {
  2226. return pData->engine->runFileCallback(FILE_CALLBACK_SAVE, isDir, title, filter);
  2227. }
  2228. intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode,
  2229. const int32_t index, const intptr_t value, void* const ptr, const float opt)
  2230. {
  2231. #ifdef DEBUG
  2232. if (opcode != NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY && opcode != NATIVE_HOST_OPCODE_REQUEST_IDLE) {
  2233. carla_debug("CarlaPluginNative::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)",
  2234. opcode, index, value, ptr, static_cast<double>(opt));
  2235. }
  2236. #endif
  2237. switch (opcode)
  2238. {
  2239. case NATIVE_HOST_OPCODE_NULL:
  2240. break;
  2241. case NATIVE_HOST_OPCODE_UPDATE_PARAMETER:
  2242. // TODO
  2243. pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr);
  2244. break;
  2245. case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM:
  2246. // TODO
  2247. pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr);
  2248. break;
  2249. case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS:
  2250. reloadParameters(nullptr, nullptr);
  2251. pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PARAMETERS, pData->id, -1, 0, 0, 0.0f, nullptr);
  2252. break;
  2253. case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
  2254. reloadPrograms(false);
  2255. pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PROGRAMS, pData->id, -1, 0, 0, 0.0f, nullptr);
  2256. break;
  2257. case NATIVE_HOST_OPCODE_RELOAD_ALL:
  2258. reload();
  2259. pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_ALL, pData->id, -1, 0, 0, 0.0f, nullptr);
  2260. break;
  2261. case NATIVE_HOST_OPCODE_UI_UNAVAILABLE:
  2262. pData->engine->callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0, 0.0f, nullptr);
  2263. fIsUiAvailable = false;
  2264. break;
  2265. case NATIVE_HOST_OPCODE_HOST_IDLE:
  2266. pData->engine->callback(true, false, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
  2267. break;
  2268. case NATIVE_HOST_OPCODE_INTERNAL_PLUGIN:
  2269. return 1;
  2270. case NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY:
  2271. switch (pData->engine->getProccessMode())
  2272. {
  2273. case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
  2274. case ENGINE_PROCESS_MODE_PATCHBAY:
  2275. fInlineDisplayNeedsRedraw = true;
  2276. break;
  2277. default:
  2278. break;
  2279. }
  2280. break;
  2281. case NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER:
  2282. CARLA_SAFE_ASSERT_RETURN(index >= 0, 0);
  2283. pData->engine->touchPluginParameter(pData->id, static_cast<uint32_t>(index), value != 0);
  2284. break;
  2285. case NATIVE_HOST_OPCODE_REQUEST_IDLE:
  2286. fNeedsIdle = true;
  2287. break;
  2288. case NATIVE_HOST_OPCODE_GET_FILE_PATH:
  2289. CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0);
  2290. {
  2291. const EngineOptions& opts(pData->engine->getOptions());
  2292. const char* const filetype = (const char*)ptr;
  2293. const char* ret = nullptr;
  2294. if (std::strcmp(filetype, "carla") == 0)
  2295. {
  2296. ret = pData->engine->getCurrentProjectFilename();
  2297. if (fLastProjectFilename != ret)
  2298. {
  2299. fLastProjectFilename = ret;
  2300. bool found;
  2301. const size_t r = fLastProjectFilename.rfind(CARLA_OS_SEP, &found);
  2302. if (found)
  2303. {
  2304. fLastProjectFolder = ret;
  2305. fLastProjectFolder[r] = '\0';
  2306. }
  2307. else
  2308. {
  2309. fLastProjectFolder.clear();
  2310. }
  2311. }
  2312. ret = fLastProjectFolder.buffer();
  2313. }
  2314. else if (std::strcmp(filetype, "audio") == 0)
  2315. ret = opts.pathAudio;
  2316. else if (std::strcmp(filetype, "midi") == 0)
  2317. ret = opts.pathMIDI;
  2318. return static_cast<intptr_t>((uintptr_t)ret);
  2319. }
  2320. break;
  2321. case NATIVE_HOST_OPCODE_UI_RESIZE:
  2322. case NATIVE_HOST_OPCODE_PREVIEW_BUFFER_DATA:
  2323. // unused here
  2324. break;
  2325. }
  2326. return 0;
  2327. // unused for now
  2328. (void)opt;
  2329. }
  2330. // -------------------------------------------------------------------
  2331. public:
  2332. void* getNativeHandle() const noexcept override
  2333. {
  2334. return fHandle;
  2335. }
  2336. const void* getNativeDescriptor() const noexcept override
  2337. {
  2338. return fDescriptor;
  2339. }
  2340. // -------------------------------------------------------------------
  2341. bool init(const CarlaPluginPtr plugin,
  2342. const char* const name, const char* const label, const uint options)
  2343. {
  2344. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  2345. // ---------------------------------------------------------------
  2346. // first checks
  2347. if (pData->client != nullptr)
  2348. {
  2349. pData->engine->setLastError("Plugin client is already registered");
  2350. return false;
  2351. }
  2352. if (label == nullptr || label[0] == '\0')
  2353. {
  2354. pData->engine->setLastError("null label");
  2355. return false;
  2356. }
  2357. // ---------------------------------------------------------------
  2358. // get descriptor that matches label
  2359. sPluginInitializer.initIfNeeded();
  2360. for (LinkedList<const NativePluginDescriptor*>::Itenerator it = gPluginDescriptors.begin2(); it.valid(); it.next())
  2361. {
  2362. fDescriptor = it.getValue(nullptr);
  2363. CARLA_SAFE_ASSERT_BREAK(fDescriptor != nullptr);
  2364. carla_debug("Check vs \"%s\"", fDescriptor->label);
  2365. if (fDescriptor->label != nullptr && std::strcmp(fDescriptor->label, label) == 0)
  2366. break;
  2367. fDescriptor = nullptr;
  2368. }
  2369. if (fDescriptor == nullptr)
  2370. {
  2371. pData->engine->setLastError("Invalid internal plugin");
  2372. return false;
  2373. }
  2374. // ---------------------------------------------------------------
  2375. // set icon
  2376. /**/ if (std::strcmp(fDescriptor->label, "audiofile") == 0)
  2377. pData->iconName = carla_strdup_safe("file");
  2378. else if (std::strcmp(fDescriptor->label, "midifile") == 0)
  2379. pData->iconName = carla_strdup_safe("file");
  2380. else if (std::strcmp(fDescriptor->label, "3bandeq") == 0)
  2381. pData->iconName = carla_strdup_safe("distrho");
  2382. else if (std::strcmp(fDescriptor->label, "3bandsplitter") == 0)
  2383. pData->iconName = carla_strdup_safe("distrho");
  2384. else if (std::strcmp(fDescriptor->label, "kars") == 0)
  2385. pData->iconName = carla_strdup_safe("distrho");
  2386. else if (std::strcmp(fDescriptor->label, "nekobi") == 0)
  2387. pData->iconName = carla_strdup_safe("distrho");
  2388. else if (std::strcmp(fDescriptor->label, "pingpongpan") == 0)
  2389. pData->iconName = carla_strdup_safe("distrho");
  2390. // ---------------------------------------------------------------
  2391. // set info
  2392. if (name != nullptr && name[0] != '\0')
  2393. pData->name = pData->engine->getUniquePluginName(name);
  2394. else if (fDescriptor->name != nullptr && fDescriptor->name[0] != '\0')
  2395. pData->name = pData->engine->getUniquePluginName(fDescriptor->name);
  2396. else
  2397. pData->name = pData->engine->getUniquePluginName(label);
  2398. {
  2399. CARLA_ASSERT(fHost.uiName == nullptr);
  2400. CarlaString uiName;
  2401. if (pData->uiTitle.isNotEmpty())
  2402. {
  2403. uiName = pData->uiTitle;
  2404. }
  2405. else
  2406. {
  2407. uiName = pData->name;
  2408. uiName += " (GUI)";
  2409. }
  2410. fHost.uiName = uiName.releaseBufferPointer();
  2411. }
  2412. // ---------------------------------------------------------------
  2413. // register client
  2414. pData->client = pData->engine->addClient(plugin);
  2415. if (pData->client == nullptr || ! pData->client->isOk())
  2416. {
  2417. pData->engine->setLastError("Failed to register plugin client");
  2418. return false;
  2419. }
  2420. // ---------------------------------------------------------------
  2421. // initialize plugin
  2422. fHandle = fDescriptor->instantiate(&fHost);
  2423. if (fHandle == nullptr)
  2424. {
  2425. pData->engine->setLastError("Plugin failed to initialize");
  2426. return false;
  2427. }
  2428. // ---------------------------------------------------------------
  2429. // set options
  2430. bool hasMidiProgs = false;
  2431. if (fDescriptor->get_midi_program_count != nullptr)
  2432. {
  2433. try {
  2434. hasMidiProgs = fDescriptor->get_midi_program_count(fHandle) > 0;
  2435. } catch (...) {}
  2436. }
  2437. pData->options = 0x0;
  2438. if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
  2439. pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
  2440. else if (options & PLUGIN_OPTION_FIXED_BUFFERS)
  2441. pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
  2442. if (pData->engine->getOptions().forceStereo)
  2443. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  2444. else if (options & PLUGIN_OPTION_FORCE_STEREO)
  2445. pData->options |= PLUGIN_OPTION_FORCE_STEREO;
  2446. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES)
  2447. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
  2448. pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  2449. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_CHANNEL_PRESSURE)
  2450. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
  2451. pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  2452. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH)
  2453. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
  2454. pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  2455. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PITCHBEND)
  2456. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
  2457. pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
  2458. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF)
  2459. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
  2460. pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  2461. if (fDescriptor->midiIns > 0)
  2462. if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
  2463. pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  2464. if (fDescriptor->supports & NATIVE_PLUGIN_SUPPORTS_PROGRAM_CHANGES)
  2465. {
  2466. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PROGRAM_CHANGES))
  2467. pData->options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  2468. // makes no sense for a plugin to set program changes supported, but it has no midi programs
  2469. CARLA_SAFE_ASSERT(! hasMidiProgs);
  2470. }
  2471. else if (hasMidiProgs)
  2472. {
  2473. if (isPluginOptionEnabled(options, PLUGIN_OPTION_MAP_PROGRAM_CHANGES))
  2474. pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  2475. }
  2476. return true;
  2477. }
  2478. private:
  2479. NativePluginHandle fHandle;
  2480. NativePluginHandle fHandle2;
  2481. NativeHostDescriptor fHost;
  2482. const NativePluginDescriptor* fDescriptor;
  2483. bool fIsProcessing;
  2484. bool fIsOffline;
  2485. bool fIsUiAvailable;
  2486. bool fIsUiVisible;
  2487. volatile bool fNeedsIdle;
  2488. bool fInlineDisplayNeedsRedraw;
  2489. int64_t fInlineDisplayLastRedrawTime;
  2490. CarlaString fLastProjectFilename;
  2491. CarlaString fLastProjectFolder;
  2492. float** fAudioAndCvInBuffers;
  2493. float** fAudioAndCvOutBuffers;
  2494. uint32_t fMidiEventInCount;
  2495. uint32_t fMidiEventOutCount;
  2496. NativeMidiEvent fMidiInEvents[kPluginMaxMidiEvents];
  2497. NativeMidiEvent fMidiOutEvents[kPluginMaxMidiEvents];
  2498. int32_t fCurMidiProgs[MAX_MIDI_CHANNELS];
  2499. uint32_t fCurBufferSize;
  2500. double fCurSampleRate;
  2501. NativePluginMidiInData fMidiIn;
  2502. NativePluginMidiOutData fMidiOut;
  2503. NativeTimeInfo fTimeInfo;
  2504. // -------------------------------------------------------------------
  2505. #define handlePtr ((CarlaPluginNative*)handle)
  2506. static uint32_t carla_host_get_buffer_size(NativeHostHandle handle) noexcept
  2507. {
  2508. return handlePtr->fCurBufferSize;
  2509. }
  2510. static double carla_host_get_sample_rate(NativeHostHandle handle) noexcept
  2511. {
  2512. return handlePtr->fCurSampleRate;
  2513. }
  2514. static bool carla_host_is_offline(NativeHostHandle handle) noexcept
  2515. {
  2516. return handlePtr->fIsOffline;
  2517. }
  2518. static const NativeTimeInfo* carla_host_get_time_info(NativeHostHandle handle) noexcept
  2519. {
  2520. return handlePtr->handleGetTimeInfo();
  2521. }
  2522. static bool carla_host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
  2523. {
  2524. return handlePtr->handleWriteMidiEvent(event);
  2525. }
  2526. static void carla_host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
  2527. {
  2528. handlePtr->handleUiParameterChanged(index, value);
  2529. }
  2530. static void carla_host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
  2531. {
  2532. handlePtr->handleUiCustomDataChanged(key, value);
  2533. }
  2534. static void carla_host_ui_closed(NativeHostHandle handle)
  2535. {
  2536. handlePtr->handleUiClosed();
  2537. }
  2538. static const char* carla_host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  2539. {
  2540. return handlePtr->handleUiOpenFile(isDir, title, filter);
  2541. }
  2542. static const char* carla_host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  2543. {
  2544. return handlePtr->handleUiSaveFile(isDir, title, filter);
  2545. }
  2546. static intptr_t carla_host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  2547. {
  2548. return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
  2549. }
  2550. #undef handlePtr
  2551. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginNative)
  2552. };
  2553. // -----------------------------------------------------------------------
  2554. CarlaPluginPtr CarlaPlugin::newNative(const Initializer& init)
  2555. {
  2556. carla_debug("CarlaPlugin::newNative({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})",
  2557. init.engine, init.filename, init.name, init.label, init.uniqueId);
  2558. std::shared_ptr<CarlaPluginNative> plugin(new CarlaPluginNative(init.engine, init.id));
  2559. if (! plugin->init(plugin, init.name, init.label, init.options))
  2560. return nullptr;
  2561. return plugin;
  2562. }
  2563. // used in CarlaStandalone.cpp
  2564. const void* carla_render_inline_display_internal(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height);
  2565. const void* carla_render_inline_display_internal(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height)
  2566. {
  2567. const std::shared_ptr<CarlaPluginNative>& nativePlugin((const std::shared_ptr<CarlaPluginNative>&)plugin);
  2568. return nativePlugin->renderInlineDisplay(width, height);
  2569. }
  2570. // -----------------------------------------------------------------------
  2571. CARLA_BACKEND_END_NAMESPACE