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.

962 lines
28KB

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