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.

687 lines
18KB

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