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.

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