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.

555 lines
14KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. main.cpp - Main file of the synthesizer
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Copyright (C) 2012-2014 Mark McCurry
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include <FL/Fl.H>
  18. #include "UI/common.H"
  19. #include <iostream>
  20. #include <cmath>
  21. #include <cctype>
  22. #include <algorithm>
  23. #include <signal.h>
  24. #include <unistd.h>
  25. #include <pthread.h>
  26. #include <getopt.h>
  27. #include "DSP/FFTwrapper.h"
  28. #include "Misc/Master.h"
  29. #include "Misc/Part.h"
  30. #include "Misc/Util.h"
  31. #include "Misc/Dump.h"
  32. extern Dump dump;
  33. //Nio System
  34. #include "Nio/Nio.h"
  35. #ifndef DISABLE_GUI
  36. #ifdef QT_GUI
  37. #include <QApplication>
  38. #include "masterui.h"
  39. QApplication *app;
  40. #elif defined FLTK_GUI
  41. #include "UI/MasterUI.h"
  42. #elif defined NTK_GUI
  43. #include "UI/MasterUI.h"
  44. #include <FL/Fl_Shared_Image.H>
  45. #include <FL/Fl_Tiled_Image.H>
  46. #include <FL/Fl_Dial.H>
  47. #include <FL/Fl_Tooltip.H>
  48. #endif // FLTK_GUI
  49. MasterUI *ui;
  50. #endif //DISABLE_GUI
  51. using namespace std;
  52. pthread_t thr4;
  53. Master *master;
  54. SYNTH_T *synth;
  55. int swaplr = 0; //1 for left-right swapping
  56. int Pexitprogram = 0; //if the UI set this to 1, the program will exit
  57. #if LASH
  58. #include "Misc/LASHClient.h"
  59. LASHClient *lash = NULL;
  60. #endif
  61. #if USE_NSM
  62. #include "UI/NSM.H"
  63. NSM_Client *nsm = 0;
  64. #endif
  65. char *instance_name = 0;
  66. void exitprogram();
  67. //cleanup on signaled exit
  68. void sigterm_exit(int /*sig*/)
  69. {
  70. Pexitprogram = 1;
  71. }
  72. #ifndef DISABLE_GUI
  73. #ifdef NTK_GUI
  74. static Fl_Tiled_Image *module_backdrop;
  75. #endif
  76. void
  77. set_module_parameters ( Fl_Widget *o )
  78. {
  79. #ifdef NTK_GUI
  80. o->box( FL_DOWN_FRAME );
  81. o->align( o->align() | FL_ALIGN_IMAGE_BACKDROP );
  82. o->color( FL_BLACK );
  83. o->image( module_backdrop );
  84. o->labeltype( FL_SHADOW_LABEL );
  85. #else
  86. o->box( FL_PLASTIC_UP_BOX );
  87. o->color( FL_CYAN );
  88. o->labeltype( FL_EMBOSSED_LABEL );
  89. #endif
  90. }
  91. #endif
  92. /*
  93. * Program initialisation
  94. */
  95. void initprogram(void)
  96. {
  97. cerr.precision(1);
  98. cerr << std::fixed;
  99. cerr << "\nSample Rate = \t\t" << synth->samplerate << endl;
  100. cerr << "Sound Buffer Size = \t" << synth->buffersize << " samples" << endl;
  101. cerr << "Internal latency = \t" << synth->buffersize_f * 1000.0f
  102. / synth->samplerate_f << " ms" << endl;
  103. cerr << "ADsynth Oscil.Size = \t" << synth->oscilsize << " samples" << endl;
  104. master = &Master::getInstance();
  105. master->swaplr = swaplr;
  106. signal(SIGINT, sigterm_exit);
  107. signal(SIGTERM, sigterm_exit);
  108. }
  109. /*
  110. * Program exit
  111. */
  112. void exitprogram()
  113. {
  114. //ensure that everything has stopped with the mutex wait
  115. pthread_mutex_lock(&master->mutex);
  116. pthread_mutex_unlock(&master->mutex);
  117. Nio::stop();
  118. #ifndef DISABLE_GUI
  119. delete ui;
  120. #endif
  121. #if LASH
  122. if(lash)
  123. delete lash;
  124. #endif
  125. #if USE_NSM
  126. if(nsm)
  127. delete nsm;
  128. #endif
  129. delete [] denormalkillbuf;
  130. FFT_cleanup();
  131. Master::deleteInstance();
  132. }
  133. int main(int argc, char *argv[])
  134. {
  135. synth = new SYNTH_T;
  136. config.init();
  137. dump.startnow();
  138. int noui = 0;
  139. cerr
  140. << "\nZynAddSubFX - Copyright (c) 2002-2011 Nasca Octavian Paul and others"
  141. << endl;
  142. cerr
  143. << " Copyright (c) 2009-2014 Mark McCurry [active maintainer]"
  144. << endl;
  145. cerr << "Compiled: " << __DATE__ << " " << __TIME__ << endl;
  146. cerr << "This program is free software (GNU GPL v.2 or later) and \n";
  147. cerr << "it comes with ABSOLUTELY NO WARRANTY.\n" << endl;
  148. if(argc == 1)
  149. cerr << "Try 'zynaddsubfx --help' for command-line options." << endl;
  150. /* Get the settings from the Config*/
  151. synth->samplerate = config.cfg.SampleRate;
  152. synth->buffersize = config.cfg.SoundBufferSize;
  153. synth->oscilsize = config.cfg.OscilSize;
  154. swaplr = config.cfg.SwapStereo;
  155. Nio::preferedSampleRate(synth->samplerate);
  156. synth->alias(); //build aliases
  157. sprng(time(NULL));
  158. /* Parse command-line options */
  159. struct option opts[] = {
  160. {
  161. "load", 2, NULL, 'l'
  162. },
  163. {
  164. "load-instrument", 2, NULL, 'L'
  165. },
  166. {
  167. "sample-rate", 2, NULL, 'r'
  168. },
  169. {
  170. "buffer-size", 2, NULL, 'b'
  171. },
  172. {
  173. "oscil-size", 2, NULL, 'o'
  174. },
  175. {
  176. "dump", 2, NULL, 'D'
  177. },
  178. {
  179. "swap", 2, NULL, 'S'
  180. },
  181. {
  182. "no-gui", 2, NULL, 'U'
  183. },
  184. {
  185. "dummy", 2, NULL, 'Y'
  186. },
  187. {
  188. "help", 2, NULL, 'h'
  189. },
  190. {
  191. "version", 2, NULL, 'v'
  192. },
  193. {
  194. "named", 1, NULL, 'N'
  195. },
  196. {
  197. "auto-connect", 0, NULL, 'a'
  198. },
  199. {
  200. "output", 1, NULL, 'O'
  201. },
  202. {
  203. "input", 1, NULL, 'I'
  204. },
  205. {
  206. "exec-after-init", 1, NULL, 'e'
  207. },
  208. {
  209. 0, 0, 0, 0
  210. }
  211. };
  212. opterr = 0;
  213. int option_index = 0, opt, exitwithhelp = 0, exitwithversion = 0;
  214. string loadfile, loadinstrument, execAfterInit;
  215. while(1) {
  216. int tmp = 0;
  217. /**\todo check this process for a small memory leak*/
  218. opt = getopt_long(argc,
  219. argv,
  220. "l:L:r:b:o:I:O:N:e:hvaSDUY",
  221. opts,
  222. &option_index);
  223. char *optarguments = optarg;
  224. #define GETOP(x) if(optarguments) \
  225. x = optarguments
  226. #define GETOPNUM(x) if(optarguments) \
  227. x = atoi(optarguments)
  228. if(opt == -1)
  229. break;
  230. switch(opt) {
  231. case 'h':
  232. exitwithhelp = 1;
  233. break;
  234. case 'v':
  235. exitwithversion = 1;
  236. break;
  237. case 'Y': /* this command a dummy command (has NO effect)
  238. and is used because I need for NSIS installer
  239. (NSIS sometimes forces a command line for a
  240. program, even if I don't need that; eg. when
  241. I want to add a icon to a shortcut.
  242. */
  243. break;
  244. case 'U':
  245. noui = 1;
  246. break;
  247. case 'l':
  248. GETOP(loadfile);
  249. break;
  250. case 'L':
  251. GETOP(loadinstrument);
  252. break;
  253. case 'r':
  254. GETOPNUM(synth->samplerate);
  255. if(synth->samplerate < 4000) {
  256. cerr << "ERROR:Incorrect sample rate: " << optarguments
  257. << endl;
  258. exit(1);
  259. }
  260. break;
  261. case 'b':
  262. GETOPNUM(synth->buffersize);
  263. if(synth->buffersize < 2) {
  264. cerr << "ERROR:Incorrect buffer size: " << optarguments
  265. << endl;
  266. exit(1);
  267. }
  268. break;
  269. case 'o':
  270. if(optarguments)
  271. synth->oscilsize = tmp = atoi(optarguments);
  272. if(synth->oscilsize < MAX_AD_HARMONICS * 2)
  273. synth->oscilsize = MAX_AD_HARMONICS * 2;
  274. synth->oscilsize =
  275. (int) powf(2,
  276. ceil(logf(synth->oscilsize - 1.0f) / logf(2.0f)));
  277. if(tmp != synth->oscilsize)
  278. cerr
  279. <<
  280. "synth->oscilsize is wrong (must be 2^n) or too small. Adjusting to "
  281. << synth->oscilsize << "." << endl;
  282. break;
  283. case 'S':
  284. swaplr = 1;
  285. break;
  286. case 'D':
  287. dump.startnow();
  288. break;
  289. case 'N':
  290. Nio::setPostfix(optarguments);
  291. break;
  292. case 'I':
  293. if(optarguments)
  294. Nio::setDefaultSource(optarguments);
  295. break;
  296. case 'O':
  297. if(optarguments)
  298. Nio::setDefaultSink(optarguments);
  299. break;
  300. case 'a':
  301. Nio::autoConnect = true;
  302. break;
  303. case 'e':
  304. GETOP(execAfterInit);
  305. break;
  306. case '?':
  307. cerr << "ERROR:Bad option or parameter.\n" << endl;
  308. exitwithhelp = 1;
  309. break;
  310. }
  311. }
  312. synth->alias();
  313. if(exitwithversion) {
  314. cout << "Version: " << VERSION << endl;
  315. return 0;
  316. }
  317. if(exitwithhelp != 0) {
  318. cout << "Usage: zynaddsubfx [OPTION]\n\n"
  319. << " -h , --help \t\t\t\t Display command-line help and exit\n"
  320. << " -v , --version \t\t\t Display version and exit\n"
  321. << " -l file, --load=FILE\t\t\t Loads a .xmz file\n"
  322. << " -L file, --load-instrument=FILE\t Loads a .xiz file\n"
  323. << " -r SR, --sample-rate=SR\t\t Set the sample rate SR\n"
  324. <<
  325. " -b BS, --buffer-size=SR\t\t Set the buffer size (granularity)\n"
  326. << " -o OS, --oscil-size=OS\t\t Set the ADsynth oscil. size\n"
  327. << " -S , --swap\t\t\t\t Swap Left <--> Right\n"
  328. << " -D , --dump\t\t\t\t Dumps midi note ON/OFF commands\n"
  329. <<
  330. " -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n"
  331. << " -N , --named\t\t\t\t Postfix IO Name when possible\n"
  332. << " -a , --auto-connect\t\t\t AutoConnect when using JACK\n"
  333. << " -O , --output\t\t\t\t Set Output Engine\n"
  334. << " -I , --input\t\t\t\t Set Input Engine\n"
  335. << " -e , --exec-after-init\t\t Run post-initialization script\n"
  336. << endl;
  337. return 0;
  338. }
  339. //produce denormal buf
  340. denormalkillbuf = new float [synth->buffersize];
  341. for(int i = 0; i < synth->buffersize; ++i)
  342. denormalkillbuf[i] = (RND - 0.5f) * 1e-16;
  343. initprogram();
  344. if(!loadfile.empty()) {
  345. int tmp = master->loadXML(loadfile.c_str());
  346. if(tmp < 0) {
  347. cerr << "ERROR: Could not load master file " << loadfile
  348. << "." << endl;
  349. exit(1);
  350. }
  351. else {
  352. master->applyparameters();
  353. cout << "Master file loaded." << endl;
  354. }
  355. }
  356. if(!loadinstrument.empty()) {
  357. int loadtopart = 0;
  358. int tmp = master->part[loadtopart]->loadXMLinstrument(
  359. loadinstrument.c_str());
  360. if(tmp < 0) {
  361. cerr << "ERROR: Could not load instrument file "
  362. << loadinstrument << '.' << endl;
  363. exit(1);
  364. }
  365. else {
  366. master->part[loadtopart]->applyparameters();
  367. cout << "Instrument file loaded." << endl;
  368. }
  369. }
  370. //Run the Nio system
  371. bool ioGood = Nio::start();
  372. if(!execAfterInit.empty()) {
  373. cout << "Executing user supplied command: " << execAfterInit << endl;
  374. if(system(execAfterInit.c_str()) == -1)
  375. cerr << "Command Failed..." << endl;
  376. }
  377. #ifndef DISABLE_GUI
  378. #ifdef NTK_GUI
  379. fl_register_images();
  380. Fl_Tooltip::textcolor(0x0);
  381. Fl_Dial::default_style(Fl_Dial::PIXMAP_DIAL);
  382. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/knob.png"))
  383. Fl_Dial::default_image(img);
  384. else
  385. Fl_Dial::default_image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/knob.png"));
  386. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/window_backdrop.png"))
  387. Fl::scheme_bg(new Fl_Tiled_Image(img));
  388. else
  389. Fl::scheme_bg(new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/window_backdrop.png")));
  390. if(Fl_Shared_Image *img = Fl_Shared_Image::get(PIXMAP_PATH "/module_backdrop.png"))
  391. module_backdrop = new Fl_Tiled_Image(img);
  392. else
  393. module_backdrop = new Fl_Tiled_Image(Fl_Shared_Image::get(SOURCE_DIR "/../pixmaps/module_backdrop.png"));
  394. Fl::background( 50, 50, 50 );
  395. Fl::background2( 70, 70, 70 );
  396. Fl::foreground( 255,255,255 );
  397. #endif
  398. ui = new MasterUI(master, &Pexitprogram);
  399. if ( !noui)
  400. {
  401. ui->showUI();
  402. if(!ioGood)
  403. fl_alert(
  404. "Default IO did not initialize.\nDefaulting to NULL backend.");
  405. }
  406. #endif
  407. #ifndef DISABLE_GUI
  408. #if USE_NSM
  409. char *nsm_url = getenv("NSM_URL");
  410. if(nsm_url) {
  411. nsm = new NSM_Client;
  412. if(!nsm->init(nsm_url))
  413. nsm->announce("ZynAddSubFX", ":switch:", argv[0]);
  414. else {
  415. delete nsm;
  416. nsm = NULL;
  417. }
  418. }
  419. #endif
  420. #endif
  421. #if USE_NSM
  422. if(!nsm)
  423. #endif
  424. {
  425. #if LASH
  426. lash = new LASHClient(&argc, &argv);
  427. #ifndef DISABLE_GUI
  428. ui->sm_indicator1->value(1);
  429. ui->sm_indicator2->value(1);
  430. ui->sm_indicator1->tooltip("LASH");
  431. ui->sm_indicator2->tooltip("LASH");
  432. #endif
  433. #endif
  434. }
  435. while(Pexitprogram == 0) {
  436. #ifndef DISABLE_GUI
  437. #if USE_NSM
  438. if(nsm) {
  439. nsm->check();
  440. goto done;
  441. }
  442. #endif
  443. #if LASH
  444. {
  445. string filename;
  446. switch(lash->checkevents(filename)) {
  447. case LASHClient::Save:
  448. ui->do_save_master(filename.c_str());
  449. lash->confirmevent(LASHClient::Save);
  450. break;
  451. case LASHClient::Restore:
  452. ui->do_load_master(filename.c_str());
  453. lash->confirmevent(LASHClient::Restore);
  454. break;
  455. case LASHClient::Quit:
  456. Pexitprogram = 1;
  457. default:
  458. break;
  459. }
  460. }
  461. #endif //LASH
  462. #if USE_NSM
  463. done:
  464. #endif
  465. Fl::wait(0.02f);
  466. #else
  467. usleep(100000);
  468. #endif
  469. }
  470. exitprogram();
  471. return 0;
  472. }