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.

CarlaEngineNative.cpp 31KB

11 years ago
11 years ago
11 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /*
  2. * Carla Plugin Engine (Native)
  3. * Copyright (C) 2013 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. #ifdef BUILD_BRIDGE
  18. # error This file should not be compiled if building bridge
  19. #endif
  20. #include "CarlaEngineInternal.hpp"
  21. #include "CarlaStateUtils.hpp"
  22. #include "CarlaNative.hpp"
  23. #include <QtCore/QProcess>
  24. #include <QtCore/QTextStream>
  25. CARLA_BACKEND_START_NAMESPACE
  26. // -----------------------------------------------------------------------
  27. class CarlaEngineNativeThread : public CarlaThread
  28. {
  29. public:
  30. enum UiState {
  31. UiNone = 0,
  32. UiHide,
  33. UiShow,
  34. UiCrashed
  35. };
  36. CarlaEngineNativeThread(CarlaEngine* const engine)
  37. : fEngine(engine),
  38. fProcess(nullptr)/*,*/
  39. //fUiState(UiNone)
  40. {
  41. carla_debug("CarlaEngineNativeThread::CarlaEngineNativeThread(%p)", engine);
  42. }
  43. ~CarlaEngineNativeThread() override
  44. {
  45. //CARLA_ASSERT_INT(fUiState == UiNone, fUiState);
  46. carla_debug("CarlaEngineNativeThread::~CarlaEngineNativeThread()");
  47. if (fProcess != nullptr)
  48. {
  49. delete fProcess;
  50. fProcess = nullptr;
  51. }
  52. }
  53. #if 0
  54. void setOscData(const char* const binary)
  55. {
  56. fBinary = binary;
  57. }
  58. UiState getUiState()
  59. {
  60. const UiState state(fUiState);
  61. fUiState = UiNone;
  62. return state;
  63. }
  64. void stop()
  65. {
  66. if (fProcess == nullptr)
  67. return;
  68. fUiState = UiNone;
  69. fProcess->kill();
  70. //fProcess->close();
  71. }
  72. #endif
  73. protected:
  74. void run() override
  75. {
  76. carla_debug("CarlaEngineNativeThread::run() - binary:\"%s\"", (const char*)fBinary);
  77. #if 0
  78. if (fProcess == nullptr)
  79. {
  80. fProcess = new QProcess(nullptr);
  81. fProcess->setProcessChannelMode(QProcess::ForwardedChannels);
  82. }
  83. else if (fProcess->state() == QProcess::Running)
  84. {
  85. carla_stderr("CarlaEngineNativeThread::run() - already running, giving up...");
  86. fUiState = UiCrashed;
  87. fProcess->terminate();
  88. //kEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, kPlugin->id(), -1, 0, 0.0f, nullptr);
  89. // TODO: tell master to hide UI
  90. return;
  91. }
  92. QStringList arguments;
  93. arguments << kEngine->getOscServerPathTCP();
  94. fProcess->start((const char*)fBinary, arguments);
  95. fProcess->waitForStarted();
  96. fUiState = UiShow;
  97. fProcess->waitForFinished(-1);
  98. if (fProcess->exitCode() == 0)
  99. {
  100. // Hide
  101. fUiState = UiHide;
  102. carla_stdout("CarlaEngineNativeThread::run() - GUI closed");
  103. }
  104. else
  105. {
  106. // Kill
  107. fUiState = UiCrashed;
  108. carla_stderr("CarlaEngineNativeThread::run() - GUI crashed while running");
  109. }
  110. #endif
  111. }
  112. private:
  113. CarlaEngine* const fEngine;
  114. CarlaString fBinary;
  115. QProcess* fProcess;
  116. // UiState fUiState;
  117. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineNativeThread)
  118. };
  119. // -----------------------------------------------------------------------
  120. class CarlaEngineNative : public CarlaEngine
  121. {
  122. public:
  123. CarlaEngineNative(const NativeHostDescriptor* const host, const bool isPatchbay)
  124. : CarlaEngine(),
  125. pHost(host),
  126. fIsPatchbay(isPatchbay),
  127. fIsActive(false),
  128. fIsRunning(false),
  129. fThread(this)
  130. {
  131. carla_debug("CarlaEngineNative::CarlaEngineNative()");
  132. // set-up engine
  133. if (fIsPatchbay)
  134. {
  135. pData->options.processMode = ENGINE_PROCESS_MODE_PATCHBAY;
  136. pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
  137. pData->options.forceStereo = false;
  138. pData->options.preferPluginBridges = false;
  139. pData->options.preferUiBridges = false;
  140. init("Carla-Patchbay");
  141. }
  142. else
  143. {
  144. pData->options.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK;
  145. pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
  146. pData->options.forceStereo = true;
  147. pData->options.preferPluginBridges = false;
  148. pData->options.preferUiBridges = false;
  149. init("Carla-Rack");
  150. }
  151. // TESTING
  152. //if (! addPlugin(PLUGIN_INTERNAL, nullptr, "Ping Pong Pan", "PingPongPan"))
  153. // carla_stdout("TESTING PLUG3 ERROR:\n%s", getLastError());
  154. #if 0
  155. // set control thread binary
  156. CarlaString threadBinary(getResourceDir());
  157. threadBinary += "/../";
  158. threadBinary += "carla_control.py";
  159. fThread.setOscData(threadBinary);
  160. // if (! addPlugin(PLUGIN_INTERNAL, nullptr, "MIDI Transpose", "midiTranspose"))
  161. // carla_stdout("TESTING PLUG1 ERROR:\n%s", getLastError());
  162. // if (! addPlugin(PLUGIN_INTERNAL, nullptr, "ZynAddSubFX", "zynaddsubfx"))
  163. // carla_stdout("TESTING PLUG2 ERROR:\n%s", getLastError());
  164. // if (! addPlugin(PLUGIN_INTERNAL, nullptr, "Ping Pong Pan", "PingPongPan"))
  165. // carla_stdout("TESTING PLUG3 ERROR:\n%s", getLastError());
  166. #endif
  167. }
  168. ~CarlaEngineNative() override
  169. {
  170. CARLA_ASSERT(! fIsActive);
  171. carla_debug("CarlaEngineNative::~CarlaEngineNative()");
  172. pData->aboutToClose = true;
  173. fIsRunning = false;
  174. removeAllPlugins();
  175. runPendingRtEvents();
  176. close();
  177. }
  178. protected:
  179. // -------------------------------------
  180. // CarlaEngine virtual calls
  181. bool init(const char* const clientName) override
  182. {
  183. carla_debug("CarlaEngineNative::init(\"%s\")", clientName);
  184. pData->bufferSize = pHost->get_buffer_size(pHost->handle);
  185. pData->sampleRate = pHost->get_sample_rate(pHost->handle);
  186. fIsRunning = true;
  187. CarlaEngine::init(clientName);
  188. return true;
  189. }
  190. bool isRunning() const noexcept override
  191. {
  192. return fIsRunning;
  193. }
  194. bool isOffline() const noexcept override
  195. {
  196. return pHost->is_offline(pHost->handle);
  197. }
  198. EngineType getType() const noexcept override
  199. {
  200. return kEngineTypePlugin;
  201. }
  202. const char* getCurrentDriverName() const noexcept override
  203. {
  204. return "Plugin";
  205. }
  206. // -------------------------------------------------------------------
  207. void bufferSizeChanged(const uint32_t newBufferSize)
  208. {
  209. pData->bufferSize = newBufferSize;
  210. CarlaEngine::bufferSizeChanged(newBufferSize);
  211. }
  212. void sampleRateChanged(const double newSampleRate)
  213. {
  214. pData->sampleRate = newSampleRate;
  215. CarlaEngine::sampleRateChanged(newSampleRate);
  216. }
  217. // -------------------------------------------------------------------
  218. // Plugin parameter calls
  219. uint32_t getParameterCount() const
  220. {
  221. if (CarlaPlugin* const plugin = _getFirstPlugin())
  222. return plugin->getParameterCount();
  223. return 0;
  224. }
  225. const NativeParameter* getParameterInfo(const uint32_t index) const
  226. {
  227. if (CarlaPlugin* const plugin = _getFirstPlugin())
  228. {
  229. if (index < plugin->getParameterCount())
  230. {
  231. static NativeParameter param;
  232. static char strBufName[STR_MAX+1];
  233. static char strBufUnit[STR_MAX+1];
  234. const ParameterData& paramData(plugin->getParameterData(index));
  235. const ParameterRanges& paramRanges(plugin->getParameterRanges(index));
  236. plugin->getParameterName(index, strBufName);
  237. plugin->getParameterUnit(index, strBufUnit);
  238. unsigned int hints = 0x0;
  239. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  240. hints |= ::PARAMETER_IS_BOOLEAN;
  241. if (paramData.hints & PARAMETER_IS_INTEGER)
  242. hints |= ::PARAMETER_IS_INTEGER;
  243. if (paramData.hints & PARAMETER_IS_LOGARITHMIC)
  244. hints |= ::PARAMETER_IS_LOGARITHMIC;
  245. if (paramData.hints & PARAMETER_IS_AUTOMABLE)
  246. hints |= ::PARAMETER_IS_AUTOMABLE;
  247. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  248. hints |= ::PARAMETER_USES_SAMPLE_RATE;
  249. if (paramData.hints & PARAMETER_USES_SCALEPOINTS)
  250. hints |= ::PARAMETER_USES_SCALEPOINTS;
  251. if (paramData.hints & PARAMETER_USES_CUSTOM_TEXT)
  252. hints |= ::PARAMETER_USES_CUSTOM_TEXT;
  253. if (paramData.type == PARAMETER_INPUT || paramData.type == PARAMETER_OUTPUT)
  254. {
  255. if (paramData.hints & PARAMETER_IS_ENABLED)
  256. hints |= ::PARAMETER_IS_ENABLED;
  257. if (paramData.type == PARAMETER_OUTPUT)
  258. hints |= ::PARAMETER_IS_OUTPUT;
  259. }
  260. param.hints = static_cast<NativeParameterHints>(hints);
  261. param.name = strBufName;
  262. param.unit = strBufUnit;
  263. param.ranges.def = paramRanges.def;
  264. param.ranges.min = paramRanges.min;
  265. param.ranges.max = paramRanges.max;
  266. param.ranges.step = paramRanges.step;
  267. param.ranges.stepSmall = paramRanges.stepSmall;
  268. param.ranges.stepLarge = paramRanges.stepLarge;
  269. param.scalePointCount = 0; // TODO
  270. param.scalePoints = nullptr;
  271. return &param;
  272. }
  273. }
  274. return nullptr;
  275. }
  276. float getParameterValue(const uint32_t index) const
  277. {
  278. if (CarlaPlugin* const plugin = _getFirstPlugin())
  279. {
  280. if (index < plugin->getParameterCount())
  281. return plugin->getParameterValue(index);
  282. }
  283. return 0.0f;
  284. }
  285. const char* getParameterText(const uint32_t index, const float value) const
  286. {
  287. if (CarlaPlugin* const plugin = _getFirstPlugin())
  288. {
  289. if (index < plugin->getParameterCount())
  290. {
  291. static char strBuf[STR_MAX+1];
  292. carla_zeroChar(strBuf, STR_MAX+1);
  293. plugin->getParameterText(index, value, strBuf);
  294. return strBuf;
  295. }
  296. }
  297. return nullptr;
  298. }
  299. // -------------------------------------------------------------------
  300. // Plugin midi-program calls
  301. uint32_t getMidiProgramCount() const
  302. {
  303. if (CarlaPlugin* const plugin = _getFirstPlugin())
  304. return plugin->getMidiProgramCount();
  305. return 0;
  306. }
  307. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const
  308. {
  309. if (CarlaPlugin* const plugin = _getFirstPlugin())
  310. {
  311. if (index < plugin->getMidiProgramCount())
  312. {
  313. static NativeMidiProgram midiProg;
  314. {
  315. const MidiProgramData& midiProgData(plugin->getMidiProgramData(index));
  316. midiProg.bank = midiProgData.bank;
  317. midiProg.program = midiProgData.program;
  318. midiProg.name = midiProgData.name;
  319. }
  320. return &midiProg;
  321. }
  322. }
  323. return nullptr;
  324. }
  325. // -------------------------------------------------------------------
  326. // Plugin state calls
  327. void setParameterValue(const uint32_t index, const float value)
  328. {
  329. if (CarlaPlugin* const plugin = _getFirstPlugin())
  330. {
  331. if (index < plugin->getParameterCount())
  332. plugin->setParameterValue(index, value, false, false, false);
  333. }
  334. }
  335. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program)
  336. {
  337. if (CarlaPlugin* const plugin = _getFirstPlugin())
  338. plugin->setMidiProgramById(bank, program, false, false, false);
  339. }
  340. // -------------------------------------------------------------------
  341. // Plugin process calls
  342. void activate()
  343. {
  344. #if 0
  345. for (uint32_t i=0; i < pData->curPluginCount; ++i)
  346. {
  347. CarlaPlugin* const plugin(pData->plugins[i].plugin);
  348. if (plugin == nullptr || ! plugin->isEnabled())
  349. continue;
  350. plugin->setActive(true, true, false);
  351. }
  352. #endif
  353. fIsActive = true;
  354. }
  355. void deactivate()
  356. {
  357. fIsActive = false;
  358. #if 0
  359. for (uint32_t i=0; i < pData->curPluginCount; ++i)
  360. {
  361. CarlaPlugin* const plugin(pData->plugins[i].plugin);
  362. if (plugin == nullptr || ! plugin->isEnabled())
  363. continue;
  364. plugin->setActive(false, true, false);
  365. }
  366. #endif
  367. // just in case
  368. runPendingRtEvents();
  369. }
  370. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount)
  371. {
  372. if (pData->curPluginCount == 0 && ! fIsPatchbay)
  373. {
  374. FLOAT_COPY(outBuffer[0], inBuffer[0], frames);
  375. FLOAT_COPY(outBuffer[1], inBuffer[1], frames);
  376. return runPendingRtEvents();;
  377. }
  378. // ---------------------------------------------------------------
  379. // Time Info
  380. const NativeTimeInfo* const timeInfo(pHost->get_time_info(pHost->handle));
  381. pData->timeInfo.playing = timeInfo->playing;
  382. pData->timeInfo.frame = timeInfo->frame;
  383. pData->timeInfo.usecs = timeInfo->usecs;
  384. pData->timeInfo.valid = 0x0;
  385. if (timeInfo->bbt.valid)
  386. {
  387. pData->timeInfo.valid |= EngineTimeInfo::kValidBBT;
  388. pData->timeInfo.bbt.bar = timeInfo->bbt.bar;
  389. pData->timeInfo.bbt.beat = timeInfo->bbt.beat;
  390. pData->timeInfo.bbt.tick = timeInfo->bbt.tick;
  391. pData->timeInfo.bbt.barStartTick = timeInfo->bbt.barStartTick;
  392. pData->timeInfo.bbt.beatsPerBar = timeInfo->bbt.beatsPerBar;
  393. pData->timeInfo.bbt.beatType = timeInfo->bbt.beatType;
  394. pData->timeInfo.bbt.ticksPerBeat = timeInfo->bbt.ticksPerBeat;
  395. pData->timeInfo.bbt.beatsPerMinute = timeInfo->bbt.beatsPerMinute;
  396. }
  397. // ---------------------------------------------------------------
  398. // initialize events
  399. carla_zeroStruct<EngineEvent>(pData->bufEvents.in, kEngineMaxInternalEventCount);
  400. carla_zeroStruct<EngineEvent>(pData->bufEvents.out, kEngineMaxInternalEventCount);
  401. // ---------------------------------------------------------------
  402. // events input (before processing)
  403. {
  404. uint32_t engineEventIndex = 0;
  405. for (uint32_t i=0; i < midiEventCount && engineEventIndex < kEngineMaxInternalEventCount; ++i)
  406. {
  407. const NativeMidiEvent& midiEvent(midiEvents[i]);
  408. EngineEvent& engineEvent(pData->bufEvents.in[engineEventIndex++]);
  409. engineEvent.time = midiEvent.time;
  410. engineEvent.fillFromMidiData(midiEvent.size, midiEvent.data);
  411. if (engineEventIndex >= kEngineMaxInternalEventCount)
  412. break;
  413. }
  414. }
  415. if (fIsPatchbay)
  416. {
  417. // -----------------------------------------------------------
  418. // create audio buffers
  419. //float* inBuf[2] = { inBuffer[0], inBuffer[1] };
  420. //float* outBuf[2] = { outBuffer[0], outBuffer[1] };
  421. //uint32_t bufCount[2] = { 2, 2 };
  422. // -----------------------------------------------------------
  423. // process
  424. //pData->processPatchbay(inBuf, outBuf, bufCount, frames, isOffline());
  425. }
  426. else
  427. {
  428. // -----------------------------------------------------------
  429. // create audio buffers
  430. float* inBuf[2] = { inBuffer[0], inBuffer[1] };
  431. float* outBuf[2] = { outBuffer[0], outBuffer[1] };
  432. // -----------------------------------------------------------
  433. // process
  434. pData->processRack(inBuf, outBuf, frames, isOffline());
  435. }
  436. // ---------------------------------------------------------------
  437. // events output (after processing)
  438. carla_zeroStruct<EngineEvent>(pData->bufEvents.in, kEngineMaxInternalEventCount);
  439. {
  440. NativeMidiEvent midiEvent;
  441. for (uint32_t i=0; i < kEngineMaxInternalEventCount; ++i)
  442. {
  443. const EngineEvent& engineEvent(pData->bufEvents.out[i]);
  444. if (engineEvent.type == kEngineEventTypeNull)
  445. break;
  446. midiEvent.time = engineEvent.time;
  447. if (engineEvent.type == CarlaBackend::kEngineEventTypeControl)
  448. {
  449. midiEvent.port = 0;
  450. engineEvent.ctrl.dumpToMidiData(engineEvent.channel, midiEvent.size, midiEvent.data);
  451. }
  452. else if (engineEvent.type == kEngineEventTypeMidi)
  453. {
  454. if (engineEvent.midi.size > 4 || engineEvent.midi.dataExt != nullptr)
  455. continue;
  456. midiEvent.port = engineEvent.midi.port;
  457. midiEvent.size = engineEvent.midi.size;
  458. midiEvent.data[0] = static_cast<uint8_t>(engineEvent.midi.data[0] + engineEvent.channel);
  459. for (uint8_t j=1; j < midiEvent.size; ++j)
  460. midiEvent.data[j] = engineEvent.midi.data[j];
  461. }
  462. else
  463. {
  464. carla_stderr("Unknown event type...");
  465. continue;
  466. }
  467. pHost->write_midi_event(pHost->handle, &midiEvent);
  468. }
  469. }
  470. runPendingRtEvents();
  471. }
  472. #if 0
  473. // -------------------------------------------------------------------
  474. // Plugin UI calls
  475. void uiShow(const bool show) override
  476. {
  477. if (show)
  478. {
  479. fThread.start();
  480. }
  481. else
  482. {
  483. #if 0
  484. for (uint32_t i=0; i < pData->curPluginCount; ++i)
  485. {
  486. CarlaPlugin* const plugin(pData->plugins[i].plugin);
  487. if (plugin == nullptr || ! plugin->enabled())
  488. continue;
  489. plugin->showGui(false);
  490. }
  491. #endif
  492. fThread.stop();
  493. }
  494. }
  495. void uiIdle() override
  496. {
  497. CarlaEngine::idle();
  498. switch(fThread.getUiState())
  499. {
  500. case CarlaEngineNativeThread::UiNone:
  501. case CarlaEngineNativeThread::UiShow:
  502. break;
  503. case CarlaEngineNativeThread::UiCrashed:
  504. hostUiUnavailable();
  505. break;
  506. case CarlaEngineNativeThread::UiHide:
  507. uiClosed();
  508. break;
  509. }
  510. }
  511. #endif
  512. #if 0
  513. void uiSetParameterValue(const uint32_t index, const float value) override
  514. {
  515. if (index >= getParameterCount())
  516. return;
  517. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  518. if (plugin == nullptr || ! plugin->isEnabled())
  519. return;
  520. plugin->uiParameterChange(index, value);
  521. }
  522. void uiSetMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  523. {
  524. return;
  525. // TODO
  526. // unused
  527. (void)channel;
  528. (void)bank;
  529. (void)program;
  530. }
  531. #endif
  532. // -------------------------------------------------------------------
  533. // Plugin state calls
  534. char* getState() const
  535. {
  536. QString string;
  537. QTextStream out(&string);
  538. out << "<?xml version='1.0' encoding='UTF-8'?>\n";
  539. out << "<!DOCTYPE CARLA-PROJECT>\n";
  540. out << "<CARLA-PROJECT VERSION='2.0'>\n";
  541. bool firstPlugin = true;
  542. char strBuf[STR_MAX+1];
  543. for (unsigned int i=0; i < pData->curPluginCount; ++i)
  544. {
  545. CarlaPlugin* const plugin(pData->plugins[i].plugin);
  546. if (plugin != nullptr && plugin->isEnabled())
  547. {
  548. if (! firstPlugin)
  549. out << "\n";
  550. strBuf[0] = '\0';
  551. plugin->getRealName(strBuf);
  552. if (strBuf[0] != '\0')
  553. out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true));
  554. QString content;
  555. fillXmlStringFromSaveState(content, plugin->getSaveState());
  556. out << " <Plugin>\n";
  557. out << content;
  558. out << " </Plugin>\n";
  559. firstPlugin = false;
  560. }
  561. }
  562. out << "</CARLA-PROJECT>\n";
  563. return strdup(string.toUtf8().constData());
  564. }
  565. void setState(const char* const data)
  566. {
  567. QDomDocument xml;
  568. xml.setContent(QString(data));
  569. QDomNode xmlNode(xml.documentElement());
  570. if (xmlNode.toElement().tagName().compare("carla-project", Qt::CaseInsensitive) != 0)
  571. {
  572. carla_stderr2("Not a valid Carla project");
  573. return;
  574. }
  575. bool pluginsAdded = false;
  576. for (QDomNode node = xmlNode.firstChild(); ! node.isNull(); node = node.nextSibling())
  577. {
  578. if (node.toElement().tagName().compare("plugin", Qt::CaseInsensitive) == 0)
  579. {
  580. SaveState saveState;
  581. fillSaveStateFromXmlNode(saveState, node);
  582. CARLA_SAFE_ASSERT_CONTINUE(saveState.type != nullptr)
  583. const void* extraStuff = nullptr;
  584. // check if using GIG, SF2 or SFZ 16outs
  585. static const char kUse16OutsSuffix[] = " (16 outs)";
  586. if (CarlaString(saveState.label).endsWith(kUse16OutsSuffix))
  587. {
  588. if (std::strcmp(saveState.type, "GIG") == 0 || std::strcmp(saveState.type, "SF2") == 0 || std::strcmp(saveState.type, "SFZ") == 0)
  589. extraStuff = (void*)0x1; // non-null
  590. }
  591. // TODO - proper find&load plugins
  592. if (addPlugin(getPluginTypeFromString(saveState.type), saveState.binary, saveState.name, saveState.label, extraStuff))
  593. {
  594. if (CarlaPlugin* const plugin = getPlugin(pData->curPluginCount-1))
  595. plugin->loadSaveState(saveState);
  596. }
  597. pluginsAdded = true;
  598. }
  599. }
  600. if (pluginsAdded)
  601. pHost->dispatcher(pHost->handle, HOST_OPCODE_RELOAD_ALL, 0, 0, nullptr, 0.0f);
  602. }
  603. // -------------------------------------------------------------------
  604. public:
  605. #define handlePtr ((CarlaEngineNative*)handle)
  606. static NativePluginHandle _instantiateRack(const NativeHostDescriptor* host)
  607. {
  608. return new CarlaEngineNative(host, false);
  609. }
  610. #ifdef HAVE_JUCE
  611. static NativePluginHandle _instantiatePatchbay(const NativeHostDescriptor* host)
  612. {
  613. return new CarlaEngineNative(host, true);
  614. }
  615. #endif
  616. static void _cleanup(NativePluginHandle handle)
  617. {
  618. delete handlePtr;
  619. }
  620. static uint32_t _get_parameter_count(NativePluginHandle handle)
  621. {
  622. return handlePtr->getParameterCount();
  623. }
  624. static const NativeParameter* _get_parameter_info(NativePluginHandle handle, uint32_t index)
  625. {
  626. return handlePtr->getParameterInfo(index);
  627. }
  628. static float _get_parameter_value(NativePluginHandle handle, uint32_t index)
  629. {
  630. return handlePtr->getParameterValue(index);
  631. }
  632. static const char* _get_parameter_text(NativePluginHandle handle, uint32_t index, float value)
  633. {
  634. return handlePtr->getParameterText(index, value);
  635. }
  636. static uint32_t _get_midi_program_count(NativePluginHandle handle)
  637. {
  638. return handlePtr->getMidiProgramCount();
  639. }
  640. static const NativeMidiProgram* _get_midi_program_info(NativePluginHandle handle, uint32_t index)
  641. {
  642. return handlePtr->getMidiProgramInfo(index);
  643. }
  644. static void _set_parameter_value(NativePluginHandle handle, uint32_t index, float value)
  645. {
  646. handlePtr->setParameterValue(index, value);
  647. }
  648. static void _set_midi_program(NativePluginHandle handle, uint8_t channel, uint32_t bank, uint32_t program)
  649. {
  650. handlePtr->setMidiProgram(channel, bank, program);
  651. }
  652. static void _activate(NativePluginHandle handle)
  653. {
  654. handlePtr->activate();
  655. }
  656. static void _deactivate(NativePluginHandle handle)
  657. {
  658. handlePtr->deactivate();
  659. }
  660. static void _process(NativePluginHandle handle, float** inBuffer, float** outBuffer, const uint32_t frames, const NativeMidiEvent* midiEvents, uint32_t midiEventCount)
  661. {
  662. handlePtr->process(inBuffer, outBuffer, frames, midiEvents, midiEventCount);
  663. }
  664. static char* _get_state(NativePluginHandle handle)
  665. {
  666. return handlePtr->getState();
  667. }
  668. static void _set_state(NativePluginHandle handle, const char* data)
  669. {
  670. handlePtr->setState(data);
  671. }
  672. static intptr_t _dispatcher(NativePluginHandle handle, NativePluginDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
  673. {
  674. switch(opcode)
  675. {
  676. case PLUGIN_OPCODE_NULL:
  677. return 0;
  678. case PLUGIN_OPCODE_BUFFER_SIZE_CHANGED:
  679. CARLA_SAFE_ASSERT_RETURN(value > 0, 0);
  680. handlePtr->bufferSizeChanged(static_cast<uint32_t>(value));
  681. return 0;
  682. case PLUGIN_OPCODE_SAMPLE_RATE_CHANGED:
  683. handlePtr->sampleRateChanged(static_cast<double>(opt));
  684. return 0;
  685. case PLUGIN_OPCODE_OFFLINE_CHANGED:
  686. handlePtr->offlineModeChanged(value != 0);
  687. return 0;
  688. case PLUGIN_OPCODE_UI_NAME_CHANGED:
  689. //handlePtr->uiNameChanged(static_cast<const char*>(ptr));
  690. return 0;
  691. }
  692. return 0;
  693. // unused
  694. (void)index;
  695. (void)ptr;
  696. }
  697. #undef handlePtr
  698. private:
  699. const NativeHostDescriptor* const pHost;
  700. const bool fIsPatchbay; // rack if false
  701. bool fIsActive, fIsRunning;
  702. CarlaEngineNativeThread fThread;
  703. CarlaPlugin* _getFirstPlugin() const noexcept
  704. {
  705. if (pData->curPluginCount == 0 || pData->plugins == nullptr)
  706. return nullptr;
  707. CarlaPlugin* const plugin(pData->plugins[0].plugin);
  708. if (plugin == nullptr || ! plugin->isEnabled())
  709. return nullptr;
  710. return pData->plugins[0].plugin;
  711. }
  712. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineNative)
  713. };
  714. // -----------------------------------------------------------------------
  715. static const NativePluginDescriptor carlaRackDesc = {
  716. /* category */ ::PLUGIN_CATEGORY_OTHER,
  717. /* hints */ static_cast<NativePluginHints>(::PLUGIN_IS_SYNTH|::PLUGIN_HAS_UI|::PLUGIN_NEEDS_FIXED_BUFFERS|::PLUGIN_NEEDS_SINGLE_THREAD|::PLUGIN_USES_STATE|::PLUGIN_USES_TIME),
  718. /* supports */ static_cast<NativePluginSupports>(::PLUGIN_SUPPORTS_EVERYTHING),
  719. /* audioIns */ 2,
  720. /* audioOuts */ 2,
  721. /* midiIns */ 1,
  722. /* midiOuts */ 1,
  723. /* paramIns */ 0,
  724. /* paramOuts */ 0,
  725. /* name */ "Carla-Rack",
  726. /* label */ "carla-rack",
  727. /* maker */ "falkTX",
  728. /* copyright */ "GNU GPL v2+",
  729. CarlaEngineNative::_instantiateRack,
  730. CarlaEngineNative::_cleanup,
  731. CarlaEngineNative::_get_parameter_count,
  732. CarlaEngineNative::_get_parameter_info,
  733. CarlaEngineNative::_get_parameter_value,
  734. CarlaEngineNative::_get_parameter_text,
  735. CarlaEngineNative::_get_midi_program_count,
  736. CarlaEngineNative::_get_midi_program_info,
  737. CarlaEngineNative::_set_parameter_value,
  738. CarlaEngineNative::_set_midi_program,
  739. /* _set_custom_data */ nullptr,
  740. /* _ui_show */ nullptr,
  741. /* _ui_idle */ nullptr,
  742. /* _ui_set_parameter_value */ nullptr,
  743. /* _ui_set_midi_program */ nullptr,
  744. /* _ui_set_custom_data */ nullptr,
  745. CarlaEngineNative::_activate,
  746. CarlaEngineNative::_deactivate,
  747. CarlaEngineNative::_process,
  748. CarlaEngineNative::_get_state,
  749. CarlaEngineNative::_set_state,
  750. CarlaEngineNative::_dispatcher
  751. };
  752. #ifdef HAVE_JUCE
  753. static const NativePluginDescriptor carlaPatchbayDesc = {
  754. /* category */ ::PLUGIN_CATEGORY_OTHER,
  755. /* hints */ static_cast<NativePluginHints>(::PLUGIN_IS_SYNTH|::PLUGIN_HAS_UI|::PLUGIN_NEEDS_FIXED_BUFFERS|::PLUGIN_NEEDS_SINGLE_THREAD|::PLUGIN_USES_STATE|::PLUGIN_USES_TIME),
  756. /* supports */ static_cast<NativePluginSupports>(::PLUGIN_SUPPORTS_EVERYTHING),
  757. /* audioIns */ 2,
  758. /* audioOuts */ 2,
  759. /* midiIns */ 1,
  760. /* midiOuts */ 1,
  761. /* paramIns */ 0,
  762. /* paramOuts */ 0,
  763. /* name */ "Carla-Patchbay",
  764. /* label */ "carla-patchbay",
  765. /* maker */ "falkTX",
  766. /* copyright */ "GNU GPL v2+",
  767. CarlaEngineNative::_instantiatePatchbay,
  768. CarlaEngineNative::_cleanup,
  769. CarlaEngineNative::_get_parameter_count,
  770. CarlaEngineNative::_get_parameter_info,
  771. CarlaEngineNative::_get_parameter_value,
  772. CarlaEngineNative::_get_parameter_text,
  773. CarlaEngineNative::_get_midi_program_count,
  774. CarlaEngineNative::_get_midi_program_info,
  775. CarlaEngineNative::_set_parameter_value,
  776. CarlaEngineNative::_set_midi_program,
  777. /* _set_custom_data */ nullptr,
  778. /* _ui_show */ nullptr,
  779. /* _ui_idle */ nullptr,
  780. /* _ui_set_parameter_value */ nullptr,
  781. /* _ui_set_midi_program */ nullptr,
  782. /* _ui_set_custom_data */ nullptr,
  783. CarlaEngineNative::_activate,
  784. CarlaEngineNative::_deactivate,
  785. CarlaEngineNative::_process,
  786. CarlaEngineNative::_get_state,
  787. CarlaEngineNative::_set_state,
  788. CarlaEngineNative::_dispatcher
  789. };
  790. #endif
  791. // -----------------------------------------------------------------------
  792. CARLA_BACKEND_END_NAMESPACE
  793. CARLA_EXPORT
  794. void carla_register_native_plugin_carla()
  795. {
  796. CARLA_BACKEND_USE_NAMESPACE
  797. carla_register_native_plugin(&carlaRackDesc);
  798. #ifdef HAVE_JUCE
  799. carla_register_native_plugin(&carlaPatchbayDesc);
  800. #endif
  801. }
  802. // -----------------------------------------------------------------------
  803. // Extra stuff for linking purposes
  804. #ifdef CARLA_PLUGIN_EXPORT
  805. CARLA_BACKEND_START_NAMESPACE
  806. CarlaEngine* CarlaEngine::newJack() { return nullptr; }
  807. CarlaEngine* CarlaEngine::newRtAudio(const AudioApi) { return nullptr; }
  808. unsigned int CarlaEngine::getRtAudioApiCount() { return 0; }
  809. const char* CarlaEngine::getRtAudioApiName(const unsigned int) { return nullptr; }
  810. const char* const* CarlaEngine::getRtAudioApiDeviceNames(const unsigned int) { return nullptr; }
  811. const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned int, const char* const) { return nullptr; }
  812. # ifdef HAVE_JUCE
  813. CarlaEngine* CarlaEngine::newJuce(const AudioApi) { return nullptr; }
  814. unsigned int CarlaEngine::getJuceApiCount() { return 0; }
  815. const char* CarlaEngine::getJuceApiName(const unsigned int) { return nullptr; }
  816. const char* const* CarlaEngine::getJuceApiDeviceNames(const unsigned int) { return nullptr; }
  817. const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const unsigned int, const char* const) { return nullptr; }
  818. # endif
  819. CARLA_BACKEND_END_NAMESPACE
  820. #endif
  821. // -----------------------------------------------------------------------