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.

888 lines
26KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2015 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 "CarlaNativeExtUI.hpp"
  18. #include "CarlaMIDI.h"
  19. #include "CarlaThread.hpp"
  20. #include "LinkedList.hpp"
  21. #include "CarlaMathUtils.hpp"
  22. #include "DSP/FFTwrapper.h"
  23. #include "Misc/Master.h"
  24. #include "Misc/MiddleWare.h"
  25. #include "Misc/Part.h"
  26. #include "Misc/Util.h"
  27. #ifdef HAVE_ZYN_UI_DEPS
  28. # include "UI/Connection.h"
  29. #endif
  30. #include <ctime>
  31. #include <set>
  32. #include <string>
  33. #include "juce_audio_basics.h"
  34. using juce::roundToIntAccurate;
  35. using juce::FloatVectorOperations;
  36. // -----------------------------------------------------------------------
  37. #ifdef HAVE_ZYN_UI_DEPS
  38. namespace GUI {
  39. Fl_Osc_Interface* genOscInterface(MiddleWare*)
  40. {
  41. return nullptr;
  42. }
  43. void raiseUi(ui_handle_t, const char *)
  44. {
  45. }
  46. #if 0
  47. ui_handle_t createUi(Fl_Osc_Interface*, void *exit)
  48. {
  49. return nullptr;
  50. }
  51. void destroyUi(ui_handle_t)
  52. {
  53. }
  54. void raiseUi(ui_handle_t, const char *, const char *, ...)
  55. {
  56. }
  57. void tickUi(ui_handle_t)
  58. {
  59. //usleep(100000);
  60. }
  61. #endif
  62. };
  63. #endif
  64. // -----------------------------------------------------------------------
  65. class ZynAddSubFxPrograms
  66. {
  67. public:
  68. ZynAddSubFxPrograms() noexcept
  69. : fInitiated(false),
  70. #ifdef CARLA_PROPER_CPP11_SUPPORT
  71. fRetProgram({0, 0, nullptr}),
  72. #endif
  73. fPrograms() {}
  74. ~ZynAddSubFxPrograms() noexcept
  75. {
  76. if (! fInitiated)
  77. return;
  78. for (LinkedList<const ProgramInfo*>::Itenerator it = fPrograms.begin(); it.valid(); it.next())
  79. {
  80. const ProgramInfo* const& pInfo(it.getValue(nullptr));
  81. delete pInfo;
  82. }
  83. fPrograms.clear();
  84. }
  85. void initIfNeeded()
  86. {
  87. if (fInitiated)
  88. return;
  89. fInitiated = true;
  90. fPrograms.append(new ProgramInfo(0, 0, "default", ""));
  91. SYNTH_T synth;
  92. Master master(synth);
  93. // refresh banks
  94. master.bank.rescanforbanks();
  95. for (std::size_t i=0, size=master.bank.banks.size(); i<size; ++i)
  96. {
  97. const std::string dir(master.bank.banks[i].dir);
  98. if (dir.empty())
  99. continue;
  100. master.bank.loadbank(dir);
  101. for (uint ninstrument = 0; ninstrument < BANK_SIZE; ++ninstrument)
  102. {
  103. const Bank::ins_t& instrument(master.bank.ins[ninstrument]);
  104. if (instrument.name.empty() || instrument.name[0] == ' ')
  105. continue;
  106. fPrograms.append(new ProgramInfo(i+1, ninstrument, instrument.name.c_str(), instrument.filename.c_str()));
  107. }
  108. }
  109. }
  110. uint32_t getNativeMidiProgramCount() const noexcept
  111. {
  112. return static_cast<uint32_t>(fPrograms.count());
  113. }
  114. const NativeMidiProgram* getNativeMidiProgramInfo(const uint32_t index) const noexcept
  115. {
  116. if (index >= fPrograms.count())
  117. return nullptr;
  118. const ProgramInfo* const pInfo(fPrograms.getAt(index, nullptr));
  119. CARLA_SAFE_ASSERT_RETURN(pInfo != nullptr, nullptr);
  120. fRetProgram.bank = pInfo->bank;
  121. fRetProgram.program = pInfo->prog;
  122. fRetProgram.name = pInfo->name;
  123. return &fRetProgram;
  124. }
  125. const char* getZynProgramFilename(const uint32_t bank, const uint32_t program) const noexcept
  126. {
  127. for (LinkedList<const ProgramInfo*>::Itenerator it = fPrograms.begin(); it.valid(); it.next())
  128. {
  129. const ProgramInfo* const& pInfo(it.getValue(nullptr));
  130. if (pInfo->bank != bank)
  131. continue;
  132. if (pInfo->prog != program)
  133. continue;
  134. return pInfo->filename;
  135. }
  136. return nullptr;
  137. }
  138. private:
  139. struct ProgramInfo {
  140. uint32_t bank;
  141. uint32_t prog;
  142. const char* name;
  143. const char* filename;
  144. ProgramInfo(uint32_t b, uint32_t p, const char* n, const char* fn) noexcept
  145. : bank(b),
  146. prog(p),
  147. name(carla_strdup_safe(n)),
  148. filename(carla_strdup_safe(fn)) {}
  149. ~ProgramInfo() noexcept
  150. {
  151. if (name != nullptr)
  152. {
  153. delete[] name;
  154. name = nullptr;
  155. }
  156. if (filename != nullptr)
  157. {
  158. delete[] filename;
  159. filename = nullptr;
  160. }
  161. }
  162. #ifdef CARLA_PROPER_CPP11_SUPPORT
  163. ProgramInfo() = delete;
  164. ProgramInfo(ProgramInfo&) = delete;
  165. ProgramInfo(const ProgramInfo&) = delete;
  166. ProgramInfo& operator=(ProgramInfo&);
  167. ProgramInfo& operator=(const ProgramInfo&);
  168. #endif
  169. };
  170. bool fInitiated;
  171. mutable NativeMidiProgram fRetProgram;
  172. LinkedList<const ProgramInfo*> fPrograms;
  173. CARLA_PREVENT_HEAP_ALLOCATION
  174. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxPrograms)
  175. };
  176. static ZynAddSubFxPrograms sPrograms;
  177. // -----------------------------------------------------------------------
  178. class ZynAddSubFxPlugin : public NativePluginAndUiClass
  179. {
  180. public:
  181. enum Parameters {
  182. kParamPart01Enabled ,
  183. kParamPart16Enabled = kParamPart01Enabled + 15,
  184. kParamPart01Volume,
  185. kParamPart16Volume = kParamPart01Volume + 15,
  186. kParamPart01Panning,
  187. kParamPart16Panning = kParamPart01Panning + 15,
  188. kParamFilterCutoff, // Filter Frequency
  189. kParamFilterQ, // Filter Resonance
  190. kParamBandwidth, // Bandwidth
  191. kParamModAmp, // FM Gain
  192. kParamResCenter, // Resonance center frequency
  193. kParamResBandwidth, // Resonance bandwidth
  194. kParamCount
  195. };
  196. ZynAddSubFxPlugin(const NativeHostDescriptor* const host)
  197. : NativePluginAndUiClass(host, "zynaddsubfx-ui"),
  198. fMiddleWare(nullptr),
  199. fMaster(nullptr),
  200. fSynth(),
  201. fIsActive(false),
  202. fMutex(),
  203. leakDetector_ZynAddSubFxPlugin()
  204. {
  205. sPrograms.initIfNeeded();
  206. // init parameters to default
  207. fParameters[kParamPart01Enabled] = 1.0f;
  208. for (int i=kParamPart16Enabled+1; --i>kParamPart01Enabled;)
  209. fParameters[i] = 0.0f;
  210. for (int i=kParamPart16Volume+1; --i>=kParamPart01Volume;)
  211. fParameters[i] = 100.0f;
  212. for (int i=kParamPart16Panning+1; --i>=kParamPart01Panning;)
  213. fParameters[i] = 64.0f;
  214. fParameters[kParamFilterCutoff] = 64.0f;
  215. fParameters[kParamFilterQ] = 64.0f;
  216. fParameters[kParamBandwidth] = 64.0f;
  217. fParameters[kParamModAmp] = 127.0f;
  218. fParameters[kParamResCenter] = 64.0f;
  219. fParameters[kParamResBandwidth] = 64.0f;
  220. fSynth.buffersize = static_cast<int>(getBufferSize());
  221. fSynth.samplerate = static_cast<uint>(getSampleRate());
  222. //if (fSynth.buffersize > 32)
  223. // fSynth.buffersize = 32;
  224. fSynth.alias();
  225. _initMaster();
  226. _setMasterParameters();
  227. }
  228. ~ZynAddSubFxPlugin() override
  229. {
  230. _deleteMaster();
  231. }
  232. protected:
  233. // -------------------------------------------------------------------
  234. // Plugin parameter calls
  235. uint32_t getParameterCount() const final
  236. {
  237. return kParamCount;
  238. }
  239. const NativeParameter* getParameterInfo(const uint32_t index) const override
  240. {
  241. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
  242. static NativeParameter param;
  243. int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE;
  244. param.name = nullptr;
  245. param.unit = nullptr;
  246. param.ranges.def = 64.0f;
  247. param.ranges.min = 0.0f;
  248. param.ranges.max = 127.0f;
  249. param.ranges.step = 1.0f;
  250. param.ranges.stepSmall = 1.0f;
  251. param.ranges.stepLarge = 20.0f;
  252. param.scalePointCount = 0;
  253. param.scalePoints = nullptr;
  254. if (index <= kParamPart16Enabled)
  255. {
  256. hints |= NATIVE_PARAMETER_IS_BOOLEAN;
  257. param.ranges.def = 0.0f;
  258. param.ranges.min = 0.0f;
  259. param.ranges.max = 1.0f;
  260. param.ranges.step = 1.0f;
  261. param.ranges.stepSmall = 1.0f;
  262. param.ranges.stepLarge = 1.0f;
  263. #define PARAM_PART_ENABLE_DESC(N) \
  264. case kParamPart01Enabled + N - 1: \
  265. param.name = "Part " #N " Enabled"; break;
  266. switch (index)
  267. {
  268. case kParamPart01Enabled:
  269. param.name = "Part 01 Enabled";
  270. param.ranges.def = 1.0f;
  271. break;
  272. PARAM_PART_ENABLE_DESC( 2)
  273. PARAM_PART_ENABLE_DESC( 3)
  274. PARAM_PART_ENABLE_DESC( 4)
  275. PARAM_PART_ENABLE_DESC( 5)
  276. PARAM_PART_ENABLE_DESC( 6)
  277. PARAM_PART_ENABLE_DESC( 7)
  278. PARAM_PART_ENABLE_DESC( 8)
  279. PARAM_PART_ENABLE_DESC( 9)
  280. PARAM_PART_ENABLE_DESC(10)
  281. PARAM_PART_ENABLE_DESC(11)
  282. PARAM_PART_ENABLE_DESC(12)
  283. PARAM_PART_ENABLE_DESC(13)
  284. PARAM_PART_ENABLE_DESC(14)
  285. PARAM_PART_ENABLE_DESC(15)
  286. PARAM_PART_ENABLE_DESC(16)
  287. }
  288. #undef PARAM_PART_ENABLE_DESC
  289. }
  290. else if (index <= kParamPart16Volume)
  291. {
  292. hints |= NATIVE_PARAMETER_IS_INTEGER;
  293. param.ranges.def = 100.0f;
  294. #define PARAM_PART_ENABLE_DESC(N) \
  295. case kParamPart01Volume + N - 1: \
  296. param.name = "Part " #N " Volume"; break;
  297. switch (index)
  298. {
  299. PARAM_PART_ENABLE_DESC( 1)
  300. PARAM_PART_ENABLE_DESC( 2)
  301. PARAM_PART_ENABLE_DESC( 3)
  302. PARAM_PART_ENABLE_DESC( 4)
  303. PARAM_PART_ENABLE_DESC( 5)
  304. PARAM_PART_ENABLE_DESC( 6)
  305. PARAM_PART_ENABLE_DESC( 7)
  306. PARAM_PART_ENABLE_DESC( 8)
  307. PARAM_PART_ENABLE_DESC( 9)
  308. PARAM_PART_ENABLE_DESC(10)
  309. PARAM_PART_ENABLE_DESC(11)
  310. PARAM_PART_ENABLE_DESC(12)
  311. PARAM_PART_ENABLE_DESC(13)
  312. PARAM_PART_ENABLE_DESC(14)
  313. PARAM_PART_ENABLE_DESC(15)
  314. PARAM_PART_ENABLE_DESC(16)
  315. }
  316. #undef PARAM_PART_ENABLE_DESC
  317. }
  318. else if (index <= kParamPart16Panning)
  319. {
  320. hints |= NATIVE_PARAMETER_IS_INTEGER;
  321. #define PARAM_PART_ENABLE_DESC(N) \
  322. case kParamPart01Panning + N - 1: \
  323. param.name = "Part " #N " Panning"; break;
  324. switch (index)
  325. {
  326. PARAM_PART_ENABLE_DESC( 1)
  327. PARAM_PART_ENABLE_DESC( 2)
  328. PARAM_PART_ENABLE_DESC( 3)
  329. PARAM_PART_ENABLE_DESC( 4)
  330. PARAM_PART_ENABLE_DESC( 5)
  331. PARAM_PART_ENABLE_DESC( 6)
  332. PARAM_PART_ENABLE_DESC( 7)
  333. PARAM_PART_ENABLE_DESC( 8)
  334. PARAM_PART_ENABLE_DESC( 9)
  335. PARAM_PART_ENABLE_DESC(10)
  336. PARAM_PART_ENABLE_DESC(11)
  337. PARAM_PART_ENABLE_DESC(12)
  338. PARAM_PART_ENABLE_DESC(13)
  339. PARAM_PART_ENABLE_DESC(14)
  340. PARAM_PART_ENABLE_DESC(15)
  341. PARAM_PART_ENABLE_DESC(16)
  342. }
  343. #undef PARAM_PART_ENABLE_DESC
  344. }
  345. else if (index <= kParamResBandwidth)
  346. {
  347. hints |= NATIVE_PARAMETER_IS_INTEGER;
  348. switch (index)
  349. {
  350. case kParamFilterCutoff:
  351. param.name = "Filter Cutoff";
  352. break;
  353. case kParamFilterQ:
  354. param.name = "Filter Q";
  355. break;
  356. case kParamBandwidth:
  357. param.name = "Bandwidth";
  358. break;
  359. case kParamModAmp:
  360. param.name = "FM Gain";
  361. param.ranges.def = 127.0f;
  362. break;
  363. case kParamResCenter:
  364. param.name = "Res Center Freq";
  365. break;
  366. case kParamResBandwidth:
  367. param.name = "Res Bandwidth";
  368. break;
  369. }
  370. }
  371. param.hints = static_cast<NativeParameterHints>(hints);
  372. return &param;
  373. }
  374. float getParameterValue(const uint32_t index) const final
  375. {
  376. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
  377. return fParameters[index];
  378. }
  379. // -------------------------------------------------------------------
  380. // Plugin midi-program calls
  381. uint32_t getMidiProgramCount() const noexcept override
  382. {
  383. return sPrograms.getNativeMidiProgramCount();
  384. }
  385. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const noexcept override
  386. {
  387. return sPrograms.getNativeMidiProgramInfo(index);
  388. }
  389. // -------------------------------------------------------------------
  390. // Plugin state calls
  391. void setParameterValue(const uint32_t index, const float value) final
  392. {
  393. CARLA_SAFE_ASSERT_RETURN(index < kParamCount,);
  394. if (index <= kParamPart16Enabled)
  395. {
  396. fParameters[index] = (value >= 0.5f) ? 1.0f : 0.0f;
  397. char msg[24];
  398. std::sprintf(msg, "/part%i/Penabled", index-kParamPart01Enabled);
  399. fMiddleWare->transmitMsg(msg, (value >= 0.5f) ? "T" : "F");
  400. }
  401. else if (index <= kParamPart16Volume)
  402. {
  403. fParameters[index] = std::round(carla_fixValue(0.0f, 127.0f, value));
  404. char msg[24];
  405. std::sprintf(msg, "/part%i/Pvolume", index-kParamPart01Volume);
  406. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[index]));
  407. }
  408. else if (index <= kParamPart16Panning)
  409. {
  410. fParameters[index] = std::round(carla_fixValue(0.0f, 127.0f, value));
  411. char msg[24];
  412. std::sprintf(msg, "/part%i/Ppanning", index-kParamPart01Panning);
  413. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[index]));
  414. }
  415. else if (index <= kParamResBandwidth)
  416. {
  417. const uint zynIndex(getZynParameterFromIndex(index));
  418. CARLA_SAFE_ASSERT_RETURN(zynIndex != C_NULL,);
  419. fParameters[index] = std::round(carla_fixValue(0.0f, 127.0f, value));
  420. for (int npart=0; npart<NUM_MIDI_PARTS; ++npart)
  421. {
  422. if (fMaster->part[npart] != nullptr)
  423. fMaster->part[npart]->SetController(zynIndex, static_cast<int>(value));
  424. }
  425. }
  426. }
  427. void setMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  428. {
  429. CARLA_SAFE_ASSERT_RETURN(program < BANK_SIZE,);
  430. if (bank == 0)
  431. {
  432. // reset part to default
  433. // TODO
  434. return;
  435. }
  436. const char* const filename(sPrograms.getZynProgramFilename(bank, program));
  437. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0',);
  438. fMiddleWare->transmitMsg("/load-part", "is", channel, filename);
  439. }
  440. void setCustomData(const char* const key, const char* const value) override
  441. {
  442. CARLA_SAFE_ASSERT_RETURN(key != nullptr,);
  443. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  444. /**/ if (std::strcmp(key, "CarlaAlternateFile1") == 0) // xmz
  445. {
  446. fMiddleWare->transmitMsg("/load_xmz", "s", value);
  447. }
  448. else if (std::strcmp(key, "CarlaAlternateFile2") == 0) // xiz
  449. {
  450. fMiddleWare->transmitMsg("/load_xiz", "is", 0, value);
  451. }
  452. }
  453. // -------------------------------------------------------------------
  454. // Plugin process calls
  455. void activate() override
  456. {
  457. fIsActive = true;
  458. }
  459. void deactivate() override
  460. {
  461. fIsActive = false;
  462. }
  463. void process(float**, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  464. {
  465. if (! fMutex.tryLock())
  466. {
  467. if (! isOffline())
  468. {
  469. FloatVectorOperations::clear(outBuffer[0], static_cast<int>(frames));
  470. FloatVectorOperations::clear(outBuffer[1], static_cast<int>(frames));
  471. return;
  472. }
  473. fMutex.lock();
  474. }
  475. for (uint32_t i=0; i < midiEventCount; ++i)
  476. {
  477. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  478. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
  479. const char channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
  480. if (MIDI_IS_STATUS_NOTE_OFF(status))
  481. {
  482. const char note = static_cast<char>(midiEvent->data[1]);
  483. fMaster->noteOff(channel, note);
  484. }
  485. else if (MIDI_IS_STATUS_NOTE_ON(status))
  486. {
  487. const char note = static_cast<char>(midiEvent->data[1]);
  488. const char velo = static_cast<char>(midiEvent->data[2]);
  489. fMaster->noteOn(channel, note, velo);
  490. }
  491. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  492. {
  493. const char note = static_cast<char>(midiEvent->data[1]);
  494. const char pressure = static_cast<char>(midiEvent->data[2]);
  495. fMaster->polyphonicAftertouch(channel, note, pressure);
  496. }
  497. else if (MIDI_IS_STATUS_CONTROL_CHANGE(status))
  498. {
  499. // skip controls which we map to parameters
  500. if (getZynParameterFromIndex(midiEvent->data[1]) != C_NULL)
  501. continue;
  502. const int control = midiEvent->data[1];
  503. const int value = midiEvent->data[2];
  504. fMaster->setController(channel, control, value);
  505. }
  506. else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
  507. {
  508. const uint8_t lsb = midiEvent->data[1];
  509. const uint8_t msb = midiEvent->data[2];
  510. const int value = ((msb << 7) | lsb) - 8192;
  511. fMaster->setController(channel, C_pitchwheel, value);
  512. }
  513. }
  514. fMaster->GetAudioOutSamples(frames, fSynth.samplerate, outBuffer[0], outBuffer[1]);
  515. fMutex.unlock();
  516. }
  517. // -------------------------------------------------------------------
  518. // Plugin UI calls
  519. #ifdef HAVE_ZYN_UI_DEPS
  520. void uiShow(const bool show) override
  521. {
  522. if (show)
  523. {
  524. if (isPipeRunning())
  525. {
  526. const CarlaMutexLocker cml(getPipeLock());
  527. writeMessage("focus\n", 6);
  528. flushMessages();
  529. return;
  530. }
  531. carla_stdout("Trying to start UI using \"%s\"", getExtUiPath());
  532. CarlaExternalUI::setData(getExtUiPath(), fMiddleWare->getServerAddress(), getUiName());
  533. if (! CarlaExternalUI::startPipeServer(true))
  534. {
  535. uiClosed();
  536. hostUiUnavailable();
  537. }
  538. }
  539. else
  540. {
  541. CarlaExternalUI::stopPipeServer(2000);
  542. }
  543. }
  544. void uiIdle() override
  545. {
  546. NativePluginAndUiClass::uiIdle();
  547. if (isPipeRunning())
  548. fMiddleWare->tick();
  549. }
  550. #endif
  551. // -------------------------------------------------------------------
  552. // Plugin state calls
  553. char* getState() const override
  554. {
  555. char* data = nullptr;
  556. if (fIsActive)
  557. {
  558. fMiddleWare->doReadOnlyOp([this, &data]{
  559. fMaster->getalldata(&data);
  560. });
  561. }
  562. else
  563. {
  564. fMaster->getalldata(&data);
  565. }
  566. return data;
  567. }
  568. void setState(const char* const data) override
  569. {
  570. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  571. const CarlaMutexLocker cml(fMutex);
  572. fMaster->putalldata(const_cast<char*>(data), 0);
  573. fMaster->applyparameters();
  574. fMiddleWare->updateResources(fMaster);
  575. _setMasterParameters();
  576. }
  577. // -------------------------------------------------------------------
  578. // Plugin dispatcher
  579. void bufferSizeChanged(const uint32_t bufferSize) final
  580. {
  581. char* const state(getState());
  582. _deleteMaster();
  583. fSynth.buffersize = static_cast<int>(bufferSize);
  584. fSynth.alias();
  585. _initMaster();
  586. setState(state);
  587. std::free(state);
  588. }
  589. void sampleRateChanged(const double sampleRate) final
  590. {
  591. char* const state(getState());
  592. _deleteMaster();
  593. fSynth.samplerate = static_cast<uint>(sampleRate);
  594. fSynth.alias();
  595. _initMaster();
  596. setState(state);
  597. std::free(state);
  598. }
  599. // -------------------------------------------------------------------
  600. private:
  601. MiddleWare* fMiddleWare;
  602. Master* fMaster;
  603. SYNTH_T fSynth;
  604. bool fIsActive;
  605. float fParameters[kParamCount];
  606. CarlaMutex fMutex;
  607. static uint getZynParameterFromIndex(const uint index)
  608. {
  609. switch (index)
  610. {
  611. case kParamFilterCutoff:
  612. return C_filtercutoff;
  613. case kParamFilterQ:
  614. return C_filterq;
  615. case kParamBandwidth:
  616. return C_bandwidth;
  617. case kParamModAmp:
  618. return C_fmamp;
  619. case kParamResCenter:
  620. return C_resonance_center;
  621. case kParamResBandwidth:
  622. return C_resonance_bandwidth;
  623. case kParamCount:
  624. return C_NULL;
  625. }
  626. return C_NULL;
  627. }
  628. // -------------------------------------------------------------------
  629. void _initMaster()
  630. {
  631. fMiddleWare = new MiddleWare(fSynth);
  632. fMaster = fMiddleWare->spawnMaster();
  633. }
  634. void _setMasterParameters()
  635. {
  636. for (int i=kParamPart16Enabled+1; --i>=kParamPart01Enabled;)
  637. {
  638. char msg[24];
  639. std::sprintf(msg, "/part%i/Penabled", i-kParamPart01Enabled);
  640. fMiddleWare->transmitMsg(msg, (fParameters[i] >= 0.5f) ? "T" : "F");
  641. }
  642. for (int i=kParamPart16Volume+1; --i>=kParamPart01Volume;)
  643. {
  644. char msg[24];
  645. std::sprintf(msg, "/part%i/Pvolume", i-kParamPart01Volume);
  646. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[i]));
  647. }
  648. for (int i=kParamPart16Panning+1; --i>=kParamPart01Panning;)
  649. {
  650. char msg[24];
  651. std::sprintf(msg, "/part%i/Ppanning", i-kParamPart01Panning);
  652. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[i]));
  653. }
  654. for (int i=0; i<NUM_MIDI_PARTS; ++i)
  655. {
  656. fMaster->part[i]->SetController(C_filtercutoff, static_cast<int>(fParameters[kParamFilterCutoff]));
  657. fMaster->part[i]->SetController(C_filterq, static_cast<int>(fParameters[kParamFilterQ]));
  658. fMaster->part[i]->SetController(C_bandwidth, static_cast<int>(fParameters[kParamBandwidth]));
  659. fMaster->part[i]->SetController(C_fmamp, static_cast<int>(fParameters[kParamModAmp]));
  660. fMaster->part[i]->SetController(C_resonance_center, static_cast<int>(fParameters[kParamResCenter]));
  661. fMaster->part[i]->SetController(C_resonance_bandwidth, static_cast<int>(fParameters[kParamResBandwidth]));
  662. }
  663. }
  664. void _deleteMaster()
  665. {
  666. fMaster = nullptr;
  667. delete fMiddleWare;
  668. fMiddleWare = nullptr;
  669. }
  670. // -------------------------------------------------------------------
  671. public:
  672. static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
  673. {
  674. static bool needsInit = true;
  675. if (needsInit)
  676. {
  677. needsInit = false;
  678. config.init();
  679. sprng(static_cast<prng_t>(std::time(nullptr)));
  680. // FIXME - kill this
  681. denormalkillbuf = new float[8192];
  682. for (int i=0; i < 8192; ++i)
  683. denormalkillbuf[i] = (RND - 0.5f) * 1e-16f;
  684. }
  685. return new ZynAddSubFxPlugin(host);
  686. }
  687. static void _cleanup(NativePluginHandle handle)
  688. {
  689. delete (ZynAddSubFxPlugin*)handle;
  690. }
  691. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  692. };
  693. // -----------------------------------------------------------------------
  694. static const NativePluginDescriptor zynaddsubfxDesc = {
  695. /* category */ NATIVE_PLUGIN_CATEGORY_SYNTH,
  696. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
  697. #ifdef HAVE_ZYN_UI_DEPS
  698. |NATIVE_PLUGIN_HAS_UI
  699. #endif
  700. |NATIVE_PLUGIN_USES_MULTI_PROGS
  701. |NATIVE_PLUGIN_USES_STATE),
  702. /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES
  703. |NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH
  704. |NATIVE_PLUGIN_SUPPORTS_PITCHBEND
  705. |NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF),
  706. /* audioIns */ 0,
  707. /* audioOuts */ 2,
  708. /* midiIns */ 1,
  709. /* midiOuts */ 0,
  710. /* paramIns */ ZynAddSubFxPlugin::kParamCount,
  711. /* paramOuts */ 0,
  712. /* name */ "ZynAddSubFX",
  713. /* label */ "zynaddsubfx",
  714. /* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul",
  715. /* copyright */ "GNU GPL v2+",
  716. PluginDescriptorFILL(ZynAddSubFxPlugin)
  717. };
  718. // -----------------------------------------------------------------------
  719. CARLA_EXPORT
  720. void carla_register_native_plugin_zynaddsubfx_synth();
  721. CARLA_EXPORT
  722. void carla_register_native_plugin_zynaddsubfx_synth()
  723. {
  724. carla_register_native_plugin(&zynaddsubfxDesc);
  725. }
  726. // -----------------------------------------------------------------------