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.cpp 18KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  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 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 <QtCore/QThread>
  25. #include "zynaddsubfx/Misc/Master.h"
  26. #include "zynaddsubfx/Misc/Part.h"
  27. #include "zynaddsubfx/Misc/Util.h"
  28. #ifdef WANT_ZYNADDSUBFX_UI
  29. // FIXME
  30. # ifdef override
  31. # define override_hack
  32. # undef override
  33. # endif
  34. # include "zynaddsubfx/UI/common.H"
  35. # include "zynaddsubfx/UI/MasterUI.h"
  36. # include <FL/Fl_Shared_Image.H>
  37. # include <FL/Fl_Tiled_Image.H>
  38. # include <FL/Fl_Dial.H>
  39. # include <FL/Fl_Theme.H>
  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. // Dummy variables and functions for linking purposes
  49. const char* instance_name = nullptr;
  50. class WavFile;
  51. namespace Nio {
  52. bool start(void){return 1;}
  53. void stop(void){}
  54. bool setSource(std::string){return true;}
  55. bool setSink(std::string){return true;}
  56. std::set<std::string> getSources(void){return std::set<std::string>();}
  57. std::set<std::string> getSinks(void){return std::set<std::string>();}
  58. std::string getSource(void){return "";}
  59. std::string getSink(void){return "";}
  60. void waveNew(WavFile*){}
  61. void waveStart(void){}
  62. void waveStop(void){}
  63. void waveEnd(void){}
  64. }
  65. SYNTH_T* synth = nullptr;
  66. #ifdef WANT_ZYNADDSUBFX_UI
  67. #define PIXMAP_PATH "./resources/zynaddsubfx/"
  68. static Fl_Tiled_Image* gModuleBackdrop = nullptr;
  69. void set_module_parameters(Fl_Widget* o)
  70. {
  71. CARLA_ASSERT(gModuleBackdrop != nullptr);
  72. o->box(FL_DOWN_FRAME);
  73. o->align(o->align() | FL_ALIGN_IMAGE_BACKDROP);
  74. o->color(FL_BLACK);
  75. o->labeltype(FL_SHADOW_LABEL);
  76. if (gModuleBackdrop != nullptr)
  77. o->image(gModuleBackdrop);
  78. }
  79. #endif
  80. class ZynAddSubFxPlugin : public PluginDescriptorClass
  81. {
  82. public:
  83. enum Parameters {
  84. PARAMETER_COUNT = 0
  85. };
  86. ZynAddSubFxPlugin(const HostDescriptor* const host)
  87. : PluginDescriptorClass(host),
  88. kMaster(new Master()),
  89. kSampleRate(getSampleRate()),
  90. fThread(kMaster, host)
  91. {
  92. fThread.start();
  93. maybeInitPrograms(kMaster);
  94. //fThread.waitForStarted();
  95. }
  96. ~ZynAddSubFxPlugin() override
  97. {
  98. //ensure that everything has stopped
  99. pthread_mutex_lock(&kMaster->mutex);
  100. pthread_mutex_unlock(&kMaster->mutex);
  101. fThread.stop();
  102. fThread.wait();
  103. delete kMaster;
  104. }
  105. protected:
  106. // -------------------------------------------------------------------
  107. // Plugin parameter calls
  108. uint32_t getParameterCount() override
  109. {
  110. return PARAMETER_COUNT;
  111. }
  112. const Parameter* getParameterInfo(const uint32_t index) override
  113. {
  114. CARLA_ASSERT(index < getParameterCount());
  115. //if (index >= PARAMETER_COUNT)
  116. return nullptr;
  117. static Parameter param;
  118. param.ranges.step = PARAMETER_RANGES_DEFAULT_STEP;
  119. param.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL;
  120. param.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE;
  121. param.scalePointCount = 0;
  122. param.scalePoints = nullptr;
  123. switch (index)
  124. {
  125. #if 0
  126. case PARAMETER_MASTER:
  127. param.hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE;
  128. param.name = "Master Volume";
  129. param.unit = nullptr;
  130. param.ranges.min = 0.0f;
  131. param.ranges.max = 100.0f;
  132. param.ranges.def = 100.0f;
  133. break;
  134. #endif
  135. }
  136. return &param;
  137. }
  138. float getParameterValue(const uint32_t index) override
  139. {
  140. CARLA_ASSERT(index < getParameterCount());
  141. switch (index)
  142. {
  143. #if 0
  144. case PARAMETER_MASTER:
  145. return kMaster->Pvolume;
  146. #endif
  147. default:
  148. return 0.0f;
  149. }
  150. }
  151. // -------------------------------------------------------------------
  152. // Plugin midi-program calls
  153. uint32_t getMidiProgramCount() override
  154. {
  155. return sPrograms.count();
  156. }
  157. const MidiProgram* getMidiProgramInfo(const uint32_t index) override
  158. {
  159. CARLA_ASSERT(index < getMidiProgramCount());
  160. if (index >= sPrograms.count())
  161. return nullptr;
  162. const ProgramInfo* const pInfo(sPrograms.getAt(index));
  163. static MidiProgram midiProgram;
  164. midiProgram.bank = pInfo->bank;
  165. midiProgram.program = pInfo->prog;
  166. midiProgram.name = pInfo->name;
  167. return &midiProgram;
  168. }
  169. // -------------------------------------------------------------------
  170. // Plugin state calls
  171. void setParameterValue(const uint32_t index, const float value) override
  172. {
  173. CARLA_ASSERT(index < getParameterCount());
  174. switch (index)
  175. {
  176. }
  177. return;
  178. // unused, TODO
  179. (void)value;
  180. }
  181. void setMidiProgram(const uint32_t bank, const uint32_t program) override
  182. {
  183. if (bank >= kMaster->bank.banks.size())
  184. return;
  185. if (program >= BANK_SIZE)
  186. return;
  187. bool isOffline = false;
  188. if (isOffline)
  189. loadProgram(kMaster, bank, program);
  190. else
  191. fThread.loadLater(bank, program);
  192. }
  193. void setCustomData(const char* const key, const char* const value)
  194. {
  195. CARLA_ASSERT(key != nullptr);
  196. CARLA_ASSERT(value != nullptr);
  197. if (std::strcmp(key, "CarlaAlternateFile1") == 0) // xmz
  198. kMaster->loadXML(value);
  199. if (std::strcmp(key, "CarlaAlternateFile2") == 0) // xiz
  200. kMaster->part[0]->loadXMLinstrument(value);
  201. }
  202. // -------------------------------------------------------------------
  203. // Plugin process calls
  204. void activate() override
  205. {
  206. // broken
  207. //for (int i=0; i < NUM_MIDI_PARTS; i++)
  208. // kMaster->setController(0, MIDI_CONTROL_ALL_SOUND_OFF, 0);
  209. }
  210. void process(float**, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const MidiEvent* const midiEvents) override
  211. {
  212. if (pthread_mutex_trylock(&kMaster->mutex) != 0)
  213. {
  214. carla_zeroFloat(outBuffer[0], frames);
  215. carla_zeroFloat(outBuffer[1], frames);
  216. return;
  217. }
  218. for (uint32_t i=0; i < midiEventCount; i++)
  219. {
  220. const MidiEvent* const midiEvent = &midiEvents[i];
  221. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent->data);
  222. const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent->data);
  223. if (MIDI_IS_STATUS_NOTE_OFF(status))
  224. {
  225. const uint8_t note = midiEvent->data[1];
  226. kMaster->noteOff(channel, note);
  227. }
  228. else if (MIDI_IS_STATUS_NOTE_ON(status))
  229. {
  230. const uint8_t note = midiEvent->data[1];
  231. const uint8_t velo = midiEvent->data[2];
  232. kMaster->noteOn(channel, note, velo);
  233. }
  234. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  235. {
  236. const uint8_t note = midiEvent->data[1];
  237. const uint8_t pressure = midiEvent->data[2];
  238. kMaster->polyphonicAftertouch(channel, note, pressure);
  239. }
  240. }
  241. kMaster->GetAudioOutSamples(frames, kSampleRate, outBuffer[0], outBuffer[1]);
  242. pthread_mutex_unlock(&kMaster->mutex);
  243. }
  244. #ifdef WANT_ZYNADDSUBFX_UI
  245. // -------------------------------------------------------------------
  246. // Plugin UI calls
  247. void uiShow(const bool show) override
  248. {
  249. if (show)
  250. fThread.uiShow();
  251. else
  252. fThread.uiHide();
  253. }
  254. #endif
  255. // -------------------------------------------------------------------
  256. // Plugin state calls
  257. char* getState() override
  258. {
  259. config.save();
  260. char* data = nullptr;
  261. kMaster->getalldata(&data);
  262. return data;
  263. }
  264. void setState(const char* const data) override
  265. {
  266. fThread.stopLoadLater();
  267. kMaster->putalldata((char*)data, 0);
  268. kMaster->applyparameters(true);
  269. }
  270. // -------------------------------------------------------------------
  271. private:
  272. struct ProgramInfo {
  273. uint32_t bank;
  274. uint32_t prog;
  275. const char* name;
  276. ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_)
  277. : bank(bank_),
  278. prog(prog_),
  279. name(carla_strdup(name_)) {}
  280. ~ProgramInfo()
  281. {
  282. if (name != nullptr)
  283. {
  284. delete[] name;
  285. name = nullptr;
  286. }
  287. }
  288. ProgramInfo() = delete;
  289. ProgramInfo(ProgramInfo&) = delete;
  290. ProgramInfo(const ProgramInfo&) = delete;
  291. };
  292. class ZynThread : public QThread
  293. {
  294. public:
  295. ZynThread(Master* const master, const HostDescriptor* const host)
  296. : kMaster(master),
  297. kHost(host),
  298. #ifdef WANT_ZYNADDSUBFX_UI
  299. fUi(nullptr),
  300. fUiClosed(0),
  301. fNextUiAction(-1),
  302. #endif
  303. fQuit(false),
  304. fChangeProgram(false),
  305. fNextBank(0),
  306. fNextProgram(0)
  307. {
  308. }
  309. ~ZynThread()
  310. {
  311. // must be closed by now
  312. #ifdef WANT_ZYNADDSUBFX_UI
  313. CARLA_ASSERT(fUi == nullptr);
  314. #endif
  315. CARLA_ASSERT(fQuit);
  316. }
  317. void loadLater(const uint32_t bank, const uint32_t program)
  318. {
  319. fNextBank = bank;
  320. fNextProgram = program;
  321. fChangeProgram = true;
  322. }
  323. void stopLoadLater()
  324. {
  325. fChangeProgram = false;
  326. fNextBank = 0;
  327. fNextProgram = 0;
  328. }
  329. void stop()
  330. {
  331. fQuit = true;
  332. quit();
  333. }
  334. #ifdef WANT_ZYNADDSUBFX_UI
  335. void uiShow()
  336. {
  337. fNextUiAction = 1;
  338. }
  339. void uiHide()
  340. {
  341. fNextUiAction = 0;
  342. }
  343. #endif
  344. protected:
  345. void run()
  346. {
  347. while (! fQuit)
  348. {
  349. #ifdef WANT_ZYNADDSUBFX_UI
  350. Fl::lock();
  351. if (fNextUiAction == 1)
  352. {
  353. static bool initialized = false;
  354. if (! initialized)
  355. {
  356. initialized = true;
  357. fl_register_images();
  358. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  359. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(PIXMAP_PATH "knob.png"))
  360. Fl_Dial::default_image(img);
  361. if (Fl_Shared_Image* const img = Fl_Shared_Image::get(PIXMAP_PATH "window_backdrop.png"))
  362. Fl::scheme_bg(new Fl_Tiled_Image(img));
  363. if(Fl_Shared_Image* const img = Fl_Shared_Image::get(PIXMAP_PATH "module_backdrop.png"))
  364. gModuleBackdrop = new Fl_Tiled_Image(img);
  365. Fl::background(50, 50, 50);
  366. Fl::background2(70, 70, 70);
  367. Fl::foreground(255, 255, 255);
  368. Fl_Theme::set("Cairo");
  369. }
  370. CARLA_ASSERT(fUi == nullptr);
  371. if (fUi == nullptr)
  372. {
  373. fUiClosed = 0;
  374. fUi = new MasterUI(kMaster, &fUiClosed);
  375. //fUi->npartcounter->callback(_npartcounterCallback, this);
  376. fUi->showUI();
  377. }
  378. }
  379. else if (fNextUiAction == 0)
  380. {
  381. CARLA_ASSERT(fUi != nullptr);
  382. if (fUi != nullptr)
  383. {
  384. delete fUi;
  385. fUi = nullptr;
  386. }
  387. }
  388. fNextUiAction = -1;
  389. if (fUiClosed != 0)
  390. {
  391. fUiClosed = 0;
  392. fNextUiAction = 0;
  393. kHost->ui_closed(kHost->handle);
  394. }
  395. Fl::check();
  396. Fl::unlock();
  397. #endif
  398. if (fChangeProgram)
  399. {
  400. fChangeProgram = false;
  401. loadProgram(kMaster, fNextBank, fNextProgram);
  402. fNextBank = 0;
  403. fNextProgram = 0;
  404. }
  405. carla_msleep(15);
  406. }
  407. #ifdef WANT_ZYNADDSUBFX_UI
  408. if (fQuit && fUi != nullptr)
  409. {
  410. Fl::lock();
  411. delete fUi;
  412. fUi = nullptr;
  413. Fl::check();
  414. Fl::unlock();
  415. }
  416. #endif
  417. }
  418. #ifdef WANT_ZYNADDSUBFX_UI
  419. void handlePartCounterCallback(Fl_Widget* widget)
  420. {
  421. carla_stdout("handlePartCounterCallback(%p)", widget);
  422. }
  423. static void _npartcounterCallback(Fl_Widget* widget, void* ptr)
  424. {
  425. ((ZynThread*)ptr)->handlePartCounterCallback(widget);
  426. }
  427. #endif
  428. private:
  429. Master* const kMaster;
  430. const HostDescriptor* const kHost;
  431. #ifdef WANT_ZYNADDSUBFX_UI
  432. MasterUI* fUi;
  433. int fUiClosed;
  434. int fNextUiAction;
  435. #endif
  436. bool fQuit;
  437. bool fChangeProgram;
  438. uint32_t fNextBank;
  439. uint32_t fNextProgram;
  440. };
  441. Master* const kMaster;
  442. const unsigned kSampleRate;
  443. ZynThread fThread;
  444. static int sInstanceCount;
  445. static NonRtList<ProgramInfo*> sPrograms;
  446. public:
  447. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  448. {
  449. if (sInstanceCount++ == 0)
  450. {
  451. CARLA_ASSERT(synth == nullptr);
  452. CARLA_ASSERT(denormalkillbuf == nullptr);
  453. synth = new SYNTH_T();
  454. synth->buffersize = host->get_buffer_size(host->handle);
  455. synth->samplerate = host->get_sample_rate(host->handle);
  456. synth->alias();
  457. config.init();
  458. config.cfg.SoundBufferSize = synth->buffersize;
  459. config.cfg.SampleRate = synth->samplerate;
  460. config.cfg.GzipCompression = 0;
  461. sprng(std::time(nullptr));
  462. denormalkillbuf = new float[synth->buffersize];
  463. for (int i=0; i < synth->buffersize; i++)
  464. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  465. Master::getInstance();
  466. }
  467. return new ZynAddSubFxPlugin(host);
  468. }
  469. static void _cleanup(PluginHandle handle)
  470. {
  471. delete (ZynAddSubFxPlugin*)handle;
  472. if (--sInstanceCount == 0)
  473. {
  474. CARLA_ASSERT(synth != nullptr);
  475. CARLA_ASSERT(denormalkillbuf != nullptr);
  476. Master::deleteInstance();
  477. delete[] denormalkillbuf;
  478. denormalkillbuf = nullptr;
  479. delete synth;
  480. synth = nullptr;
  481. }
  482. }
  483. static void maybeInitPrograms(Master* const master)
  484. {
  485. static bool doSearch = true;
  486. if (! doSearch)
  487. return;
  488. doSearch = false;
  489. pthread_mutex_lock(&master->mutex);
  490. // refresh banks
  491. master->bank.rescanforbanks();
  492. for (uint32_t i=0, size = master->bank.banks.size(); i < size; i++)
  493. {
  494. if (master->bank.banks[i].dir.empty())
  495. continue;
  496. master->bank.loadbank(master->bank.banks[i].dir);
  497. for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++)
  498. {
  499. const std::string insName(master->bank.getname(instrument));
  500. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  501. continue;
  502. sPrograms.append(new ProgramInfo(i, instrument, insName.c_str()));
  503. }
  504. }
  505. pthread_mutex_unlock(&master->mutex);
  506. }
  507. static void loadProgram(Master* const master, const uint32_t bank, const uint32_t program)
  508. {
  509. const std::string& bankdir(master->bank.banks[bank].dir);
  510. if (! bankdir.empty())
  511. {
  512. pthread_mutex_lock(&master->mutex);
  513. master->bank.loadbank(bankdir);
  514. for (int i=0; i < NUM_MIDI_PARTS; i++)
  515. master->bank.loadfromslot(program, master->part[i]);
  516. master->applyparameters(false);
  517. pthread_mutex_unlock(&master->mutex);
  518. }
  519. }
  520. static void clearPrograms()
  521. {
  522. for (auto it = sPrograms.begin(); it.valid(); it.next())
  523. {
  524. ProgramInfo* const programInfo(*it);
  525. delete programInfo;
  526. }
  527. sPrograms.clear();
  528. }
  529. private:
  530. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  531. };
  532. int ZynAddSubFxPlugin::sInstanceCount = 0;
  533. NonRtList<ZynAddSubFxPlugin::ProgramInfo*> ZynAddSubFxPlugin::sPrograms;
  534. struct ProgramsDestructor {
  535. ProgramsDestructor() {}
  536. ~ProgramsDestructor()
  537. {
  538. ZynAddSubFxPlugin::clearPrograms();
  539. }
  540. } programsDestructor;
  541. // -----------------------------------------------------------------------
  542. static const PluginDescriptor zynAddSubFxDesc = {
  543. /* category */ PLUGIN_CATEGORY_SYNTH,
  544. #ifdef WANT_ZYNADDSUBFX_UI
  545. /* hints */ static_cast<PluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_GUI/*|PLUGIN_USES_SINGLE_THREAD*/|PLUGIN_USES_STATE),
  546. #else
  547. /* hints */ static_cast<PluginHints>(PLUGIN_IS_SYNTH|PLUGIN_USES_STATE),
  548. #endif
  549. /* audioIns */ 2,
  550. /* audioOuts */ 2,
  551. /* midiIns */ 1,
  552. /* midiOuts */ 0,
  553. /* paramIns */ ZynAddSubFxPlugin::PARAMETER_COUNT,
  554. /* paramOuts */ 0,
  555. /* name */ "ZynAddSubFX",
  556. /* label */ "zynaddsubfx",
  557. /* maker */ "falkTX",
  558. /* copyright */ "GNU GPL v2+",
  559. PluginDescriptorFILL(ZynAddSubFxPlugin)
  560. };
  561. // -----------------------------------------------------------------------
  562. void carla_register_native_plugin_zynaddsubfx()
  563. {
  564. carla_register_native_plugin(&zynAddSubFxDesc);
  565. }
  566. // -----------------------------------------------------------------------