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.

carla-dssi.cpp 44KB

10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
10 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406
  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #define CARLA_NATIVE_PLUGIN_DSSI
  18. #include "carla-native-base.cpp"
  19. #include "juce_audio_basics.h"
  20. #include "juce_gui_basics.h"
  21. #include "CarlaString.hpp"
  22. #include "dssi/dssi.h"
  23. #include "ladspa/ladspa.h"
  24. using namespace juce;
  25. // -----------------------------------------------------------------------
  26. // Juce Message Thread
  27. class JuceMessageThread : public Thread
  28. {
  29. public:
  30. JuceMessageThread()
  31. : Thread("JuceMessageThread"),
  32. fInitialised(false)
  33. {
  34. startThread(7);
  35. while (! fInitialised)
  36. sleep(1);
  37. }
  38. ~JuceMessageThread()
  39. {
  40. signalThreadShouldExit();
  41. JUCEApplication::quit();
  42. waitForThreadToExit(5000);
  43. clearSingletonInstance();
  44. }
  45. void run()
  46. {
  47. initialiseJuce_GUI();
  48. fInitialised = true;
  49. MessageManager::getInstance()->setCurrentThreadAsMessageThread();
  50. while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil(250))
  51. {}
  52. }
  53. juce_DeclareSingleton(JuceMessageThread, false);
  54. private:
  55. bool fInitialised;
  56. };
  57. juce_ImplementSingleton(JuceMessageThread)
  58. static Array<void*> gActivePlugins;
  59. // -----------------------------------------------------------------------
  60. // LV2 descriptor functions
  61. class NativePlugin : public LV2_External_UI_Widget
  62. {
  63. public:
  64. static const uint32_t kMaxMidiEvents = 512;
  65. NativePlugin(const NativePluginDescriptor* const desc, const double sampleRate, const char* const bundlePath, const LV2_Feature* const* features)
  66. : fHandle(nullptr),
  67. fDescriptor(desc),
  68. fMidiEventCount(0),
  69. fUiWasShown(false),
  70. fIsProcessing(false),
  71. fVolume(1.0f),
  72. fDryWet(1.0f),
  73. fBufferSize(0),
  74. fSampleRate(sampleRate),
  75. fUridMap(nullptr)
  76. {
  77. run = extui_run;
  78. show = extui_show;
  79. hide = extui_hide;
  80. CarlaString resourceDir(bundlePath);
  81. #ifdef CARLA_OS_WIN
  82. resourceDir += "\\resources\\";
  83. #else
  84. resourceDir += "/resources/";
  85. #endif
  86. fHost.handle = this;
  87. fHost.resourceDir = resourceDir.dup();
  88. fHost.uiName = nullptr;
  89. fHost.get_buffer_size = host_get_buffer_size;
  90. fHost.get_sample_rate = host_get_sample_rate;
  91. fHost.is_offline = host_is_offline;
  92. fHost.get_time_info = host_get_time_info;
  93. fHost.write_midi_event = host_write_midi_event;
  94. fHost.ui_parameter_changed = host_ui_parameter_changed;
  95. fHost.ui_custom_data_changed = host_ui_custom_data_changed;
  96. fHost.ui_closed = host_ui_closed;
  97. fHost.ui_open_file = host_ui_open_file;
  98. fHost.ui_save_file = host_ui_save_file;
  99. fHost.dispatcher = host_dispatcher;
  100. const LV2_Options_Option* options = nullptr;
  101. const LV2_URID_Map* uridMap = nullptr;
  102. const LV2_URID_Unmap* uridUnmap = nullptr;
  103. for (int i=0; features[i] != nullptr; ++i)
  104. {
  105. if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
  106. options = (const LV2_Options_Option*)features[i]->data;
  107. else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
  108. uridMap = (const LV2_URID_Map*)features[i]->data;
  109. else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0)
  110. uridUnmap = (const LV2_URID_Unmap*)features[i]->data;
  111. }
  112. if (options == nullptr || uridMap == nullptr)
  113. {
  114. carla_stderr("Host doesn't provides option or urid-map features");
  115. return;
  116. }
  117. for (int i=0; options[i].key != 0; ++i)
  118. {
  119. if (uridUnmap != nullptr)
  120. {
  121. carla_debug("Host option %i:\"%s\"", i, uridUnmap->unmap(uridUnmap->handle, options[i].key));
  122. }
  123. if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
  124. {
  125. if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
  126. {
  127. fBufferSize = *(const int*)options[i].value;
  128. if (fBufferSize == 0)
  129. carla_stderr("Host provides maxBlockLength but has null value");
  130. }
  131. else
  132. carla_stderr("Host provides maxBlockLength but has wrong value type");
  133. break;
  134. }
  135. }
  136. fUridMap = uridMap;
  137. if (fDescriptor->midiIns > 0)
  138. fUI.portOffset += desc->midiIns;
  139. else if (fDescriptor->hints & PLUGIN_USES_TIME)
  140. fUI.portOffset += 1;
  141. fUI.portOffset += desc->midiOuts;
  142. fUI.portOffset += 1; // freewheel
  143. fUI.portOffset += desc->audioIns;
  144. fUI.portOffset += desc->audioOuts;
  145. }
  146. ~NativePlugin()
  147. {
  148. CARLA_ASSERT(fHandle == nullptr);
  149. CARLA_ASSERT(! fUiWasShown);
  150. if (fHost.resourceDir != nullptr)
  151. {
  152. delete[] fHost.resourceDir;
  153. fHost.resourceDir = nullptr;
  154. }
  155. }
  156. bool init()
  157. {
  158. if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr)
  159. {
  160. carla_stderr("Plugin is missing something...");
  161. return false;
  162. }
  163. if (fBufferSize == 0)
  164. {
  165. carla_stderr("Host is missing bufferSize feature");
  166. //return false;
  167. // as testing, continue for now
  168. fBufferSize = 1024;
  169. }
  170. fHandle = fDescriptor->instantiate(&fHost);
  171. if (fHandle == nullptr)
  172. return false;
  173. carla_zeroStruct<NativeMidiEvent>(fMidiEvents, kMaxMidiEvents*2);
  174. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  175. fPorts.init(fDescriptor, fHandle);
  176. fUris.map(fUridMap);
  177. return true;
  178. }
  179. // -------------------------------------------------------------------
  180. // LV2 functions
  181. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  182. {
  183. fPorts.connectPort(fDescriptor, port, dataLocation);
  184. }
  185. void lv2_activate()
  186. {
  187. if (fDescriptor->activate != nullptr)
  188. fDescriptor->activate(fHandle);
  189. carla_zeroStruct<NativeTimeInfo>(fTimeInfo);
  190. }
  191. void lv2_deactivate()
  192. {
  193. if (fDescriptor->deactivate != nullptr)
  194. fDescriptor->deactivate(fHandle);
  195. }
  196. void lv2_cleanup()
  197. {
  198. if (fDescriptor->cleanup != nullptr)
  199. fDescriptor->cleanup(fHandle);
  200. fHandle = nullptr;
  201. if (fUiWasShown)
  202. {
  203. CARLA_SAFE_ASSERT_RETURN(gActivePlugins.contains(this),);
  204. gActivePlugins.removeFirstMatchingValue(this);
  205. JUCE_AUTORELEASEPOOL
  206. {
  207. MessageManagerLock mmLock;
  208. if (gActivePlugins.size() == 0)
  209. {
  210. JuceMessageThread::deleteInstance();
  211. shutdownJuce_GUI();
  212. }
  213. }
  214. fUiWasShown = false;
  215. }
  216. }
  217. void lv2_run(const uint32_t frames)
  218. {
  219. if (frames == 0)
  220. {
  221. updateParameterOutputs();
  222. return;
  223. }
  224. // Check for updated parameters
  225. float curValue;
  226. for (uint32_t i=0; i < fPorts.paramCount; ++i)
  227. {
  228. CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)
  229. curValue = *fPorts.paramsPtr[i];
  230. if (fPorts.paramsLast[i] != curValue && (fDescriptor->get_parameter_info(fHandle, i)->hints & PARAMETER_IS_OUTPUT) == 0)
  231. {
  232. fPorts.paramsLast[i] = curValue;
  233. fDescriptor->set_parameter_value(fHandle, i, curValue);
  234. }
  235. }
  236. if (fDescriptor->midiIns > 0 || (fDescriptor->hints & PLUGIN_USES_TIME) != 0)
  237. {
  238. fMidiEventCount = 0;
  239. carla_zeroStruct<NativeMidiEvent>(fMidiEvents, kMaxMidiEvents*2);
  240. LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], iter)
  241. {
  242. const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter);
  243. if (event == nullptr)
  244. continue;
  245. if (event->body.size > 4)
  246. continue;
  247. if (event->time.frames >= frames)
  248. break;
  249. if (event->body.type == fUris.midiEvent)
  250. {
  251. if (fMidiEventCount >= kMaxMidiEvents*2)
  252. continue;
  253. const uint8_t* const data((const uint8_t*)(event + 1));
  254. fMidiEvents[fMidiEventCount].port = 0;
  255. fMidiEvents[fMidiEventCount].time = (uint32_t)event->time.frames;
  256. fMidiEvents[fMidiEventCount].size = (uint8_t)event->body.size;
  257. for (uint32_t i=0; i < event->body.size; ++i)
  258. fMidiEvents[fMidiEventCount].data[i] = data[i];
  259. fMidiEventCount += 1;
  260. continue;
  261. }
  262. if (event->body.type == fUris.atomBlank)
  263. {
  264. const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);
  265. if (obj->body.otype != fUris.timePos)
  266. continue;
  267. LV2_Atom* bar = nullptr;
  268. LV2_Atom* barBeat = nullptr;
  269. LV2_Atom* beatsPerBar = nullptr;
  270. LV2_Atom* bpm = nullptr;
  271. LV2_Atom* beatUnit = nullptr;
  272. LV2_Atom* frame = nullptr;
  273. LV2_Atom* speed = nullptr;
  274. lv2_atom_object_get(obj,
  275. fUris.timeBar, &bar,
  276. fUris.timeBarBeat, &barBeat,
  277. fUris.timeBeatsPerBar, &beatsPerBar,
  278. fUris.timeBeatsPerMinute, &bpm,
  279. fUris.timeBeatUnit, &beatUnit,
  280. fUris.timeFrame, &frame,
  281. fUris.timeSpeed, &speed,
  282. nullptr);
  283. if (bpm != nullptr && bpm->type == fUris.atomFloat)
  284. {
  285. fTimeInfo.bbt.beatsPerMinute = ((LV2_Atom_Float*)bpm)->body;
  286. fTimeInfo.bbt.valid = true;
  287. }
  288. if (beatsPerBar != nullptr && beatsPerBar->type == fUris.atomFloat)
  289. {
  290. float beatsPerBarValue = ((LV2_Atom_Float*)beatsPerBar)->body;
  291. fTimeInfo.bbt.beatsPerBar = beatsPerBarValue;
  292. if (bar != nullptr && bar->type == fUris.atomLong)
  293. {
  294. //float barValue = ((LV2_Atom_Long*)bar)->body;
  295. //curPosInfo.ppqPositionOfLastBarStart = barValue * beatsPerBarValue;
  296. if (barBeat != nullptr && barBeat->type == fUris.atomFloat)
  297. {
  298. //float barBeatValue = ((LV2_Atom_Float*)barBeat)->body;
  299. //curPosInfo.ppqPosition = curPosInfo.ppqPositionOfLastBarStart + barBeatValue;
  300. }
  301. }
  302. }
  303. if (beatUnit != nullptr && beatUnit->type == fUris.atomFloat)
  304. fTimeInfo.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body;
  305. if (frame != nullptr && frame->type == fUris.atomLong)
  306. fTimeInfo.frame = ((LV2_Atom_Long*)frame)->body;
  307. if (speed != nullptr && speed->type == fUris.atomFloat)
  308. fTimeInfo.playing = ((LV2_Atom_Float*)speed)->body == 1.0f;
  309. continue;
  310. }
  311. }
  312. for (uint32_t i=1; i < fDescriptor->midiIns; ++i)
  313. {
  314. LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[i], iter)
  315. {
  316. const LV2_Atom_Event* const event((const LV2_Atom_Event*)iter);
  317. if (event == nullptr)
  318. continue;
  319. if (event->body.type != fUris.midiEvent)
  320. continue;
  321. if (event->body.size > 4)
  322. continue;
  323. if (event->time.frames >= frames)
  324. break;
  325. if (fMidiEventCount >= kMaxMidiEvents*2)
  326. break;
  327. const uint8_t* const data((const uint8_t*)(event + 1));
  328. fMidiEvents[fMidiEventCount].port = (uint8_t)i;
  329. fMidiEvents[fMidiEventCount].size = (uint8_t)event->body.size;
  330. fMidiEvents[fMidiEventCount].time = (uint32_t)event->time.frames;
  331. for (uint32_t j=0; j < event->body.size; ++j)
  332. fMidiEvents[fMidiEventCount].data[j] = data[j];
  333. fMidiEventCount += 1;
  334. }
  335. }
  336. }
  337. fIsProcessing = true;
  338. fDescriptor->process(fHandle, fPorts.audioIns, fPorts.audioOuts, frames, fMidiEvents, fMidiEventCount);
  339. fIsProcessing = false;
  340. if (fDryWet != 1.0f && fDescriptor->audioIns == fDescriptor->audioOuts)
  341. {
  342. for (uint32_t i=0; i < fDescriptor->audioOuts; ++i)
  343. {
  344. FloatVectorOperations::multiply(fPorts.audioIns[i], fVolume*(1.0f-fDryWet), frames);
  345. FloatVectorOperations::multiply(fPorts.audioOuts[i], fVolume*fDryWet, frames);
  346. FloatVectorOperations::add(fPorts.audioOuts[i], fPorts.audioIns[i], frames);
  347. }
  348. }
  349. else if (fVolume != 1.0f)
  350. {
  351. for (uint32_t i=0; i < fDescriptor->audioOuts; ++i)
  352. FloatVectorOperations::multiply(fPorts.audioOuts[i], fVolume, frames);
  353. }
  354. // TODO - midi out
  355. updateParameterOutputs();
  356. }
  357. // -------------------------------------------------------------------
  358. uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) const
  359. {
  360. // currently unused
  361. return LV2_OPTIONS_SUCCESS;
  362. }
  363. uint32_t lv2_set_options(const LV2_Options_Option* const options)
  364. {
  365. for (int i=0; options[i].key != 0; ++i)
  366. {
  367. if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength))
  368. {
  369. if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Int))
  370. {
  371. fBufferSize = *(const int*)options[i].value;
  372. if (fDescriptor->dispatcher != nullptr)
  373. fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_BUFFER_SIZE_CHANGED, 0, fBufferSize, nullptr, 0.0f);
  374. }
  375. else
  376. carla_stderr("Host changed maxBlockLength but with wrong value type");
  377. }
  378. else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_CORE__sampleRate))
  379. {
  380. if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Double))
  381. {
  382. fSampleRate = *(const double*)options[i].value;
  383. if (fDescriptor->dispatcher != nullptr)
  384. fDescriptor->dispatcher(fHandle, PLUGIN_OPCODE_SAMPLE_RATE_CHANGED, 0, 0, nullptr, (float)fSampleRate);
  385. }
  386. else
  387. carla_stderr("Host changed sampleRate but with wrong value type");
  388. }
  389. }
  390. return LV2_OPTIONS_SUCCESS;
  391. }
  392. const LV2_Program_Descriptor* lv2_get_program(const uint32_t index)
  393. {
  394. if (fDescriptor->category == PLUGIN_CATEGORY_SYNTH)
  395. return nullptr;
  396. if (fDescriptor->get_midi_program_count == nullptr)
  397. return nullptr;
  398. if (fDescriptor->get_midi_program_info == nullptr)
  399. return nullptr;
  400. if (index >= fDescriptor->get_midi_program_count(fHandle))
  401. return nullptr;
  402. const NativeMidiProgram* const midiProg(fDescriptor->get_midi_program_info(fHandle, index));
  403. if (midiProg == nullptr)
  404. return nullptr;
  405. fProgramDesc.bank = midiProg->bank;
  406. fProgramDesc.program = midiProg->program;
  407. fProgramDesc.name = midiProg->name;
  408. return &fProgramDesc;
  409. }
  410. void lv2_select_program(uint32_t bank, uint32_t program)
  411. {
  412. if (fDescriptor->category == PLUGIN_CATEGORY_SYNTH)
  413. return;
  414. if (fDescriptor->set_midi_program == nullptr)
  415. return;
  416. fDescriptor->set_midi_program(fHandle, 0, bank, program);
  417. }
  418. LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle, const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const
  419. {
  420. if ((fDescriptor->hints & PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr)
  421. return LV2_STATE_ERR_NO_FEATURE;
  422. if (char* const state = fDescriptor->get_state(fHandle))
  423. {
  424. store(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), state, std::strlen(state), fUris.atomString, LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
  425. std::free(state);
  426. return LV2_STATE_SUCCESS;
  427. }
  428. return LV2_STATE_ERR_UNKNOWN;
  429. }
  430. LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* const /*features*/) const
  431. {
  432. if ((fDescriptor->hints & PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr)
  433. return LV2_STATE_ERR_NO_FEATURE;
  434. size_t size = 0;
  435. uint32_t type = 0;
  436. const void* data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags);
  437. if (size == 0)
  438. return LV2_STATE_ERR_UNKNOWN;
  439. if (type == 0)
  440. return LV2_STATE_ERR_UNKNOWN;
  441. if (data == nullptr)
  442. return LV2_STATE_ERR_UNKNOWN;
  443. if (type != fUris.atomString)
  444. return LV2_STATE_ERR_BAD_TYPE;
  445. fDescriptor->set_state(fHandle, (const char*)data);
  446. return LV2_STATE_SUCCESS;
  447. }
  448. // -------------------------------------------------------------------
  449. bool lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features)
  450. {
  451. for (int i=0; features[i] != nullptr; ++i)
  452. {
  453. if (std::strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host) == 0 ||
  454. std::strcmp(features[i]->URI, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0)
  455. {
  456. fUI.host = (const LV2_External_UI_Host*)features[i]->data;
  457. break;
  458. }
  459. }
  460. if (fUI.host == nullptr)
  461. return false;
  462. fUI.writeFunction = writeFunction;
  463. fUI.controller = controller;
  464. *widget = this;
  465. fHost.uiName = fUI.host->plugin_human_id;
  466. return true;
  467. }
  468. void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const
  469. {
  470. if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr)
  471. return;
  472. if (portIndex >= fUI.portOffset || ! fUI.isVisible)
  473. return;
  474. if (fDescriptor->ui_set_parameter_value == nullptr)
  475. return;
  476. const float value(*(const float*)buffer);
  477. fDescriptor->ui_set_parameter_value(fHandle, portIndex-fUI.portOffset, value);
  478. }
  479. void lv2ui_cleanup()
  480. {
  481. fUI.host = nullptr;
  482. fUI.writeFunction = nullptr;
  483. fUI.controller = nullptr;
  484. if (! fUI.isVisible)
  485. return;
  486. if (fDescriptor->ui_show != nullptr)
  487. fDescriptor->ui_show(fHandle, false);
  488. fUI.isVisible = false;
  489. }
  490. // -------------------------------------------------------------------
  491. void lv2ui_select_program(uint32_t bank, uint32_t program) const
  492. {
  493. if (fDescriptor->category == PLUGIN_CATEGORY_SYNTH)
  494. return;
  495. if (fDescriptor->ui_set_midi_program == nullptr)
  496. return;
  497. fDescriptor->ui_set_midi_program(fHandle, 0, bank, program);
  498. }
  499. // -------------------------------------------------------------------
  500. protected:
  501. void handleUiRun()
  502. {
  503. if (fDescriptor->ui_idle != nullptr)
  504. fDescriptor->ui_idle(fHandle);
  505. }
  506. void handleUiShow()
  507. {
  508. if (fDescriptor->ui_show != nullptr)
  509. {
  510. if (fDescriptor->hints & PLUGIN_NEEDS_UI_JUCE)
  511. {
  512. JUCE_AUTORELEASEPOOL
  513. {
  514. if (gActivePlugins.size() == 0)
  515. {
  516. initialiseJuce_GUI();
  517. JuceMessageThread::getInstance();
  518. }
  519. }
  520. fDescriptor->ui_show(fHandle, true);
  521. fUiWasShown = true;
  522. gActivePlugins.add(this);
  523. }
  524. else
  525. fDescriptor->ui_show(fHandle, true);
  526. }
  527. fUI.isVisible = true;
  528. }
  529. void handleUiHide()
  530. {
  531. if (fDescriptor->ui_show != nullptr)
  532. fDescriptor->ui_show(fHandle, false);
  533. fUI.isVisible = false;
  534. }
  535. // -------------------------------------------------------------------
  536. uint32_t handleGetBufferSize() const
  537. {
  538. return fBufferSize;
  539. }
  540. double handleGetSampleRate() const
  541. {
  542. return fSampleRate;
  543. }
  544. bool handleIsOffline() const
  545. {
  546. CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false);
  547. return (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);
  548. }
  549. const NativeTimeInfo* handleGetTimeInfo() const
  550. {
  551. CARLA_SAFE_ASSERT_RETURN(fIsProcessing, nullptr);
  552. return &fTimeInfo;
  553. }
  554. bool handleWriteMidiEvent(const NativeMidiEvent* const event)
  555. {
  556. CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false);
  557. CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false);
  558. CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
  559. CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);
  560. // reverse-find first free event, and put it there
  561. for (uint32_t i=(kMaxMidiEvents*2)-1; i > fMidiEventCount; --i)
  562. {
  563. if (fMidiEvents[i].data[0] == 0)
  564. {
  565. std::memcpy(&fMidiEvents[i], event, sizeof(NativeMidiEvent));
  566. return true;
  567. }
  568. }
  569. return false;
  570. }
  571. void handleUiParameterChanged(const uint32_t index, const float value) const
  572. {
  573. if (fUI.writeFunction != nullptr && fUI.controller != nullptr)
  574. fUI.writeFunction(fUI.controller, index+fUI.portOffset, sizeof(float), 0, &value);
  575. }
  576. void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const
  577. {
  578. //storeCustomData(key, value);
  579. }
  580. void handleUiClosed()
  581. {
  582. if (fUI.host != nullptr && fUI.host->ui_closed != nullptr && fUI.controller != nullptr)
  583. fUI.host->ui_closed(fUI.controller);
  584. fUI.host = nullptr;
  585. fUI.writeFunction = nullptr;
  586. fUI.controller = nullptr;
  587. fUI.isVisible = false;
  588. }
  589. const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  590. {
  591. // TODO
  592. return nullptr;
  593. }
  594. const char* handleUiSaveFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const
  595. {
  596. // TODO
  597. return nullptr;
  598. }
  599. intptr_t handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  600. {
  601. carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, opt);
  602. intptr_t ret = 0;
  603. switch (opcode)
  604. {
  605. case HOST_OPCODE_NULL:
  606. break;
  607. case HOST_OPCODE_SET_VOLUME:
  608. fVolume = opt;
  609. break;
  610. case HOST_OPCODE_SET_DRYWET:
  611. fDryWet = opt;
  612. break;
  613. case HOST_OPCODE_SET_BALANCE_LEFT:
  614. case HOST_OPCODE_SET_BALANCE_RIGHT:
  615. case HOST_OPCODE_SET_PANNING:
  616. // nothing
  617. break;
  618. case HOST_OPCODE_GET_PARAMETER_MIDI_CC:
  619. case HOST_OPCODE_SET_PARAMETER_MIDI_CC:
  620. case HOST_OPCODE_SET_PROCESS_PRECISION:
  621. case HOST_OPCODE_UPDATE_PARAMETER:
  622. case HOST_OPCODE_UPDATE_MIDI_PROGRAM:
  623. case HOST_OPCODE_RELOAD_PARAMETERS:
  624. case HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
  625. case HOST_OPCODE_RELOAD_ALL:
  626. // nothing
  627. break;
  628. case HOST_OPCODE_UI_UNAVAILABLE:
  629. handleUiClosed();
  630. break;
  631. }
  632. return ret;
  633. // unused for now
  634. (void)index;
  635. (void)value;
  636. (void)ptr;
  637. }
  638. void updateParameterOutputs()
  639. {
  640. for (uint32_t i=0; i < fPorts.paramCount; ++i)
  641. {
  642. if (fDescriptor->get_parameter_info(fHandle, i)->hints & PARAMETER_IS_OUTPUT)
  643. {
  644. fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);
  645. if (fPorts.paramsPtr[i] != nullptr)
  646. *fPorts.paramsPtr[i] = fPorts.paramsLast[i];
  647. }
  648. }
  649. }
  650. // -------------------------------------------------------------------
  651. private:
  652. // Native data
  653. NativePluginHandle fHandle;
  654. NativeHostDescriptor fHost;
  655. const NativePluginDescriptor* const fDescriptor;
  656. LV2_Program_Descriptor fProgramDesc;
  657. uint32_t fMidiEventCount;
  658. NativeMidiEvent fMidiEvents[kMaxMidiEvents*2];
  659. NativeTimeInfo fTimeInfo;
  660. bool fUiWasShown;
  661. bool fIsProcessing;
  662. float fVolume;
  663. float fDryWet;
  664. // Lv2 host data
  665. uint32_t fBufferSize;
  666. double fSampleRate;
  667. const LV2_URID_Map* fUridMap;
  668. struct URIDs {
  669. LV2_URID atomBlank;
  670. LV2_URID atomFloat;
  671. LV2_URID atomLong;
  672. LV2_URID atomSequence;
  673. LV2_URID atomString;
  674. LV2_URID midiEvent;
  675. LV2_URID timePos;
  676. LV2_URID timeBar;
  677. LV2_URID timeBarBeat;
  678. LV2_URID timeBeatsPerBar;
  679. LV2_URID timeBeatsPerMinute;
  680. LV2_URID timeBeatUnit;
  681. LV2_URID timeFrame;
  682. LV2_URID timeSpeed;
  683. URIDs()
  684. : atomBlank(0),
  685. atomFloat(0),
  686. atomLong(0),
  687. atomSequence(0),
  688. atomString(0),
  689. midiEvent(0),
  690. timePos(0),
  691. timeBar(0),
  692. timeBarBeat(0),
  693. timeBeatsPerBar(0),
  694. timeBeatsPerMinute(0),
  695. timeBeatUnit(0),
  696. timeFrame(0),
  697. timeSpeed(0) {}
  698. void map(const LV2_URID_Map* const uridMap)
  699. {
  700. atomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank);
  701. atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
  702. atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long);
  703. atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence);
  704. atomString = uridMap->map(uridMap->handle, LV2_ATOM__String);
  705. midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent);
  706. timePos = uridMap->map(uridMap->handle, LV2_TIME__Position);
  707. timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar);
  708. timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat);
  709. timeBeatUnit = uridMap->map(uridMap->handle, LV2_TIME__beatUnit);
  710. timeFrame = uridMap->map(uridMap->handle, LV2_TIME__frame);
  711. timeSpeed = uridMap->map(uridMap->handle, LV2_TIME__speed);
  712. timeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar);
  713. timeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute);
  714. }
  715. } fUris;
  716. struct UI {
  717. const LV2_External_UI_Host* host;
  718. LV2UI_Write_Function writeFunction;
  719. LV2UI_Controller controller;
  720. uint32_t portOffset;
  721. bool isVisible;
  722. UI()
  723. : host(nullptr),
  724. writeFunction(nullptr),
  725. controller(nullptr),
  726. portOffset(0),
  727. isVisible(false) {}
  728. } fUI;
  729. struct Ports {
  730. LV2_Atom_Sequence** eventsIn;
  731. LV2_Atom_Sequence** midiOuts;
  732. float** audioIns;
  733. float** audioOuts;
  734. float* freewheel;
  735. uint32_t paramCount;
  736. float* paramsLast;
  737. float** paramsPtr;
  738. Ports()
  739. : eventsIn(nullptr),
  740. midiOuts(nullptr),
  741. audioIns(nullptr),
  742. audioOuts(nullptr),
  743. freewheel(nullptr),
  744. paramCount(0),
  745. paramsLast(nullptr),
  746. paramsPtr(nullptr) {}
  747. ~Ports()
  748. {
  749. if (eventsIn != nullptr)
  750. {
  751. delete[] eventsIn;
  752. eventsIn = nullptr;
  753. }
  754. if (midiOuts != nullptr)
  755. {
  756. delete[] midiOuts;
  757. midiOuts = nullptr;
  758. }
  759. if (audioIns != nullptr)
  760. {
  761. delete[] audioIns;
  762. audioIns = nullptr;
  763. }
  764. if (audioOuts != nullptr)
  765. {
  766. delete[] audioOuts;
  767. audioOuts = nullptr;
  768. }
  769. if (paramsLast != nullptr)
  770. {
  771. delete[] paramsLast;
  772. paramsLast = nullptr;
  773. }
  774. if (paramsPtr != nullptr)
  775. {
  776. delete[] paramsPtr;
  777. paramsPtr = nullptr;
  778. }
  779. }
  780. void init(const NativePluginDescriptor* const desc, NativePluginHandle handle)
  781. {
  782. CARLA_SAFE_ASSERT_RETURN(desc != nullptr && handle != nullptr,)
  783. if (desc->midiIns > 0)
  784. {
  785. eventsIn = new LV2_Atom_Sequence*[desc->midiIns];
  786. for (uint32_t i=0; i < desc->midiIns; ++i)
  787. eventsIn[i] = nullptr;
  788. }
  789. else if (desc->hints & PLUGIN_USES_TIME)
  790. {
  791. eventsIn = new LV2_Atom_Sequence*[1];
  792. eventsIn[0] = nullptr;
  793. }
  794. if (desc->midiOuts > 0)
  795. {
  796. midiOuts = new LV2_Atom_Sequence*[desc->midiOuts];
  797. for (uint32_t i=0; i < desc->midiOuts; ++i)
  798. midiOuts[i] = nullptr;
  799. }
  800. if (desc->audioIns > 0)
  801. {
  802. audioIns = new float*[desc->audioIns];
  803. for (uint32_t i=0; i < desc->audioIns; ++i)
  804. audioIns[i] = nullptr;
  805. }
  806. if (desc->audioOuts > 0)
  807. {
  808. audioOuts = new float*[desc->audioOuts];
  809. for (uint32_t i=0; i < desc->audioOuts; ++i)
  810. audioOuts[i] = nullptr;
  811. }
  812. if (desc->get_parameter_count != nullptr && desc->get_parameter_info != nullptr && desc->get_parameter_value != nullptr && desc->set_parameter_value != nullptr)
  813. {
  814. paramCount = desc->get_parameter_count(handle);
  815. if (paramCount > 0)
  816. {
  817. paramsLast = new float[paramCount];
  818. paramsPtr = new float*[paramCount];
  819. for (uint32_t i=0; i < paramCount; ++i)
  820. {
  821. paramsLast[i] = desc->get_parameter_value(handle, i);
  822. paramsPtr[i] = nullptr;
  823. }
  824. }
  825. }
  826. }
  827. void connectPort(const NativePluginDescriptor* const desc, const uint32_t port, void* const dataLocation)
  828. {
  829. uint32_t index = 0;
  830. if (desc->midiIns > 0 || (desc->hints & PLUGIN_USES_TIME) != 0)
  831. {
  832. if (port == index++)
  833. {
  834. eventsIn[0] = (LV2_Atom_Sequence*)dataLocation;
  835. return;
  836. }
  837. }
  838. for (uint32_t i=1; i < desc->midiIns; ++i)
  839. {
  840. if (port == index++)
  841. {
  842. eventsIn[i] = (LV2_Atom_Sequence*)dataLocation;
  843. return;
  844. }
  845. }
  846. for (uint32_t i=0; i < desc->midiOuts; ++i)
  847. {
  848. if (port == index++)
  849. {
  850. midiOuts[i] = (LV2_Atom_Sequence*)dataLocation;
  851. return;
  852. }
  853. }
  854. if (port == index++)
  855. {
  856. freewheel = (float*)dataLocation;
  857. return;
  858. }
  859. for (uint32_t i=0; i < desc->audioIns; ++i)
  860. {
  861. if (port == index++)
  862. {
  863. audioIns[i] = (float*)dataLocation;
  864. return;
  865. }
  866. }
  867. for (uint32_t i=0; i < desc->audioOuts; ++i)
  868. {
  869. if (port == index++)
  870. {
  871. audioOuts[i] = (float*)dataLocation;
  872. return;
  873. }
  874. }
  875. for (uint32_t i=0; i < paramCount; ++i)
  876. {
  877. if (port == index++)
  878. {
  879. paramsPtr[i] = (float*)dataLocation;
  880. return;
  881. }
  882. }
  883. }
  884. } fPorts;
  885. // -------------------------------------------------------------------
  886. #define handlePtr ((NativePlugin*)_this_)
  887. static void extui_run(LV2_External_UI_Widget* _this_)
  888. {
  889. handlePtr->handleUiRun();
  890. }
  891. static void extui_show(LV2_External_UI_Widget* _this_)
  892. {
  893. handlePtr->handleUiShow();
  894. }
  895. static void extui_hide(LV2_External_UI_Widget* _this_)
  896. {
  897. handlePtr->handleUiHide();
  898. }
  899. #undef handlePtr
  900. // -------------------------------------------------------------------
  901. #define handlePtr ((NativePlugin*)handle)
  902. static uint32_t host_get_buffer_size(NativeHostHandle handle)
  903. {
  904. return handlePtr->handleGetBufferSize();
  905. }
  906. static double host_get_sample_rate(NativeHostHandle handle)
  907. {
  908. return handlePtr->handleGetSampleRate();
  909. }
  910. static bool host_is_offline(NativeHostHandle handle)
  911. {
  912. return handlePtr->handleIsOffline();
  913. }
  914. static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle)
  915. {
  916. return handlePtr->handleGetTimeInfo();
  917. }
  918. static bool host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event)
  919. {
  920. return handlePtr->handleWriteMidiEvent(event);
  921. }
  922. static void host_ui_parameter_changed(NativeHostHandle handle, uint32_t index, float value)
  923. {
  924. handlePtr->handleUiParameterChanged(index, value);
  925. }
  926. static void host_ui_custom_data_changed(NativeHostHandle handle, const char* key, const char* value)
  927. {
  928. handlePtr->handleUiCustomDataChanged(key, value);
  929. }
  930. static void host_ui_closed(NativeHostHandle handle)
  931. {
  932. handlePtr->handleUiClosed();
  933. }
  934. static const char* host_ui_open_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  935. {
  936. return handlePtr->handleUiOpenFile(isDir, title, filter);
  937. }
  938. static const char* host_ui_save_file(NativeHostHandle handle, bool isDir, const char* title, const char* filter)
  939. {
  940. return handlePtr->handleUiSaveFile(isDir, title, filter);
  941. }
  942. static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  943. {
  944. return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
  945. }
  946. #undef handlePtr
  947. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePlugin)
  948. };
  949. // -----------------------------------------------------------------------
  950. // LV2 plugin descriptor functions
  951. static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  952. {
  953. carla_debug("lv2_instantiate(%p, %g, %s, %p)", lv2Descriptor, sampleRate, bundlePath, features);
  954. const NativePluginDescriptor* pluginDesc = nullptr;
  955. const char* pluginLabel = nullptr;
  956. if (std::strncmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla/plugins/", 37) == 0)
  957. pluginLabel = lv2Descriptor->URI+37;
  958. if (pluginLabel == nullptr)
  959. {
  960. carla_stderr("Failed to find carla native plugin with URI \"%s\"", lv2Descriptor->URI);
  961. return nullptr;
  962. }
  963. carla_debug("lv2_instantiate() - looking up label \"%s\"", pluginLabel);
  964. PluginListManager& plm(PluginListManager::getInstance());
  965. for (LinkedList<const NativePluginDescriptor*>::Itenerator it = plm.descs.begin(); it.valid(); it.next())
  966. {
  967. const NativePluginDescriptor* const& tmpDesc(it.getValue());
  968. if (std::strcmp(tmpDesc->label, pluginLabel) == 0)
  969. {
  970. pluginDesc = tmpDesc;
  971. break;
  972. }
  973. }
  974. if (pluginDesc == nullptr)
  975. {
  976. carla_stderr("Failed to find carla native plugin with label \"%s\"", pluginLabel);
  977. return nullptr;
  978. }
  979. NativePlugin* const plugin(new NativePlugin(pluginDesc, sampleRate, bundlePath, features));
  980. if (! plugin->init())
  981. {
  982. carla_stderr("Failed to init plugin");
  983. delete plugin;
  984. return nullptr;
  985. }
  986. return (LV2_Handle)plugin;
  987. }
  988. #define instancePtr ((NativePlugin*)instance)
  989. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  990. {
  991. instancePtr->lv2_connect_port(port, dataLocation);
  992. }
  993. static void lv2_activate(LV2_Handle instance)
  994. {
  995. carla_debug("lv2_activate(%p)", instance);
  996. instancePtr->lv2_activate();
  997. }
  998. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  999. {
  1000. instancePtr->lv2_run(sampleCount);
  1001. }
  1002. static void lv2_deactivate(LV2_Handle instance)
  1003. {
  1004. carla_debug("lv2_deactivate(%p)", instance);
  1005. instancePtr->lv2_deactivate();
  1006. }
  1007. static void lv2_cleanup(LV2_Handle instance)
  1008. {
  1009. carla_debug("lv2_cleanup(%p)", instance);
  1010. instancePtr->lv2_cleanup();
  1011. delete instancePtr;
  1012. }
  1013. static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
  1014. {
  1015. carla_debug("lv2_get_options(%p, %p)", instance, options);
  1016. return instancePtr->lv2_get_options(options);
  1017. }
  1018. static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
  1019. {
  1020. carla_debug("lv2_set_options(%p, %p)", instance, options);
  1021. return instancePtr->lv2_set_options(options);
  1022. }
  1023. static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index)
  1024. {
  1025. carla_debug("lv2_get_program(%p, %i)", instance, index);
  1026. return instancePtr->lv2_get_program(index);
  1027. }
  1028. static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program)
  1029. {
  1030. carla_debug("lv2_select_program(%p, %i, %i)", instance, bank, program);
  1031. return instancePtr->lv2_select_program(bank, program);
  1032. }
  1033. static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
  1034. {
  1035. carla_debug("lv2_save(%p, %p, %p, %i, %p)", instance, store, handle, flags, features);
  1036. return instancePtr->lv2_save(store, handle, flags, features);
  1037. }
  1038. static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
  1039. {
  1040. carla_debug("lv2_restore(%p, %p, %p, %i, %p)", instance, retrieve, handle, flags, features);
  1041. return instancePtr->lv2_restore(retrieve, handle, flags, features);
  1042. }
  1043. #undef instancePtr
  1044. // -----------------------------------------------------------------------
  1045. // LV2 UI descriptor functions
  1046. static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*, LV2UI_Write_Function writeFunction,
  1047. LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features)
  1048. {
  1049. carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features);
  1050. NativePlugin* plugin = nullptr;
  1051. for (int i=0; features[i] != nullptr; ++i)
  1052. {
  1053. if (std::strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0)
  1054. {
  1055. plugin = (NativePlugin*)features[i]->data;
  1056. break;
  1057. }
  1058. }
  1059. if (plugin == nullptr)
  1060. {
  1061. carla_stderr("Host doesn't support instance-access, cannot show UI");
  1062. return nullptr;
  1063. }
  1064. if (! plugin->lv2ui_instantiate(writeFunction, controller, widget, features))
  1065. {
  1066. carla_stderr("Host doesn't support external UI");
  1067. return nullptr;
  1068. }
  1069. return (LV2UI_Handle)plugin;
  1070. }
  1071. #define uiPtr ((NativePlugin*)ui)
  1072. static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
  1073. {
  1074. carla_debug("lv2ui_port_event(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer);
  1075. uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
  1076. }
  1077. static void lv2ui_cleanup(LV2UI_Handle ui)
  1078. {
  1079. carla_debug("lv2ui_cleanup(%p)", ui);
  1080. uiPtr->lv2ui_cleanup();
  1081. }
  1082. static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program)
  1083. {
  1084. carla_debug("lv2ui_select_program(%p, %i, %i)", ui, bank, program);
  1085. uiPtr->lv2ui_select_program(bank, program);
  1086. }
  1087. #undef uiPtr
  1088. // -----------------------------------------------------------------------
  1089. // Startup code
  1090. CARLA_EXPORT
  1091. const DSSI_Descriptor* dssi_descriptor(ulong index)
  1092. {
  1093. carla_debug("dssi_descriptor(%i)", index);
  1094. PluginListManager& plm(PluginListManager::getInstance());
  1095. if (index >= plm.descs.count())
  1096. {
  1097. carla_debug("dssi_descriptor(%i) - out of bounds", index);
  1098. return nullptr;
  1099. }
  1100. if (index < plm.dssiDescs.count())
  1101. {
  1102. carla_debug("lv2_descriptor(%i) - found previously allocated", index);
  1103. return plm.dssiDescs.getAt(index, nullptr);
  1104. }
  1105. const NativePluginDescriptor* const pluginDesc(plm.descs.getAt(index, nullptr));
  1106. CARLA_SAFE_ASSERT_RETURN(pluginDesc != nullptr, nullptr);
  1107. CarlaString tmpURI;
  1108. tmpURI = "http://kxstudio.sf.net/carla/plugins/";
  1109. tmpURI += pluginDesc->label;
  1110. carla_debug("lv2_descriptor(%i) - not found, allocating new with uri \"%s\"", index, (const char*)tmpURI);
  1111. const DSSI_Descriptor dssiDescTmp = {
  1112. /* URI */ carla_strdup(tmpURI),
  1113. /* instantiate */ lv2_instantiate,
  1114. /* connect_port */ lv2_connect_port,
  1115. /* activate */ lv2_activate,
  1116. /* run */ lv2_run,
  1117. /* deactivate */ lv2_deactivate,
  1118. /* cleanup */ lv2_cleanup,
  1119. /* extension_data */ lv2_extension_data
  1120. };
  1121. DSSI_Descriptor* const dssiDesc(new DSSI_Descriptor);
  1122. std::memcpy(dssiDesc, &dssiDescTmp, sizeof(DSSI_Descriptor));
  1123. plm.dssiDescs.append(dssiDesc);
  1124. return dssiDesc;
  1125. }
  1126. CARLA_EXPORT
  1127. const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
  1128. {
  1129. carla_debug("lv2ui_descriptor(%i)", index);
  1130. static const LV2UI_Descriptor lv2UiDesc = {
  1131. /* URI */ "http://kxstudio.sf.net/carla/ui",
  1132. /* instantiate */ lv2ui_instantiate,
  1133. /* cleanup */ lv2ui_cleanup,
  1134. /* port_event */ lv2ui_port_event,
  1135. /* extension_data */ lv2ui_extension_data
  1136. };
  1137. return (index == 0) ? &lv2UiDesc : nullptr;
  1138. }
  1139. // -----------------------------------------------------------------------