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.

612 lines
16KB

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