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.

681 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. 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. // -----------------------------------------------------------------------