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.

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