Fixing the character set (now utf-8).
[terminatorX.git] / src / main.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2011  Alexander König
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     (at your option) 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     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18     
19     File: main.c
20     
21     Description: This contains the main() function. All the initializing
22                  happens here.
23     
24     Changes:
25     
26     19 Mar 1999: Applied a patch by Andrew C. Bul+hac?k (eMail: acb@zikzak.net)
27                  that fixes wavfile reading routine for the overreading bug.
28                  
29     20 Mar 1999: Big endian support.
30     
31     23 Mar 1999: display of new keys (<-, ->)
32     
33     4 October 1999: Rewrite ;) - back to C++
34 */
35
36 #define TX_GTKRC "/usr/share/themes/terminatorX/gtk/gtkrc"
37
38 #define BENCH_CYCLES 100000
39
40 #include <stdio.h>
41 #include "tX_mastergui.h"
42 #include <malloc.h>
43 #include <math.h>
44 #include <stdio.h>
45 #ifndef WIN32
46 #include <unistd.h>
47 #endif
48
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #endif
52
53 #include "tX_endian.h"
54 #include "tX_types.h"
55 #include "tX_global.h"
56 #include "tX_audiodevice.h"
57 #include "version.h"
58 #include "tX_dialog.h"
59 #include <gtk/gtk.h>
60 #include <glib.h>
61 #include <string.h>
62
63 #include "tX_ladspa.h"
64 #include "tX_ladspa_class.h"
65 #include "tX_engine.h"
66 #include "tX_capabilities.h"
67 #include "tX_pbutton.h"
68
69 #ifdef CREATE_BENCHMARK 
70 #include "tX_vtt.h"
71 #endif
72
73 #ifdef USE_SCHEDULER
74 #include <sched.h>
75 #include <sys/types.h>
76 #include <unistd.h>
77 #endif
78
79 #ifdef USE_JACK 
80 void jack_check()
81 {
82         if ((!tX_jack_client::get_instance()) && (globals.audiodevice_type==JACK)) {
83                 tx_note("Couldn't connect to JACK server - JACK output not available.\n\nIf you want to use JACK, ensure the JACK daemon is running before you start terminatorX.", true);
84         }
85 }
86 #endif // USE_JACK
87
88 static bool timesup=false;
89
90 gboolean timeout(void *)
91 {
92         timesup=true;
93         return FALSE;
94 }
95
96 void show_help()
97 {
98                         
99         fprintf(stderr, "\
100 usage: terminatorX [options]n\
101 \n\
102   -h, --help                    Display help info\n\
103   -f, --file                    Load saved terminatorX set file\n\
104   -r, --rc-file [file]          Load alternate rc file\n\
105   -d, --dont-save               Do not save settings at exit\n\
106   -s, --std-out                 Use stdout for sound output\n\
107   --device=[output device]      Use alternate device for sound output\n\
108 \n");
109 }
110
111 int parse_args(int *argc, char **argv)
112 {
113         // pass over argv once to see if we need to load an alternate_rc file
114         for (int i = 1 ; i != *argc ; ++i ) {
115                 if ((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) {
116                         if (argv[i+1] ) {       
117                                 ++i;
118                                 fprintf(stderr, "tX: Loading alternate rc file %s\n", argv[i]);
119                                 globals.alternate_rc = argv[i];
120                         } else {
121                                 show_help();    
122                                 exit(1);
123                         }
124                         break;
125                 }
126         }
127         
128         // load up the global values
129         load_globals();
130
131         // default the flag options, or they'll be set from last execution... (think globals.no_gui ;)
132         globals.no_gui = 0;
133         globals.alternate_rc = 0;
134         globals.store_globals = 1;
135         globals.startup_set = 0;
136                 
137         // then pass over again, this time setting passed values
138         for (int i = 1 ; i < *argc ; ++i ) {
139                 if ((strcmp(argv[i], "-f") == 0) || (strcmp(argv[i], "--file") == 0)) {
140                         ++i;
141                         globals.startup_set = argv[i];
142                 } else if (((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) && (argv[i+1])) {
143                         ++i;
144                         globals.alternate_rc = argv[i];
145                 } else if ((strcmp(argv[i], "-d") == 0) || (strcmp(argv[i], "--dont-save") == 0)) {
146                         fprintf(stderr, "tX: Do not save settings on exit\n");
147                         globals.store_globals = 0;
148
149                 } else if ((strcmp(argv[i], "-s") == 0) || (strcmp(argv[i], "--std-out") == 0)) {
150                         globals.use_stdout_cmdline = 1;
151                         globals.use_stdout = 1;
152                 } else if ((strncmp(argv[i], "--device",8) == 0)) {
153                         if (strlen(argv[i]+9)<=PATH_MAX)
154                                 strcpy(globals.oss_device,argv[i]+9);
155                         else {
156                                 show_help();
157                                 exit(1);
158                         }
159                 } else {
160                         show_help();
161                         exit(1);
162                 }
163         }
164         return 1;
165 }
166
167 void checkenv(const char *name)
168 {
169         char *value;
170         int length;
171         
172         value=getenv(name);
173         if (value) {
174                 length=strlen(value);
175                 /*
176                  strnlen requires extra macros...
177                  length=strnlen(value, PATH_MAX+1);
178                 */
179                 
180                 if (length>=PATH_MAX) {
181                         tX_error("Your \"%s\" environment variable seems malicious (%i chars).", name, length);
182                         tX_error("Please correct that and restart terminatorX.");
183                         exit(-1);
184                 }
185         }
186 }
187
188 int main(int argc, char **argv)
189 {
190         fprintf(stderr, "%s - Copyright (C) 1999-2011 by Alexander König\n", VERSIONSTRING);
191         fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
192
193 #ifdef USE_CAPABILITIES 
194         if (!geteuid()) {
195                 if (prctl(PR_SET_KEEPCAPS, 1, -1, -1, -1)) {
196                         tX_error("failed to keep capabilites.");
197                 }
198                 set_nice_capability(CAP_PERMITTED);
199         }
200 #endif
201
202         if ((!geteuid()) && (getuid() != geteuid())) {
203                 tX_msg("runnig suid-root - dropping root privileges.");
204                 
205                 int result=setuid(getuid());
206                 
207                 if (result) {
208                         tX_error("main() Panic: can't drop root privileges.");
209                         exit(2);
210                 }
211         }
212         
213         /* No suidroot below this comment. */
214         
215 #ifdef USE_CAPABILITIES         
216         set_nice_capability(CAP_EFFECTIVE);     
217 #endif
218         
219         /* Theses checks are now sort of unecessary... Anyway... */
220         checkenv("HOME");
221         checkenv("XLOCALEDIR"); 
222
223         gtk_init (&argc, &argv);
224         gtk_set_locale();
225         
226 #ifdef USE_STARTUP_NOTIFICATION
227         // startup isn't really finished with the nagbox alone...
228         gtk_window_set_auto_startup_notification(FALSE);
229 #endif  
230         
231         parse_args(&argc, argv); // loads settings
232
233         if (globals.show_nag) { 
234                 show_about(1);
235                 g_timeout_add(2000, (GSourceFunc) timeout, NULL);
236         }
237         
238         tX_engine *engine=tX_engine::get_instance();
239         LADSPA_Class::init();
240         LADSPA_Plugin::init();
241
242 #ifdef USE_JACK 
243         tX_jack_client::init();
244 #endif  
245
246 #ifdef USE_SCHEDULER
247         tX_debug("main() GUI thread is p:%i, t:%i and has policy %i.", getpid(), (int) pthread_self(), sched_getscheduler(getpid()));
248 #endif  
249         tx_icons_init();
250         create_mastergui(globals.width, globals.height);
251         
252         if (globals.show_nag) {
253                 while (!timesup) {
254                         while (gtk_events_pending()) gtk_main_iteration(); 
255                         gdk_flush();                            
256                         usleep(250);
257                 }
258                 destroy_about();
259         }
260         
261 #ifdef USE_JACK
262         jack_check();
263 #endif
264         display_mastergui();
265                 
266         if (globals.startup_set) {
267                 while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
268                 tX_cursor::set_cursor(tX_cursor::WAIT_CURSOR);
269                 load_tt_part(globals.startup_set);
270                 tX_cursor::reset_cursor();
271         } else {
272 #ifdef USE_ALSA_MIDI_IN
273                 if (globals.auto_assign_midi) tX_midiin::auto_assign_midi_mappings(NULL, NULL);
274 #endif          
275         }
276
277 #ifdef USE_STARTUP_NOTIFICATION
278         gdk_notify_startup_complete();
279 #endif  
280         
281 #ifndef CREATE_BENCHMARK
282         gtk_main();
283
284         store_globals();
285
286         delete engine;
287 #ifdef USE_JACK 
288         if (tX_jack_client::get_instance()) {
289                 delete tX_jack_client::get_instance();
290         }
291 #endif // USE_JACK
292         
293         fprintf(stderr, "Have a nice life.\n");
294 #else // CREATE_BENCHMARK
295         gtk_widget_hide(main_window);
296         while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
297         gdk_flush();
298         
299         vtt_class::set_sample_rate(48000);
300         
301         printf("\n* BENCHMARKING *\n");
302         
303         GTimer *bench_time = g_timer_new();
304         gulong micros;
305         double ratio;
306         double res;
307         list <vtt_class *> :: iterator vtt;
308         
309         for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++) {
310                 if ((*vtt)->autotrigger) (*vtt)->trigger();
311         }
312         
313         sleep(3);       
314         g_timer_start(bench_time);
315         
316         for (int i=0; i<BENCH_CYCLES; i++) {
317                 vtt_class::render_all_turntables();
318         }
319         g_timer_stop(bench_time);
320         res=g_timer_elapsed(bench_time, &micros);
321         
322         ratio=((double) BENCH_CYCLES)/res;
323         printf ("Rendered %i blocks in %f secons,\n=> %f blocks per second.\n\n", (long) BENCH_CYCLES, res, ratio);
324 #endif // CREATE_BENCHMARK
325         return (0);
326 }