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.

944 lines
25KB

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