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.

265 lines
6.5KB

  1. /* SpiralSynthModular
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  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 for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <iostream>
  22. #include <cstdlib>
  23. #include <FL/Fl.H>
  24. #include <FL/Fl_Tooltip.h>
  25. #include <unistd.h>
  26. #include <sys/time.h>
  27. #include <sys/resource.h>
  28. #include "SpiralSynthModular.h"
  29. #include "SpiralSound/SpiralInfo.h"
  30. pthread_t loopthread,watchdogthread;
  31. SynthModular *synth;
  32. char watchdog_check = 1;
  33. char gui_watchdog_check = 1;
  34. int pthread_create_realtime (pthread_t *new_thread,
  35. void *(*start)(void *), void *arg,
  36. int priority);
  37. bool CallbackOnly = false;
  38. bool FIFO = false;
  39. bool GUI = true;
  40. /////////////////////////////////////////////////////////////
  41. void watchdog (void *arg)
  42. {
  43. pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  44. watchdog_check = 0;
  45. gui_watchdog_check = 0;
  46. while (1)
  47. {
  48. usleep (10000000);
  49. // gui watchdog goes off with modal dialog boxes
  50. if (watchdog_check == 0)// || gui_watchdog_check== 0)
  51. {
  52. cerr<<"ssm watchdog: timeout - killing ssm"<<endl;
  53. if (watchdog_check==0) cerr<<"diagnosis: audio hung?"<<endl;
  54. if (gui_watchdog_check==0) cerr<<"diagnosis: gui starved by audio"<<endl;
  55. exit (1);
  56. }
  57. watchdog_check = 0;
  58. gui_watchdog_check = 0;
  59. }
  60. }
  61. ///////////////////////////////////////////////////////////////////////
  62. void audioloop(void* o)
  63. {
  64. while(1)
  65. {
  66. if (!synth->CallbackMode())
  67. {
  68. // do funky stuff
  69. synth->Update();
  70. // put the brakes on if there is no blocking output running
  71. if (!synth->IsBlockingOutputPluginReady()||
  72. synth->IsPaused())
  73. {
  74. usleep(10000);
  75. }
  76. }
  77. else
  78. {
  79. // the engine is currently in callback mode, so we don't
  80. // need to do anything unless we are switched back
  81. usleep(1000000);
  82. }
  83. watchdog_check = 1;
  84. }
  85. }
  86. //////////////////////////////////////////////////////
  87. #if __APPLE__
  88. #include <CoreFoundation/CFBundle.h>
  89. #include <libgen.h>
  90. #endif
  91. #include "GraphSort.h"
  92. int main(int argc, char **argv)
  93. {
  94. #if __APPLE__
  95. // --with-plugindir=./Libraries
  96. system("pwd");
  97. CFBundleRef main = CFBundleGetMainBundle();
  98. CFURLRef url = main ? CFBundleCopyExecutableURL(main) : NULL;
  99. CFStringRef path = url ? CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle) : NULL;
  100. char * dst = (char*)CFStringGetCStringPtr(path, 0);
  101. printf("main %p url %p path %p dst %p", main, url, path, dst);
  102. if (dst) {
  103. printf("Have a valid name '%s'\n", dst);
  104. chdir(dirname(dst));
  105. chdir("..");
  106. } else
  107. printf("No base pathname\n");
  108. #endif
  109. srand(time(NULL));
  110. SpiralInfo::Get()->LoadPrefs();
  111. // get args
  112. string cmd_filename="";
  113. bool cmd_specd = false;
  114. string cmd_pluginPath="";
  115. // parse the args
  116. if (argc>1)
  117. {
  118. for (int a=1; a<argc; a++)
  119. {
  120. if (!strcmp(argv[a],"--NoGUI")) GUI = false;
  121. else if (!strcmp(argv[a],"--Realtime")) FIFO = true;
  122. else if (!strcmp(argv[a],"-h"))
  123. {
  124. cout<<"usage: spiralsynthmodular [patch.ssm] [options]"<<endl<<endl
  125. <<"options list"<<endl
  126. <<"-h : help"<<endl
  127. <<"-v : print version"<<endl
  128. <<"--NoGUI : run without GUI (only useful when loading patch from command line"<<endl
  129. <<"--Realtime : spawn audio thread with FIFO scheduling (run as root)"<<endl
  130. <<"--PluginPath <PATH> : look for plugins in the specified directory"<<endl;
  131. exit(0);
  132. }
  133. else if (!strcmp(argv[a],"-v"))
  134. {
  135. cout<<VER_STRING<<endl; exit(0);
  136. }
  137. else if (!strcmp(argv[a],"--PluginPath"))
  138. {
  139. a++;
  140. cmd_pluginPath=argv[a];
  141. }
  142. else
  143. {
  144. cmd_filename = argv[1];
  145. cmd_specd = true;
  146. }
  147. }
  148. }
  149. // set some fltk defaults
  150. Fl_Tooltip::size(10);
  151. Fl::visible_focus(false);
  152. Fl::visual(FL_DOUBLE|FL_RGB);
  153. synth=new SynthModular;
  154. // setup the synth
  155. Fl_Window* win = synth->CreateWindow();
  156. synth->LoadPlugins(cmd_pluginPath);
  157. win->xclass("");
  158. if (GUI) win->show(1, argv); // prevents stuff happening before the plugins have loaded
  159. // spawn the audio thread
  160. if (FIFO)
  161. {
  162. pthread_create_realtime(&watchdogthread,(void*(*)(void*))watchdog,NULL,sched_get_priority_max(SCHED_FIFO));
  163. pthread_create_realtime(&loopthread,(void*(*)(void*))audioloop,NULL,sched_get_priority_max(SCHED_FIFO)-1);
  164. }
  165. else
  166. {
  167. pthread_create(&loopthread,NULL,(void*(*)(void*))audioloop,NULL);
  168. // reduce the priority of the gui
  169. if (setpriority(PRIO_PROCESS,0,20)) cerr<<"Could not set priority for GUI thread"<<endl;
  170. }
  171. // do we need to load a patch on startup?
  172. if (cmd_specd) synth->LoadPatch(cmd_filename.c_str());
  173. if (!GUI)
  174. {
  175. // if there is no gui needed, there is nothing more to do here
  176. Fl::check();
  177. for (;;) sleep(1);
  178. }
  179. for (;;)
  180. {
  181. if (!Fl::check()) break;
  182. synth->UpdatePluginGUIs(); // deletes any if necc
  183. usleep(10000);
  184. gui_watchdog_check=1;
  185. }
  186. //pthread_cancel(loopthread);
  187. delete synth;
  188. return 1;
  189. }
  190. // nicked from Paul Barton-Davis' Ardour code :)
  191. int pthread_create_realtime (pthread_t *new_thread,
  192. void *(*start)(void *), void *arg,
  193. int priority)
  194. {
  195. pthread_attr_t *rt_attributes;
  196. struct sched_param *rt_param;
  197. int retval;
  198. rt_attributes = (pthread_attr_t *) malloc (sizeof (pthread_attr_t));
  199. rt_param = (struct sched_param *) malloc (sizeof (struct sched_param));
  200. pthread_attr_init (rt_attributes);
  201. if (seteuid (0)) {
  202. cerr << "Cannot obtain root UID for RT scheduling operations"
  203. << endl;
  204. return -1;
  205. } else {
  206. if (pthread_attr_setschedpolicy (rt_attributes, SCHED_FIFO)) {
  207. cerr << "Cannot set FIFO scheduling attributes for RT thread" << endl;
  208. }
  209. if (pthread_attr_setscope (rt_attributes, PTHREAD_SCOPE_SYSTEM)) {
  210. cerr << "Cannot set scheduling scope for RT thread" << endl;
  211. }
  212. rt_param->sched_priority = priority;
  213. if (pthread_attr_setschedparam (rt_attributes, rt_param)) {
  214. cerr << "Cannot set scheduling priority for RT thread" << endl;
  215. }
  216. }
  217. retval = pthread_create (new_thread, rt_attributes, start, arg);
  218. seteuid (getuid());
  219. return retval;
  220. }