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.

CarlaPlugin.cpp 91KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
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
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
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
9 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
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
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
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
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
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760
  1. /*
  2. * Carla Plugin
  3. * Copyright (C) 2011-2020 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 "CarlaBase64Utils.hpp"
  21. #include "CarlaMathUtils.hpp"
  22. #include "CarlaMIDI.h"
  23. #include "CarlaPluginUI.hpp"
  24. #include "CarlaScopeUtils.hpp"
  25. #include "CarlaStringList.hpp"
  26. #include <ctime>
  27. #include "water/files/File.h"
  28. #include "water/streams/MemoryOutputStream.h"
  29. #include "water/xml/XmlDocument.h"
  30. #include "water/xml/XmlElement.h"
  31. using water::CharPointer_UTF8;
  32. using water::File;
  33. using water::MemoryOutputStream;
  34. using water::Result;
  35. using water::String;
  36. using water::XmlDocument;
  37. using water::XmlElement;
  38. CARLA_BACKEND_START_NAMESPACE
  39. // -------------------------------------------------------------------------------------------------------------------
  40. // Fallback data
  41. static const ParameterData kParameterDataNull = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, 0, CONTROL_INDEX_NONE, 0.0f, 1.0f, 0x0 };
  42. static const ParameterRanges kParameterRangesNull = { 0.0f, 0.0f, 1.0f, 0.01f, 0.0001f, 0.1f };
  43. static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr };
  44. static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
  45. static /* */ CustomData kCustomDataFallbackNC = { nullptr, nullptr, nullptr };
  46. static const PluginPostRtEvent kPluginPostRtEventFallback = { kPluginPostRtEventNull, false, 0, 0, 0, 0.0f };
  47. // -------------------------------------------------------------------------------------------------------------------
  48. // ParamSymbol struct, needed for CarlaPlugin::loadStateSave()
  49. struct ParamSymbol {
  50. int32_t index;
  51. const char* symbol;
  52. ParamSymbol(const uint32_t i, const char* const s)
  53. : index(static_cast<int32_t>(i)),
  54. symbol(carla_strdup(s)) {}
  55. ~ParamSymbol() noexcept
  56. {
  57. CARLA_SAFE_ASSERT_RETURN(symbol != nullptr,)
  58. delete[] symbol;
  59. symbol = nullptr;
  60. }
  61. #ifdef CARLA_PROPER_CPP11_SUPPORT
  62. ParamSymbol() = delete;
  63. CARLA_DECLARE_NON_COPY_STRUCT(ParamSymbol)
  64. #endif
  65. };
  66. // -------------------------------------------------------------------------------------------------------------------
  67. // Constructor and destructor
  68. CarlaPlugin::CarlaPlugin(CarlaEngine* const engine, const uint id)
  69. : pData(new ProtectedData(engine, id))
  70. {
  71. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  72. CARLA_SAFE_ASSERT(id < engine->getMaxPluginNumber());
  73. carla_debug("CarlaPlugin::CarlaPlugin(%p, %i)", engine, id);
  74. switch (engine->getProccessMode())
  75. {
  76. case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
  77. case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
  78. CARLA_SAFE_ASSERT(id < MAX_DEFAULT_PLUGINS);
  79. break;
  80. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  81. CARLA_SAFE_ASSERT(id < MAX_RACK_PLUGINS);
  82. break;
  83. case ENGINE_PROCESS_MODE_PATCHBAY:
  84. CARLA_SAFE_ASSERT(id < MAX_PATCHBAY_PLUGINS);
  85. break;
  86. case ENGINE_PROCESS_MODE_BRIDGE:
  87. CARLA_SAFE_ASSERT(id == 0);
  88. break;
  89. }
  90. }
  91. CarlaPlugin::~CarlaPlugin()
  92. {
  93. carla_debug("CarlaPlugin::~CarlaPlugin()");
  94. delete pData;
  95. }
  96. // -------------------------------------------------------------------
  97. // Information (base)
  98. uint CarlaPlugin::getId() const noexcept
  99. {
  100. return pData->id;
  101. }
  102. uint CarlaPlugin::getHints() const noexcept
  103. {
  104. return pData->hints;
  105. }
  106. uint CarlaPlugin::getOptionsEnabled() const noexcept
  107. {
  108. return pData->options;
  109. }
  110. bool CarlaPlugin::isEnabled() const noexcept
  111. {
  112. return pData->enabled;
  113. }
  114. const char* CarlaPlugin::getName() const noexcept
  115. {
  116. return pData->name;
  117. }
  118. const char* CarlaPlugin::getFilename() const noexcept
  119. {
  120. return pData->filename;
  121. }
  122. const char* CarlaPlugin::getIconName() const noexcept
  123. {
  124. return pData->iconName;
  125. }
  126. PluginCategory CarlaPlugin::getCategory() const noexcept
  127. {
  128. return getPluginCategoryFromName(pData->name);
  129. }
  130. int64_t CarlaPlugin::getUniqueId() const noexcept
  131. {
  132. return 0;
  133. }
  134. uint32_t CarlaPlugin::getLatencyInFrames() const noexcept
  135. {
  136. return 0;
  137. }
  138. // -------------------------------------------------------------------
  139. // Information (count)
  140. uint32_t CarlaPlugin::getAudioInCount() const noexcept
  141. {
  142. return pData->audioIn.count;
  143. }
  144. uint32_t CarlaPlugin::getAudioOutCount() const noexcept
  145. {
  146. return pData->audioOut.count;
  147. }
  148. uint32_t CarlaPlugin::getCVInCount() const noexcept
  149. {
  150. return pData->cvIn.count;
  151. }
  152. uint32_t CarlaPlugin::getCVOutCount() const noexcept
  153. {
  154. return pData->cvOut.count;
  155. }
  156. uint32_t CarlaPlugin::getMidiInCount() const noexcept
  157. {
  158. return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_IN) ? 1 : 0;
  159. }
  160. uint32_t CarlaPlugin::getMidiOutCount() const noexcept
  161. {
  162. return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_OUT) ? 1 : 0;
  163. }
  164. uint32_t CarlaPlugin::getParameterCount() const noexcept
  165. {
  166. return pData->param.count;
  167. }
  168. uint32_t CarlaPlugin::getParameterScalePointCount(const uint32_t parameterId) const noexcept
  169. {
  170. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
  171. return 0;
  172. }
  173. uint32_t CarlaPlugin::getProgramCount() const noexcept
  174. {
  175. return pData->prog.count;
  176. }
  177. uint32_t CarlaPlugin::getMidiProgramCount() const noexcept
  178. {
  179. return pData->midiprog.count;
  180. }
  181. uint32_t CarlaPlugin::getCustomDataCount() const noexcept
  182. {
  183. return static_cast<uint32_t>(pData->custom.count());
  184. }
  185. // -------------------------------------------------------------------
  186. // Information (current data)
  187. int32_t CarlaPlugin::getCurrentProgram() const noexcept
  188. {
  189. return pData->prog.current;
  190. }
  191. int32_t CarlaPlugin::getCurrentMidiProgram() const noexcept
  192. {
  193. return pData->midiprog.current;
  194. }
  195. const ParameterData& CarlaPlugin::getParameterData(const uint32_t parameterId) const noexcept
  196. {
  197. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterDataNull);
  198. return pData->param.data[parameterId];
  199. }
  200. const ParameterRanges& CarlaPlugin::getParameterRanges(const uint32_t parameterId) const noexcept
  201. {
  202. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterRangesNull);
  203. return pData->param.ranges[parameterId];
  204. }
  205. bool CarlaPlugin::isParameterOutput(const uint32_t parameterId) const noexcept
  206. {
  207. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  208. return (pData->param.data[parameterId].type == PARAMETER_OUTPUT);
  209. }
  210. const MidiProgramData& CarlaPlugin::getMidiProgramData(const uint32_t index) const noexcept
  211. {
  212. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, kMidiProgramDataNull);
  213. return pData->midiprog.data[index];
  214. }
  215. const CustomData& CarlaPlugin::getCustomData(const uint32_t index) const noexcept
  216. {
  217. return pData->custom.getAt(index, kCustomDataFallback);
  218. }
  219. std::size_t CarlaPlugin::getChunkData(void** const dataPtr) noexcept
  220. {
  221. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
  222. CARLA_SAFE_ASSERT(false); // this should never happen
  223. return 0;
  224. }
  225. // -------------------------------------------------------------------
  226. // Information (per-plugin data)
  227. uint CarlaPlugin::getOptionsAvailable() const noexcept
  228. {
  229. CARLA_SAFE_ASSERT(false); // this should never happen
  230. return 0x0;
  231. }
  232. float CarlaPlugin::getParameterValue(const uint32_t parameterId) const noexcept
  233. {
  234. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
  235. CARLA_SAFE_ASSERT(false); // this should never happen
  236. return 0.0f;
  237. }
  238. float CarlaPlugin::getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept
  239. {
  240. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
  241. CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), 0.0f);
  242. CARLA_SAFE_ASSERT(false); // this should never happen
  243. return 0.0f;
  244. }
  245. bool CarlaPlugin::getLabel(char* const strBuf) const noexcept
  246. {
  247. strBuf[0] = '\0';
  248. return false;
  249. }
  250. bool CarlaPlugin::getMaker(char* const strBuf) const noexcept
  251. {
  252. strBuf[0] = '\0';
  253. return false;
  254. }
  255. bool CarlaPlugin::getCopyright(char* const strBuf) const noexcept
  256. {
  257. strBuf[0] = '\0';
  258. return false;
  259. }
  260. bool CarlaPlugin::getRealName(char* const strBuf) const noexcept
  261. {
  262. strBuf[0] = '\0';
  263. return false;
  264. }
  265. bool CarlaPlugin::getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept
  266. {
  267. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  268. CARLA_SAFE_ASSERT(false); // this should never happen
  269. strBuf[0] = '\0';
  270. return false;
  271. }
  272. bool CarlaPlugin::getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept
  273. {
  274. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  275. strBuf[0] = '\0';
  276. return false;
  277. }
  278. bool CarlaPlugin::getParameterText(const uint32_t parameterId, char* const strBuf) noexcept
  279. {
  280. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  281. CARLA_SAFE_ASSERT(false); // this should never happen
  282. strBuf[0] = '\0';
  283. return false;
  284. }
  285. bool CarlaPlugin::getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept
  286. {
  287. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  288. strBuf[0] = '\0';
  289. return false;
  290. }
  291. bool CarlaPlugin::getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept
  292. {
  293. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  294. strBuf[0] = '\0';
  295. return false;
  296. }
  297. bool CarlaPlugin::getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept
  298. {
  299. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  300. strBuf[0] = '\0';
  301. return false;
  302. }
  303. bool CarlaPlugin::getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept
  304. {
  305. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  306. CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), false);
  307. CARLA_SAFE_ASSERT(false); // this should never happen
  308. strBuf[0] = '\0';
  309. return false;
  310. }
  311. float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept
  312. {
  313. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  314. CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f);
  315. switch (parameterId)
  316. {
  317. case PARAMETER_ACTIVE:
  318. return pData->active;
  319. case PARAMETER_CTRL_CHANNEL:
  320. return pData->ctrlChannel;
  321. case PARAMETER_DRYWET:
  322. return pData->postProc.dryWet;
  323. case PARAMETER_VOLUME:
  324. return pData->postProc.volume;
  325. case PARAMETER_BALANCE_LEFT:
  326. return pData->postProc.balanceLeft;
  327. case PARAMETER_BALANCE_RIGHT:
  328. return pData->postProc.balanceRight;
  329. case PARAMETER_PANNING:
  330. return pData->postProc.panning;
  331. };
  332. #endif
  333. CARLA_SAFE_ASSERT_RETURN(parameterId >= 0, 0.0f);
  334. return getParameterValue(static_cast<uint32_t>(parameterId));
  335. }
  336. bool CarlaPlugin::getProgramName(const uint32_t index, char* const strBuf) const noexcept
  337. {
  338. CARLA_SAFE_ASSERT_RETURN(index < pData->prog.count, false);
  339. CARLA_SAFE_ASSERT_RETURN(pData->prog.names[index] != nullptr, false);
  340. std::strncpy(strBuf, pData->prog.names[index], STR_MAX);
  341. return true;
  342. }
  343. bool CarlaPlugin::getMidiProgramName(const uint32_t index, char* const strBuf) const noexcept
  344. {
  345. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, false);
  346. CARLA_SAFE_ASSERT_RETURN(pData->midiprog.data[index].name != nullptr, false);
  347. std::strncpy(strBuf, pData->midiprog.data[index].name, STR_MAX);
  348. return true;
  349. }
  350. void CarlaPlugin::getParameterCountInfo(uint32_t& ins, uint32_t& outs) const noexcept
  351. {
  352. ins = 0;
  353. outs = 0;
  354. for (uint32_t i=0; i < pData->param.count; ++i)
  355. {
  356. if (pData->param.data[i].type == PARAMETER_INPUT)
  357. ++ins;
  358. else if (pData->param.data[i].type == PARAMETER_OUTPUT)
  359. ++outs;
  360. }
  361. }
  362. // -------------------------------------------------------------------
  363. // Set data (state)
  364. void CarlaPlugin::prepareForSave(bool)
  365. {
  366. }
  367. void CarlaPlugin::resetParameters() noexcept
  368. {
  369. for (uint i=0; i < pData->param.count; ++i)
  370. {
  371. const ParameterData& paramData(pData->param.data[i]);
  372. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  373. if (paramData.type != PARAMETER_INPUT)
  374. continue;
  375. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  376. continue;
  377. setParameterValue(i, paramRanges.def, true, true, true);
  378. }
  379. }
  380. void CarlaPlugin::randomizeParameters() noexcept
  381. {
  382. float value, random;
  383. char strBuf[STR_MAX+1];
  384. strBuf[STR_MAX] = '\0';
  385. std::srand(static_cast<uint>(std::time(nullptr)));
  386. for (uint i=0; i < pData->param.count; ++i)
  387. {
  388. const ParameterData& paramData(pData->param.data[i]);
  389. if (paramData.type != PARAMETER_INPUT)
  390. continue;
  391. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  392. continue;
  393. if (! getParameterName(i, strBuf))
  394. strBuf[0] = '\0';
  395. if (std::strstr(strBuf, "olume") != nullptr)
  396. continue;
  397. if (std::strstr(strBuf, "Master") != nullptr)
  398. continue;
  399. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  400. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  401. {
  402. random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
  403. value = random > 0.5f ? paramRanges.max : paramRanges.min;
  404. }
  405. else
  406. {
  407. random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
  408. value = random * (paramRanges.max - paramRanges.min) + paramRanges.min;
  409. if (paramData.hints & PARAMETER_IS_INTEGER)
  410. value = std::rint(value);
  411. }
  412. setParameterValue(i, value, true, true, true);
  413. }
  414. }
  415. const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave)
  416. {
  417. pData->stateSave.clear();
  418. if (callPrepareForSave)
  419. {
  420. pData->stateSave.temporary = true;
  421. prepareForSave(true);
  422. }
  423. const PluginType pluginType(getType());
  424. char strBuf[STR_MAX+1];
  425. carla_zeroChars(strBuf, STR_MAX+1);
  426. // ---------------------------------------------------------------
  427. // Basic info
  428. if (! getLabel(strBuf))
  429. strBuf[0] = '\0';
  430. pData->stateSave.type = carla_strdup(getPluginTypeAsString(pluginType));
  431. pData->stateSave.name = carla_strdup(pData->name);
  432. pData->stateSave.label = carla_strdup(strBuf);
  433. pData->stateSave.uniqueId = getUniqueId();
  434. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  435. pData->stateSave.options = pData->options;
  436. #endif
  437. if (pData->filename != nullptr)
  438. pData->stateSave.binary = carla_strdup(pData->filename);
  439. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  440. // ---------------------------------------------------------------
  441. // Internals
  442. pData->stateSave.active = pData->active;
  443. pData->stateSave.dryWet = pData->postProc.dryWet;
  444. pData->stateSave.volume = pData->postProc.volume;
  445. pData->stateSave.balanceLeft = pData->postProc.balanceLeft;
  446. pData->stateSave.balanceRight = pData->postProc.balanceRight;
  447. pData->stateSave.panning = pData->postProc.panning;
  448. pData->stateSave.ctrlChannel = pData->ctrlChannel;
  449. #endif
  450. if (pData->hints & PLUGIN_IS_BRIDGE)
  451. waitForBridgeSaveSignal();
  452. // ---------------------------------------------------------------
  453. // Chunk
  454. bool usingChunk = false;
  455. if (pData->options & PLUGIN_OPTION_USE_CHUNKS)
  456. {
  457. void* data = nullptr;
  458. const std::size_t dataSize(getChunkData(&data));
  459. if (data != nullptr && dataSize > 0)
  460. {
  461. pData->stateSave.chunk = CarlaString::asBase64(data, dataSize).dup();
  462. if (pluginType != PLUGIN_INTERNAL)
  463. usingChunk = true;
  464. }
  465. }
  466. // ---------------------------------------------------------------
  467. // Current Program
  468. if (pData->prog.current >= 0 && pluginType != PLUGIN_LV2)
  469. {
  470. pData->stateSave.currentProgramIndex = pData->prog.current;
  471. pData->stateSave.currentProgramName = carla_strdup(pData->prog.names[pData->prog.current]);
  472. }
  473. // ---------------------------------------------------------------
  474. // Current MIDI Program
  475. if (pData->midiprog.current >= 0 && pluginType != PLUGIN_LV2 && pluginType != PLUGIN_SF2)
  476. {
  477. const MidiProgramData& mpData(pData->midiprog.getCurrent());
  478. pData->stateSave.currentMidiBank = static_cast<int32_t>(mpData.bank);
  479. pData->stateSave.currentMidiProgram = static_cast<int32_t>(mpData.program);
  480. }
  481. // ---------------------------------------------------------------
  482. // Parameters
  483. const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
  484. for (uint32_t i=0; i < pData->param.count; ++i)
  485. {
  486. const ParameterData& paramData(pData->param.data[i]);
  487. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  488. continue;
  489. if (paramData.hints & PARAMETER_IS_NOT_SAVED)
  490. continue;
  491. const bool dummy = paramData.type != PARAMETER_INPUT || usingChunk;
  492. if (dummy && paramData.mappedControlIndex <= CONTROL_INDEX_NONE)
  493. continue;
  494. CarlaStateSave::Parameter* const stateParameter(new CarlaStateSave::Parameter());
  495. stateParameter->dummy = dummy;
  496. stateParameter->index = paramData.index;
  497. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  498. if (paramData.mappedControlIndex != CONTROL_INDEX_MIDI_LEARN)
  499. {
  500. stateParameter->mappedControlIndex = paramData.mappedControlIndex;
  501. stateParameter->midiChannel = paramData.midiChannel;
  502. if (paramData.hints & PARAMETER_MAPPED_RANGES_SET)
  503. {
  504. stateParameter->mappedMinimum = paramData.mappedMinimum;
  505. stateParameter->mappedMaximum = paramData.mappedMaximum;
  506. stateParameter->mappedRangeValid = true;
  507. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  508. {
  509. stateParameter->mappedMinimum /= sampleRate;
  510. stateParameter->mappedMaximum /= sampleRate;
  511. }
  512. }
  513. }
  514. #endif
  515. if (! getParameterName(i, strBuf))
  516. strBuf[0] = '\0';
  517. stateParameter->name = carla_strdup(strBuf);
  518. if (! getParameterSymbol(i, strBuf))
  519. strBuf[0] = '\0';
  520. stateParameter->symbol = carla_strdup(strBuf);;
  521. if (! dummy)
  522. {
  523. stateParameter->value = getParameterValue(i);
  524. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  525. stateParameter->value /= sampleRate;
  526. }
  527. pData->stateSave.parameters.append(stateParameter);
  528. }
  529. // ---------------------------------------------------------------
  530. // Custom Data
  531. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  532. {
  533. const CustomData& cData(it.getValue(kCustomDataFallback));
  534. CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
  535. CarlaStateSave::CustomData* stateCustomData(new CarlaStateSave::CustomData());
  536. stateCustomData->type = carla_strdup(cData.type);
  537. stateCustomData->key = carla_strdup(cData.key);
  538. stateCustomData->value = carla_strdup(cData.value);
  539. pData->stateSave.customData.append(stateCustomData);
  540. }
  541. return pData->stateSave;
  542. }
  543. void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave)
  544. {
  545. const bool usesMultiProgs(pData->hints & PLUGIN_USES_MULTI_PROGS);
  546. const PluginType pluginType(getType());
  547. char strBuf[STR_MAX+1];
  548. carla_zeroChars(strBuf, STR_MAX+1);
  549. // ---------------------------------------------------------------
  550. // Part 1 - PRE-set custom data (only those which reload programs)
  551. for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
  552. {
  553. const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
  554. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
  555. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
  556. const char* const key(stateCustomData->key);
  557. /**/ if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
  558. std::strcmp (key, "load" ) == 0 ||
  559. std::strncmp(key, "patches", 7) == 0 ))
  560. pass();
  561. else if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
  562. pass();
  563. else
  564. continue;
  565. setCustomData(stateCustomData->type, key, stateCustomData->value, true);
  566. }
  567. // ---------------------------------------------------------------
  568. // Part 2 - set program
  569. if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr)
  570. {
  571. int32_t programId = -1;
  572. // index < count
  573. if (stateSave.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
  574. {
  575. programId = stateSave.currentProgramIndex;
  576. }
  577. // index not valid, try to find by name
  578. else
  579. {
  580. for (uint32_t i=0; i < pData->prog.count; ++i)
  581. {
  582. if (getProgramName(i, strBuf) && std::strcmp(stateSave.currentProgramName, strBuf) == 0)
  583. {
  584. programId = static_cast<int32_t>(i);
  585. break;
  586. }
  587. }
  588. }
  589. // set program now, if valid
  590. if (programId >= 0)
  591. setProgram(programId, true, true, true);
  592. }
  593. // ---------------------------------------------------------------
  594. // Part 3 - set midi program
  595. if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0 && ! usesMultiProgs)
  596. setMidiProgramById(static_cast<uint32_t>(stateSave.currentMidiBank), static_cast<uint32_t>(stateSave.currentMidiProgram), true, true, true);
  597. // ---------------------------------------------------------------
  598. // Part 4a - get plugin parameter symbols
  599. LinkedList<ParamSymbol*> paramSymbols;
  600. if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2)
  601. {
  602. for (uint32_t i=0; i < pData->param.count; ++i)
  603. {
  604. if (pData->param.data[i].hints & PARAMETER_IS_NOT_SAVED)
  605. continue;
  606. if (getParameterSymbol(i, strBuf))
  607. {
  608. ParamSymbol* const paramSymbol(new ParamSymbol(i, strBuf));
  609. paramSymbols.append(paramSymbol);
  610. }
  611. }
  612. }
  613. // ---------------------------------------------------------------
  614. // Part 4b - set parameter values (carefully)
  615. const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
  616. for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next())
  617. {
  618. CarlaStateSave::Parameter* const stateParameter(it.getValue(nullptr));
  619. CARLA_SAFE_ASSERT_CONTINUE(stateParameter != nullptr);
  620. int32_t index = -1;
  621. if (pluginType == PLUGIN_LADSPA)
  622. {
  623. // Try to set by symbol, otherwise use index
  624. if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
  625. {
  626. for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
  627. {
  628. ParamSymbol* const paramSymbol(it2.getValue(nullptr));
  629. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
  630. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
  631. if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
  632. {
  633. index = paramSymbol->index;
  634. break;
  635. }
  636. }
  637. if (index == -1)
  638. index = stateParameter->index;
  639. }
  640. else
  641. {
  642. index = stateParameter->index;
  643. }
  644. }
  645. else if (pluginType == PLUGIN_LV2)
  646. {
  647. // Symbol only
  648. if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
  649. {
  650. for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
  651. {
  652. ParamSymbol* const paramSymbol(it2.getValue(nullptr));
  653. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
  654. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
  655. if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
  656. {
  657. index = paramSymbol->index;
  658. break;
  659. }
  660. }
  661. if (index == -1)
  662. carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'",
  663. stateParameter->symbol, pData->name);
  664. }
  665. else
  666. {
  667. carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name);
  668. }
  669. }
  670. else
  671. {
  672. // Index only
  673. index = stateParameter->index;
  674. }
  675. // Now set parameter
  676. if (index >= 0 && index < static_cast<int32_t>(pData->param.count))
  677. {
  678. //CARLA_SAFE_ASSERT(stateParameter->isInput == (pData
  679. if (! stateParameter->dummy)
  680. {
  681. if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
  682. stateParameter->value *= sampleRate;
  683. setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true);
  684. }
  685. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  686. if (stateParameter->mappedRangeValid)
  687. {
  688. if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
  689. {
  690. stateParameter->mappedMinimum *= sampleRate;
  691. stateParameter->mappedMaximum *= sampleRate;
  692. }
  693. setParameterMappedRange(static_cast<uint32_t>(index),
  694. stateParameter->mappedMinimum,
  695. stateParameter->mappedMaximum, true, true);
  696. }
  697. setParameterMappedControlIndex(static_cast<uint32_t>(index),
  698. stateParameter->mappedControlIndex, true, true, false);
  699. setParameterMidiChannel(static_cast<uint32_t>(index), stateParameter->midiChannel, true, true);
  700. #endif
  701. }
  702. else
  703. carla_stderr("Could not set parameter '%s' value for '%s'",
  704. stateParameter->name, pData->name);
  705. }
  706. // ---------------------------------------------------------------
  707. // Part 4c - clear
  708. for (LinkedList<ParamSymbol*>::Itenerator it = paramSymbols.begin2(); it.valid(); it.next())
  709. {
  710. ParamSymbol* const paramSymbol(it.getValue(nullptr));
  711. delete paramSymbol;
  712. }
  713. paramSymbols.clear();
  714. // ---------------------------------------------------------------
  715. // Part 5 - set custom data
  716. for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
  717. {
  718. const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
  719. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
  720. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
  721. const char* const key(stateCustomData->key);
  722. if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
  723. std::strcmp (key, "load" ) == 0 ||
  724. std::strncmp(key, "patches", 7) == 0 ))
  725. continue;
  726. if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
  727. continue;
  728. setCustomData(stateCustomData->type, key, stateCustomData->value, true);
  729. }
  730. // ---------------------------------------------------------------
  731. // Part 5x - set lv2 state
  732. if (pluginType == PLUGIN_LV2)
  733. {
  734. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  735. {
  736. const CustomData& customData(it.getValue(kCustomDataFallback));
  737. CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
  738. if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
  739. continue;
  740. restoreLV2State(stateSave.temporary);
  741. break;
  742. }
  743. }
  744. // ---------------------------------------------------------------
  745. // Part 6 - set chunk
  746. if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
  747. {
  748. std::vector<uint8_t> chunk(carla_getChunkFromBase64String(stateSave.chunk));
  749. #ifdef CARLA_PROPER_CPP11_SUPPORT
  750. setChunkData(chunk.data(), chunk.size());
  751. #else
  752. setChunkData(&chunk.front(), chunk.size());
  753. #endif
  754. }
  755. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  756. // ---------------------------------------------------------------
  757. // Part 6 - set internal stuff
  758. const uint availOptions(getOptionsAvailable());
  759. for (uint i=0; i<10; ++i) // FIXME - get this value somehow...
  760. {
  761. const uint option(1u << i);
  762. if (availOptions & option)
  763. setOption(option, (stateSave.options & option) != 0, true);
  764. }
  765. setDryWet(stateSave.dryWet, true, true);
  766. setVolume(stateSave.volume, true, true);
  767. setBalanceLeft(stateSave.balanceLeft, true, true);
  768. setBalanceRight(stateSave.balanceRight, true, true);
  769. setPanning(stateSave.panning, true, true);
  770. setCtrlChannel(stateSave.ctrlChannel, true, true);
  771. setActive(stateSave.active, true, true);
  772. if (! pData->engine->isLoadingProject())
  773. pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0, 0.0f, nullptr);
  774. #endif
  775. }
  776. bool CarlaPlugin::saveStateToFile(const char* const filename)
  777. {
  778. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
  779. carla_debug("CarlaPlugin::saveStateToFile(\"%s\")", filename);
  780. MemoryOutputStream out, streamState;
  781. getStateSave().dumpToMemoryStream(streamState);
  782. out << "<?xml version='1.0' encoding='UTF-8'?>\n";
  783. out << "<!DOCTYPE CARLA-PRESET>\n";
  784. out << "<CARLA-PRESET VERSION='2.0'>\n";
  785. out << streamState;
  786. out << "</CARLA-PRESET>\n";
  787. const String jfilename = String(CharPointer_UTF8(filename));
  788. File file(jfilename);
  789. if (file.replaceWithData(out.getData(), out.getDataSize()))
  790. return true;
  791. pData->engine->setLastError("Failed to write file");
  792. return false;
  793. }
  794. bool CarlaPlugin::loadStateFromFile(const char* const filename)
  795. {
  796. // TODO set errors
  797. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
  798. carla_debug("CarlaPlugin::loadStateFromFile(\"%s\")", filename);
  799. const String jfilename = String(CharPointer_UTF8(filename));
  800. File file(jfilename);
  801. CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(), false);
  802. XmlDocument xml(file);
  803. CarlaScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
  804. CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
  805. CARLA_SAFE_ASSERT_RETURN(xmlElement->getTagName().equalsIgnoreCase("carla-preset"), false);
  806. // completely load file
  807. xmlElement = xml.getDocumentElement(false);
  808. CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
  809. if (pData->stateSave.fillFromXmlElement(xmlElement))
  810. {
  811. loadStateSave(pData->stateSave);
  812. return true;
  813. }
  814. return false;
  815. }
  816. bool CarlaPlugin::exportAsLV2(const char* const lv2path)
  817. {
  818. CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
  819. carla_debug("CarlaPlugin::exportAsLV2(\"%s\")", lv2path);
  820. CarlaString bundlepath(lv2path);
  821. if (! bundlepath.endsWith(".lv2"))
  822. bundlepath += ".lv2";
  823. const File bundlefolder(bundlepath.buffer());
  824. if (bundlefolder.existsAsFile())
  825. {
  826. pData->engine->setLastError("Requested filename already exists as file, use a folder instead");
  827. return false;
  828. }
  829. if (! bundlefolder.exists())
  830. {
  831. const Result res(bundlefolder.createDirectory());
  832. if (res.failed())
  833. {
  834. pData->engine->setLastError(res.getErrorMessage().toRawUTF8());
  835. return false;
  836. }
  837. }
  838. CarlaString symbol(pData->name);
  839. symbol.toBasic();
  840. {
  841. const CarlaString pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");
  842. if (! saveStateToFile(pluginFilename))
  843. return false;
  844. }
  845. {
  846. MemoryOutputStream manifestStream;
  847. manifestStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
  848. manifestStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  849. manifestStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
  850. manifestStream << "\n";
  851. manifestStream << "<" << symbol.buffer() << ".ttl>\n";
  852. manifestStream << " a lv2:Plugin ;\n";
  853. manifestStream << " lv2:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
  854. manifestStream << " rdfs:seeAlso <" << symbol.buffer() << ".ttl> .\n";
  855. manifestStream << "\n";
  856. manifestStream << "<ext-ui>\n";
  857. manifestStream << " a <http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget> ;\n";
  858. manifestStream << " ui:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
  859. manifestStream << " lv2:extensionData <http://lv2plug.in/ns/extensions/ui#idleInterface> ,\n";
  860. manifestStream << " <http://lv2plug.in/ns/extensions/ui#showInterface> ;\n";
  861. manifestStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .\n";
  862. manifestStream << "\n";
  863. const CarlaString manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
  864. const File manifestFile(manifestFilename.buffer());
  865. if (! manifestFile.replaceWithData(manifestStream.getData(), manifestStream.getDataSize()))
  866. {
  867. pData->engine->setLastError("Failed to write manifest.ttl file");
  868. return false;
  869. }
  870. }
  871. {
  872. MemoryOutputStream mainStream;
  873. mainStream << "@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n";
  874. mainStream << "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
  875. mainStream << "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
  876. mainStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
  877. mainStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  878. mainStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
  879. mainStream << "\n";
  880. mainStream << "<>\n";
  881. mainStream << " a lv2:Plugin ;\n";
  882. mainStream << "\n";
  883. mainStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,\n";
  884. mainStream << " <http://lv2plug.in/ns/ext/options#options> ,\n";
  885. mainStream << " <http://lv2plug.in/ns/ext/urid#map> ;\n";
  886. mainStream << "\n";
  887. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  888. {
  889. mainStream << " ui:ui <ext-ui> ;\n";
  890. mainStream << "\n";
  891. }
  892. const uint32_t midiIns = getMidiInCount();
  893. const uint32_t midiOuts = getMidiOutCount();
  894. int portIndex = 0;
  895. if (midiIns > 0)
  896. {
  897. mainStream << " lv2:port [\n";
  898. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  899. mainStream << " lv2:index 0 ;\n";
  900. mainStream << " lv2:symbol \"clv2_events_in\" ;\n";
  901. mainStream << " lv2:name \"Events Input\" ;\n";
  902. mainStream << " atom:bufferType atom:Sequence ;\n";
  903. mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,\n";
  904. mainStream << " <http://lv2plug.in/ns/ext/time#Position> ;\n";
  905. mainStream << " ] ;\n";
  906. ++portIndex;
  907. for (uint32_t i=1; i<midiIns; ++i)
  908. {
  909. const String portIndexNum(portIndex++);
  910. const String portIndexLabel(portIndex);
  911. mainStream << " lv2:port [\n";
  912. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  913. mainStream << " lv2:index " << portIndexNum << " ;\n";
  914. mainStream << " lv2:symbol \"clv2_midi_in_" << portIndexLabel << "\" ;\n";
  915. mainStream << " lv2:name \"MIDI Input " << portIndexLabel << "\" ;\n";
  916. mainStream << " ] ;\n";
  917. }
  918. }
  919. else
  920. {
  921. mainStream << " lv2:port [\n";
  922. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  923. mainStream << " lv2:index 0 ;\n";
  924. mainStream << " lv2:symbol \"clv2_time_info\" ;\n";
  925. mainStream << " lv2:name \"Time Info\" ;\n";
  926. mainStream << " atom:bufferType atom:Sequence ;\n";
  927. mainStream << " atom:supports <http://lv2plug.in/ns/ext/time#Position> ;\n";
  928. mainStream << " ] ;\n";
  929. ++portIndex;
  930. }
  931. for (uint32_t i=0; i<midiOuts; ++i)
  932. {
  933. const String portIndexNum(portIndex++);
  934. const String portIndexLabel(portIndex);
  935. mainStream << " lv2:port [\n";
  936. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  937. mainStream << " lv2:index " << portIndexNum << " ;\n";
  938. mainStream << " lv2:symbol \"clv2_midi_out_" << portIndexLabel << "\" ;\n";
  939. mainStream << " lv2:name \"MIDI Output " << portIndexLabel << "\" ;\n";
  940. mainStream << " atom:bufferType atom:Sequence ;\n";
  941. mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
  942. mainStream << " ] ;\n";
  943. }
  944. mainStream << " lv2:port [\n";
  945. mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
  946. mainStream << " lv2:index " << String(portIndex++) << " ;\n";
  947. mainStream << " lv2:name \"freewheel\" ;\n";
  948. mainStream << " lv2:symbol \"clv2_freewheel\" ;\n";
  949. mainStream << " lv2:default 0 ;\n";
  950. mainStream << " lv2:minimum 0 ;\n";
  951. mainStream << " lv2:maximum 1 ;\n";
  952. mainStream << " lv2:designation lv2:freeWheeling ;\n";
  953. mainStream << " lv2:portProperty lv2:toggled , lv2:integer ;\n";
  954. mainStream << " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#notOnGUI> ;\n";
  955. mainStream << " ] ;\n";
  956. for (uint32_t i=0; i<pData->audioIn.count; ++i)
  957. {
  958. const String portIndexNum(portIndex++);
  959. const String portIndexLabel(i+1);
  960. mainStream << " lv2:port [\n";
  961. mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
  962. mainStream << " lv2:index " << portIndexNum << " ;\n";
  963. mainStream << " lv2:symbol \"clv2_audio_in_" << portIndexLabel << "\" ;\n";
  964. mainStream << " lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
  965. mainStream << " ] ;\n";
  966. }
  967. for (uint32_t i=0; i<pData->audioOut.count; ++i)
  968. {
  969. const String portIndexNum(portIndex++);
  970. const String portIndexLabel(i+1);
  971. mainStream << " lv2:port [\n";
  972. mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
  973. mainStream << " lv2:index " << portIndexNum << " ;\n";
  974. mainStream << " lv2:symbol \"clv2_audio_out_" << portIndexLabel << "\" ;\n";
  975. mainStream << " lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
  976. mainStream << " ] ;\n";
  977. }
  978. CarlaStringList uniqueSymbolNames;
  979. char strBufName[STR_MAX+1];
  980. char strBufSymbol[STR_MAX+1];
  981. carla_zeroChars(strBufName, STR_MAX+1);
  982. carla_zeroChars(strBufSymbol, STR_MAX+1);
  983. for (uint32_t i=0; i<pData->param.count; ++i)
  984. {
  985. const ParameterData& paramData(pData->param.data[i]);
  986. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  987. const String portIndexNum(portIndex++);
  988. mainStream << " lv2:port [\n";
  989. if (paramData.type == PARAMETER_INPUT)
  990. mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
  991. else
  992. mainStream << " a lv2:OutputPort, lv2:ControlPort ;\n";
  993. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  994. mainStream << " lv2:portProperty lv2:toggled ;\n";
  995. if (paramData.hints & PARAMETER_IS_INTEGER)
  996. mainStream << " lv2:portProperty lv2:integer ;\n";
  997. // TODO logarithmic, enabled (not on gui), automable, samplerate, scalepoints
  998. if (! getParameterName(i, strBufName))
  999. strBufName[0] = '\0';
  1000. if (! getParameterSymbol(i, strBufSymbol))
  1001. strBufSymbol[0] = '\0';
  1002. if (strBufSymbol[0] == '\0')
  1003. {
  1004. CarlaString s(strBufName);
  1005. s.toBasic();
  1006. std::memcpy(strBufSymbol, s.buffer(), s.length()+1);
  1007. if (strBufSymbol[0] >= '0' && strBufSymbol[0] <= '9')
  1008. {
  1009. const size_t len(std::strlen(strBufSymbol));
  1010. std::memmove(strBufSymbol+1, strBufSymbol, len);
  1011. strBufSymbol[0] = '_';
  1012. strBufSymbol[len+1] = '\0';
  1013. }
  1014. }
  1015. if (uniqueSymbolNames.contains(strBufSymbol))
  1016. std::snprintf(strBufSymbol, STR_MAX, "clv2_param_%d", i+1);
  1017. mainStream << " lv2:index " << portIndexNum << " ;\n";
  1018. mainStream << " lv2:symbol \"" << strBufSymbol << "\" ;\n";
  1019. mainStream << " lv2:name \"\"\"" << strBufName << "\"\"\" ;\n";
  1020. mainStream << " lv2:default " << String(paramRanges.def) << " ;\n";
  1021. mainStream << " lv2:minimum " << String(paramRanges.min) << " ;\n";
  1022. mainStream << " lv2:maximum " << String(paramRanges.max) << " ;\n";
  1023. // TODO midiCC, midiChannel
  1024. mainStream << " ] ;\n";
  1025. }
  1026. char strBuf[STR_MAX+1];
  1027. carla_zeroChars(strBuf, STR_MAX+1);
  1028. if (! getMaker(strBuf))
  1029. strBuf[0] = '\0';
  1030. mainStream << " rdfs:comment \"Plugin generated using Carla LV2 export.\" ;\n";
  1031. mainStream << " doap:name \"\"\"" << getName() << "\"\"\" ;\n";
  1032. mainStream << " doap:maintainer [ foaf:name \"\"\"" << strBuf << "\"\"\" ] .\n";
  1033. mainStream << "\n";
  1034. const CarlaString mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
  1035. const File mainFile(mainFilename.buffer());
  1036. if (! mainFile.replaceWithData(mainStream.getData(), mainStream.getDataSize()))
  1037. {
  1038. pData->engine->setLastError("Failed to write main plugin ttl file");
  1039. return false;
  1040. }
  1041. }
  1042. const CarlaString binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);
  1043. const File binaryFileSource(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("carla-bridge-lv2" CARLA_LIB_EXT));
  1044. const File binaryFileTarget(binaryFilename.buffer());
  1045. const EngineOptions& opts(pData->engine->getOptions());
  1046. const CarlaString binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
  1047. const CarlaString resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");
  1048. if (! binaryFileSource.copyFileTo(binaryFileTarget))
  1049. {
  1050. pData->engine->setLastError("Failed to copy plugin binary");
  1051. return false;
  1052. }
  1053. #ifdef CARLA_OS_WIN
  1054. File(opts.resourceDir).copyDirectoryTo(File(resFolderTarget.buffer()));
  1055. // Copying all the binaries is pointless, just go through the expected needed bits
  1056. const File binFolder1(opts.binaryDir);
  1057. const File binFolder2(binFolderTarget.buffer());
  1058. binFolder2.createDirectory();
  1059. static const char* files[] = {
  1060. "carla-bridge-native.exe",
  1061. "carla-bridge-win32.exe",
  1062. "carla-discovery-win32.exe",
  1063. "carla-discovery-win64.exe",
  1064. "libcarla_utils.dll"
  1065. };
  1066. for (int i=0; i<5; ++i)
  1067. binFolder1.getChildFile(files[i]).copyFileTo(binFolder2.getChildFile(files[i]));;
  1068. #else
  1069. File(opts.binaryDir).createSymbolicLink(File(binFolderTarget.buffer()), true);
  1070. File(opts.resourceDir).createSymbolicLink(File(resFolderTarget.buffer()), true);
  1071. #endif
  1072. return true;
  1073. }
  1074. // -------------------------------------------------------------------
  1075. // Set data (internal stuff)
  1076. void CarlaPlugin::setId(const uint newId) noexcept
  1077. {
  1078. pData->id = newId;
  1079. }
  1080. void CarlaPlugin::setName(const char* const newName)
  1081. {
  1082. CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
  1083. if (pData->name != nullptr)
  1084. delete[] pData->name;
  1085. pData->name = carla_strdup(newName);
  1086. }
  1087. void CarlaPlugin::setOption(const uint option, const bool yesNo, const bool sendCallback)
  1088. {
  1089. CARLA_SAFE_ASSERT_UINT2_RETURN(getOptionsAvailable() & option, getOptionsAvailable(), option,);
  1090. if (yesNo)
  1091. pData->options |= option;
  1092. else
  1093. pData->options &= ~option;
  1094. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1095. if (sendCallback)
  1096. pData->engine->callback(true, true,
  1097. ENGINE_CALLBACK_OPTION_CHANGED,
  1098. pData->id,
  1099. static_cast<int>(option),
  1100. yesNo ? 1 : 0,
  1101. 0, 0.0f, nullptr);
  1102. #else
  1103. // unused
  1104. return; (void)sendCallback;
  1105. #endif
  1106. }
  1107. void CarlaPlugin::setEnabled(const bool yesNo) noexcept
  1108. {
  1109. if (pData->enabled == yesNo)
  1110. return;
  1111. pData->masterMutex.lock();
  1112. pData->enabled = yesNo;
  1113. if (yesNo && ! pData->client->isActive())
  1114. pData->client->activate();
  1115. pData->masterMutex.unlock();
  1116. }
  1117. void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept
  1118. {
  1119. if (pData->engineBridged) {
  1120. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1121. } else if (pData->enginePlugin) {
  1122. // nothing here
  1123. } else {
  1124. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1125. }
  1126. if (pData->active == active)
  1127. return;
  1128. {
  1129. const ScopedSingleProcessLocker spl(this, true);
  1130. if (active)
  1131. activate();
  1132. else
  1133. deactivate();
  1134. }
  1135. pData->active = active;
  1136. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1137. const float value = active ? 1.0f : 0.0f;
  1138. pData->engine->callback(sendCallback, sendOsc,
  1139. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1140. pData->id,
  1141. PARAMETER_ACTIVE,
  1142. 0, 0,
  1143. value,
  1144. nullptr);
  1145. #endif
  1146. }
  1147. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1148. void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1149. {
  1150. if (pData->engineBridged) {
  1151. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1152. } else {
  1153. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1154. }
  1155. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
  1156. const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
  1157. if (carla_isEqual(pData->postProc.dryWet, fixedValue))
  1158. return;
  1159. pData->postProc.dryWet = fixedValue;
  1160. pData->engine->callback(sendCallback, sendOsc,
  1161. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1162. pData->id,
  1163. PARAMETER_DRYWET,
  1164. 0, 0,
  1165. fixedValue,
  1166. nullptr);
  1167. }
  1168. void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1169. {
  1170. if (pData->engineBridged) {
  1171. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1172. } else {
  1173. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1174. }
  1175. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
  1176. const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
  1177. if (carla_isEqual(pData->postProc.volume, fixedValue))
  1178. return;
  1179. pData->postProc.volume = fixedValue;
  1180. pData->engine->callback(sendCallback, sendOsc,
  1181. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1182. pData->id,
  1183. PARAMETER_VOLUME,
  1184. 0, 0,
  1185. fixedValue,
  1186. nullptr);
  1187. }
  1188. void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1189. {
  1190. if (pData->engineBridged) {
  1191. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1192. } else {
  1193. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1194. }
  1195. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1196. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1197. if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
  1198. return;
  1199. pData->postProc.balanceLeft = fixedValue;
  1200. pData->engine->callback(sendCallback, sendOsc,
  1201. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1202. pData->id,
  1203. PARAMETER_BALANCE_LEFT,
  1204. 0, 0,
  1205. fixedValue,
  1206. nullptr);
  1207. }
  1208. void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1209. {
  1210. if (pData->engineBridged) {
  1211. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1212. } else {
  1213. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1214. }
  1215. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1216. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1217. if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
  1218. return;
  1219. pData->postProc.balanceRight = fixedValue;
  1220. pData->engine->callback(sendCallback, sendOsc,
  1221. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1222. pData->id,
  1223. PARAMETER_BALANCE_RIGHT,
  1224. 0, 0,
  1225. fixedValue,
  1226. nullptr);
  1227. }
  1228. void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1229. {
  1230. if (pData->engineBridged) {
  1231. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1232. } else {
  1233. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1234. }
  1235. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1236. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1237. if (carla_isEqual(pData->postProc.panning, fixedValue))
  1238. return;
  1239. pData->postProc.panning = fixedValue;
  1240. pData->engine->callback(sendCallback, sendOsc,
  1241. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1242. pData->id,
  1243. PARAMETER_PANNING,
  1244. 0, 0,
  1245. fixedValue,
  1246. nullptr);
  1247. }
  1248. void CarlaPlugin::setDryWetRT(const float value, const bool sendCallbackLater) noexcept
  1249. {
  1250. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
  1251. const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
  1252. if (carla_isEqual(pData->postProc.dryWet, fixedValue))
  1253. return;
  1254. pData->postProc.dryWet = fixedValue;
  1255. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_DRYWET, 0, 0, fixedValue);
  1256. }
  1257. void CarlaPlugin::setVolumeRT(const float value, const bool sendCallbackLater) noexcept
  1258. {
  1259. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
  1260. const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
  1261. if (carla_isEqual(pData->postProc.volume, fixedValue))
  1262. return;
  1263. pData->postProc.volume = fixedValue;
  1264. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_VOLUME, 0, 0, fixedValue);
  1265. }
  1266. void CarlaPlugin::setBalanceLeftRT(const float value, const bool sendCallbackLater) noexcept
  1267. {
  1268. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1269. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1270. if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
  1271. return;
  1272. pData->postProc.balanceLeft = fixedValue;
  1273. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_BALANCE_LEFT, 0, 0, fixedValue);
  1274. }
  1275. void CarlaPlugin::setBalanceRightRT(const float value, const bool sendCallbackLater) noexcept
  1276. {
  1277. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1278. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1279. if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
  1280. return;
  1281. pData->postProc.balanceRight = fixedValue;
  1282. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_BALANCE_RIGHT, 0, 0, fixedValue);
  1283. }
  1284. void CarlaPlugin::setPanningRT(const float value, const bool sendCallbackLater) noexcept
  1285. {
  1286. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1287. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1288. if (carla_isEqual(pData->postProc.panning, fixedValue))
  1289. return;
  1290. pData->postProc.panning = fixedValue;
  1291. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_PANNING, 0, 0, fixedValue);
  1292. }
  1293. #endif // ! BUILD_BRIDGE_ALTERNATIVE_ARCH
  1294. void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept
  1295. {
  1296. if (pData->engineBridged) {
  1297. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1298. } else {
  1299. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1300. }
  1301. CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,);
  1302. if (pData->ctrlChannel == channel)
  1303. return;
  1304. pData->ctrlChannel = channel;
  1305. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1306. const float channelf = static_cast<float>(channel);
  1307. pData->engine->callback(sendCallback, sendOsc,
  1308. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1309. pData->id,
  1310. PARAMETER_CTRL_CHANNEL,
  1311. 0, 0,
  1312. channelf, nullptr);
  1313. #endif
  1314. }
  1315. // -------------------------------------------------------------------
  1316. // Set data (plugin-specific stuff)
  1317. void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1318. {
  1319. if (pData->engineBridged) {
  1320. // NOTE: some LV2 plugins feedback messages to UI on purpose
  1321. CARLA_SAFE_ASSERT_RETURN(getType() == PLUGIN_LV2 || !sendGui,);
  1322. } else if (pData->enginePlugin) {
  1323. // nothing here
  1324. } else {
  1325. CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback,); // never call this from RT
  1326. }
  1327. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1328. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1329. uiParameterChange(parameterId, value);
  1330. pData->engine->callback(sendCallback, sendOsc,
  1331. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1332. pData->id,
  1333. static_cast<int>(parameterId),
  1334. 0, 0,
  1335. value,
  1336. nullptr);
  1337. }
  1338. void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value, const bool sendCallbackLater) noexcept
  1339. {
  1340. pData->postponeRtEvent(kPluginPostRtEventParameterChange,
  1341. sendCallbackLater, static_cast<int32_t>(parameterId), 0, 0, value);
  1342. }
  1343. void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1344. {
  1345. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1346. CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,);
  1347. switch (rindex)
  1348. {
  1349. case PARAMETER_ACTIVE:
  1350. return setActive((value > 0.0f), sendOsc, sendCallback);
  1351. case PARAMETER_CTRL_CHANNEL:
  1352. return setCtrlChannel(int8_t(value), sendOsc, sendCallback);
  1353. case PARAMETER_DRYWET:
  1354. return setDryWet(value, sendOsc, sendCallback);
  1355. case PARAMETER_VOLUME:
  1356. return setVolume(value, sendOsc, sendCallback);
  1357. case PARAMETER_BALANCE_LEFT:
  1358. return setBalanceLeft(value, sendOsc, sendCallback);
  1359. case PARAMETER_BALANCE_RIGHT:
  1360. return setBalanceRight(value, sendOsc, sendCallback);
  1361. case PARAMETER_PANNING:
  1362. return setPanning(value, sendOsc, sendCallback);
  1363. }
  1364. #endif
  1365. CARLA_SAFE_ASSERT_RETURN(rindex >= 0,);
  1366. for (uint32_t i=0; i < pData->param.count; ++i)
  1367. {
  1368. if (pData->param.data[i].rindex == rindex)
  1369. {
  1370. //if (carla_isNotEqual(getParameterValue(i), value))
  1371. setParameterValue(i, value, sendGui, sendOsc, sendCallback);
  1372. break;
  1373. }
  1374. }
  1375. }
  1376. void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept
  1377. {
  1378. if (pData->engineBridged) {
  1379. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1380. } else {
  1381. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1382. }
  1383. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1384. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1385. if (pData->param.data[parameterId].midiChannel == channel)
  1386. return;
  1387. pData->param.data[parameterId].midiChannel = channel;
  1388. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1389. pData->engine->callback(sendCallback, sendOsc,
  1390. ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
  1391. pData->id,
  1392. static_cast<int>(parameterId),
  1393. channel,
  1394. 0, 0.0f, nullptr);
  1395. #endif
  1396. }
  1397. void CarlaPlugin::setParameterMappedControlIndex(const uint32_t parameterId, const int16_t index,
  1398. const bool sendOsc, const bool sendCallback,
  1399. const bool reconfigureNow) noexcept
  1400. {
  1401. if (pData->engineBridged) {
  1402. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1403. } else {
  1404. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1405. }
  1406. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1407. CARLA_SAFE_ASSERT_RETURN(index >= CONTROL_INDEX_NONE && index <= CONTROL_INDEX_MAX_ALLOWED,);
  1408. ParameterData& paramData(pData->param.data[parameterId]);
  1409. if (paramData.mappedControlIndex == index)
  1410. return;
  1411. const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
  1412. if ((paramData.hints & PARAMETER_MAPPED_RANGES_SET) == 0x0)
  1413. setParameterMappedRange(parameterId, paramRanges.min, paramRanges.max, true, true);
  1414. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1415. char strBuf[STR_MAX+1];
  1416. carla_zeroChars(strBuf, STR_MAX+1);
  1417. if (! getParameterName(parameterId, strBuf))
  1418. std::snprintf(strBuf, STR_MAX, "Param %u", parameterId);
  1419. const uint portNameSize = pData->engine->getMaxPortNameSize();
  1420. if (portNameSize < STR_MAX)
  1421. strBuf[portNameSize] = '\0';
  1422. // was learning something else before, stop that first
  1423. if (pData->midiLearnParameterIndex >= 0 && pData->midiLearnParameterIndex != static_cast<int32_t>(parameterId))
  1424. {
  1425. const int32_t oldParameterId = pData->midiLearnParameterIndex;
  1426. pData->midiLearnParameterIndex = -1;
  1427. CARLA_SAFE_ASSERT_RETURN(oldParameterId < static_cast<int32_t>(pData->param.count),);
  1428. pData->param.data[oldParameterId].mappedControlIndex = CONTROL_INDEX_NONE;
  1429. pData->engine->callback(true, true,
  1430. ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
  1431. pData->id,
  1432. oldParameterId,
  1433. CONTROL_INDEX_NONE,
  1434. 0, 0.0f, nullptr);
  1435. }
  1436. // mapping new parameter to CV
  1437. if (index == CONTROL_INDEX_CV)
  1438. {
  1439. CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,);
  1440. CARLA_SAFE_ASSERT_RETURN(paramData.type == PARAMETER_INPUT,);
  1441. CARLA_SAFE_ASSERT_RETURN(paramData.hints & PARAMETER_CAN_BE_CV_CONTROLLED,);
  1442. CarlaEngineCVPort* const cvPort =
  1443. (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, strBuf, true, parameterId);
  1444. cvPort->setRange(paramData.mappedMinimum, paramData.mappedMaximum);
  1445. pData->event.cvSourcePorts->addCVSource(cvPort, parameterId, reconfigureNow);
  1446. }
  1447. // unmapping from CV
  1448. else if (paramData.mappedControlIndex == CONTROL_INDEX_CV)
  1449. {
  1450. CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,);
  1451. CARLA_SAFE_ASSERT(pData->client->removePort(kEnginePortTypeCV, strBuf, true));
  1452. CARLA_SAFE_ASSERT(pData->event.cvSourcePorts->removeCVSource(parameterId));
  1453. }
  1454. // mapping to something new
  1455. else if (paramData.mappedControlIndex == CONTROL_INDEX_NONE)
  1456. {
  1457. // when doing MIDI CC mapping, ensure ranges are within bounds
  1458. if (paramData.mappedMinimum < paramRanges.min || paramData.mappedMaximum > paramRanges.max)
  1459. setParameterMappedRange(parameterId,
  1460. std::max(paramData.mappedMinimum, paramRanges.min),
  1461. std::min(paramData.mappedMaximum, paramRanges.max),
  1462. true, true);
  1463. }
  1464. #endif
  1465. paramData.mappedControlIndex = index;
  1466. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1467. if (index == CONTROL_INDEX_MIDI_LEARN)
  1468. pData->midiLearnParameterIndex = static_cast<int32_t>(parameterId);
  1469. else
  1470. pData->midiLearnParameterIndex = -1;
  1471. pData->engine->callback(sendCallback, sendOsc,
  1472. ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
  1473. pData->id,
  1474. static_cast<int>(parameterId),
  1475. index,
  1476. 0, 0.0f, nullptr);
  1477. #else
  1478. return;
  1479. // unused
  1480. (void)reconfigureNow;
  1481. #endif
  1482. }
  1483. void CarlaPlugin::setParameterMappedRange(const uint32_t parameterId, const float minimum, const float maximum,
  1484. const bool sendOsc, const bool sendCallback) noexcept
  1485. {
  1486. if (pData->engineBridged) {
  1487. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1488. } else {
  1489. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1490. }
  1491. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1492. ParameterData& paramData(pData->param.data[parameterId]);
  1493. if (carla_isEqual(paramData.mappedMinimum, minimum) &&
  1494. carla_isEqual(paramData.mappedMaximum, maximum) &&
  1495. (paramData.hints & PARAMETER_MAPPED_RANGES_SET) != 0x0)
  1496. return;
  1497. if (paramData.mappedControlIndex != CONTROL_INDEX_NONE && paramData.mappedControlIndex != CONTROL_INDEX_CV)
  1498. {
  1499. const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
  1500. CARLA_SAFE_ASSERT_RETURN(minimum >= paramRanges.min,);
  1501. CARLA_SAFE_ASSERT_RETURN(maximum <= paramRanges.max,);
  1502. }
  1503. paramData.hints |= PARAMETER_MAPPED_RANGES_SET;
  1504. paramData.mappedMinimum = minimum;
  1505. paramData.mappedMaximum = maximum;
  1506. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1507. if (pData->event.cvSourcePorts != nullptr && paramData.mappedControlIndex == CONTROL_INDEX_CV)
  1508. pData->event.cvSourcePorts->setCVSourceRange(parameterId, minimum, maximum);
  1509. char strBuf[STR_MAX+1];
  1510. carla_zeroChars(strBuf, STR_MAX+1);
  1511. std::snprintf(strBuf, STR_MAX, "%.12g:%.12g", static_cast<double>(minimum), static_cast<double>(maximum));
  1512. pData->engine->callback(sendCallback, sendOsc,
  1513. ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED,
  1514. pData->id,
  1515. static_cast<int>(parameterId),
  1516. 0, 0, 0.0f,
  1517. strBuf);
  1518. #endif
  1519. }
  1520. void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool)
  1521. {
  1522. CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
  1523. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  1524. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  1525. // Ignore some keys
  1526. if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0)
  1527. {
  1528. const PluginType ptype = getType();
  1529. if ((ptype == PLUGIN_INTERNAL && std::strncmp(key, "CarlaAlternateFile", 18) == 0) ||
  1530. (ptype == PLUGIN_DSSI && std::strcmp (key, "guiVisible") == 0) ||
  1531. (ptype == PLUGIN_LV2 && std::strncmp(key, "OSC:", 4) == 0))
  1532. return;
  1533. }
  1534. // Check if we already have this key
  1535. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  1536. {
  1537. CustomData& customData(it.getValue(kCustomDataFallbackNC));
  1538. CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
  1539. if (std::strcmp(customData.key, key) == 0)
  1540. {
  1541. if (customData.value != nullptr)
  1542. delete[] customData.value;
  1543. customData.value = carla_strdup(value);
  1544. return;
  1545. }
  1546. }
  1547. // Otherwise store it
  1548. CustomData customData;
  1549. customData.type = carla_strdup(type);
  1550. customData.key = carla_strdup(key);
  1551. customData.value = carla_strdup(value);
  1552. pData->custom.append(customData);
  1553. }
  1554. void CarlaPlugin::setChunkData(const void* const data, const std::size_t dataSize)
  1555. {
  1556. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  1557. CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
  1558. CARLA_SAFE_ASSERT(false); // this should never happen
  1559. }
  1560. void CarlaPlugin::setProgram(const int32_t index,
  1561. const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
  1562. {
  1563. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->prog.count),);
  1564. pData->prog.current = index;
  1565. pData->engine->callback(sendCallback, sendOsc,
  1566. ENGINE_CALLBACK_PROGRAM_CHANGED,
  1567. pData->id,
  1568. index,
  1569. 0, 0, 0.0f, nullptr);
  1570. // Change default parameter values
  1571. if (index >= 0)
  1572. {
  1573. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1574. uiProgramChange(static_cast<uint32_t>(index));
  1575. switch (getType())
  1576. {
  1577. case PLUGIN_SF2:
  1578. case PLUGIN_SFZ:
  1579. break;
  1580. default:
  1581. pData->updateParameterValues(this, sendCallback, sendOsc, true);
  1582. break;
  1583. }
  1584. }
  1585. }
  1586. void CarlaPlugin::setMidiProgram(const int32_t index,
  1587. const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
  1588. {
  1589. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
  1590. pData->midiprog.current = index;
  1591. pData->engine->callback(sendCallback, sendOsc,
  1592. ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
  1593. pData->id,
  1594. index,
  1595. 0, 0, 0.0f, nullptr);
  1596. // Change default parameter values
  1597. if (index >= 0)
  1598. {
  1599. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1600. uiMidiProgramChange(static_cast<uint32_t>(index));
  1601. switch (getType())
  1602. {
  1603. case PLUGIN_SF2:
  1604. case PLUGIN_SFZ:
  1605. break;
  1606. default:
  1607. pData->updateParameterValues(this, sendCallback, sendOsc, true);
  1608. break;
  1609. }
  1610. }
  1611. }
  1612. void CarlaPlugin::setMidiProgramById(const uint32_t bank, const uint32_t program, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1613. {
  1614. for (uint32_t i=0; i < pData->midiprog.count; ++i)
  1615. {
  1616. if (pData->midiprog.data[i].bank == bank && pData->midiprog.data[i].program == program)
  1617. return setMidiProgram(static_cast<int32_t>(i), sendGui, sendOsc, sendCallback);
  1618. }
  1619. }
  1620. void CarlaPlugin::setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
  1621. {
  1622. CARLA_SAFE_ASSERT_RETURN(uindex < pData->prog.count,);
  1623. const int32_t index = static_cast<int32_t>(uindex);
  1624. pData->prog.current = index;
  1625. // Change default parameter values
  1626. switch (getType())
  1627. {
  1628. case PLUGIN_SF2:
  1629. case PLUGIN_SFZ:
  1630. break;
  1631. default:
  1632. pData->updateDefaultParameterValues(this);
  1633. break;
  1634. }
  1635. pData->postponeRtEvent(kPluginPostRtEventProgramChange, sendCallbackLater, index, 0, 0, 0.0f);
  1636. }
  1637. void CarlaPlugin::setMidiProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
  1638. {
  1639. CARLA_SAFE_ASSERT_RETURN(uindex < pData->midiprog.count,);
  1640. const int32_t index = static_cast<int32_t>(uindex);
  1641. pData->midiprog.current = index;
  1642. // Change default parameter values
  1643. switch (getType())
  1644. {
  1645. case PLUGIN_SF2:
  1646. case PLUGIN_SFZ:
  1647. break;
  1648. default:
  1649. pData->updateDefaultParameterValues(this);
  1650. break;
  1651. }
  1652. pData->postponeRtEvent(kPluginPostRtEventMidiProgramChange, sendCallbackLater, index, 0, 0, 0.0f);
  1653. }
  1654. // -------------------------------------------------------------------
  1655. // Plugin state
  1656. void CarlaPlugin::reloadPrograms(const bool)
  1657. {
  1658. }
  1659. // -------------------------------------------------------------------
  1660. // Plugin processing
  1661. void CarlaPlugin::activate() noexcept
  1662. {
  1663. CARLA_SAFE_ASSERT(! pData->active);
  1664. }
  1665. void CarlaPlugin::deactivate() noexcept
  1666. {
  1667. CARLA_SAFE_ASSERT(pData->active);
  1668. }
  1669. void CarlaPlugin::bufferSizeChanged(const uint32_t)
  1670. {
  1671. }
  1672. void CarlaPlugin::sampleRateChanged(const double)
  1673. {
  1674. }
  1675. void CarlaPlugin::offlineModeChanged(const bool)
  1676. {
  1677. }
  1678. // -------------------------------------------------------------------
  1679. // Misc
  1680. void CarlaPlugin::idle()
  1681. {
  1682. if (! pData->enabled)
  1683. return;
  1684. const bool hasUI(pData->hints & PLUGIN_HAS_CUSTOM_UI);
  1685. const bool needsUiMainThread(pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD);
  1686. const uint32_t latency(getLatencyInFrames());
  1687. if (pData->latency.frames != latency)
  1688. {
  1689. carla_stdout("latency changed to %i samples", latency);
  1690. const ScopedSingleProcessLocker sspl(this, true);
  1691. pData->client->setLatency(latency);
  1692. #ifndef BUILD_BRIDGE
  1693. pData->latency.recreateBuffers(pData->latency.channels, latency);
  1694. #else
  1695. pData->latency.frames = latency;
  1696. #endif
  1697. }
  1698. ProtectedData::PostRtEvents::Access rtEvents(pData->postRtEvents);
  1699. if (rtEvents.isEmpty())
  1700. return;
  1701. for (RtLinkedList<PluginPostRtEvent>::Itenerator it = rtEvents.getDataIterator(); it.valid(); it.next())
  1702. {
  1703. const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
  1704. CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
  1705. switch (event.type)
  1706. {
  1707. case kPluginPostRtEventNull: {
  1708. } break;
  1709. case kPluginPostRtEventDebug: {
  1710. pData->engine->callback(true, true,
  1711. ENGINE_CALLBACK_DEBUG, pData->id,
  1712. event.value1, event.value2, event.value3, event.valuef, nullptr);
  1713. } break;
  1714. case kPluginPostRtEventParameterChange: {
  1715. // Update UI
  1716. if (event.value1 >= 0 && hasUI)
  1717. {
  1718. if (needsUiMainThread)
  1719. pData->postUiEvents.append(event);
  1720. else
  1721. uiParameterChange(static_cast<uint32_t>(event.value1), event.valuef);
  1722. }
  1723. if (event.sendCallback)
  1724. {
  1725. // Update Host
  1726. pData->engine->callback(true, true,
  1727. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1728. pData->id,
  1729. event.value1,
  1730. 0, 0,
  1731. event.valuef,
  1732. nullptr);
  1733. }
  1734. } break;
  1735. case kPluginPostRtEventProgramChange: {
  1736. // Update UI
  1737. if (event.value1 >= 0 && hasUI)
  1738. {
  1739. if (needsUiMainThread)
  1740. pData->postUiEvents.append(event);
  1741. else
  1742. uiProgramChange(static_cast<uint32_t>(event.value1));
  1743. }
  1744. // Update param values
  1745. for (uint32_t j=0; j < pData->param.count; ++j)
  1746. {
  1747. const float paramDefault(pData->param.ranges[j].def);
  1748. const float paramValue(getParameterValue(j));
  1749. pData->engine->callback(true, true,
  1750. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1751. pData->id,
  1752. static_cast<int>(j),
  1753. 0, 0,
  1754. paramValue,
  1755. nullptr);
  1756. pData->engine->callback(true, true,
  1757. ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
  1758. pData->id,
  1759. static_cast<int>(j),
  1760. 0, 0,
  1761. paramDefault,
  1762. nullptr);
  1763. }
  1764. if (event.sendCallback)
  1765. {
  1766. // Update Host
  1767. pData->engine->callback(true, true,
  1768. ENGINE_CALLBACK_PROGRAM_CHANGED,
  1769. pData->id,
  1770. event.value1,
  1771. 0, 0, 0.0f, nullptr);
  1772. }
  1773. } break;
  1774. case kPluginPostRtEventMidiProgramChange: {
  1775. // Update UI
  1776. if (event.value1 >= 0 && hasUI)
  1777. {
  1778. if (needsUiMainThread)
  1779. pData->postUiEvents.append(event);
  1780. else
  1781. uiMidiProgramChange(static_cast<uint32_t>(event.value1));
  1782. }
  1783. // Update param values
  1784. for (uint32_t j=0; j < pData->param.count; ++j)
  1785. {
  1786. const float paramDefault(pData->param.ranges[j].def);
  1787. const float paramValue(getParameterValue(j));
  1788. pData->engine->callback(true, true,
  1789. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1790. pData->id,
  1791. static_cast<int>(j),
  1792. 0, 0,
  1793. paramValue,
  1794. nullptr);
  1795. pData->engine->callback(true, true,
  1796. ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
  1797. pData->id,
  1798. static_cast<int>(j),
  1799. 0, 0,
  1800. paramDefault,
  1801. nullptr);
  1802. }
  1803. if (event.sendCallback)
  1804. {
  1805. // Update Host
  1806. pData->engine->callback(true, true,
  1807. ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
  1808. pData->id,
  1809. event.value1,
  1810. 0, 0, 0.0f, nullptr);
  1811. }
  1812. } break;
  1813. case kPluginPostRtEventNoteOn: {
  1814. CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
  1815. CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
  1816. CARLA_SAFE_ASSERT_BREAK(event.value3 >= 0 && event.value3 < MAX_MIDI_VALUE);
  1817. const uint8_t channel = static_cast<uint8_t>(event.value1);
  1818. const uint8_t note = static_cast<uint8_t>(event.value2);
  1819. const uint8_t velocity = static_cast<uint8_t>(event.value3);
  1820. // Update UI
  1821. if (hasUI)
  1822. {
  1823. if (needsUiMainThread)
  1824. pData->postUiEvents.append(event);
  1825. else
  1826. uiNoteOn(channel, note, velocity);
  1827. }
  1828. if (event.sendCallback)
  1829. {
  1830. // Update Host
  1831. pData->engine->callback(true, true,
  1832. ENGINE_CALLBACK_NOTE_ON,
  1833. pData->id,
  1834. event.value1,
  1835. event.value2,
  1836. event.value3,
  1837. 0.0f, nullptr);
  1838. }
  1839. } break;
  1840. case kPluginPostRtEventNoteOff: {
  1841. CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
  1842. CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
  1843. const uint8_t channel = static_cast<uint8_t>(event.value1);
  1844. const uint8_t note = static_cast<uint8_t>(event.value2);
  1845. // Update UI
  1846. if (hasUI)
  1847. {
  1848. if (needsUiMainThread)
  1849. pData->postUiEvents.append(event);
  1850. else
  1851. uiNoteOff(channel, note);
  1852. }
  1853. if (event.sendCallback)
  1854. {
  1855. // Update Host
  1856. pData->engine->callback(true, true,
  1857. ENGINE_CALLBACK_NOTE_OFF,
  1858. pData->id,
  1859. event.value1,
  1860. event.value2,
  1861. 0, 0.0f, nullptr);
  1862. }
  1863. } break;
  1864. case kPluginPostRtEventMidiLearn: {
  1865. CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
  1866. CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
  1867. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1868. if (event.sendCallback)
  1869. {
  1870. const int32_t parameterId = event.value1;
  1871. const int32_t midiCC = event.value2;
  1872. const int32_t midiChannel = event.value3;
  1873. pData->engine->callback(true, true,
  1874. ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
  1875. pData->id,
  1876. parameterId,
  1877. midiCC,
  1878. 0, 0.0f, nullptr);
  1879. pData->engine->callback(true, true,
  1880. ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
  1881. pData->id,
  1882. parameterId,
  1883. midiChannel,
  1884. 0, 0.0f, nullptr);
  1885. }
  1886. #endif
  1887. } break;
  1888. }
  1889. }
  1890. }
  1891. bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept
  1892. {
  1893. if (forcedOffline)
  1894. {
  1895. #ifndef STOAT_TEST_BUILD
  1896. pData->masterMutex.lock();
  1897. return true;
  1898. #endif
  1899. }
  1900. return pData->masterMutex.tryLock();
  1901. }
  1902. void CarlaPlugin::unlock() noexcept
  1903. {
  1904. pData->masterMutex.unlock();
  1905. }
  1906. // -------------------------------------------------------------------
  1907. // Plugin buffers
  1908. void CarlaPlugin::initBuffers() const noexcept
  1909. {
  1910. pData->audioIn.initBuffers();
  1911. pData->audioOut.initBuffers();
  1912. pData->cvIn.initBuffers();
  1913. pData->cvOut.initBuffers();
  1914. pData->event.initBuffers();
  1915. }
  1916. void CarlaPlugin::clearBuffers() noexcept
  1917. {
  1918. pData->clearBuffers();
  1919. }
  1920. // -------------------------------------------------------------------
  1921. // OSC stuff
  1922. // FIXME
  1923. void CarlaPlugin::handleOscMessage(const char* const, const int, const void* const, const char* const, const lo_message)
  1924. {
  1925. // do nothing
  1926. }
  1927. // -------------------------------------------------------------------
  1928. // MIDI events
  1929. void CarlaPlugin::sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback)
  1930. {
  1931. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1932. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1933. CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
  1934. if (! pData->active)
  1935. return;
  1936. ExternalMidiNote extNote;
  1937. extNote.channel = static_cast<int8_t>(channel);
  1938. extNote.note = note;
  1939. extNote.velo = velo;
  1940. pData->extNotes.appendNonRT(extNote);
  1941. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1942. {
  1943. if (velo > 0)
  1944. uiNoteOn(channel, note, velo);
  1945. else
  1946. uiNoteOff(channel, note);
  1947. }
  1948. pData->engine->callback(sendCallback, sendOsc,
  1949. (velo > 0) ? ENGINE_CALLBACK_NOTE_ON : ENGINE_CALLBACK_NOTE_OFF,
  1950. pData->id,
  1951. channel,
  1952. note,
  1953. velo,
  1954. 0.0f, nullptr);
  1955. }
  1956. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1957. void CarlaPlugin::postponeRtAllNotesOff()
  1958. {
  1959. if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS)
  1960. return;
  1961. PluginPostRtEvent postEvent = {
  1962. kPluginPostRtEventNoteOff,
  1963. true,
  1964. pData->ctrlChannel,
  1965. 0, 0, 0.0f
  1966. };
  1967. for (int32_t i=0; i < MAX_MIDI_NOTE; ++i)
  1968. {
  1969. postEvent.value2 = i;
  1970. pData->postRtEvents.appendRT(postEvent);
  1971. }
  1972. }
  1973. #endif
  1974. // -------------------------------------------------------------------
  1975. // UI Stuff
  1976. void CarlaPlugin::setCustomUITitle(const char* const title) noexcept
  1977. {
  1978. pData->uiTitle = title;
  1979. }
  1980. void CarlaPlugin::showCustomUI(const bool yesNo)
  1981. {
  1982. if (yesNo) {
  1983. CARLA_SAFE_ASSERT(false);
  1984. }
  1985. }
  1986. void* CarlaPlugin::embedCustomUI(void*)
  1987. {
  1988. return nullptr;
  1989. }
  1990. void CarlaPlugin::uiIdle()
  1991. {
  1992. if (pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD)
  1993. {
  1994. // Update parameter outputs
  1995. for (uint32_t i=0; i < pData->param.count; ++i)
  1996. {
  1997. if (pData->param.data[i].type == PARAMETER_OUTPUT)
  1998. uiParameterChange(i, getParameterValue(i));
  1999. }
  2000. const CarlaMutexLocker sl(pData->postUiEvents.mutex);
  2001. for (LinkedList<PluginPostRtEvent>::Itenerator it = pData->postUiEvents.data.begin2(); it.valid(); it.next())
  2002. {
  2003. const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
  2004. CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
  2005. switch (event.type)
  2006. {
  2007. case kPluginPostRtEventNull:
  2008. case kPluginPostRtEventDebug:
  2009. case kPluginPostRtEventMidiLearn:
  2010. break;
  2011. case kPluginPostRtEventParameterChange:
  2012. uiParameterChange(static_cast<uint32_t>(event.value1), event.valuef);
  2013. break;
  2014. case kPluginPostRtEventProgramChange:
  2015. uiProgramChange(static_cast<uint32_t>(event.value1));
  2016. break;
  2017. case kPluginPostRtEventMidiProgramChange:
  2018. uiMidiProgramChange(static_cast<uint32_t>(event.value1));
  2019. break;
  2020. case kPluginPostRtEventNoteOn:
  2021. uiNoteOn(static_cast<uint8_t>(event.value1),
  2022. static_cast<uint8_t>(event.value2),
  2023. static_cast<uint8_t>(event.value3));
  2024. break;
  2025. case kPluginPostRtEventNoteOff:
  2026. uiNoteOff(static_cast<uint8_t>(event.value1),
  2027. static_cast<uint8_t>(event.value2));
  2028. break;
  2029. }
  2030. }
  2031. pData->postUiEvents.data.clear();
  2032. }
  2033. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  2034. if (pData->transientTryCounter == 0)
  2035. return;
  2036. if (++pData->transientTryCounter % 10 != 0)
  2037. return;
  2038. if (pData->transientTryCounter >= 200)
  2039. return;
  2040. carla_stdout("Trying to get window...");
  2041. CarlaString uiTitle;
  2042. if (pData->uiTitle.isNotEmpty())
  2043. {
  2044. uiTitle = pData->uiTitle;
  2045. }
  2046. else
  2047. {
  2048. uiTitle = pData->name;
  2049. uiTitle += " (GUI)";
  2050. }
  2051. if (CarlaPluginUI::tryTransientWinIdMatch(getUiBridgeProcessId(), uiTitle,
  2052. pData->engine->getOptions().frontendWinId, pData->transientFirstTry))
  2053. {
  2054. pData->transientTryCounter = 0;
  2055. pData->transientFirstTry = false;
  2056. }
  2057. #endif
  2058. }
  2059. void CarlaPlugin::uiParameterChange(const uint32_t index, const float value) noexcept
  2060. {
  2061. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  2062. return;
  2063. // unused
  2064. (void)value;
  2065. }
  2066. void CarlaPlugin::uiProgramChange(const uint32_t index) noexcept
  2067. {
  2068. CARLA_SAFE_ASSERT_RETURN(index < getProgramCount(),);
  2069. }
  2070. void CarlaPlugin::uiMidiProgramChange(const uint32_t index) noexcept
  2071. {
  2072. CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(),);
  2073. }
  2074. void CarlaPlugin::uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept
  2075. {
  2076. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  2077. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  2078. CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
  2079. }
  2080. void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note) noexcept
  2081. {
  2082. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  2083. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  2084. }
  2085. CarlaEngine* CarlaPlugin::getEngine() const noexcept
  2086. {
  2087. return pData->engine;
  2088. }
  2089. CarlaEngineClient* CarlaPlugin::getEngineClient() const noexcept
  2090. {
  2091. return pData->client;
  2092. }
  2093. CarlaEngineAudioPort* CarlaPlugin::getAudioInPort(const uint32_t index) const noexcept
  2094. {
  2095. return pData->audioIn.ports[index].port;
  2096. }
  2097. CarlaEngineAudioPort* CarlaPlugin::getAudioOutPort(const uint32_t index) const noexcept
  2098. {
  2099. return pData->audioOut.ports[index].port;
  2100. }
  2101. CarlaEngineCVPort* CarlaPlugin::getCVInPort(const uint32_t index) const noexcept
  2102. {
  2103. return pData->cvIn.ports[index].port;
  2104. }
  2105. CarlaEngineCVPort* CarlaPlugin::getCVOutPort(const uint32_t index) const noexcept
  2106. {
  2107. return pData->cvOut.ports[index].port;
  2108. }
  2109. CarlaEngineEventPort* CarlaPlugin::getDefaultEventInPort() const noexcept
  2110. {
  2111. return pData->event.portIn;
  2112. }
  2113. CarlaEngineEventPort* CarlaPlugin::getDefaultEventOutPort() const noexcept
  2114. {
  2115. return pData->event.portOut;
  2116. }
  2117. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  2118. void CarlaPlugin::checkForMidiLearn(EngineEvent& event) noexcept
  2119. {
  2120. if (pData->midiLearnParameterIndex < 0)
  2121. return;
  2122. if (event.ctrl.param == MIDI_CONTROL_BANK_SELECT || event.ctrl.param == MIDI_CONTROL_BANK_SELECT__LSB)
  2123. return;
  2124. if (event.ctrl.param >= MAX_MIDI_CONTROL)
  2125. return;
  2126. const uint32_t parameterId = static_cast<uint32_t>(pData->midiLearnParameterIndex);
  2127. CARLA_SAFE_ASSERT_UINT2_RETURN(parameterId < pData->param.count, parameterId, pData->param.count,);
  2128. ParameterData& paramData(pData->param.data[parameterId]);
  2129. CARLA_SAFE_ASSERT_INT_RETURN(paramData.mappedControlIndex == CONTROL_INDEX_MIDI_LEARN,
  2130. paramData.mappedControlIndex,);
  2131. event.ctrl.handled = true;
  2132. paramData.mappedControlIndex = static_cast<int16_t>(event.ctrl.param);
  2133. paramData.midiChannel = event.channel;
  2134. pData->postponeRtEvent(kPluginPostRtEventMidiLearn, true,
  2135. pData->midiLearnParameterIndex, event.ctrl.param, event.channel, 0.0f);
  2136. pData->midiLearnParameterIndex = -1;
  2137. }
  2138. #endif
  2139. void* CarlaPlugin::getNativeHandle() const noexcept
  2140. {
  2141. return nullptr;
  2142. }
  2143. const void* CarlaPlugin::getNativeDescriptor() const noexcept
  2144. {
  2145. return nullptr;
  2146. }
  2147. uintptr_t CarlaPlugin::getUiBridgeProcessId() const noexcept
  2148. {
  2149. return 0;
  2150. }
  2151. // -------------------------------------------------------------------
  2152. uint32_t CarlaPlugin::getPatchbayNodeId() const noexcept
  2153. {
  2154. return pData->nodeId;
  2155. }
  2156. void CarlaPlugin::setPatchbayNodeId(const uint32_t nodeId) noexcept
  2157. {
  2158. pData->nodeId = nodeId;
  2159. }
  2160. // -------------------------------------------------------------------
  2161. void CarlaPlugin::cloneLV2Files(const CarlaPlugin&)
  2162. {
  2163. carla_stderr2("Warning: cloneLV2Files() called for non-implemented type");
  2164. }
  2165. void CarlaPlugin::restoreLV2State(const bool temporary) noexcept
  2166. {
  2167. carla_stderr2("Warning: restoreLV2State(%s) called for non-implemented type", bool2str(temporary));
  2168. }
  2169. void CarlaPlugin::prepareForDeletion() noexcept
  2170. {
  2171. carla_debug("CarlaPlugin::prepareForDeletion");
  2172. const CarlaMutexLocker cml(pData->masterMutex);
  2173. pData->client->deactivate(true);
  2174. }
  2175. void CarlaPlugin::waitForBridgeSaveSignal() noexcept
  2176. {
  2177. }
  2178. // -------------------------------------------------------------------
  2179. // Scoped Disabler
  2180. CarlaPlugin::ScopedDisabler::ScopedDisabler(CarlaPlugin* const plugin) noexcept
  2181. : fPlugin(plugin),
  2182. fWasEnabled(false)
  2183. {
  2184. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  2185. CARLA_SAFE_ASSERT_RETURN(plugin->pData != nullptr,);
  2186. CARLA_SAFE_ASSERT_RETURN(plugin->pData->client != nullptr,);
  2187. carla_debug("CarlaPlugin::ScopedDisabler(%p)", plugin);
  2188. plugin->pData->masterMutex.lock();
  2189. if (plugin->pData->enabled)
  2190. {
  2191. fWasEnabled = true;
  2192. plugin->pData->enabled = false;
  2193. if (plugin->pData->client->isActive())
  2194. plugin->pData->client->deactivate(false);
  2195. }
  2196. }
  2197. CarlaPlugin::ScopedDisabler::~ScopedDisabler() noexcept
  2198. {
  2199. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  2200. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  2201. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData->client != nullptr,);
  2202. carla_debug("CarlaPlugin::~ScopedDisabler()");
  2203. if (fWasEnabled)
  2204. {
  2205. fPlugin->pData->enabled = true;
  2206. fPlugin->pData->client->activate();
  2207. }
  2208. fPlugin->pData->masterMutex.unlock();
  2209. }
  2210. // -------------------------------------------------------------------
  2211. // Scoped Process Locker
  2212. CarlaPlugin::ScopedSingleProcessLocker::ScopedSingleProcessLocker(CarlaPlugin* const plugin, const bool block) noexcept
  2213. : fPlugin(plugin),
  2214. fBlock(block)
  2215. {
  2216. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  2217. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  2218. carla_debug("CarlaPlugin::ScopedSingleProcessLocker(%p, %s)", plugin, bool2str(block));
  2219. if (! fBlock)
  2220. return;
  2221. plugin->pData->singleMutex.lock();
  2222. }
  2223. CarlaPlugin::ScopedSingleProcessLocker::~ScopedSingleProcessLocker() noexcept
  2224. {
  2225. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  2226. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  2227. carla_debug("CarlaPlugin::~ScopedSingleProcessLocker()");
  2228. if (! fBlock)
  2229. return;
  2230. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  2231. if (fPlugin->pData->singleMutex.wasTryLockCalled())
  2232. fPlugin->pData->needsReset = true;
  2233. #endif
  2234. fPlugin->pData->singleMutex.unlock();
  2235. }
  2236. // -------------------------------------------------------------------
  2237. CARLA_BACKEND_END_NAMESPACE