Collection of tools useful for audio production
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.

465 lines
13KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * 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 COPYING file
  16. */
  17. #include "carla_midi.h"
  18. #include "carla_native.hpp"
  19. #include "zynaddsubfx/Misc/Master.h"
  20. #include "zynaddsubfx/Misc/Util.h"
  21. #include <climits>
  22. #ifdef WANT_ZYNADDSUBFX_GUI
  23. # define PIXMAP_PATH "/usr/share/zynaddsubfx/pixmaps"
  24. # define SOURCE_DIR ""
  25. # include <FL/Fl.H>
  26. # include <FL/Fl_Shared_Image.H>
  27. # include <FL/Fl_Tiled_Image.H>
  28. # include <FL/Fl_Dial.H>
  29. # include "zynaddsubfx/UI/MasterUI.h"
  30. // this is used to know wherever gui stuff is initialized
  31. static Fl_Tiled_Image* s_moduleBackdrop = nullptr;
  32. void set_module_parameters(Fl_Widget* o)
  33. {
  34. o->box(FL_DOWN_FRAME);
  35. o->align(o->align() | FL_ALIGN_IMAGE_BACKDROP);
  36. o->color(FL_BLACK );
  37. o->image(s_moduleBackdrop);
  38. o->labeltype(FL_SHADOW_LABEL);
  39. }
  40. #endif
  41. SYNTH_T* synth = nullptr;
  42. class ZynAddSubFxPlugin : public PluginDescriptorClass
  43. {
  44. public:
  45. enum Parameters {
  46. PARAMETER_MASTER,
  47. PARAMETER_MAX
  48. };
  49. ZynAddSubFxPlugin(const HostDescriptor* host)
  50. : PluginDescriptorClass(host)
  51. {
  52. qDebug("ZynAddSubFxPlugin::ZynAddSubFxPlugin(), s_instanceCount=%i", s_instanceCount);
  53. m_master = new Master;
  54. #ifdef WANT_ZYNADDSUBFX_GUI
  55. m_masterUI = nullptr;
  56. m_uiClosed = 0;
  57. #endif
  58. // refresh banks
  59. m_master->bank.rescanforbanks();
  60. for (size_t i=0, size = m_master->bank.banks.size(); i < size; i++)
  61. {
  62. if (m_master->bank.banks[i].dir.empty())
  63. continue;
  64. m_master->bank.loadbank(m_master->bank.banks[i].dir);
  65. for (unsigned int instrument = 0; instrument < BANK_SIZE; instrument++)
  66. {
  67. const std::string insName = m_master->bank.getname(instrument);
  68. if (insName.empty() || insName[0] == '\0' || insName[0] == ' ')
  69. continue;
  70. ProgramInfo pInfo;
  71. pInfo.bank = i;
  72. pInfo.prog = instrument;
  73. pInfo.name = insName;
  74. m_programs.push_back(pInfo);
  75. }
  76. }
  77. }
  78. ~ZynAddSubFxPlugin()
  79. {
  80. qDebug("ZynAddSubFxPlugin::~ZynAddSubFxPlugin(), s_instanceCount=%i", s_instanceCount);
  81. //ensure that everything has stopped with the mutex wait
  82. pthread_mutex_lock(&m_master->mutex);
  83. pthread_mutex_unlock(&m_master->mutex);
  84. m_programs.clear();
  85. #ifdef WANT_ZYNADDSUBFX_GUI
  86. if (m_masterUI)
  87. delete m_masterUI;
  88. #endif
  89. delete m_master;
  90. }
  91. protected:
  92. // -------------------------------------------------------------------
  93. // Plugin parameter calls
  94. uint32_t getParameterCount()
  95. {
  96. return PARAMETER_MAX;
  97. }
  98. const Parameter* getParameterInfo(uint32_t index)
  99. {
  100. CARLA_ASSERT(index < getParameterCount());
  101. if (index >= PARAMETER_MAX)
  102. return nullptr;
  103. static Parameter param;
  104. param.ranges.step = PARAMETER_RANGES_DEFAULT_STEP;
  105. param.ranges.stepSmall = PARAMETER_RANGES_DEFAULT_STEP_SMALL;
  106. param.ranges.stepLarge = PARAMETER_RANGES_DEFAULT_STEP_LARGE;
  107. param.scalePointCount = 0;
  108. param.scalePoints = nullptr;
  109. switch (index)
  110. {
  111. case PARAMETER_MASTER:
  112. param.hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE;
  113. param.name = "Master Volume";
  114. param.unit = nullptr;
  115. param.ranges.min = 0.0f;
  116. param.ranges.max = 100.0f;
  117. param.ranges.def = 100.0f;
  118. break;
  119. }
  120. return &param;
  121. }
  122. float getParameterValue(uint32_t index)
  123. {
  124. switch (index)
  125. {
  126. case PARAMETER_MASTER:
  127. return m_master->Pvolume;
  128. default:
  129. return 0.0f;
  130. }
  131. }
  132. // -------------------------------------------------------------------
  133. // Plugin midi-program calls
  134. uint32_t getMidiProgramCount()
  135. {
  136. return m_programs.size();
  137. }
  138. const MidiProgram* getMidiProgramInfo(uint32_t index)
  139. {
  140. CARLA_ASSERT(index < getMidiProgramCount());
  141. if (index >= m_programs.size())
  142. return nullptr;
  143. const ProgramInfo pInfo(m_programs[index]);
  144. static MidiProgram midiProgram;
  145. midiProgram.bank = pInfo.bank;
  146. midiProgram.program = pInfo.prog;
  147. midiProgram.name = pInfo.name.c_str();
  148. return &midiProgram;
  149. }
  150. // -------------------------------------------------------------------
  151. // Plugin state calls
  152. void setParameterValue(uint32_t index, float value)
  153. {
  154. switch (index)
  155. {
  156. case PARAMETER_MASTER:
  157. m_master->setPvolume((char)rint(value));
  158. break;
  159. }
  160. }
  161. void setMidiProgram(uint32_t bank, uint32_t program)
  162. {
  163. if (bank >= m_master->bank.banks.size())
  164. return;
  165. if (program >= BANK_SIZE)
  166. return;
  167. const std::string bankdir = m_master->bank.banks[bank].dir;
  168. if (! bankdir.empty())
  169. {
  170. pthread_mutex_lock(&m_master->mutex);
  171. m_master->bank.loadbank(bankdir);
  172. m_master->bank.loadfromslot(program, m_master->part[0]);
  173. pthread_mutex_unlock(&m_master->mutex);
  174. }
  175. }
  176. // -------------------------------------------------------------------
  177. // Plugin UI calls
  178. #ifdef WANT_ZYNADDSUBFX_GUI
  179. void uiShow(bool show)
  180. {
  181. if (! m_masterUI)
  182. {
  183. if (! s_moduleBackdrop)
  184. {
  185. fl_register_images();
  186. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  187. if (Fl_Shared_Image* img = Fl_Shared_Image::get(PIXMAP_PATH "/knob.png"))
  188. Fl_Dial::default_image(img);
  189. else
  190. Fl_Dial::default_image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/knob.png"));
  191. if (Fl_Shared_Image* img = Fl_Shared_Image::get(PIXMAP_PATH "/window_backdrop.png"))
  192. Fl::scheme_bg(new Fl_Tiled_Image(img));
  193. else
  194. Fl::scheme_bg(new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/window_backdrop.png")));
  195. if (Fl_Shared_Image* img = Fl_Shared_Image::get(PIXMAP_PATH "/module_backdrop.png"))
  196. s_moduleBackdrop = new Fl_Tiled_Image(img);
  197. else
  198. s_moduleBackdrop = new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/module_backdrop.png"));
  199. Fl::background(50, 50, 50);
  200. Fl::background2(70, 70, 70);
  201. Fl::foreground(255, 255, 255);
  202. }
  203. m_masterUI = new MasterUI(m_master, &m_uiClosed);
  204. }
  205. if (show)
  206. {
  207. m_masterUI->showUI();
  208. }
  209. else
  210. {
  211. // same as showUI
  212. switch (config.cfg.UserInterfaceMode)
  213. {
  214. case 0:
  215. m_masterUI->selectuiwindow->hide();
  216. break;
  217. case 1:
  218. m_masterUI->masterwindow->hide();
  219. break;
  220. case 2:
  221. m_masterUI->simplemasterwindow->hide();
  222. break;
  223. };
  224. }
  225. }
  226. void uiIdle()
  227. {
  228. if (m_masterUI)
  229. Fl::check();
  230. }
  231. #endif
  232. // -------------------------------------------------------------------
  233. // Plugin process calls
  234. void activate()
  235. {
  236. m_master->setController(0, MIDI_CONTROL_ALL_SOUND_OFF, 0);
  237. }
  238. void process(float**, float** outBuffer, uint32_t frames, uint32_t midiEventCount, MidiEvent* midiEvents)
  239. {
  240. unsigned long from_frame = 0;
  241. unsigned long event_index = 0;
  242. unsigned long next_event_frame = 0;
  243. unsigned long to_frame = 0;
  244. pthread_mutex_lock(&m_master->mutex);
  245. do {
  246. /* Find the time of the next event, if any */
  247. if (event_index >= midiEventCount)
  248. next_event_frame = ULONG_MAX;
  249. else
  250. next_event_frame = midiEvents[event_index].time;
  251. /* find the end of the sub-sample to be processed this time round... */
  252. /* if the next event falls within the desired sample interval... */
  253. if ((next_event_frame < frames) && (next_event_frame >= to_frame))
  254. /* set the end to be at that event */
  255. to_frame = next_event_frame;
  256. else
  257. /* ...else go for the whole remaining sample */
  258. to_frame = frames;
  259. if (from_frame < to_frame)
  260. {
  261. // call master to fill from `from_frame` to `to_frame`:
  262. m_master->GetAudioOutSamples(to_frame - from_frame, (int)getSampleRate(), &outBuffer[0][from_frame], &outBuffer[1][from_frame]);
  263. // next sub-sample please...
  264. from_frame = to_frame;
  265. }
  266. // Now process any event(s) at the current timing point
  267. while (event_index < midiEventCount && midiEvents[event_index].time == to_frame)
  268. {
  269. uint8_t status = midiEvents[event_index].data[0];
  270. uint8_t channel = status & 0x0F;
  271. if (MIDI_IS_STATUS_NOTE_OFF(status))
  272. {
  273. uint8_t note = midiEvents[event_index].data[1];
  274. m_master->noteOff(channel, note);
  275. }
  276. else if (MIDI_IS_STATUS_NOTE_ON(status))
  277. {
  278. uint8_t note = midiEvents[event_index].data[1];
  279. uint8_t velo = midiEvents[event_index].data[2];
  280. m_master->noteOn(channel, note, velo);
  281. }
  282. else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
  283. {
  284. uint8_t note = midiEvents[event_index].data[1];
  285. uint8_t pressure = midiEvents[event_index].data[2];
  286. m_master->polyphonicAftertouch(channel, note, pressure);
  287. }
  288. event_index++;
  289. }
  290. // Keep going until we have the desired total length of sample...
  291. } while (to_frame < frames);
  292. pthread_mutex_unlock(&m_master->mutex);
  293. }
  294. // -------------------------------------------------------------------
  295. private:
  296. struct ProgramInfo {
  297. uint32_t bank;
  298. uint32_t prog;
  299. std::string name;
  300. };
  301. std::vector<ProgramInfo> m_programs;
  302. Master* m_master;
  303. #ifdef WANT_ZYNADDSUBFX_GUI
  304. MasterUI* m_masterUI;
  305. int m_uiClosed;
  306. #endif
  307. public:
  308. static int s_instanceCount;
  309. static PluginHandle _instantiate(const PluginDescriptor*, HostDescriptor* host)
  310. {
  311. if (s_instanceCount++ == 0)
  312. {
  313. synth = new SYNTH_T;
  314. synth->buffersize = host->get_buffer_size(host->handle);
  315. synth->samplerate = host->get_sample_rate(host->handle);
  316. synth->alias();
  317. config.init();
  318. config.cfg.SoundBufferSize = synth->buffersize;
  319. config.cfg.SampleRate = synth->samplerate;
  320. config.cfg.GzipCompression = 0;
  321. //Nio::preferedSampleRate(synth->samplerate);
  322. sprng(time(NULL));
  323. denormalkillbuf = new float [synth->buffersize];
  324. for (int i=0; i < synth->buffersize; i++)
  325. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  326. Master::getInstance();
  327. }
  328. return new ZynAddSubFxPlugin(host);
  329. }
  330. static void _cleanup(PluginHandle handle)
  331. {
  332. delete (ZynAddSubFxPlugin*)handle;
  333. if (--s_instanceCount == 0)
  334. {
  335. if (s_moduleBackdrop)
  336. {
  337. delete s_moduleBackdrop;
  338. s_moduleBackdrop = nullptr;
  339. }
  340. Master::deleteInstance();
  341. delete[] denormalkillbuf;
  342. denormalkillbuf = nullptr;
  343. delete synth;
  344. synth = nullptr;
  345. }
  346. }
  347. };
  348. int ZynAddSubFxPlugin::s_instanceCount = 0;
  349. // -----------------------------------------------------------------------
  350. static PluginDescriptor zynAddSubFxDesc = {
  351. /* category */ PLUGIN_CATEGORY_SYNTH,
  352. #ifdef WANT_ZYNADDSUBFX_GUI
  353. /* hints */ PLUGIN_IS_SYNTH | PLUGIN_HAS_GUI | PLUGIN_USES_SINGLE_THREAD,
  354. #else
  355. /* hints */ PLUGIN_IS_SYNTH | PLUGIN_USES_SINGLE_THREAD,
  356. #endif
  357. /* audioIns */ 2,
  358. /* audioOuts */ 2,
  359. /* midiIns */ 1,
  360. /* midiOuts */ 0,
  361. /* paramIns */ ZynAddSubFxPlugin::PARAMETER_MAX,
  362. /* paramOuts */ 0,
  363. /* name */ "ZynAddSubFX",
  364. /* label */ "zynaddsubfx",
  365. /* maker */ "falkTX",
  366. /* copyright */ "GNU GPL v2+",
  367. PluginDescriptorFILL(ZynAddSubFxPlugin)
  368. };
  369. // -----------------------------------------------------------------------
  370. void carla_register_native_plugin_zynaddsubfx()
  371. {
  372. carla_register_native_plugin(&zynAddSubFxDesc);
  373. }
  374. // -----------------------------------------------------------------------