|  | /*  SpiralSynthModular
 *  Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ 
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <cstdlib>
#include <FL/Fl.H>
#include <FL/Fl_Tooltip.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "SpiralSynthModular.h"
pthread_t loopthread,watchdogthread;
SynthModular *synth;
char watchdog_check = 1;
char gui_watchdog_check = 1;
int pthread_create_realtime (pthread_t *new_thread,
			 void *(*start)(void *), void *arg,
			 int priority);
bool CallbackOnly = false;
bool FIFO = false;
bool GUI = true;
/////////////////////////////////////////////////////////////
void watchdog (void *arg)
{	
	pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	watchdog_check = 0;
	gui_watchdog_check = 0;
	
	while (1) 
	{
		usleep (10000000);
		// gui watchdog goes off with modal dialog boxes
		if (watchdog_check == 0)// || gui_watchdog_check== 0) 
		{
			cerr<<"ssm watchdog: timeout - killing ssm"<<endl;
			if (watchdog_check==0) cerr<<"diagnosis: audio hung?"<<endl;
			if (gui_watchdog_check==0) cerr<<"diagnosis: gui starved by audio"<<endl;
			exit (1);
		}
		watchdog_check = 0;
		gui_watchdog_check = 0;
	}
}
///////////////////////////////////////////////////////////////////////
void audioloop(void* o)
{
	while(1)
	{		
		if (!synth->CallbackMode()) 
		{
			// do funky stuff
			synth->Update();
			// put the brakes on if there is no blocking output running
			if (!synth->IsBlockingOutputPluginReady()||
				 synth->IsPaused()) 
			{
				usleep(10000);
			}
		}
		else
		{
			// the engine is currently in callback mode, so we don't
			// need to do anything unless we are switched back 
			usleep(1000000);
		}
		
		watchdog_check = 1;
	}
}
//////////////////////////////////////////////////////
#if __APPLE__
#include <CoreFoundation/CFBundle.h>
#include <libgen.h>
#endif
int main(int argc, char **argv)
{
#if __APPLE__
	// --with-plugindir=./Libraries
	system("pwd");
	CFBundleRef main	= CFBundleGetMainBundle();
	CFURLRef	url		= main ? CFBundleCopyExecutableURL(main) : NULL;
	CFStringRef path	= url ? CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle) : NULL;
	char *		dst		= (char*)CFStringGetCStringPtr(path, 0);
	
	printf("main %p url %p path %p dst %p", main, url, path, dst);
	if (dst) {
		printf("Have a valid name '%s'\n", dst);
		chdir(dirname(dst));
		chdir("..");
	} else
		printf("No base pathname\n");
#endif
	srand(time(NULL));
	SpiralSynthModularInfo::Get()->LoadPrefs();
	
	// get args
    string cmd_filename="";
    bool cmd_specd = false;
	string cmd_pluginPath="";
	
	// parse the args
    if (argc>1) 
	{
		for (int a=1; a<argc; a++)
		{
			if (!strcmp(argv[a],"--NoGUI")) GUI = false;
			else if (!strcmp(argv[a],"--Realtime")) FIFO = true;
			else if (!strcmp(argv[a],"-h")) 
			{	
				cout<<"usage: spiralsynthmodular [patch.ssm] [options]"<<endl<<endl
				<<"options list"<<endl
				<<"-h : help"<<endl
				<<"-v : print version"<<endl
				<<"--NoGUI : run without GUI (only useful when loading patch from command line"<<endl
				<<"--Realtime : spawn audio thread with FIFO scheduling (run as root)"<<endl
				<<"--PluginPath <PATH> : look for plugins in the specified directory"<<endl;
				exit(0);
			}
			else if (!strcmp(argv[a],"-v")) 
			{
				cout<<VER_STRING<<endl; exit(0);
			} 			
			else if (!strcmp(argv[a],"--PluginPath"))
			{
				a++;
				cmd_pluginPath=argv[a];
			}
			else 
			{
				cmd_filename = argv[1];
				cmd_specd = true;
			}
		}
    }	
	
	// set some fltk defaults
	Fl_Tooltip::size(10);	
	Fl::visible_focus(false);
	Fl::visual(FL_DOUBLE|FL_RGB);
	
	synth=new SynthModular;
	
	// setup the synth
	Fl_Window* win = synth->CreateWindow();
	synth->LoadPlugins(cmd_pluginPath);
	win->xclass("");
	if (GUI) win->show(1, argv); // prevents stuff happening before the plugins have loaded
	
	// spawn the audio thread
	if (FIFO) 
	{	
		pthread_create_realtime(&watchdogthread,(void*(*)(void*))watchdog,NULL,sched_get_priority_max(SCHED_FIFO));
		pthread_create_realtime(&loopthread,(void*(*)(void*))audioloop,NULL,sched_get_priority_max(SCHED_FIFO)-1);
	}
	else 
	{
		pthread_create(&loopthread,NULL,(void*(*)(void*))audioloop,NULL);
		// reduce the priority of the gui
		if (setpriority(PRIO_PROCESS,0,20)) cerr<<"Could not set priority for GUI thread"<<endl;
	}
	
	// do we need to load a patch on startup? 
    if (cmd_specd) synth->LoadPatch(cmd_filename.c_str());        
	
	if (!GUI)
	{	
		// if there is no gui needed, there is nothing more to do here
		Fl::check();
		for (;;) sleep(1);
	}
	
    for (;;)
	{
    	if (!Fl::check()) break;    	
		synth->UpdatePluginGUIs(); // deletes any if necc
		usleep(10000);
		gui_watchdog_check=1;
  	}
	
	//pthread_cancel(loopthread);
	delete synth;	
	return 1;
}
// nicked from Paul Barton-Davis' Ardour code :)
int pthread_create_realtime (pthread_t *new_thread,
			 void *(*start)(void *), void *arg,
			 int priority)
{	
	pthread_attr_t *rt_attributes;
	struct sched_param *rt_param;
	int retval;
	rt_attributes = (pthread_attr_t *) malloc (sizeof (pthread_attr_t));
	rt_param = (struct sched_param *) malloc (sizeof (struct sched_param));
	pthread_attr_init (rt_attributes);
	if (seteuid (0)) {
		cerr << "Cannot obtain root UID for RT scheduling operations"
		      << endl;
		return -1;
	} else {
	    if (pthread_attr_setschedpolicy (rt_attributes, SCHED_FIFO)) {
		cerr << "Cannot set FIFO scheduling attributes for RT thread" << endl;
	    }
	    
	    if (pthread_attr_setscope (rt_attributes, PTHREAD_SCOPE_SYSTEM)) {
		cerr << "Cannot set scheduling scope for RT thread" << endl;
	    }
	    
	    rt_param->sched_priority = priority;
	    if (pthread_attr_setschedparam (rt_attributes, rt_param)) {
		cerr << "Cannot set scheduling priority for RT thread" << endl;
	    }
	}
	retval = pthread_create (new_thread, rt_attributes, start, arg);
	seteuid (getuid());
	return retval;
}
 |