Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CarlaPluginNative.cpp 95KB

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