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