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.

zynaddsubfx-synth.cpp 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2013 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. // for UINT32_MAX
  18. #define __STDC_LIMIT_MACROS
  19. #include <cstdint>
  20. #include "CarlaNative.hpp"
  21. #include "CarlaMIDI.h"
  22. #include "CarlaThread.hpp"
  23. #include "LinkedList.hpp"
  24. #include "zynaddsubfx/DSP/FFTwrapper.h"
  25. #include "zynaddsubfx/Misc/Master.h"
  26. #include "zynaddsubfx/Misc/Part.h"
  27. #include "zynaddsubfx/Misc/Util.h"
  28. #ifdef WANT_ZYNADDSUBFX_UI
  29. # ifdef override
  30. # define override_hack
  31. # undef override
  32. # endif
  33. # include "zynaddsubfx/UI/common.H"
  34. # include "zynaddsubfx/UI/MasterUI.h"
  35. # include <FL/Fl_Shared_Image.H>
  36. # include <FL/Fl_Tiled_Image.H>
  37. # include <FL/Fl_Theme.H>
  38. # ifdef override_hack
  39. # define override
  40. # undef override_hack
  41. # endif
  42. #endif
  43. #include <ctime>
  44. #include <set>
  45. #include <string>
  46. #ifdef HAVE_JUCE
  47. # include "juce_audio_basics.h"
  48. using juce::FloatVectorOperations;
  49. #endif
  50. #ifdef WANT_ZYNADDSUBFX_UI
  51. static Fl_Tiled_Image* gModuleBackdrop = nullptr;
  52. static CarlaString gPixmapPath;
  53. extern CarlaString gUiPixmapPath;
  54. void set_module_parameters(Fl_Widget* o)
  55. {
  56. CARLA_ASSERT(gModuleBackdrop != nullptr);
  57. o->box(FL_DOWN_FRAME);
  58. o->align(o->align() | FL_ALIGN_IMAGE_BACKDROP);
  59. o->color(FL_BLACK);
  60. o->labeltype(FL_SHADOW_LABEL);
  61. if (gModuleBackdrop != nullptr)
  62. o->image(gModuleBackdrop);
  63. }
  64. #endif
  65. // -----------------------------------------------------------------------
  66. class ZynAddSubFxPrograms
  67. {
  68. public:
  69. ZynAddSubFxPrograms()
  70. : fInitiated(false)
  71. {
  72. }
  73. ~ZynAddSubFxPrograms()
  74. {
  75. if (! fInitiated)
  76. return;
  77. for (auto it = fPrograms.begin(); it.valid(); it.next())
  78. {
  79. const ProgramInfo* const& pInfo(it.getValue());
  80. delete pInfo;
  81. }
  82. fPrograms.clear();
  83. FFT_cleanup();
  84. }
  85. void init()
  86. {
  87. if (fInitiated)
  88. return;
  89. fInitiated = true;
  90. fPrograms.append(new ProgramInfo(0, 0, "default"));
  91. Master& master(Master::getInstance());
  92. pthread_mutex_lock(&master.mutex);
  93. // refresh banks
  94. master.bank.rescanforbanks();
  95. for (uint32_t i=0, size = master.bank.banks.size(); i < size; ++i)
  96. {
  97. if (master.bank.banks[i].dir.empty())
  98. continue;
  99. master.bank.loadbank(master.bank.banks[i].dir);
  100. for (unsigned int instrument = 0; instrument < BANK_SIZE; ++instrument)
  101. {
  102. const std::string insName(master.bank.getname(instrument));
  103. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  104. continue;
  105. fPrograms.append(new ProgramInfo(i+1, instrument, insName.c_str()));
  106. }
  107. }
  108. pthread_mutex_unlock(&master.mutex);
  109. }
  110. void load(Master* const master, const uint8_t channel, const uint32_t bank, const uint32_t program)
  111. {
  112. if (bank == 0)
  113. {
  114. pthread_mutex_lock(&master->mutex);
  115. master->partonoff(channel, 1);
  116. master->part[channel]->defaults();
  117. master->part[channel]->applyparameters(false);
  118. pthread_mutex_unlock(&master->mutex);
  119. return;
  120. }
  121. const std::string& bankdir(master->bank.banks[bank-1].dir);
  122. if (! bankdir.empty())
  123. {
  124. pthread_mutex_lock(&master->mutex);
  125. master->partonoff(channel, 1);
  126. master->bank.loadbank(bankdir);
  127. master->bank.loadfromslot(program, master->part[channel]);
  128. master->part[channel]->applyparameters(false);
  129. pthread_mutex_unlock(&master->mutex);
  130. }
  131. }
  132. uint32_t count()
  133. {
  134. return fPrograms.count();
  135. }
  136. const NativeMidiProgram* getInfo(const uint32_t index)
  137. {
  138. if (index >= fPrograms.count())
  139. return nullptr;
  140. const ProgramInfo*& pInfo(fPrograms.getAt(index));
  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 bank_, uint32_t prog_, const char* name_)
  152. : bank(bank_),
  153. prog(prog_),
  154. name(carla_strdup(name_)) {}
  155. ~ProgramInfo()
  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. NativeMidiProgram fRetProgram;
  173. LinkedList<const ProgramInfo*> fPrograms;
  174. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxPrograms)
  175. };
  176. static ZynAddSubFxPrograms sPrograms;
  177. // -----------------------------------------------------------------------
  178. class ZynAddSubFxInstanceCount
  179. {
  180. public:
  181. ZynAddSubFxInstanceCount()
  182. : fCount(0)
  183. {
  184. }
  185. ~ZynAddSubFxInstanceCount()
  186. {
  187. CARLA_ASSERT(fCount == 0);
  188. }
  189. void addOne(const NativeHostDescriptor* const host)
  190. {
  191. if (fCount++ == 0)
  192. {
  193. CARLA_ASSERT(synth == nullptr);
  194. CARLA_ASSERT(denormalkillbuf == nullptr);
  195. reinit(host);
  196. #ifdef WANT_ZYNADDSUBFX_UI
  197. if (gPixmapPath.isEmpty())
  198. {
  199. gPixmapPath = host->resourceDir;
  200. gPixmapPath += "/zynaddsubfx/";
  201. gUiPixmapPath = gPixmapPath;
  202. }
  203. #endif
  204. }
  205. }
  206. void removeOne()
  207. {
  208. if (--fCount == 0)
  209. {
  210. CARLA_ASSERT(synth != nullptr);
  211. CARLA_ASSERT(denormalkillbuf != nullptr);
  212. Master::deleteInstance();
  213. delete[] denormalkillbuf;
  214. denormalkillbuf = nullptr;
  215. delete synth;
  216. synth = nullptr;
  217. }
  218. }
  219. void reinit(const NativeHostDescriptor* const host)
  220. {
  221. Master::deleteInstance();
  222. if (denormalkillbuf != nullptr)
  223. {
  224. delete[] denormalkillbuf;
  225. denormalkillbuf = nullptr;
  226. }
  227. if (synth != nullptr)
  228. {
  229. delete synth;
  230. synth = nullptr;
  231. }
  232. synth = new SYNTH_T();
  233. synth->buffersize = host->get_buffer_size(host->handle);
  234. synth->samplerate = host->get_sample_rate(host->handle);
  235. synth->alias();
  236. config.init();
  237. config.cfg.SoundBufferSize = synth->buffersize;
  238. config.cfg.SampleRate = synth->samplerate;
  239. config.cfg.GzipCompression = 0;
  240. sprng(std::time(nullptr));
  241. denormalkillbuf = new float[synth->buffersize];
  242. for (int i=0; i < synth->buffersize; ++i)
  243. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  244. Master::getInstance();
  245. }
  246. void maybeReinit(const NativeHostDescriptor* const host)
  247. {
  248. if (host->get_buffer_size(host->handle) == static_cast<uint32_t>(synth->buffersize) &&
  249. host->get_sample_rate(host->handle) == static_cast<double>(synth->samplerate))
  250. return;
  251. reinit(host);
  252. }
  253. private:
  254. int fCount;
  255. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxInstanceCount)
  256. };
  257. static ZynAddSubFxInstanceCount sInstanceCount;
  258. // -----------------------------------------------------------------------
  259. class ZynAddSubFxThread : public CarlaThread
  260. {
  261. public:
  262. ZynAddSubFxThread(Master* const master, const NativeHostDescriptor* const host)
  263. : CarlaThread("ZynAddSubFxThread"),
  264. fMaster(master),
  265. kHost(host),
  266. #ifdef WANT_ZYNADDSUBFX_UI
  267. fUi(nullptr),
  268. fUiClosed(0),
  269. fNextUiAction(-1),
  270. #endif
  271. fChangeProgram(false),
  272. fNextChannel(0),
  273. fNextBank(0),
  274. fNextProgram(0)
  275. {
  276. }
  277. ~ZynAddSubFxThread()
  278. {
  279. #ifdef WANT_ZYNADDSUBFX_UI
  280. // must be closed by now
  281. CARLA_ASSERT(fUi == nullptr);
  282. #endif
  283. }
  284. void loadProgramLater(const uint8_t channel, const uint32_t bank, const uint32_t program)
  285. {
  286. fNextChannel = channel;
  287. fNextBank = bank;
  288. fNextProgram = program;
  289. fChangeProgram = true;
  290. }
  291. void stopLoadProgramLater()
  292. {
  293. fChangeProgram = false;
  294. fNextChannel = 0;
  295. fNextBank = 0;
  296. fNextProgram = 0;
  297. }
  298. void setMaster(Master* const master)
  299. {
  300. fMaster = master;
  301. }
  302. #ifdef WANT_ZYNADDSUBFX_UI
  303. void uiHide()
  304. {
  305. fNextUiAction = 0;
  306. }
  307. void uiShow()
  308. {
  309. fNextUiAction = 1;
  310. }
  311. void uiRepaint()
  312. {
  313. if (fUi != nullptr)
  314. fNextUiAction = 2;
  315. }
  316. void uiChangeName(const char* const name)
  317. {
  318. if (fUi != nullptr)
  319. {
  320. Fl::lock();
  321. fUi->masterwindow->label(name);
  322. Fl::unlock();
  323. }
  324. }
  325. #endif
  326. protected:
  327. void run() override
  328. {
  329. while (! shouldExit())
  330. {
  331. #ifdef WANT_ZYNADDSUBFX_UI
  332. Fl::lock();
  333. if (fNextUiAction == 2) // repaint
  334. {
  335. CARLA_ASSERT(fUi != nullptr);
  336. if (fUi != nullptr)
  337. fUi->refresh_master_ui();
  338. }
  339. else if (fNextUiAction == 1) // init/show
  340. {
  341. static bool initialized = false;
  342. if (! initialized)
  343. {
  344. initialized = true;
  345. fl_register_images();
  346. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  347. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "knob.png"))
  348. Fl_Dial::default_image(img);
  349. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "window_backdrop.png"))
  350. Fl::scheme_bg(new Fl_Tiled_Image(img));
  351. if(Fl_Shared_Image* const img = Fl_Shared_Image::get(gPixmapPath + "module_backdrop.png"))
  352. gModuleBackdrop = new Fl_Tiled_Image(img);
  353. Fl::background(50, 50, 50);
  354. Fl::background2(70, 70, 70);
  355. Fl::foreground(255, 255, 255);
  356. Fl_Theme::set("Cairo");
  357. }
  358. CARLA_ASSERT(fUi == nullptr);
  359. if (fUi == nullptr)
  360. {
  361. fUiClosed = 0;
  362. fUi = new MasterUI(fMaster, &fUiClosed);
  363. fUi->masterwindow->label(kHost->uiName);
  364. fUi->showUI();
  365. }
  366. }
  367. else if (fNextUiAction == 0) // close
  368. {
  369. CARLA_ASSERT(fUi != nullptr);
  370. if (fUi != nullptr)
  371. {
  372. delete fUi;
  373. fUi = nullptr;
  374. }
  375. }
  376. fNextUiAction = -1;
  377. if (fUiClosed != 0)
  378. {
  379. fUiClosed = 0;
  380. fNextUiAction = 0;
  381. kHost->ui_closed(kHost->handle);
  382. }
  383. Fl::check();
  384. Fl::unlock();
  385. #endif
  386. if (fChangeProgram)
  387. {
  388. fChangeProgram = false;
  389. sPrograms.load(fMaster, fNextChannel, fNextBank, fNextProgram);
  390. fNextChannel = 0;
  391. fNextBank = 0;
  392. fNextProgram = 0;
  393. #ifdef WANT_ZYNADDSUBFX_UI
  394. if (fUi != nullptr)
  395. {
  396. Fl::lock();
  397. fUi->refresh_master_ui();
  398. Fl::unlock();
  399. }
  400. #endif
  401. carla_msleep(15);
  402. }
  403. else
  404. {
  405. carla_msleep(30);
  406. }
  407. }
  408. #ifdef WANT_ZYNADDSUBFX_UI
  409. if (shouldExit() || fUi != nullptr)
  410. {
  411. Fl::lock();
  412. delete fUi;
  413. fUi = nullptr;
  414. Fl::check();
  415. Fl::unlock();
  416. }
  417. #endif
  418. }
  419. private:
  420. Master* fMaster;
  421. const NativeHostDescriptor* const kHost;
  422. #ifdef WANT_ZYNADDSUBFX_UI
  423. MasterUI* fUi;
  424. int fUiClosed;
  425. volatile int fNextUiAction;
  426. #endif
  427. volatile bool fChangeProgram;
  428. volatile uint8_t fNextChannel;
  429. volatile uint32_t fNextBank;
  430. volatile uint32_t fNextProgram;
  431. };
  432. // -----------------------------------------------------------------------
  433. class ZynAddSubFxPlugin : public NativePluginClass
  434. {
  435. public:
  436. ZynAddSubFxPlugin(const NativeHostDescriptor* const host)
  437. : NativePluginClass(host),
  438. fMaster(new Master()),
  439. fSampleRate(getSampleRate()),
  440. fIsActive(false),
  441. fThread(fMaster, host)
  442. {
  443. fThread.start();
  444. for (int i = 0; i < NUM_MIDI_PARTS; ++i)
  445. fMaster->partonoff(i, 1);
  446. sPrograms.init();
  447. }
  448. ~ZynAddSubFxPlugin() override
  449. {
  450. deleteMaster();
  451. }
  452. protected:
  453. // -------------------------------------------------------------------
  454. // Plugin midi-program calls
  455. uint32_t getMidiProgramCount() const override
  456. {
  457. return sPrograms.count();
  458. }
  459. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override
  460. {
  461. return sPrograms.getInfo(index);
  462. }
  463. // -------------------------------------------------------------------
  464. // Plugin state calls
  465. void setMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  466. {
  467. if (bank >= fMaster->bank.banks.size())
  468. return;
  469. if (program >= BANK_SIZE)
  470. return;
  471. if (isOffline() || ! fIsActive)
  472. {
  473. sPrograms.load(fMaster, channel, bank, program);
  474. #ifdef WANT_ZYNADDSUBFX_UI
  475. fThread.uiRepaint();
  476. #endif
  477. }
  478. else
  479. fThread.loadProgramLater(channel, bank, program);
  480. }
  481. void setCustomData(const char* const key, const char* const value) override
  482. {
  483. CARLA_SAFE_ASSERT_RETURN(key != nullptr,);
  484. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  485. if (std::strcmp(key, "CarlaAlternateFile1") == 0) // xmz
  486. fMaster->loadXML(value);
  487. else if (std::strcmp(key, "CarlaAlternateFile2") == 0) // xiz
  488. fMaster->part[0]->loadXMLinstrument(value);
  489. }
  490. // -------------------------------------------------------------------
  491. // Plugin process calls
  492. void activate() override
  493. {
  494. fIsActive = true;
  495. }
  496. void deactivate() override
  497. {
  498. fIsActive = false;
  499. }
  500. void process(float**, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  501. {
  502. if (pthread_mutex_trylock(&fMaster->mutex) != 0)
  503. {
  504. #ifdef HAVE_JUCE
  505. FloatVectorOperations::clear(outBuffer[0], frames);
  506. FloatVectorOperations::clear(outBuffer[1], frames);
  507. #else
  508. carla_zeroFloat(outBuffer[0], frames);
  509. carla_zeroFloat(outBuffer[1], frames);
  510. #endif
  511. return;
  512. }
  513. for (uint32_t i=0; i < midiEventCount; ++i)
  514. {
  515. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  516. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
  517. const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
  518. if (MIDI_IS_STATUS_NOTE_OFF(status))
  519. {
  520. const uint8_t note = midiEvent->data[1];
  521. fMaster->noteOff(channel, note);
  522. }
  523. else if (MIDI_IS_STATUS_NOTE_ON(status))
  524. {
  525. const uint8_t note = midiEvent->data[1];
  526. const uint8_t velo = midiEvent->data[2];
  527. fMaster->noteOn(channel, note, velo);
  528. }
  529. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  530. {
  531. const uint8_t note = midiEvent->data[1];
  532. const uint8_t pressure = midiEvent->data[2];
  533. fMaster->polyphonicAftertouch(channel, note, pressure);
  534. }
  535. else if (MIDI_IS_STATUS_CONTROL_CHANGE(status))
  536. {
  537. const uint8_t control = midiEvent->data[1];
  538. const uint8_t value = midiEvent->data[2];
  539. fMaster->setController(channel, control, value);
  540. }
  541. else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
  542. {
  543. const uint8_t lsb = midiEvent->data[1];
  544. const uint8_t msb = midiEvent->data[2];
  545. const int value = ((msb << 7) | lsb) - 8192;
  546. fMaster->setController(channel, C_pitchwheel, value);
  547. }
  548. }
  549. fMaster->GetAudioOutSamples(frames, fSampleRate, outBuffer[0], outBuffer[1]);
  550. pthread_mutex_unlock(&fMaster->mutex);
  551. }
  552. #ifdef WANT_ZYNADDSUBFX_UI
  553. // -------------------------------------------------------------------
  554. // Plugin UI calls
  555. void uiShow(const bool show) override
  556. {
  557. if (show)
  558. fThread.uiShow();
  559. else
  560. fThread.uiHide();
  561. }
  562. #endif
  563. // -------------------------------------------------------------------
  564. // Plugin state calls
  565. char* getState() const override
  566. {
  567. config.save();
  568. char* data = nullptr;
  569. fMaster->getalldata(&data);
  570. return data;
  571. }
  572. void setState(const char* const data) override
  573. {
  574. fThread.stopLoadProgramLater();
  575. fMaster->putalldata((char*)data, 0);
  576. fMaster->applyparameters(true);
  577. }
  578. // -------------------------------------------------------------------
  579. // Plugin dispatcher
  580. // TODO - save&load current state
  581. void bufferSizeChanged(const uint32_t) final
  582. {
  583. deleteMaster();
  584. sInstanceCount.maybeReinit(getHostHandle());
  585. initMaster();
  586. }
  587. void sampleRateChanged(const double sampleRate) final
  588. {
  589. fSampleRate = sampleRate;
  590. deleteMaster();
  591. sInstanceCount.maybeReinit(getHostHandle());
  592. initMaster();
  593. }
  594. void initMaster()
  595. {
  596. fMaster = new Master();
  597. fThread.setMaster(fMaster);
  598. fThread.start();
  599. for (int i = 0; i < NUM_MIDI_PARTS; ++i)
  600. fMaster->partonoff(i, 1);
  601. }
  602. void deleteMaster()
  603. {
  604. //ensure that everything has stopped
  605. pthread_mutex_lock(&fMaster->mutex);
  606. pthread_mutex_unlock(&fMaster->mutex);
  607. fThread.stop(-1);
  608. delete fMaster;
  609. fMaster = nullptr;
  610. }
  611. #ifdef WANT_ZYNADDSUBFX_UI
  612. void uiNameChanged(const char* const uiName) override
  613. {
  614. fThread.uiChangeName(uiName);
  615. }
  616. #endif
  617. // -------------------------------------------------------------------
  618. private:
  619. Master* fMaster;
  620. unsigned fSampleRate;
  621. bool fIsActive;
  622. ZynAddSubFxThread fThread;
  623. public:
  624. static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
  625. {
  626. sInstanceCount.addOne(host);
  627. return new ZynAddSubFxPlugin(host);
  628. }
  629. static void _cleanup(NativePluginHandle handle)
  630. {
  631. delete (ZynAddSubFxPlugin*)handle;
  632. sInstanceCount.removeOne();
  633. }
  634. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  635. };
  636. // -----------------------------------------------------------------------
  637. static const NativePluginDescriptor zynaddsubfxDesc = {
  638. /* category */ PLUGIN_CATEGORY_SYNTH,
  639. #ifdef WANT_ZYNADDSUBFX_UI
  640. /* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_USES_STATE),
  641. #else
  642. /* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_USES_STATE),
  643. #endif
  644. /* supports */ static_cast<NativePluginSupports>(PLUGIN_SUPPORTS_CONTROL_CHANGES|PLUGIN_SUPPORTS_NOTE_AFTERTOUCH|PLUGIN_SUPPORTS_PITCHBEND|PLUGIN_SUPPORTS_ALL_SOUND_OFF),
  645. /* audioIns */ 0,
  646. /* audioOuts */ 2,
  647. /* midiIns */ 1,
  648. /* midiOuts */ 0,
  649. /* paramIns */ 0,
  650. /* paramOuts */ 0,
  651. /* name */ "ZynAddSubFX",
  652. /* label */ "zynaddsubfx",
  653. /* maker */ "falkTX",
  654. /* copyright */ "GNU GPL v2+",
  655. PluginDescriptorFILL(ZynAddSubFxPlugin)
  656. };
  657. // -----------------------------------------------------------------------
  658. CARLA_EXPORT
  659. void carla_register_native_plugin_zynaddsubfx_synth()
  660. {
  661. carla_register_native_plugin(&zynaddsubfxDesc);
  662. }
  663. // -----------------------------------------------------------------------