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.

1031 lines
28KB

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