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