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.

659 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. #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. config.save();
  239. return kMaster->getalldata((char**)data);
  240. }
  241. void setChunk(void* const data, const size_t size)
  242. {
  243. fThread.stopLoadLater();
  244. kMaster->putalldata((char*)data, size);
  245. kMaster->applyparameters(true);
  246. }
  247. // -------------------------------------------------------------------
  248. private:
  249. struct ProgramInfo {
  250. uint32_t bank;
  251. uint32_t prog;
  252. const char* name;
  253. ProgramInfo(uint32_t bank_, uint32_t prog_, const char* name_)
  254. : bank(bank_),
  255. prog(prog_),
  256. name(carla_strdup(name_)) {}
  257. ~ProgramInfo()
  258. {
  259. if (name != nullptr)
  260. {
  261. delete[] name;
  262. name = nullptr;
  263. }
  264. }
  265. ProgramInfo() = delete;
  266. ProgramInfo(ProgramInfo&) = delete;
  267. ProgramInfo(const ProgramInfo&) = delete;
  268. };
  269. class ZynThread : public CarlaThread
  270. {
  271. public:
  272. ZynThread(Master* const master, const HostDescriptor* const host)
  273. : kMaster(master),
  274. kHost(host),
  275. #ifdef WANT_ZYNADDSUBFX_UI
  276. fUi(nullptr),
  277. fUiClosed(0),
  278. fNextUiAction(-1),
  279. #endif
  280. fQuit(false),
  281. fChangeProgram(false),
  282. fNextBank(0),
  283. fNextProgram(0)
  284. {
  285. }
  286. ~ZynThread()
  287. {
  288. // must be closed by now
  289. CARLA_ASSERT(fUi == nullptr);
  290. CARLA_ASSERT(fQuit);
  291. }
  292. void loadLater(const uint32_t bank, const uint32_t program)
  293. {
  294. fNextBank = bank;
  295. fNextProgram = program;
  296. fChangeProgram = true;
  297. }
  298. void stopLoadLater()
  299. {
  300. fChangeProgram = false;
  301. fNextBank = 0;
  302. fNextProgram = 0;
  303. }
  304. void stop()
  305. {
  306. fQuit = true;
  307. CarlaThread::stop();
  308. }
  309. #ifdef WANT_ZYNADDSUBFX_UI
  310. void uiShow()
  311. {
  312. fNextUiAction = 1;
  313. }
  314. void uiHide()
  315. {
  316. fNextUiAction = 0;
  317. }
  318. #endif
  319. protected:
  320. void run()
  321. {
  322. while (! fQuit)
  323. {
  324. #ifdef WANT_ZYNADDSUBFX_UI
  325. if (fNextUiAction == 1)
  326. {
  327. static bool initialized = false;
  328. if (! initialized)
  329. {
  330. initialized = true;
  331. fl_register_images();
  332. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  333. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/knob.png"))
  334. Fl_Dial::default_image(img);
  335. else
  336. Fl_Dial::default_image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/knob.png"));
  337. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/window_backdrop.png"))
  338. Fl::scheme_bg(new Fl_Tiled_Image(img));
  339. else
  340. Fl::scheme_bg(new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/window_backdrop.png")));
  341. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/module_backdrop.png"))
  342. gModuleBackdrop = new Fl_Tiled_Image(img);
  343. else
  344. gModuleBackdrop = new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/module_backdrop.png"));
  345. Fl::background(50, 50, 50);
  346. Fl::background2(70, 70, 70);
  347. Fl::foreground(255, 255, 255);
  348. }
  349. CARLA_ASSERT(fUi == nullptr);
  350. if (fUi == nullptr)
  351. {
  352. fUiClosed = 0;
  353. fUi = new MasterUI(kMaster, &fUiClosed);
  354. fUi->showUI();
  355. }
  356. }
  357. else if (fNextUiAction == 0)
  358. {
  359. CARLA_ASSERT(fUi != nullptr);
  360. if (fUi != nullptr)
  361. {
  362. delete fUi;
  363. fUi = nullptr;
  364. }
  365. }
  366. fNextUiAction = -1;
  367. if (fUiClosed != 0)
  368. {
  369. fUiClosed = 0;
  370. fNextUiAction = 0;
  371. kHost->ui_closed(kHost->handle);
  372. }
  373. Fl::check();
  374. #endif
  375. if (fChangeProgram)
  376. {
  377. fChangeProgram = false;
  378. loadProgram(kMaster, fNextBank, fNextProgram);
  379. fNextBank = 0;
  380. fNextProgram = 0;
  381. }
  382. carla_msleep(15);
  383. }
  384. #ifdef WANT_ZYNADDSUBFX_UI
  385. if (fQuit && fUi != nullptr)
  386. {
  387. delete fUi;
  388. fUi = nullptr;
  389. Fl::check();
  390. }
  391. #endif
  392. }
  393. private:
  394. Master* const kMaster;
  395. const HostDescriptor* const kHost;
  396. #ifdef WANT_ZYNADDSUBFX_UI
  397. MasterUI* fUi;
  398. int fUiClosed;
  399. int fNextUiAction;
  400. #endif
  401. bool fQuit;
  402. bool fChangeProgram;
  403. uint32_t fNextBank;
  404. uint32_t fNextProgram;
  405. };
  406. Master* const kMaster;
  407. const unsigned kSampleRate;
  408. ZynThread fThread;
  409. static int sInstanceCount;
  410. static NonRtList<ProgramInfo*> sPrograms;
  411. public:
  412. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  413. {
  414. if (sInstanceCount++ == 0)
  415. {
  416. CARLA_ASSERT(synth == nullptr);
  417. CARLA_ASSERT(denormalkillbuf == nullptr);
  418. synth = new SYNTH_T();
  419. synth->buffersize = host->get_buffer_size(host->handle);
  420. synth->samplerate = host->get_sample_rate(host->handle);
  421. synth->alias();
  422. config.init();
  423. config.cfg.SoundBufferSize = synth->buffersize;
  424. config.cfg.SampleRate = synth->samplerate;
  425. config.cfg.GzipCompression = 0;
  426. sprng(std::time(nullptr));
  427. denormalkillbuf = new float[synth->buffersize];
  428. for (int i=0; i < synth->buffersize; i++)
  429. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  430. Master::getInstance();
  431. }
  432. return new ZynAddSubFxPlugin(host);
  433. }
  434. static void _cleanup(PluginHandle handle)
  435. {
  436. delete (ZynAddSubFxPlugin*)handle;
  437. if (--sInstanceCount == 0)
  438. {
  439. CARLA_ASSERT(synth != nullptr);
  440. CARLA_ASSERT(denormalkillbuf != nullptr);
  441. Master::deleteInstance();
  442. delete[] denormalkillbuf;
  443. denormalkillbuf = nullptr;
  444. delete synth;
  445. synth = nullptr;
  446. }
  447. }
  448. static void maybeInitPrograms(Master* const master)
  449. {
  450. static bool doSearch = true;
  451. if (! doSearch)
  452. return;
  453. doSearch = false;
  454. pthread_mutex_lock(&master->mutex);
  455. // refresh banks
  456. master->bank.rescanforbanks();
  457. for (uint32_t i=0, size = master->bank.banks.size(); i < size; i++)
  458. {
  459. if (master->bank.banks[i].dir.empty())
  460. continue;
  461. master->bank.loadbank(master->bank.banks[i].dir);
  462. for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++)
  463. {
  464. const std::string insName(master->bank.getname(instrument));
  465. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  466. continue;
  467. sPrograms.append(new ProgramInfo(i, instrument, insName.c_str()));
  468. }
  469. }
  470. pthread_mutex_unlock(&master->mutex);
  471. }
  472. static void loadProgram(Master* const master, const uint32_t bank, const uint32_t program)
  473. {
  474. const std::string& bankdir(master->bank.banks[bank].dir);
  475. if (! bankdir.empty())
  476. {
  477. pthread_mutex_lock(&master->mutex);
  478. master->bank.loadbank(bankdir);
  479. for (int i=0; i < NUM_MIDI_PARTS; i++)
  480. master->bank.loadfromslot(program, master->part[i]);
  481. master->applyparameters(false);
  482. pthread_mutex_unlock(&master->mutex);
  483. }
  484. }
  485. static void clearPrograms()
  486. {
  487. for (auto it = sPrograms.begin(); it.valid(); it.next())
  488. {
  489. ProgramInfo* const programInfo(*it);
  490. delete programInfo;
  491. }
  492. sPrograms.clear();
  493. }
  494. private:
  495. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ZynAddSubFxPlugin)
  496. };
  497. int ZynAddSubFxPlugin::sInstanceCount = 0;
  498. NonRtList<ZynAddSubFxPlugin::ProgramInfo*> ZynAddSubFxPlugin::sPrograms;
  499. struct ProgramsDestructor {
  500. ProgramsDestructor() {}
  501. ~ProgramsDestructor()
  502. {
  503. ZynAddSubFxPlugin::clearPrograms();
  504. }
  505. } programsDestructor;
  506. // -----------------------------------------------------------------------
  507. static const PluginDescriptor zynAddSubFxDesc = {
  508. /* category */ PLUGIN_CATEGORY_SYNTH,
  509. #ifdef WANT_ZYNADDSUBFX_UI
  510. /* hints */ static_cast<PluginHints>(PLUGIN_IS_SYNTH | PLUGIN_HAS_GUI | PLUGIN_USES_CHUNKS | PLUGIN_USES_SINGLE_THREAD),
  511. #else
  512. /* hints */ static_cast<PluginHints>(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS),
  513. #endif
  514. /* audioIns */ 2,
  515. /* audioOuts */ 2,
  516. /* midiIns */ 1,
  517. /* midiOuts */ 0,
  518. /* paramIns */ ZynAddSubFxPlugin::PARAMETER_COUNT,
  519. /* paramOuts */ 0,
  520. /* name */ "ZynAddSubFX",
  521. /* label */ "zynaddsubfx",
  522. /* maker */ "falkTX",
  523. /* copyright */ "GNU GPL v2+",
  524. PluginDescriptorFILL(ZynAddSubFxPlugin)
  525. };
  526. // -----------------------------------------------------------------------
  527. void carla_register_native_plugin_zynaddsubfx()
  528. {
  529. carla_register_native_plugin(&zynAddSubFxDesc);
  530. }
  531. // -----------------------------------------------------------------------