11f11cf5e2508a8f0ce6c03a14a37d73b7adec65
[terminatorX.git] / src / main.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2002  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 #ifdef USE_3DNOW
54 #include "3dnow.h"
55 #endif
56
57 #include "tX_endian.h"
58 #include "tX_types.h"
59 #include "tX_global.h"
60 #include "version.h"
61 #include "tX_dialog.h"
62 #include <gtk/gtk.h>
63 #include <glib.h>
64
65 #include "tX_ladspa.h"
66
67 #include "tX_engine.h"
68
69 #ifdef CREATE_BENCHMARK 
70 #include "tX_vtt.h"
71 #endif
72
73 GTimer *my_time;
74 gint idle_tag;
75
76 #ifdef USE_3DNOW
77 /*      Function to test if multimedia instructions are supported...
78 */
79 inline int
80 tx_mm_support(void)
81 {
82         /* Returns 1 if MMX instructions are supported,
83            3 if Cyrix MMX and Extended MMX instructions are supported
84            5 if AMD MMX and 3DNow! instructions are supported
85            0 if hardware does not support any of these
86         */
87         register int rval = 0;
88
89         __asm__ __volatile__ (
90                 /* See if CPUID instruction is supported ... */
91                 /* ... Get copies of EFLAGS into eax and ecx */
92                 "pushf\n\t"
93                 "popl %%eax\n\t"
94                 "movl %%eax, %%ecx\n\t"
95
96                 /* ... Toggle the ID bit in one copy and store */
97                 /*     to the EFLAGS reg */
98                 "xorl $0x200000, %%eax\n\t"
99                 "push %%eax\n\t"
100                 "popf\n\t"
101
102                 /* ... Get the (hopefully modified) EFLAGS */
103                 "pushf\n\t"
104                 "popl %%eax\n\t"
105
106                 /* ... Compare and test result */
107                 "xorl %%eax, %%ecx\n\t"
108                 "testl $0x200000, %%ecx\n\t"
109                 "jz NotSupported1\n\t"          /* CPUID not supported */
110
111
112                 /* Get standard CPUID information, and
113                        go to a specific vendor section */
114                 "movl $0, %%eax\n\t"
115                 "cpuid\n\t"
116
117                 /* Check for Intel */
118                 "cmpl $0x756e6547, %%ebx\n\t"
119                 "jne TryAMD\n\t"
120                 "cmpl $0x49656e69, %%edx\n\t"
121                 "jne TryAMD\n\t"
122                 "cmpl $0x6c65746e, %%ecx\n"
123                 "jne TryAMD\n\t"
124                 "jmp Intel\n\t"
125
126                 /* Check for AMD */
127                 "\nTryAMD:\n\t"
128                 "cmpl $0x68747541, %%ebx\n\t"
129                 "jne TryCyrix\n\t"
130                 "cmpl $0x69746e65, %%edx\n\t"
131                 "jne TryCyrix\n\t"
132                 "cmpl $0x444d4163, %%ecx\n"
133                 "jne TryCyrix\n\t"
134                 "jmp AMD\n\t"
135
136                 /* Check for Cyrix */
137                 "\nTryCyrix:\n\t"
138                 "cmpl $0x69727943, %%ebx\n\t"
139                 "jne NotSupported2\n\t"
140                 "cmpl $0x736e4978, %%edx\n\t"
141                 "jne NotSupported3\n\t"
142                 "cmpl $0x64616574, %%ecx\n\t"
143                 "jne NotSupported4\n\t"
144                 /* Drop through to Cyrix... */
145
146
147                 /* Cyrix Section */
148                 /* See if extended CPUID level 80000001 is supported */
149                 /* The value of CPUID/80000001 for the 6x86MX is undefined
150                    according to the Cyrix CPU Detection Guide (Preliminary
151                    Rev. 1.01 table 1), so we'll check the value of eax for
152                    CPUID/0 to see if standard CPUID level 2 is supported.
153                    According to the table, the only CPU which supports level
154                    2 is also the only one which supports extended CPUID levels.
155                 */
156                 "cmpl $0x2, %%eax\n\t"
157                 "jne MMXtest\n\t"       /* Use standard CPUID instead */
158
159                 /* Extended CPUID supported (in theory), so get extended
160                    features */
161                 "movl $0x80000001, %%eax\n\t"
162                 "cpuid\n\t"
163                 "testl $0x00800000, %%eax\n\t"  /* Test for MMX */
164                 "jz NotSupported5\n\t"          /* MMX not supported */
165                 "testl $0x01000000, %%eax\n\t"  /* Test for Ext'd MMX */
166                 "jnz EMMXSupported\n\t"
167                 "movl $1, %0\n\n\t"             /* MMX Supported */
168                 "jmp Return\n\n"
169                 "EMMXSupported:\n\t"
170                 "movl $3, %0\n\n\t"             /* EMMX and MMX Supported */
171                 "jmp Return\n\t"
172
173
174                 /* AMD Section */
175                 "AMD:\n\t"
176
177                 /* See if extended CPUID is supported */
178                 "movl $0x80000000, %%eax\n\t"
179                 "cpuid\n\t"
180                 "cmpl $0x80000000, %%eax\n\t"
181                 "jl MMXtest\n\t"        /* Use standard CPUID instead */
182
183                 /* Extended CPUID supported, so get extended features */
184                 "movl $0x80000001, %%eax\n\t"
185                 "cpuid\n\t"
186                 "testl $0x00800000, %%edx\n\t"  /* Test for MMX */
187                 "jz NotSupported6\n\t"          /* MMX not supported */
188                 "testl $0x80000000, %%edx\n\t"  /* Test for 3DNow! */
189                 "jnz ThreeDNowSupported\n\t"
190                 "movl $1, %0\n\n\t"             /* MMX Supported */
191                 "jmp Return\n\n"
192                 "ThreeDNowSupported:\n\t"
193                 "movl $5, %0\n\n\t"             /* 3DNow! and MMX Supported */
194                 "jmp Return\n\t"
195
196
197                 /* Intel Section */
198                 "Intel:\n\t"
199
200                 /* Check for MMX */
201                 "MMXtest:\n\t"
202                 "movl $1, %%eax\n\t"
203                 "cpuid\n\t"
204                 "testl $0x00800000, %%edx\n\t"  /* Test for MMX */
205                 "jz NotSupported7\n\t"          /* MMX Not supported */
206                 "movl $1, %0\n\n\t"             /* MMX Supported */
207                 "jmp Return\n\t"
208
209                 /* Nothing supported */
210                 "\nNotSupported1:\n\t"
211                 "#movl $101, %0\n\n\t"
212                 "\nNotSupported2:\n\t"
213                 "#movl $102, %0\n\n\t"
214                 "\nNotSupported3:\n\t"
215                 "#movl $103, %0\n\n\t"
216                 "\nNotSupported4:\n\t"
217                 "#movl $104, %0\n\n\t"
218                 "\nNotSupported5:\n\t"
219                 "#movl $105, %0\n\n\t"
220                 "\nNotSupported6:\n\t"
221                 "#movl $106, %0\n\n\t"
222                 "\nNotSupported7:\n\t"
223                 "#movl $107, %0\n\n\t"
224                 "movl $0, %0\n\n\t"
225
226                 "Return:\n\t"
227                 : "=g" (rval)
228                 : /* no input */
229                 : "eax", "ebx", "ecx", "edx"
230         );
231
232         /* Return */
233         return(rval);
234 }
235
236 #endif
237
238 int idle()
239 {
240         gdouble time;
241         gulong ms;
242         
243         time=g_timer_elapsed(my_time, &ms);
244         if (time > 1.5)
245         {
246                 gtk_idle_remove(idle_tag);
247                 destroy_about();                
248                 display_mastergui();            
249         }
250         
251         return TRUE;
252 }
253
254 void show_help()
255 {
256                         
257         fprintf(stderr, "\
258 usage: terminatorX [options]n\
259 \n\
260   -h, --help                    Display help info\n\
261   -f, --file                    Load saved terminatorX set file\n\
262   -r, --rc-file [file]          Load alternate rc file\n\
263   -d, --dont-save               Do not save settings at exit\n\
264   -s, --std-out                 Use stdout for sound output\n\
265   --device=[output device]      Use alternate device for sound output\n\
266 \n");
267 /*
268   -n, --no-gui                  Run terminatorX with no GUI\n\
269   -m, --midi-in [file]          Use [file] for midi input\n\
270   -o, --midi-out [file]         Use [file] for midi input\n\
271   -s, --std-out                 Use stdout for sound output\n\
272 \n");
273 */
274 }
275
276
277 int parse_args(int *argc, char **argv)
278 {
279         // pass over argv once to see if we need to load an alternate_rc file
280         for (int i = 1 ; i != *argc ; ++i )
281         {
282                 if ((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) 
283                 {
284                         if (argv[i+1] )
285                         {       
286                                 ++i;
287                                 fprintf(stderr, "tX: Loading alternate rc file %s\n", argv[i]);
288                                 globals.alternate_rc = argv[i];
289                         }
290                         else
291                         {
292                                 show_help();    
293                                 exit(1);
294                         }
295                         break;
296                 }
297         }
298         
299         // load up the global values
300         load_globals();
301
302         // default the flag options, or they'll be set from last execution... (think globals.no_gui ;)
303         globals.no_gui = 0;
304         globals.alternate_rc = 0;
305         globals.store_globals = 1;
306         globals.startup_set = 0;
307                 
308         // then pass over again, this time setting passed values
309         for (int i = 1 ; i < *argc ; ++i )
310         {
311                 if ((strcmp(argv[i], "-f") == 0) || (strcmp(argv[i], "--file") == 0))
312                 {
313                         ++i;
314                         globals.startup_set = argv[i];
315                 }       
316                 else if (((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) && (argv[i+1]))
317                 {
318                         ++i;
319                         globals.alternate_rc = argv[i];
320                 }
321                 else if ((strcmp(argv[i], "-d") == 0) || (strcmp(argv[i], "--dont-save") == 0))
322                 {
323                         fprintf(stderr, "tX: Do not save settings on exit\n");
324                         globals.store_globals = 0;
325
326                 }
327                 else if ((strcmp(argv[i], "-s") == 0) || (strcmp(argv[i], "--std-out") == 0))
328                 {
329                         globals.use_stdout_cmdline = 1;
330                         globals.use_stdout = 1;
331                 }
332                 else if ((strncmp(argv[i], "--device",8) == 0))
333                 {
334                         if (strlen(argv[i]+9)<=PATH_MAX)
335                                 strcpy(globals.audio_device,argv[i]+9);
336                         else
337                         {
338                                 show_help();
339                                 exit(1);
340                         }
341                 }
342 /*              
343                 else if ((strcmp(argv[i], "-m") == 0) || (strcmp(argv[i], "--midi-in") == 0))
344                 {
345                 }
346                 else if ((strcmp(argv[i], "-s") == 0) || (strcmp(argv[i], "--std-out") == 0))
347                 {
348                 }       
349                 else if ((strcmp(argv[i], "-n") == 0) || (strcmp(argv[i], "--no-gui") == 0))
350                 {
351                         globals.no_gui = 1;
352                         fprintf(stderr, "tX: Run without a GUI\n");
353                 }
354 */
355                 else
356                 {
357                         show_help();
358                         exit(1);
359                 }
360         }
361         return 1;
362 }
363
364 int main(int argc, char **argv)
365 {
366         FILE *gtk_rc_file;
367         
368         fprintf(stderr, "%s - Copyright (C) 1999-2002 by Alexander König\n", VERSIONSTRING);
369         fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
370
371         engine=new tX_engine();
372         
373 #ifdef USE_3DNOW
374         if (tx_mm_support()!=5)
375         {
376                 printf("3DNow! not detected. Giving up.\n");
377                 return(1);
378         }
379         else
380         printf("3DNow! accelerations available.\n");    
381 #endif
382 //      gtk_set_locale ();
383         gtk_init (&argc, &argv);
384         
385 /*      gtk_rc_file=fopen(TX_GTKRC, "r");
386         if (gtk_rc_file)
387         {
388                 fprintf (stderr, "Using terminatorX gtkrc.\n");
389                 fclose(gtk_rc_file);
390                 gtk_rc_parse(TX_GTKRC);
391         } */
392
393         parse_args(&argc, argv); 
394
395         if (globals.show_nag)
396         {       
397                 show_about(1);
398
399                 my_time=g_timer_new();
400                 g_timer_start(my_time);         
401         
402                 idle_tag=gtk_idle_add((GtkFunction)idle, NULL);
403         }
404         
405         LADSPA_Plugin :: init();
406 //      LADSPA_Plugin :: status();
407                         
408         create_mastergui(globals.width, globals.height);
409                 
410         if (!globals.show_nag)  display_mastergui();
411                 
412         if (globals.startup_set)
413         {
414                 while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
415                 load_tt_part(globals.startup_set);
416         }
417                 
418 #ifndef CREATE_BENCHMARK
419
420 //      gdk_input_init();
421
422         gtk_main();
423
424         store_globals();
425
426         delete engine;
427         
428         fprintf(stderr, "Have a nice life.\n");
429 #else
430         gtk_widget_hide(main_window);
431         while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
432         gdk_flush();
433         
434         vtt_class::set_mix_buffer_size(globals.true_block_size);
435         printf("\n* BENCHMARKING *\nBlocksize is %i samples.\n", globals.true_block_size);
436         
437         GTimer *bench_time = g_timer_new();
438         gulong micros;
439         double ratio;
440         double res;
441         list <vtt_class *> :: iterator vtt;
442         
443         for (vtt=vtt_class::main_list.begin(); vtt!=vtt_class::main_list.end(); vtt++)
444         {
445                 if ((*vtt)->autotrigger) (*vtt)->trigger();
446         }
447         sleep(3);
448         
449         g_timer_start(bench_time);
450         for (int i=0; i<BENCH_CYCLES; i++)
451         {
452                 vtt_class::render_all_turntables();
453         }
454         g_timer_stop(bench_time);
455         res=g_timer_elapsed(bench_time, &micros);
456         
457         ratio=((double) BENCH_CYCLES)/res;
458         printf ("Rendered %i blocks in %f secons,\n=> %f blocks per second.\n\n", (long) BENCH_CYCLES, res, ratio);
459 #endif
460         return (0);
461 }