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

10 years ago
10 years ago
8 years ago
9 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2017 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 "CarlaNativeExtUI.hpp"
  18. #include "CarlaMIDI.h"
  19. #include "CarlaThread.hpp"
  20. #include "LinkedList.hpp"
  21. #include "CarlaMathUtils.hpp"
  22. #include "Misc/Master.h"
  23. #include "Misc/MiddleWare.h"
  24. #include "Misc/Part.h"
  25. #include "Misc/Util.h"
  26. #include <ctime>
  27. #include <set>
  28. #include <string>
  29. #include "AppConfig.h"
  30. #include "juce_audio_basics/juce_audio_basics.h"
  31. using juce::roundToIntAccurate;
  32. using juce::FloatVectorOperations;
  33. using juce::ScopedPointer;
  34. // #define ZYN_MSG_ANYWHERE
  35. // -----------------------------------------------------------------------
  36. class ZynAddSubFxPrograms
  37. {
  38. public:
  39. ZynAddSubFxPrograms() noexcept
  40. : fInitiated(false),
  41. #ifdef CARLA_PROPER_CPP11_SUPPORT
  42. fRetProgram({0, 0, nullptr}),
  43. #endif
  44. fProgramCount(0),
  45. fPrograms(nullptr) {}
  46. ~ZynAddSubFxPrograms() noexcept
  47. {
  48. if (! fInitiated)
  49. return;
  50. for (uint32_t i=0; i<fProgramCount; ++i)
  51. delete fPrograms[i];
  52. delete[] fPrograms;
  53. }
  54. void initIfNeeded()
  55. {
  56. if (fInitiated)
  57. return;
  58. fInitiated = true;
  59. std::vector<const ProgramInfo*> programs;
  60. programs.push_back(new ProgramInfo(0, 0, "default", ""));
  61. CarlaConfig config;
  62. config.init();
  63. SYNTH_T synth;
  64. Master master(synth, &config);
  65. // refresh banks
  66. master.bank.rescanforbanks();
  67. for (std::size_t i=0, size=master.bank.banks.size(); i<size; ++i)
  68. {
  69. const std::string dir(master.bank.banks[i].dir);
  70. if (dir.empty())
  71. continue;
  72. master.bank.loadbank(dir);
  73. for (uint ninstrument = 0; ninstrument < BANK_SIZE; ++ninstrument)
  74. {
  75. const Bank::ins_t& instrument(master.bank.ins[ninstrument]);
  76. if (instrument.name.empty() || instrument.name[0] == ' ')
  77. continue;
  78. programs.push_back(new ProgramInfo(i+1, ninstrument, instrument.name.c_str(), instrument.filename.c_str()));
  79. }
  80. }
  81. fPrograms = new const ProgramInfo*[programs.size()];
  82. for (const ProgramInfo* p : programs)
  83. fPrograms[fProgramCount++] = p;
  84. }
  85. uint32_t getNativeMidiProgramCount() const noexcept
  86. {
  87. return fProgramCount;
  88. }
  89. const NativeMidiProgram* getNativeMidiProgramInfo(const uint32_t index) const noexcept
  90. {
  91. if (index >= fProgramCount)
  92. return nullptr;
  93. const ProgramInfo* const pInfo(fPrograms[index]);
  94. CARLA_SAFE_ASSERT_RETURN(pInfo != nullptr, nullptr);
  95. fRetProgram.bank = pInfo->bank;
  96. fRetProgram.program = pInfo->prog;
  97. fRetProgram.name = pInfo->name;
  98. return &fRetProgram;
  99. }
  100. const char* getZynProgramFilename(const uint32_t bank, const uint32_t program) const noexcept
  101. {
  102. for (uint32_t i=0; i<fProgramCount; ++i)
  103. {
  104. const ProgramInfo* const pInfo(fPrograms[i]);
  105. if (pInfo->bank != bank)
  106. continue;
  107. if (pInfo->prog != program)
  108. continue;
  109. return pInfo->filename;
  110. }
  111. return nullptr;
  112. }
  113. private:
  114. struct ProgramInfo {
  115. uint32_t bank;
  116. uint32_t prog;
  117. const char* name;
  118. const char* filename;
  119. ProgramInfo(uint32_t b, uint32_t p, const char* n, const char* fn) noexcept
  120. : bank(b),
  121. prog(p),
  122. name(carla_strdup_safe(n)),
  123. filename(carla_strdup_safe(fn)) {}
  124. ~ProgramInfo() noexcept
  125. {
  126. if (name != nullptr)
  127. {
  128. delete[] name;
  129. name = nullptr;
  130. }
  131. if (filename != nullptr)
  132. {
  133. delete[] filename;
  134. filename = nullptr;
  135. }
  136. }
  137. #ifdef CARLA_PROPER_CPP11_SUPPORT
  138. ProgramInfo() = delete;
  139. ProgramInfo(ProgramInfo&) = delete;
  140. ProgramInfo(const ProgramInfo&) = delete;
  141. ProgramInfo& operator=(ProgramInfo&);
  142. ProgramInfo& operator=(const ProgramInfo&);
  143. #endif
  144. };
  145. bool fInitiated;
  146. mutable NativeMidiProgram fRetProgram;
  147. uint32_t fProgramCount;
  148. const ProgramInfo** fPrograms;
  149. CARLA_PREVENT_HEAP_ALLOCATION
  150. CARLA_DECLARE_NON_COPY_CLASS(ZynAddSubFxPrograms)
  151. };
  152. static ZynAddSubFxPrograms sPrograms;
  153. // -----------------------------------------------------------------------
  154. class MiddleWareThread : private CarlaThread
  155. {
  156. public:
  157. class ScopedStopper
  158. {
  159. public:
  160. ScopedStopper(MiddleWareThread& mwt) noexcept
  161. : wasRunning(mwt.isThreadRunning()),
  162. thread(mwt),
  163. middleWare(mwt.fMiddleWare)
  164. {
  165. if (wasRunning)
  166. thread.stop();
  167. }
  168. ~ScopedStopper() noexcept
  169. {
  170. if (wasRunning)
  171. thread.start(middleWare);
  172. }
  173. void updateMiddleWare(MiddleWare* const mw) noexcept
  174. {
  175. middleWare = mw;
  176. }
  177. private:
  178. const bool wasRunning;
  179. MiddleWareThread& thread;
  180. MiddleWare* middleWare;
  181. CARLA_PREVENT_HEAP_ALLOCATION
  182. CARLA_DECLARE_NON_COPY_CLASS(ScopedStopper)
  183. };
  184. MiddleWareThread()
  185. : CarlaThread("ZynMiddleWare"),
  186. fMiddleWare(nullptr) {}
  187. void start(MiddleWare* const mw) noexcept
  188. {
  189. fMiddleWare = mw;
  190. startThread();
  191. }
  192. void stop() noexcept
  193. {
  194. stopThread(1000);
  195. fMiddleWare = nullptr;
  196. }
  197. private:
  198. MiddleWare* fMiddleWare;
  199. void run() noexcept override
  200. {
  201. for (; ! shouldThreadExit();)
  202. {
  203. CARLA_SAFE_ASSERT_RETURN(fMiddleWare != nullptr,);
  204. try {
  205. fMiddleWare->tick();
  206. } CARLA_SAFE_EXCEPTION("ZynAddSubFX MiddleWare tick");
  207. carla_msleep(1);
  208. }
  209. }
  210. CARLA_DECLARE_NON_COPY_CLASS(MiddleWareThread)
  211. };
  212. // -----------------------------------------------------------------------
  213. class ZynAddSubFxPlugin : public NativePluginAndUiClass
  214. {
  215. public:
  216. enum Parameters {
  217. kParamPart01Enabled ,
  218. kParamPart16Enabled = kParamPart01Enabled + 15,
  219. kParamPart01Volume,
  220. kParamPart16Volume = kParamPart01Volume + 15,
  221. kParamPart01Panning,
  222. kParamPart16Panning = kParamPart01Panning + 15,
  223. kParamFilterCutoff, // Filter Frequency
  224. kParamFilterQ, // Filter Resonance
  225. kParamBandwidth, // Bandwidth
  226. kParamModAmp, // FM Gain
  227. kParamResCenter, // Resonance center frequency
  228. kParamResBandwidth, // Resonance bandwidth
  229. kParamCount
  230. };
  231. ZynAddSubFxPlugin(const NativeHostDescriptor* const host)
  232. : NativePluginAndUiClass(host, "zynaddsubfx-ui"),
  233. fMiddleWare(nullptr),
  234. fMaster(nullptr),
  235. fSynth(),
  236. fDefaultState(nullptr),
  237. fMutex(),
  238. fMiddleWareThread(new MiddleWareThread())
  239. {
  240. isPlugin = true;
  241. sPrograms.initIfNeeded();
  242. fConfig.init();
  243. // init parameters to default
  244. fParameters[kParamPart01Enabled] = 1.0f;
  245. for (int i=kParamPart16Enabled+1; --i>kParamPart01Enabled;)
  246. fParameters[i] = 0.0f;
  247. for (int i=kParamPart16Volume+1; --i>=kParamPart01Volume;)
  248. fParameters[i] = 100.0f;
  249. for (int i=kParamPart16Panning+1; --i>=kParamPart01Panning;)
  250. fParameters[i] = 64.0f;
  251. fParameters[kParamFilterCutoff] = 64.0f;
  252. fParameters[kParamFilterQ] = 64.0f;
  253. fParameters[kParamBandwidth] = 64.0f;
  254. fParameters[kParamModAmp] = 127.0f;
  255. fParameters[kParamResCenter] = 64.0f;
  256. fParameters[kParamResBandwidth] = 64.0f;
  257. fSynth.buffersize = static_cast<int>(getBufferSize());
  258. fSynth.samplerate = static_cast<uint>(getSampleRate());
  259. if (fSynth.buffersize > 32)
  260. fSynth.buffersize = 32;
  261. fSynth.alias();
  262. _initMaster();
  263. _setMasterParameters();
  264. fMaster->getalldata(&fDefaultState);
  265. fMiddleWareThread->start(fMiddleWare);
  266. }
  267. ~ZynAddSubFxPlugin() override
  268. {
  269. fMiddleWareThread->stop();
  270. _deleteMaster();
  271. std::free(fDefaultState);
  272. }
  273. protected:
  274. // -------------------------------------------------------------------
  275. // Plugin parameter calls
  276. uint32_t getParameterCount() const final
  277. {
  278. return kParamCount;
  279. }
  280. const NativeParameter* getParameterInfo(const uint32_t index) const override
  281. {
  282. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
  283. static NativeParameter param;
  284. int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE;
  285. param.name = nullptr;
  286. param.unit = nullptr;
  287. param.ranges.def = 64.0f;
  288. param.ranges.min = 0.0f;
  289. param.ranges.max = 127.0f;
  290. param.ranges.step = 1.0f;
  291. param.ranges.stepSmall = 1.0f;
  292. param.ranges.stepLarge = 20.0f;
  293. param.scalePointCount = 0;
  294. param.scalePoints = nullptr;
  295. if (index <= kParamPart16Enabled)
  296. {
  297. hints |= NATIVE_PARAMETER_IS_BOOLEAN;
  298. param.ranges.def = 0.0f;
  299. param.ranges.min = 0.0f;
  300. param.ranges.max = 1.0f;
  301. param.ranges.step = 1.0f;
  302. param.ranges.stepSmall = 1.0f;
  303. param.ranges.stepLarge = 1.0f;
  304. #define PARAM_PART_ENABLE_DESC(N) \
  305. case kParamPart01Enabled + N - 1: \
  306. param.name = "Part " #N " Enabled"; break;
  307. switch (index)
  308. {
  309. PARAM_PART_ENABLE_DESC( 1)
  310. PARAM_PART_ENABLE_DESC( 2)
  311. PARAM_PART_ENABLE_DESC( 3)
  312. PARAM_PART_ENABLE_DESC( 4)
  313. PARAM_PART_ENABLE_DESC( 5)
  314. PARAM_PART_ENABLE_DESC( 6)
  315. PARAM_PART_ENABLE_DESC( 7)
  316. PARAM_PART_ENABLE_DESC( 8)
  317. PARAM_PART_ENABLE_DESC( 9)
  318. PARAM_PART_ENABLE_DESC(10)
  319. PARAM_PART_ENABLE_DESC(11)
  320. PARAM_PART_ENABLE_DESC(12)
  321. PARAM_PART_ENABLE_DESC(13)
  322. PARAM_PART_ENABLE_DESC(14)
  323. PARAM_PART_ENABLE_DESC(15)
  324. PARAM_PART_ENABLE_DESC(16)
  325. }
  326. #undef PARAM_PART_ENABLE_DESC
  327. }
  328. else if (index <= kParamPart16Volume)
  329. {
  330. hints |= NATIVE_PARAMETER_IS_INTEGER;
  331. param.ranges.def = 100.0f;
  332. #define PARAM_PART_ENABLE_DESC(N) \
  333. case kParamPart01Volume + N - 1: \
  334. param.name = "Part " #N " Volume"; break;
  335. switch (index)
  336. {
  337. PARAM_PART_ENABLE_DESC( 1)
  338. PARAM_PART_ENABLE_DESC( 2)
  339. PARAM_PART_ENABLE_DESC( 3)
  340. PARAM_PART_ENABLE_DESC( 4)
  341. PARAM_PART_ENABLE_DESC( 5)
  342. PARAM_PART_ENABLE_DESC( 6)
  343. PARAM_PART_ENABLE_DESC( 7)
  344. PARAM_PART_ENABLE_DESC( 8)
  345. PARAM_PART_ENABLE_DESC( 9)
  346. PARAM_PART_ENABLE_DESC(10)
  347. PARAM_PART_ENABLE_DESC(11)
  348. PARAM_PART_ENABLE_DESC(12)
  349. PARAM_PART_ENABLE_DESC(13)
  350. PARAM_PART_ENABLE_DESC(14)
  351. PARAM_PART_ENABLE_DESC(15)
  352. PARAM_PART_ENABLE_DESC(16)
  353. }
  354. #undef PARAM_PART_ENABLE_DESC
  355. }
  356. else if (index <= kParamPart16Panning)
  357. {
  358. hints |= NATIVE_PARAMETER_IS_INTEGER;
  359. #define PARAM_PART_ENABLE_DESC(N) \
  360. case kParamPart01Panning + N - 1: \
  361. param.name = "Part " #N " Panning"; break;
  362. switch (index)
  363. {
  364. PARAM_PART_ENABLE_DESC( 1)
  365. PARAM_PART_ENABLE_DESC( 2)
  366. PARAM_PART_ENABLE_DESC( 3)
  367. PARAM_PART_ENABLE_DESC( 4)
  368. PARAM_PART_ENABLE_DESC( 5)
  369. PARAM_PART_ENABLE_DESC( 6)
  370. PARAM_PART_ENABLE_DESC( 7)
  371. PARAM_PART_ENABLE_DESC( 8)
  372. PARAM_PART_ENABLE_DESC( 9)
  373. PARAM_PART_ENABLE_DESC(10)
  374. PARAM_PART_ENABLE_DESC(11)
  375. PARAM_PART_ENABLE_DESC(12)
  376. PARAM_PART_ENABLE_DESC(13)
  377. PARAM_PART_ENABLE_DESC(14)
  378. PARAM_PART_ENABLE_DESC(15)
  379. PARAM_PART_ENABLE_DESC(16)
  380. }
  381. #undef PARAM_PART_ENABLE_DESC
  382. }
  383. else if (index <= kParamResBandwidth)
  384. {
  385. hints |= NATIVE_PARAMETER_IS_INTEGER;
  386. switch (index)
  387. {
  388. case kParamFilterCutoff:
  389. param.name = "Filter Cutoff";
  390. break;
  391. case kParamFilterQ:
  392. param.name = "Filter Q";
  393. break;
  394. case kParamBandwidth:
  395. param.name = "Bandwidth";
  396. break;
  397. case kParamModAmp:
  398. param.name = "FM Gain";
  399. param.ranges.def = 127.0f;
  400. break;
  401. case kParamResCenter:
  402. param.name = "Res Center Freq";
  403. break;
  404. case kParamResBandwidth:
  405. param.name = "Res Bandwidth";
  406. break;
  407. }
  408. }
  409. param.hints = static_cast<NativeParameterHints>(hints);
  410. return &param;
  411. }
  412. float getParameterValue(const uint32_t index) const final
  413. {
  414. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
  415. return fParameters[index];
  416. }
  417. // -------------------------------------------------------------------
  418. // Plugin midi-program calls
  419. uint32_t getMidiProgramCount() const noexcept override
  420. {
  421. return sPrograms.getNativeMidiProgramCount();
  422. }
  423. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const noexcept override
  424. {
  425. return sPrograms.getNativeMidiProgramInfo(index);
  426. }
  427. // -------------------------------------------------------------------
  428. // Plugin state calls
  429. void setParameterValue(const uint32_t index, const float value) final
  430. {
  431. CARLA_SAFE_ASSERT_RETURN(index < kParamCount,);
  432. if (index <= kParamPart16Enabled)
  433. {
  434. fParameters[index] = (value >= 0.5f) ? 1.0f : 0.0f;
  435. char msg[24];
  436. std::sprintf(msg, "/part%i/Penabled", index-kParamPart01Enabled);
  437. #ifdef ZYN_MSG_ANYWHERE
  438. fMiddleWare->messageAnywhere(msg, (value >= 0.5f) ? "T" : "F");
  439. #else
  440. fMiddleWare->transmitMsg("/echo", "ss", "OSC_URL", "");
  441. fMiddleWare->activeUrl("");
  442. fMiddleWare->transmitMsg(msg, (value >= 0.5f) ? "T" : "F");
  443. #endif
  444. }
  445. else if (index <= kParamPart16Volume)
  446. {
  447. if (carla_isEqual(fParameters[index], value))
  448. return;
  449. fParameters[index] = std::round(carla_fixedValue(0.0f, 127.0f, value));
  450. char msg[24];
  451. std::sprintf(msg, "/part%i/Pvolume", index-kParamPart01Volume);
  452. #ifdef ZYN_MSG_ANYWHERE
  453. fMiddleWare->messageAnywhere(msg, "i", static_cast<int>(fParameters[index]));
  454. #else
  455. fMiddleWare->transmitMsg("/echo", "ss", "OSC_URL", "");
  456. fMiddleWare->activeUrl("");
  457. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[index]));
  458. #endif
  459. }
  460. else if (index <= kParamPart16Panning)
  461. {
  462. if (carla_isEqual(fParameters[index], value))
  463. return;
  464. fParameters[index] = std::round(carla_fixedValue(0.0f, 127.0f, value));
  465. char msg[24];
  466. std::sprintf(msg, "/part%i/Ppanning", index-kParamPart01Panning);
  467. #ifdef ZYN_MSG_ANYWHERE
  468. fMiddleWare->messageAnywhere(msg, "i", static_cast<int>(fParameters[index]));
  469. #else
  470. fMiddleWare->transmitMsg("/echo", "ss", "OSC_URL", "");
  471. fMiddleWare->activeUrl("");
  472. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[index]));
  473. #endif
  474. }
  475. else if (index <= kParamResBandwidth)
  476. {
  477. const MidiControllers zynControl(getZynControlFromIndex(index));
  478. CARLA_SAFE_ASSERT_RETURN(zynControl != C_NULL,);
  479. fParameters[index] = std::round(carla_fixedValue(0.0f, 127.0f, value));
  480. for (int npart=0; npart<NUM_MIDI_PARTS; ++npart)
  481. {
  482. if (fMaster->part[npart] != nullptr)
  483. fMaster->part[npart]->SetController(zynControl, static_cast<int>(value));
  484. }
  485. }
  486. }
  487. void setMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  488. {
  489. CARLA_SAFE_ASSERT_RETURN(program < BANK_SIZE,);
  490. if (bank == 0)
  491. {
  492. // reset part to default
  493. setState(fDefaultState);
  494. return;
  495. }
  496. const char* const filename(sPrograms.getZynProgramFilename(bank, program));
  497. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0',);
  498. #ifdef ZYN_MSG_ANYWHERE
  499. fMiddleWare->messageAnywhere("/load-part", "is", channel, filename);
  500. #else
  501. fMiddleWare->transmitMsg("/load-part", "is", channel, filename);
  502. #endif
  503. }
  504. void setCustomData(const char* const key, const char* const value) override
  505. {
  506. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  507. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  508. /**/ if (std::strcmp(key, "CarlaAlternateFile1") == 0) // xmz
  509. {
  510. #ifdef ZYN_MSG_ANYWHERE
  511. fMiddleWare->messageAnywhere("/load_xmz", "s", value);
  512. #else
  513. fMiddleWare->transmitMsg("/load_xmz", "s", value);
  514. #endif
  515. }
  516. else if (std::strcmp(key, "CarlaAlternateFile2") == 0) // xiz
  517. {
  518. #ifdef ZYN_MSG_ANYWHERE
  519. fMiddleWare->messageAnywhere("/load_xiz", "is", 0, value);
  520. #else
  521. fMiddleWare->transmitMsg("/load_xiz", "is", 0, value);
  522. #endif
  523. }
  524. }
  525. // -------------------------------------------------------------------
  526. // Plugin process calls
  527. void process(float**, float** const outBuffer, const uint32_t frames,
  528. const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  529. {
  530. if (! fMutex.tryLock())
  531. {
  532. if (! isOffline())
  533. {
  534. FloatVectorOperations::clear(outBuffer[0], static_cast<int>(frames));
  535. FloatVectorOperations::clear(outBuffer[1], static_cast<int>(frames));
  536. return;
  537. }
  538. fMutex.lock();
  539. }
  540. uint32_t framesOffset = 0;
  541. for (uint32_t i=0; i < midiEventCount; ++i)
  542. {
  543. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  544. if (midiEvent->time >= frames)
  545. continue;
  546. if (midiEvent->time > framesOffset)
  547. {
  548. fMaster->GetAudioOutSamples(midiEvent->time-framesOffset, fSynth.samplerate, outBuffer[0]+framesOffset,
  549. outBuffer[1]+framesOffset);
  550. framesOffset = midiEvent->time;
  551. }
  552. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
  553. const char channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
  554. if (MIDI_IS_STATUS_NOTE_OFF(status))
  555. {
  556. const char note = static_cast<char>(midiEvent->data[1]);
  557. fMaster->noteOff(channel, note);
  558. }
  559. else if (MIDI_IS_STATUS_NOTE_ON(status))
  560. {
  561. const char note = static_cast<char>(midiEvent->data[1]);
  562. const char velo = static_cast<char>(midiEvent->data[2]);
  563. fMaster->noteOn(channel, note, velo);
  564. }
  565. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  566. {
  567. const char note = static_cast<char>(midiEvent->data[1]);
  568. const char pressure = static_cast<char>(midiEvent->data[2]);
  569. fMaster->polyphonicAftertouch(channel, note, pressure);
  570. }
  571. else if (MIDI_IS_STATUS_CONTROL_CHANGE(status))
  572. {
  573. // skip controls which we map to parameters
  574. if (getIndexFromZynControl(midiEvent->data[1]) != kParamCount)
  575. continue;
  576. const int control = midiEvent->data[1];
  577. const int value = midiEvent->data[2];
  578. fMaster->setController(channel, control, value);
  579. }
  580. else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
  581. {
  582. const uint8_t lsb = midiEvent->data[1];
  583. const uint8_t msb = midiEvent->data[2];
  584. const int value = ((msb << 7) | lsb) - 8192;
  585. fMaster->setController(channel, C_pitchwheel, value);
  586. }
  587. }
  588. if (frames > framesOffset)
  589. fMaster->GetAudioOutSamples(frames-framesOffset, fSynth.samplerate, outBuffer[0]+framesOffset,
  590. outBuffer[1]+framesOffset);
  591. fMutex.unlock();
  592. }
  593. // -------------------------------------------------------------------
  594. // Plugin UI calls
  595. #ifdef HAVE_ZYN_UI_DEPS
  596. void uiShow(const bool show) override
  597. {
  598. if (show)
  599. {
  600. if (isPipeRunning())
  601. {
  602. const CarlaMutexLocker cml(getPipeLock());
  603. writeMessage("focus\n", 6);
  604. flushMessages();
  605. return;
  606. }
  607. carla_stdout("Trying to start UI using \"%s\"", getExtUiPath());
  608. CarlaExternalUI::setData(getExtUiPath(), fMiddleWare->getServerAddress(), getUiName());
  609. if (! CarlaExternalUI::startPipeServer(true))
  610. {
  611. uiClosed();
  612. hostUiUnavailable();
  613. }
  614. }
  615. else
  616. {
  617. CarlaExternalUI::stopPipeServer(2000);
  618. }
  619. }
  620. #endif
  621. // -------------------------------------------------------------------
  622. // Plugin state calls
  623. char* getState() const override
  624. {
  625. const MiddleWareThread::ScopedStopper mwss(*fMiddleWareThread);
  626. char* data = nullptr;
  627. fMaster->getalldata(&data);
  628. return data;
  629. }
  630. void setState(const char* const data) override
  631. {
  632. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  633. const MiddleWareThread::ScopedStopper mwss(*fMiddleWareThread);
  634. const CarlaMutexLocker cml(fMutex);
  635. fMaster->defaults();
  636. fMaster->putalldata(data);
  637. fMaster->applyparameters();
  638. fMaster->initialize_rt();
  639. fMiddleWare->updateResources(fMaster);
  640. _setMasterParameters();
  641. }
  642. // -------------------------------------------------------------------
  643. // Plugin dispatcher
  644. void bufferSizeChanged(const uint32_t bufferSize) final
  645. {
  646. MiddleWareThread::ScopedStopper mwss(*fMiddleWareThread);
  647. char* const state(getState());
  648. _deleteMaster();
  649. fSynth.buffersize = static_cast<int>(bufferSize);
  650. if (fSynth.buffersize > 32)
  651. fSynth.buffersize = 32;
  652. fSynth.alias();
  653. _initMaster();
  654. mwss.updateMiddleWare(fMiddleWare);
  655. setState(state);
  656. std::free(state);
  657. }
  658. void sampleRateChanged(const double sampleRate) final
  659. {
  660. MiddleWareThread::ScopedStopper mwss(*fMiddleWareThread);
  661. char* const state(getState());
  662. _deleteMaster();
  663. fSynth.samplerate = static_cast<uint>(sampleRate);
  664. fSynth.alias();
  665. _initMaster();
  666. mwss.updateMiddleWare(fMiddleWare);
  667. setState(state);
  668. std::free(state);
  669. }
  670. // -------------------------------------------------------------------
  671. private:
  672. MiddleWare* fMiddleWare;
  673. Master* fMaster;
  674. SYNTH_T fSynth;
  675. CarlaConfig fConfig;
  676. char* fDefaultState;
  677. float fParameters[kParamCount];
  678. CarlaMutex fMutex;
  679. ScopedPointer<MiddleWareThread> fMiddleWareThread;
  680. static MidiControllers getZynControlFromIndex(const uint index)
  681. {
  682. switch (index)
  683. {
  684. case kParamFilterCutoff:
  685. return C_filtercutoff;
  686. case kParamFilterQ:
  687. return C_filterq;
  688. case kParamBandwidth:
  689. return C_bandwidth;
  690. case kParamModAmp:
  691. return C_fmamp;
  692. case kParamResCenter:
  693. return C_resonance_center;
  694. case kParamResBandwidth:
  695. return C_resonance_bandwidth;
  696. default:
  697. return C_NULL;
  698. }
  699. }
  700. static Parameters getIndexFromZynControl(const uint8_t control)
  701. {
  702. switch (control)
  703. {
  704. case C_filtercutoff:
  705. return kParamFilterCutoff;
  706. case C_filterq:
  707. return kParamFilterQ;
  708. case C_bandwidth:
  709. return kParamBandwidth;
  710. case C_fmamp:
  711. return kParamModAmp;
  712. case C_resonance_center:
  713. return kParamResCenter;
  714. case C_resonance_bandwidth:
  715. return kParamResBandwidth;
  716. default:
  717. return kParamCount;
  718. }
  719. }
  720. // -------------------------------------------------------------------
  721. void _initMaster()
  722. {
  723. fMiddleWare = new MiddleWare(std::move(fSynth), &fConfig);
  724. fMiddleWare->setUiCallback(__uiCallback, this);
  725. fMiddleWare->setIdleCallback(_idleCallback, this);
  726. _masterChangedCallback(fMiddleWare->spawnMaster());
  727. }
  728. void _setMasterParameters()
  729. {
  730. #ifndef ZYN_MSG_ANYWHERE
  731. fMiddleWare->transmitMsg("/echo", "ss", "OSC_URL", "");
  732. fMiddleWare->activeUrl("");
  733. #endif
  734. char msg[24];
  735. for (int i=kParamPart16Enabled+1; --i>=kParamPart01Enabled;)
  736. {
  737. std::sprintf(msg, "/part%i/Penabled", i-kParamPart01Enabled);
  738. #ifdef ZYN_MSG_ANYWHERE
  739. fMiddleWare->messageAnywhere(msg, (fParameters[i] >= 0.5f) ? "T" : "F");
  740. #else
  741. fMiddleWare->transmitMsg(msg, (fParameters[i] >= 0.5f) ? "T" : "F");
  742. #endif
  743. }
  744. for (int i=kParamPart16Volume+1; --i>=kParamPart01Volume;)
  745. {
  746. std::sprintf(msg, "/part%i/Pvolume", i-kParamPart01Volume);
  747. #ifdef ZYN_MSG_ANYWHERE
  748. fMiddleWare->messageAnywhere(msg, "i", static_cast<int>(fParameters[i]));
  749. #else
  750. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[i]));
  751. #endif
  752. }
  753. for (int i=kParamPart16Panning+1; --i>=kParamPart01Panning;)
  754. {
  755. std::sprintf(msg, "/part%i/Ppanning", i-kParamPart01Panning);
  756. #ifdef ZYN_MSG_ANYWHERE
  757. fMiddleWare->messageAnywhere(msg, "i", static_cast<int>(fParameters[i]));
  758. #else
  759. fMiddleWare->transmitMsg(msg, "i", static_cast<int>(fParameters[i]));
  760. #endif
  761. }
  762. for (int i=0; i<NUM_MIDI_PARTS; ++i)
  763. {
  764. fMaster->part[i]->SetController(C_filtercutoff, static_cast<int>(fParameters[kParamFilterCutoff]));
  765. fMaster->part[i]->SetController(C_filterq, static_cast<int>(fParameters[kParamFilterQ]));
  766. fMaster->part[i]->SetController(C_bandwidth, static_cast<int>(fParameters[kParamBandwidth]));
  767. fMaster->part[i]->SetController(C_fmamp, static_cast<int>(fParameters[kParamModAmp]));
  768. fMaster->part[i]->SetController(C_resonance_center, static_cast<int>(fParameters[kParamResCenter]));
  769. fMaster->part[i]->SetController(C_resonance_bandwidth, static_cast<int>(fParameters[kParamResBandwidth]));
  770. }
  771. }
  772. void _deleteMaster()
  773. {
  774. fMaster = nullptr;
  775. delete fMiddleWare;
  776. fMiddleWare = nullptr;
  777. }
  778. void _masterChangedCallback(Master* m)
  779. {
  780. fMaster = m;
  781. fMaster->setMasterChangedCallback(__masterChangedCallback, this);
  782. }
  783. static void __masterChangedCallback(void* ptr, Master* m)
  784. {
  785. ((ZynAddSubFxPlugin*)ptr)->_masterChangedCallback(m);
  786. }
  787. void _uiCallback(const char* const msg)
  788. {
  789. if (std::strncmp(msg, "/part", 5) != 0)
  790. return;
  791. const char* msgtmp = msg;
  792. msgtmp += 5;
  793. CARLA_SAFE_ASSERT_RETURN( msgtmp[0] >= '0' && msgtmp[0] <= '9',);
  794. CARLA_SAFE_ASSERT_RETURN((msgtmp[1] >= '0' && msgtmp[1] <= '9') || msgtmp[1] == '/',);
  795. char partnstr[3] = { '\0', '\0', '\0' };
  796. partnstr[0] = msgtmp[0];
  797. ++msgtmp;
  798. if (msgtmp[0] >= '0' && msgtmp[0] <= '9')
  799. {
  800. partnstr[1] = msgtmp[0];
  801. ++msgtmp;
  802. }
  803. const int partn = std::atoi(partnstr);
  804. ++msgtmp;
  805. /**/ if (std::strcmp(msgtmp, "Penabled") == 0)
  806. {
  807. const int index = kParamPart01Enabled+partn;
  808. const bool enbl = rtosc_argument(msg,0).T;
  809. fParameters[index] = enbl ? 1.0f : 0.0f;
  810. uiParameterChanged(kParamPart01Enabled+partn, enbl ? 1.0f : 0.0f);
  811. }
  812. else if (std::strcmp(msgtmp, "Pvolume") == 0)
  813. {
  814. const int index = kParamPart01Volume+partn;
  815. const int value = rtosc_argument(msg,0).i;
  816. fParameters[index] = value;
  817. uiParameterChanged(kParamPart01Volume+partn, value);
  818. }
  819. else if (std::strcmp(msgtmp, "Ppanning") == 0)
  820. {
  821. const int index = kParamPart01Panning+partn;
  822. const int value = rtosc_argument(msg,0).i;
  823. fParameters[index] = value;
  824. uiParameterChanged(kParamPart01Panning+partn, value);
  825. }
  826. }
  827. static void __uiCallback(void* ptr, const char* msg)
  828. {
  829. ((ZynAddSubFxPlugin*)ptr)->_uiCallback(msg);
  830. }
  831. static void _idleCallback(void* ptr)
  832. {
  833. ((ZynAddSubFxPlugin*)ptr)->hostGiveIdle();
  834. }
  835. // -------------------------------------------------------------------
  836. PluginClassEND(ZynAddSubFxPlugin)
  837. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  838. };
  839. // -----------------------------------------------------------------------
  840. static const NativePluginDescriptor zynaddsubfxDesc = {
  841. /* category */ NATIVE_PLUGIN_CATEGORY_SYNTH,
  842. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH
  843. #ifdef HAVE_ZYN_UI_DEPS
  844. |NATIVE_PLUGIN_HAS_UI
  845. #endif
  846. |NATIVE_PLUGIN_USES_MULTI_PROGS
  847. |NATIVE_PLUGIN_USES_STATE),
  848. /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_CONTROL_CHANGES
  849. |NATIVE_PLUGIN_SUPPORTS_NOTE_AFTERTOUCH
  850. |NATIVE_PLUGIN_SUPPORTS_PITCHBEND
  851. |NATIVE_PLUGIN_SUPPORTS_ALL_SOUND_OFF),
  852. /* audioIns */ 0,
  853. /* audioOuts */ 2,
  854. /* midiIns */ 1,
  855. /* midiOuts */ 0,
  856. /* paramIns */ ZynAddSubFxPlugin::kParamCount,
  857. /* paramOuts */ 0,
  858. /* name */ "ZynAddSubFX",
  859. /* label */ "zynaddsubfx",
  860. /* maker */ "falkTX, Mark McCurry, Nasca Octavian Paul",
  861. /* copyright */ "GNU GPL v2+",
  862. PluginDescriptorFILL(ZynAddSubFxPlugin)
  863. };
  864. // -----------------------------------------------------------------------
  865. CARLA_EXPORT
  866. void carla_register_native_plugin_zynaddsubfx_synth();
  867. CARLA_EXPORT
  868. void carla_register_native_plugin_zynaddsubfx_synth()
  869. {
  870. carla_register_native_plugin(&zynaddsubfxDesc);
  871. }
  872. // -----------------------------------------------------------------------