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.

514 lines
15KB

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