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.

817 lines
20KB

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