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.

1016 lines
27KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-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. #include "CarlaNative.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/Part.h"
  25. #include "Misc/Util.h"
  26. #ifdef WANT_ZYNADDSUBFX_UI
  27. # ifdef override
  28. # define override_hack
  29. # undef override
  30. # endif
  31. # include "UI/common.H"
  32. # include "UI/MasterUI.h"
  33. # include <FL/Fl_Shared_Image.H>
  34. # include <FL/Fl_Tiled_Image.H>
  35. # include <FL/Fl_Theme.H>
  36. # ifdef override_hack
  37. # define override
  38. # undef override_hack
  39. # endif
  40. #endif
  41. #include <ctime>
  42. #include <set>
  43. #include <string>
  44. #include "juce_audio_basics.h"
  45. using juce::FloatVectorOperations;
  46. #ifdef WANT_ZYNADDSUBFX_UI
  47. static Fl_Tiled_Image* gModuleBackdrop = nullptr;
  48. static CarlaString gPixmapPath;
  49. extern CarlaString gUiPixmapPath;
  50. void set_module_parameters(Fl_Widget* o)
  51. {
  52. CARLA_SAFE_ASSERT_RETURN(gModuleBackdrop != nullptr,);
  53. o->box(FL_DOWN_FRAME);
  54. o->align(o->align() | FL_ALIGN_IMAGE_BACKDROP);
  55. o->color(FL_BLACK);
  56. o->labeltype(FL_SHADOW_LABEL);
  57. o->image(gModuleBackdrop);
  58. }
  59. #endif
  60. // -----------------------------------------------------------------------
  61. class ZynAddSubFxPrograms
  62. {
  63. public:
  64. ZynAddSubFxPrograms() noexcept
  65. : fInitiated(false),
  66. #ifdef CARLA_PROPER_CPP11_SUPPORT
  67. fRetProgram({0, 0, nullptr}),
  68. #endif
  69. fPrograms() {}
  70. ~ZynAddSubFxPrograms() noexcept
  71. {
  72. if (! fInitiated)
  73. return;
  74. for (LinkedList<const ProgramInfo*>::Itenerator it = fPrograms.begin(); it.valid(); it.next())
  75. {
  76. const ProgramInfo* const& pInfo(it.getValue(nullptr));
  77. delete pInfo;
  78. }
  79. fPrograms.clear();
  80. }
  81. void initIfNeeded()
  82. {
  83. if (fInitiated)
  84. return;
  85. fInitiated = true;
  86. Master& master(Master::getInstance());
  87. pthread_mutex_lock(&master.mutex);
  88. fPrograms.append(new ProgramInfo(0, 0, "default"));
  89. // refresh banks
  90. master.bank.rescanforbanks();
  91. for (uint32_t i=0, size=static_cast<uint32_t>(master.bank.banks.size()); i<size; ++i)
  92. {
  93. if (master.bank.banks[i].dir.empty())
  94. continue;
  95. master.bank.loadbank(master.bank.banks[i].dir);
  96. for (uint instrument = 0; instrument < BANK_SIZE; ++instrument)
  97. {
  98. const std::string insName(master.bank.getname(instrument));
  99. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  100. continue;
  101. fPrograms.append(new ProgramInfo(i+1, instrument, insName.c_str()));
  102. }
  103. }
  104. pthread_mutex_unlock(&master.mutex);
  105. }
  106. void load(Master* const master, const uint8_t channel, const uint32_t bank, const uint32_t program)
  107. {
  108. if (bank == 0)
  109. {
  110. pthread_mutex_lock(&master->mutex);
  111. master->partonoff(channel, 1);
  112. master->part[channel]->defaults();
  113. master->part[channel]->applyparameters(false);
  114. pthread_mutex_unlock(&master->mutex);
  115. return;
  116. }
  117. const std::string& bankdir(master->bank.banks[bank-1].dir);
  118. if (! bankdir.empty())
  119. {
  120. pthread_mutex_lock(&master->mutex);
  121. master->partonoff(channel, 1);
  122. master->bank.loadbank(bankdir);
  123. master->bank.loadfromslot(program, master->part[channel]);
  124. master->part[channel]->applyparameters(false);
  125. pthread_mutex_unlock(&master->mutex);
  126. }
  127. }
  128. uint32_t count() const noexcept
  129. {
  130. return static_cast<uint32_t>(fPrograms.count());
  131. }
  132. const NativeMidiProgram* getInfo(const uint32_t index) const noexcept
  133. {
  134. if (index >= fPrograms.count())
  135. return nullptr;
  136. const ProgramInfo* const pInfo(fPrograms.getAt(index, nullptr));
  137. CARLA_SAFE_ASSERT_RETURN(pInfo != nullptr, nullptr);
  138. fRetProgram.bank = pInfo->bank;
  139. fRetProgram.program = pInfo->prog;
  140. fRetProgram.name = pInfo->name;
  141. return &fRetProgram;
  142. }
  143. private:
  144. struct ProgramInfo {
  145. uint32_t bank;
  146. uint32_t prog;
  147. const char* name;
  148. ProgramInfo(uint32_t b, uint32_t p, const char* n) noexcept
  149. : bank(b),
  150. prog(p),
  151. name(carla_strdup_safe(n)) {}
  152. ~ProgramInfo() noexcept
  153. {
  154. if (name != nullptr)
  155. {
  156. delete[] name;
  157. name = nullptr;
  158. }
  159. }
  160. #ifdef CARLA_PROPER_CPP11_SUPPORT
  161. ProgramInfo() = delete;
  162. ProgramInfo(ProgramInfo&) = delete;
  163. ProgramInfo(const ProgramInfo&) = delete;
  164. ProgramInfo& operator=(ProgramInfo&);
  165. ProgramInfo& operator=(const ProgramInfo&);
  166. #endif
  167. };
  168. bool fInitiated;
  169. mutable NativeMidiProgram fRetProgram;
  170. LinkedList<const ProgramInfo*> fPrograms;
  171. CARLA_PREVENT_HEAP_ALLOCATION
  172. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxPrograms)
  173. };
  174. static ZynAddSubFxPrograms sPrograms;
  175. // -----------------------------------------------------------------------
  176. class ZynAddSubFxInstanceCount
  177. {
  178. public:
  179. ZynAddSubFxInstanceCount()
  180. : fCount(0) {}
  181. ~ZynAddSubFxInstanceCount()
  182. {
  183. CARLA_ASSERT(fCount == 0);
  184. }
  185. void addOne(const NativeHostDescriptor* const host)
  186. {
  187. if (fCount++ != 0)
  188. return;
  189. CARLA_SAFE_ASSERT(synth == nullptr);
  190. CARLA_SAFE_ASSERT(denormalkillbuf == nullptr);
  191. reinit(host);
  192. #ifdef WANT_ZYNADDSUBFX_UI
  193. if (gPixmapPath.isEmpty())
  194. {
  195. gPixmapPath = host->resourceDir;
  196. gPixmapPath += "/zynaddsubfx/";
  197. gUiPixmapPath = gPixmapPath;
  198. }
  199. #endif
  200. }
  201. void removeOne()
  202. {
  203. if (--fCount != 0)
  204. return;
  205. CARLA_SAFE_ASSERT(synth != nullptr);
  206. CARLA_SAFE_ASSERT(denormalkillbuf != nullptr);
  207. Master::deleteInstance();
  208. delete[] denormalkillbuf;
  209. denormalkillbuf = nullptr;
  210. delete synth;
  211. synth = nullptr;
  212. }
  213. void reinit(const NativeHostDescriptor* const host)
  214. {
  215. Master::deleteInstance();
  216. if (denormalkillbuf != nullptr)
  217. {
  218. delete[] denormalkillbuf;
  219. denormalkillbuf = nullptr;
  220. }
  221. if (synth != nullptr)
  222. {
  223. delete synth;
  224. synth = nullptr;
  225. }
  226. synth = new SYNTH_T();
  227. synth->buffersize = static_cast<int>(host->get_buffer_size(host->handle));
  228. synth->samplerate = static_cast<uint>(host->get_sample_rate(host->handle));
  229. if (synth->buffersize > 32)
  230. synth->buffersize = 32;
  231. synth->alias();
  232. config.init();
  233. config.cfg.SoundBufferSize = synth->buffersize;
  234. config.cfg.SampleRate = static_cast<int>(synth->samplerate);
  235. config.cfg.GzipCompression = 0;
  236. sprng(static_cast<prng_t>(std::time(nullptr)));
  237. denormalkillbuf = new float[synth->buffersize];
  238. for (int i=0; i < synth->buffersize; ++i)
  239. denormalkillbuf[i] = (RND - 0.5f) * 1e-16f;
  240. Master::getInstance();
  241. }
  242. void maybeReinit(const NativeHostDescriptor* const host)
  243. {
  244. if (static_cast< int>(host->get_buffer_size(host->handle)) == synth->buffersize &&
  245. static_cast<uint>(host->get_sample_rate(host->handle)) == synth->samplerate)
  246. return;
  247. reinit(host);
  248. }
  249. private:
  250. int fCount;
  251. CARLA_PREVENT_HEAP_ALLOCATION
  252. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxInstanceCount)
  253. };
  254. static ZynAddSubFxInstanceCount sInstanceCount;
  255. // -----------------------------------------------------------------------
  256. class ZynAddSubFxThread : public CarlaThread
  257. {
  258. public:
  259. ZynAddSubFxThread(Master* const master, const NativeHostDescriptor* const host)
  260. : CarlaThread("ZynAddSubFxThread"),
  261. fMaster(master),
  262. kHost(host),
  263. #ifdef WANT_ZYNADDSUBFX_UI
  264. fUi(nullptr),
  265. fUiClosed(0),
  266. fNextUiAction(-1),
  267. #endif
  268. fChangeProgram(false),
  269. fNextChannel(0),
  270. fNextBank(0),
  271. fNextProgram(0) {}
  272. ~ZynAddSubFxThread()
  273. {
  274. #ifdef WANT_ZYNADDSUBFX_UI
  275. // must be closed by now
  276. CARLA_SAFE_ASSERT(fUi == nullptr);
  277. #endif
  278. }
  279. void loadProgramLater(const uint8_t channel, const uint32_t bank, const uint32_t program)
  280. {
  281. fNextChannel = channel;
  282. fNextBank = bank;
  283. fNextProgram = program;
  284. fChangeProgram = true;
  285. }
  286. void stopLoadProgramLater()
  287. {
  288. fChangeProgram = false;
  289. fNextChannel = 0;
  290. fNextBank = 0;
  291. fNextProgram = 0;
  292. }
  293. void setMaster(Master* const master)
  294. {
  295. fMaster = master;
  296. }
  297. #ifdef WANT_ZYNADDSUBFX_UI
  298. void uiHide()
  299. {
  300. fNextUiAction = 0;
  301. }
  302. void uiShow()
  303. {
  304. fNextUiAction = 1;
  305. }
  306. void uiRepaint()
  307. {
  308. if (fUi != nullptr)
  309. fNextUiAction = 2;
  310. }
  311. void uiChangeName(const char* const name)
  312. {
  313. if (fUi != nullptr)
  314. {
  315. Fl::lock();
  316. fUi->masterwindow->label(name);
  317. Fl::unlock();
  318. }
  319. }
  320. #endif
  321. protected:
  322. void run() override
  323. {
  324. while (! shouldThreadExit())
  325. {
  326. #ifdef WANT_ZYNADDSUBFX_UI
  327. Fl::lock();
  328. if (fNextUiAction == 2) // repaint
  329. {
  330. CARLA_ASSERT(fUi != nullptr);
  331. if (fUi != nullptr)
  332. fUi->refresh_master_ui();
  333. }
  334. else if (fNextUiAction == 1) // init/show
  335. {
  336. static bool initialized = false;
  337. if (! initialized)
  338. {
  339. initialized = true;
  340. fl_register_images();
  341. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  342. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "knob.png"))
  343. Fl_Dial::default_image(img);
  344. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "window_backdrop.png"))
  345. Fl::scheme_bg(new Fl_Tiled_Image(img));
  346. if(Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "module_backdrop.png"))
  347. gModuleBackdrop = new Fl_Tiled_Image(img);
  348. Fl::background(50, 50, 50);
  349. Fl::background2(70, 70, 70);
  350. Fl::foreground(255, 255, 255);
  351. Fl_Theme::set("Cairo");
  352. }
  353. if (fUi == nullptr)
  354. {
  355. fUiClosed = 0;
  356. fUi = new MasterUI(fMaster, &fUiClosed);
  357. fUi->masterwindow->label(kHost->uiName);
  358. fUi->showUI();
  359. }
  360. else
  361. fUi->showUI();
  362. }
  363. else if (fNextUiAction == 0) // close
  364. {
  365. CARLA_ASSERT(fUi != nullptr);
  366. if (fUi != nullptr)
  367. {
  368. delete fUi;
  369. fUi = nullptr;
  370. }
  371. }
  372. fNextUiAction = -1;
  373. if (fUiClosed != 0)
  374. {
  375. fUiClosed = 0;
  376. fNextUiAction = 0;
  377. kHost->ui_closed(kHost->handle);
  378. }
  379. Fl::check();
  380. Fl::unlock();
  381. #endif
  382. if (fChangeProgram)
  383. {
  384. fChangeProgram = false;
  385. sPrograms.load(fMaster, fNextChannel, fNextBank, fNextProgram);
  386. fNextChannel = 0;
  387. fNextBank = 0;
  388. fNextProgram = 0;
  389. #ifdef WANT_ZYNADDSUBFX_UI
  390. if (fUi != nullptr)
  391. {
  392. Fl::lock();
  393. fUi->refresh_master_ui();
  394. Fl::unlock();
  395. }
  396. #endif
  397. carla_msleep(15);
  398. }
  399. else
  400. {
  401. carla_msleep(30);
  402. }
  403. }
  404. #ifdef WANT_ZYNADDSUBFX_UI
  405. if (fUi != nullptr)
  406. {
  407. Fl::lock();
  408. delete fUi;
  409. fUi = nullptr;
  410. Fl::check();
  411. Fl::unlock();
  412. }
  413. #endif
  414. }
  415. private:
  416. Master* fMaster;
  417. const NativeHostDescriptor* const kHost;
  418. #ifdef WANT_ZYNADDSUBFX_UI
  419. MasterUI* fUi;
  420. int fUiClosed;
  421. volatile int fNextUiAction;
  422. #endif
  423. volatile bool fChangeProgram;
  424. volatile uint8_t fNextChannel;
  425. volatile uint32_t fNextBank;
  426. volatile uint32_t fNextProgram;
  427. CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
  428. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxThread)
  429. };
  430. // -----------------------------------------------------------------------
  431. class ZynAddSubFxPlugin : public NativePluginClass
  432. {
  433. public:
  434. enum Parameters {
  435. kParamFilterCutoff = 0, // Filter Frequency
  436. kParamFilterQ, // Filter Resonance
  437. kParamBandwidth, // Bandwidth
  438. kParamModAmp, // FM Gain
  439. kParamResCenter, // Resonance center frequency
  440. kParamResBandwidth, // Resonance bandwidth
  441. kParamCount
  442. };
  443. ZynAddSubFxPlugin(const NativeHostDescriptor* const host)
  444. : NativePluginClass(host),
  445. fMaster(nullptr),
  446. fSampleRate(static_cast<uint>(getSampleRate())),
  447. fIsActive(false),
  448. fThread(nullptr, host),
  449. leakDetector_ZynAddSubFxPlugin()
  450. {
  451. // init parameters to default
  452. fParameters[kParamFilterCutoff] = 64.0f;
  453. fParameters[kParamFilterQ] = 64.0f;
  454. fParameters[kParamBandwidth] = 64.0f;
  455. fParameters[kParamModAmp] = 127.0f;
  456. fParameters[kParamResCenter] = 64.0f;
  457. fParameters[kParamResBandwidth] = 64.0f;
  458. _initMaster();
  459. sPrograms.initIfNeeded();
  460. }
  461. ~ZynAddSubFxPlugin() override
  462. {
  463. _deleteMaster();
  464. }
  465. protected:
  466. // -------------------------------------------------------------------
  467. // Plugin parameter calls
  468. uint32_t getParameterCount() const final
  469. {
  470. return kParamCount;
  471. }
  472. const NativeParameter* getParameterInfo(const uint32_t index) const override
  473. {
  474. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
  475. static NativeParameter param;
  476. int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_INTEGER|NATIVE_PARAMETER_IS_AUTOMABLE;
  477. param.name = nullptr;
  478. param.unit = nullptr;
  479. param.ranges.def = 64.0f;
  480. param.ranges.min = 0.0f;
  481. param.ranges.max = 127.0f;
  482. param.ranges.step = 1.0f;
  483. param.ranges.stepSmall = 1.0f;
  484. param.ranges.stepLarge = 20.0f;
  485. param.scalePointCount = 0;
  486. param.scalePoints = nullptr;
  487. switch (index)
  488. {
  489. case kParamFilterCutoff:
  490. param.name = "Filter Cutoff";
  491. break;
  492. case kParamFilterQ:
  493. param.name = "Filter Q";
  494. break;
  495. case kParamBandwidth:
  496. param.name = "Bandwidth";
  497. break;
  498. case kParamModAmp:
  499. param.name = "FM Gain";
  500. param.ranges.def = 127.0f;
  501. break;
  502. case kParamResCenter:
  503. param.name = "Res Center Freq";
  504. break;
  505. case kParamResBandwidth:
  506. param.name = "Res Bandwidth";
  507. break;
  508. }
  509. param.hints = static_cast<NativeParameterHints>(hints);
  510. return &param;
  511. }
  512. float getParameterValue(const uint32_t index) const final
  513. {
  514. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
  515. return fParameters[index];
  516. }
  517. // -------------------------------------------------------------------
  518. // Plugin midi-program calls
  519. uint32_t getMidiProgramCount() const override
  520. {
  521. return sPrograms.count();
  522. }
  523. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override
  524. {
  525. return sPrograms.getInfo(index);
  526. }
  527. // -------------------------------------------------------------------
  528. // Plugin state calls
  529. void setParameterValue(const uint32_t index, const float value) final
  530. {
  531. CARLA_SAFE_ASSERT_RETURN(index < kParamCount,);
  532. const uint zynIndex(getZynParameterFromIndex(index));
  533. CARLA_SAFE_ASSERT_RETURN(zynIndex != C_NULL,);
  534. fParameters[index] = value;
  535. for (int npart=0; npart<NUM_MIDI_PARTS; ++npart)
  536. {
  537. if (fMaster->part[npart] != nullptr && fMaster->part[npart]->Penabled != 0)
  538. fMaster->part[npart]->SetController(zynIndex, static_cast<int>(value));
  539. }
  540. }
  541. void setMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  542. {
  543. if (bank >= fMaster->bank.banks.size())
  544. return;
  545. if (program >= BANK_SIZE)
  546. return;
  547. if (isOffline() || ! fIsActive)
  548. {
  549. sPrograms.load(fMaster, channel, bank, program);
  550. #ifdef WANT_ZYNADDSUBFX_UI
  551. fThread.uiRepaint();
  552. #endif
  553. return;
  554. }
  555. fThread.loadProgramLater(channel, bank, program);
  556. }
  557. void setCustomData(const char* const key, const char* const value) override
  558. {
  559. CARLA_SAFE_ASSERT_RETURN(key != nullptr,);
  560. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  561. pthread_mutex_lock(&fMaster->mutex);
  562. /**/ if (std::strcmp(key, "CarlaAlternateFile1") == 0) // xmz
  563. {
  564. fMaster->defaults();
  565. fMaster->loadXML(value);
  566. }
  567. else if (std::strcmp(key, "CarlaAlternateFile2") == 0) // xiz
  568. {
  569. fMaster->part[0]->defaultsinstrument();
  570. fMaster->part[0]->loadXMLinstrument(value);
  571. }
  572. pthread_mutex_unlock(&fMaster->mutex);
  573. fMaster->applyparameters();
  574. }
  575. // -------------------------------------------------------------------
  576. // Plugin process calls
  577. void activate() override
  578. {
  579. fIsActive = true;
  580. }
  581. void deactivate() override
  582. {
  583. fIsActive = false;
  584. }
  585. void process(float**, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  586. {
  587. if (pthread_mutex_trylock(&fMaster->mutex) != 0)
  588. {
  589. FloatVectorOperations::clear(outBuffer[0], static_cast<int>(frames));
  590. FloatVectorOperations::clear(outBuffer[1], static_cast<int>(frames));
  591. return;
  592. }
  593. for (uint32_t i=0; i < midiEventCount; ++i)
  594. {
  595. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  596. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
  597. const char channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
  598. if (MIDI_IS_STATUS_NOTE_OFF(status))
  599. {
  600. const char note = static_cast<char>(midiEvent->data[1]);
  601. fMaster->noteOff(channel, note);
  602. }
  603. else if (MIDI_IS_STATUS_NOTE_ON(status))
  604. {
  605. const char note = static_cast<char>(midiEvent->data[1]);
  606. const char velo = static_cast<char>(midiEvent->data[2]);
  607. fMaster->noteOn(channel, note, velo);
  608. }
  609. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  610. {
  611. const char note = static_cast<char>(midiEvent->data[1]);
  612. const char pressure = static_cast<char>(midiEvent->data[2]);
  613. fMaster->polyphonicAftertouch(channel, note, pressure);
  614. }
  615. else if (MIDI_IS_STATUS_CONTROL_CHANGE(status))
  616. {
  617. // skip controls which we map to parameters
  618. if (getZynParameterFromIndex(midiEvent->data[1]) == C_NULL)
  619. continue;
  620. const int control = midiEvent->data[1];
  621. const int value = midiEvent->data[2];
  622. fMaster->setController(channel, control, value);
  623. }
  624. else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
  625. {
  626. const uint8_t lsb = midiEvent->data[1];
  627. const uint8_t msb = midiEvent->data[2];
  628. const int value = ((msb << 7) | lsb) - 8192;
  629. fMaster->setController(channel, C_pitchwheel, value);
  630. }
  631. }
  632. fMaster->GetAudioOutSamples(frames, fSampleRate, outBuffer[0], outBuffer[1]);
  633. pthread_mutex_unlock(&fMaster->mutex);
  634. }
  635. #ifdef WANT_ZYNADDSUBFX_UI
  636. // -------------------------------------------------------------------
  637. // Plugin UI calls
  638. void uiShow(const bool show) override
  639. {
  640. if (show)
  641. fThread.uiShow();
  642. else
  643. fThread.uiHide();
  644. }
  645. #endif
  646. // -------------------------------------------------------------------
  647. // Plugin state calls
  648. char* getState() const override
  649. {
  650. config.save();
  651. char* data = nullptr;
  652. fMaster->getalldata(&data);
  653. return data;
  654. }
  655. void setState(const char* const data) override
  656. {
  657. fThread.stopLoadProgramLater();
  658. fMaster->putalldata(const_cast<char*>(data), 0);
  659. fMaster->applyparameters(true);
  660. }
  661. // -------------------------------------------------------------------
  662. // Plugin dispatcher
  663. void bufferSizeChanged(const uint32_t) final
  664. {
  665. char* const state(getState());
  666. _deleteMaster();
  667. sInstanceCount.maybeReinit(getHostHandle());
  668. _initMaster();
  669. if (state != nullptr)
  670. {
  671. fMaster->putalldata(state, 0);
  672. fMaster->applyparameters(true);
  673. std::free(state);
  674. }
  675. }
  676. void sampleRateChanged(const double sampleRate) final
  677. {
  678. fSampleRate = static_cast<uint>(sampleRate);
  679. char* const state(getState());
  680. _deleteMaster();
  681. sInstanceCount.maybeReinit(getHostHandle());
  682. _initMaster();
  683. if (state != nullptr)
  684. {
  685. fMaster->putalldata(state, 0);
  686. fMaster->applyparameters(true);
  687. std::free(state);
  688. }
  689. }
  690. #ifdef WANT_ZYNADDSUBFX_UI
  691. void uiNameChanged(const char* const uiName) override
  692. {
  693. fThread.uiChangeName(uiName);
  694. }
  695. #endif
  696. // -------------------------------------------------------------------
  697. private:
  698. Master* fMaster;
  699. uint fSampleRate;
  700. bool fIsActive;
  701. float fParameters[kParamCount];
  702. ZynAddSubFxThread fThread;
  703. /*
  704. static Parameters getParameterFromZynIndex(const MidiControllers index)
  705. {
  706. switch (index)
  707. {
  708. case C_filtercutoff:
  709. return kParamFilterCutoff;
  710. case C_filterq:
  711. return kParamFilterQ;
  712. case C_bandwidth:
  713. return kParamBandwidth;
  714. case C_fmamp:
  715. return kParamModAmp;
  716. case C_resonance_center:
  717. return kParamResCenter;
  718. case C_resonance_bandwidth:
  719. return kParamResBandwidth;
  720. default:
  721. return kParamCount;
  722. }
  723. }
  724. */
  725. static uint getZynParameterFromIndex(const uint index)
  726. {
  727. switch (index)
  728. {
  729. case kParamFilterCutoff:
  730. return C_filtercutoff;
  731. case kParamFilterQ:
  732. return C_filterq;
  733. case kParamBandwidth:
  734. return C_bandwidth;
  735. case kParamModAmp:
  736. return C_fmamp;
  737. case kParamResCenter:
  738. return C_resonance_center;
  739. case kParamResBandwidth:
  740. return C_resonance_bandwidth;
  741. case kParamCount:
  742. return C_NULL;
  743. }
  744. return C_NULL;
  745. }
  746. // -------------------------------------------------------------------
  747. void _initMaster()
  748. {
  749. fMaster = new Master();
  750. fThread.setMaster(fMaster);
  751. fThread.startThread();
  752. for (int i=0; i<NUM_MIDI_PARTS; ++i)
  753. {
  754. fMaster->partonoff(i, 1);
  755. for (int npart=0; npart<NUM_MIDI_PARTS; ++npart)
  756. {
  757. fMaster->part[npart]->SetController(C_filtercutoff, static_cast<int>(fParameters[kParamFilterCutoff]));
  758. fMaster->part[npart]->SetController(C_filterq, static_cast<int>(fParameters[kParamFilterQ]));
  759. fMaster->part[npart]->SetController(C_bandwidth, static_cast<int>(fParameters[kParamBandwidth]));
  760. fMaster->part[npart]->SetController(C_fmamp, static_cast<int>(fParameters[kParamModAmp]));
  761. fMaster->part[npart]->SetController(C_resonance_center, static_cast<int>(fParameters[kParamResCenter]));
  762. fMaster->part[npart]->SetController(C_resonance_bandwidth, static_cast<int>(fParameters[kParamResBandwidth]));
  763. }
  764. }
  765. }
  766. void _deleteMaster()
  767. {
  768. //ensure that everything has stopped
  769. pthread_mutex_lock(&fMaster->mutex);
  770. pthread_mutex_unlock(&fMaster->mutex);
  771. fThread.stopThread(-1);
  772. delete fMaster;
  773. fMaster = nullptr;
  774. }
  775. // -------------------------------------------------------------------
  776. public:
  777. static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
  778. {
  779. sInstanceCount.addOne(host);
  780. return new ZynAddSubFxPlugin(host);
  781. }
  782. static void _cleanup(NativePluginHandle handle)
  783. {
  784. delete (ZynAddSubFxPlugin*)handle;
  785. sInstanceCount.removeOne();
  786. }
  787. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  788. };
  789. // -----------------------------------------------------------------------
  790. static const NativePluginDescriptor zynaddsubfxDesc = {
  791. /* category */ NATIVE_PLUGIN_CATEGORY_SYNTH,
  792. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
  793. #ifdef WANT_ZYNADDSUBFX_UI
  794. |NATIVE_PLUGIN_HAS_UI
  795. #endif
  796. |NATIVE_PLUGIN_USES_MULTI_PROGS
  797. |NATIVE_PLUGIN_USES_STATE),
  798. /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES
  799. |NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH
  800. |NATIVE_PLUGIN_SUPPORTS_PITCHBEND
  801. |NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF),
  802. /* audioIns */ 0,
  803. /* audioOuts */ 2,
  804. /* midiIns */ 1,
  805. /* midiOuts */ 0,
  806. /* paramIns */ ZynAddSubFxPlugin::kParamCount,
  807. /* paramOuts */ 0,
  808. /* name */ "ZynAddSubFX",
  809. /* label */ "zynaddsubfx",
  810. /* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul",
  811. /* copyright */ "GNU GPL v2+",
  812. PluginDescriptorFILL(ZynAddSubFxPlugin)
  813. };
  814. // -----------------------------------------------------------------------
  815. CARLA_EXPORT
  816. void carla_register_native_plugin_zynaddsubfx_synth();
  817. CARLA_EXPORT
  818. void carla_register_native_plugin_zynaddsubfx_synth()
  819. {
  820. carla_register_native_plugin(&zynaddsubfxDesc);
  821. }
  822. // -----------------------------------------------------------------------