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.

649 lines
17KB

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