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 28KB

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