1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_main.cpp
27 // desc: chuck entry point
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // additional contributors:
32 // Ananya Misra (amisra@cs.princeton.edu)
33 // Spencer Salazar (salazar@cs.princeton.edu)
34 // date: version 1.1.x.x - Autumn 2002
35 // version 1.2.x.x - Autumn 2004
36 //-----------------------------------------------------------------------------
41 #include "chuck_compile.h"
43 #include "chuck_bbq.h"
44 #include "chuck_errmsg.h"
45 #include "chuck_lang.h"
46 #include "chuck_otf.h"
47 #include "chuck_shell.h"
48 #include "chuck_console.h"
49 #include "chuck_globals.h"
51 #include "util_string.h"
52 #include "util_thread.h"
53 #include "util_network.h"
54 #include "hidio_sdl.h"
57 #ifndef __PLATFORM_WIN32__
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
65 #if defined(__MACOSX_CORE__)
66 t_CKINT g_priority
= 80;
67 t_CKINT g_priority_low
= 60;
68 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
69 t_CKINT g_priority
= THREAD_PRIORITY_HIGHEST
;
70 t_CKINT g_priority_low
= THREAD_PRIORITY_HIGHEST
;
72 t_CKINT g_priority
= 0x7fffffff;
73 t_CKINT g_priority_low
= 0x7fffffff;
76 // thread id for otf thread
77 CHUCK_THREAD g_tid_otf
= 0;
78 // thread id for shell
79 CHUCK_THREAD g_tid_shell
= 0;
81 // default destination host name
82 char g_host
[256] = "127.0.0.1";
87 //-----------------------------------------------------------------------------
90 //-----------------------------------------------------------------------------
91 extern "C" void signal_int( int sig_num
)
93 fprintf( stderr
, "[chuck]: cleaning up...\n" );
99 Chuck_Compiler
* compiler
= g_compiler
;
100 // flag the global one
112 // things don't work so good on windows...
113 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
114 // pthread_kill( g_tid_otf, 2 );
115 if( g_tid_otf
) pthread_cancel( g_tid_otf
);
116 if( g_tid_whatever
) pthread_cancel( g_tid_whatever
);
117 // if( g_tid_otf ) usleep( 50000 );
120 if( g_tid_otf
) CloseHandle( g_tid_otf
);
122 // will this work for windows?
124 SAFE_DELETE( compiler
);
126 // ck_close( g_sock );
129 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
130 // pthread_join( g_tid_otf, NULL );
139 //-----------------------------------------------------------------------------
140 // name: next_power_2()
142 // thanks: to Niklas Werner / music-dsp
143 //-----------------------------------------------------------------------------
144 t_CKUINT
next_power_2( t_CKUINT n
)
147 for( ; n
&= n
-1; nn
= n
);
154 //-----------------------------------------------------------------------------
157 //-----------------------------------------------------------------------------
160 // TODO: play white noise and/or sound effects
161 srand( time( NULL
) );
164 int n
= (int)(rand() / (float)RAND_MAX
* poop_size
);
165 printf( "%s\n", poop
[n
] );
166 usleep( (unsigned long)(rand() / (float)RAND_MAX
* 2000000) );
173 //-----------------------------------------------------------------------------
174 // name: init_shell()
176 //-----------------------------------------------------------------------------
177 t_CKBOOL
init_shell( Chuck_Shell
* shell
, Chuck_Shell_UI
* ui
, Chuck_VM
* vm
)
179 // initialize shell UI
182 fprintf( stderr
, "[chuck]: error starting shell UI...\n" );
187 if( !shell
->init( vm
, ui
) )
189 fprintf( stderr
, "[chuck]: error starting shell...\n" );
199 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
203 t_CKBOOL
get_count( const char * arg
, t_CKUINT
* out
)
206 if( !strncmp( arg
, "--", 2 ) ) arg
+= 2;
207 else if( !strncmp( arg
, "-", 1 ) ) arg
+= 1;
211 if( *arg
== '\0' ) return FALSE
;
213 if( *arg
< '0' || *arg
> '9' ) return FALSE
;
216 *out
= (t_CKUINT
)atoi( arg
);
224 //-----------------------------------------------------------------------------
227 //-----------------------------------------------------------------------------
230 fprintf( stderr
, "\n" );
231 fprintf( stderr
, "chuck version: %s\n", CK_VERSION
);
232 #if defined(__PLATFORM_WIN32__)
233 fprintf( stderr
, " exe target: microsoft win32\n" );
234 #elif defined(__WINDOWS_DS__)
235 fprintf( stderr
, " exe target: microsoft win32 + cygwin\n" );
236 #elif defined(__LINUX_ALSA__)
237 fprintf( stderr
, " exe target: linux (alsa)\n" );
238 #elif defined(__LINUX_OSS__)
239 fprintf( stderr
, " exe target: linux (oss)\n" );
240 #elif defined(__LINUX_JACK__)
241 fprintf( stderr
, " exe target: linux (jack)\n" );
242 #elif defined(__MACOSX_UB__)
243 fprintf( stderr
, " exe target: mac os x : universal binary\n" );
244 #elif defined(__MACOSX_CORE__) && defined(__LITTLE_ENDIAN__)
245 fprintf( stderr
, " exe target: mac os x : intel\n" );
246 #elif defined(__MACOSX_CORE__)
247 fprintf( stderr
, " exe target: mac os x : powerpc\n" );
249 fprintf( stderr
, " exe target: uh... unknown\n" );
251 fprintf( stderr
, " http://chuck.cs.princeton.edu/\n\n" );
257 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
263 fprintf( stderr
, "usage: chuck --[options|commands] [+-=^] file1 file2 file3 ...\n" );
264 fprintf( stderr
, " [options] = halt|loop|audio|silent|dump|nodump|server|about|\n" );
265 fprintf( stderr
, " srate<N>|bufsize<N>|bufnum<N>|dac<N>|adc<N>|\n" );
266 fprintf( stderr
, " remote<hostname>|port<N>|verbose<N>|probe|\n" );
267 fprintf( stderr
, " channels<N>|out<N>|in<N>|shell|empty|level<N>|\n" );
268 fprintf( stderr
, " blocking|callback|deprecate:{stop|warn|ignore}\n" );
269 fprintf( stderr
, " [commands] = add|remove|replace|remove.all|status|time|kill\n" );
270 fprintf( stderr
, " [+-=^] = shortcuts for add, remove, replace, status\n" );
277 //-----------------------------------------------------------------------------
280 //-----------------------------------------------------------------------------
281 int main( int argc
, char ** argv
)
283 Chuck_Compiler
* compiler
= NULL
;
284 Chuck_VM
* vm
= NULL
;
285 Chuck_VM_Code
* code
= NULL
;
286 Chuck_VM_Shred
* shred
= NULL
;
288 t_CKBOOL enable_audio
= TRUE
;
289 t_CKBOOL vm_halt
= TRUE
;
290 t_CKUINT srate
= SAMPLING_RATE_DEFAULT
;
291 t_CKUINT buffer_size
= BUFFER_SIZE_DEFAULT
;
292 t_CKUINT num_buffers
= NUM_BUFFERS_DEFAULT
;
295 t_CKUINT dac_chans
= 2;
296 t_CKUINT adc_chans
= 2;
297 t_CKBOOL dump
= FALSE
;
298 t_CKBOOL probe
= FALSE
;
299 t_CKBOOL set_priority
= FALSE
;
300 t_CKBOOL auto_depend
= FALSE
;
301 t_CKBOOL block
= FALSE
;
302 t_CKBOOL enable_shell
= FALSE
;
303 t_CKBOOL no_vm
= FALSE
;
304 t_CKBOOL load_hid
= FALSE
;
305 t_CKBOOL enable_server
= TRUE
;
306 t_CKBOOL do_watchdog
= TRUE
;
307 t_CKINT log_level
= CK_LOG_CORE
;
308 t_CKINT deprecate_level
= 1; // warn
310 string filename
= "";
313 #if defined(__MACOSX_CORE__)
315 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
326 EM_setlog( log_level
);
328 // parse command line args
329 for( i
= 1; i
< argc
; i
++ )
331 if( argv
[i
][0] == '-' || argv
[i
][0] == '+' ||
332 argv
[i
][0] == '=' || argv
[i
][0] == '^' || argv
[i
][0] == '@' )
334 if( !strcmp(argv
[i
], "--dump") || !strcmp(argv
[i
], "+d")
335 || !strcmp(argv
[i
], "--nodump") || !strcmp(argv
[i
], "-d") )
337 else if( get_count( argv
[i
], &count
) )
339 else if( !strcmp(argv
[i
], "--audio") || !strcmp(argv
[i
], "-a") )
341 else if( !strcmp(argv
[i
], "--silent") || !strcmp(argv
[i
], "-s") )
342 enable_audio
= FALSE
;
343 else if( !strcmp(argv
[i
], "--halt") || !strcmp(argv
[i
], "-t") )
345 else if( !strcmp(argv
[i
], "--loop") || !strcmp(argv
[i
], "-l") )
346 { vm_halt
= FALSE
; enable_server
= TRUE
; }
347 else if( !strcmp(argv
[i
], "--server") )
348 enable_server
= TRUE
;
349 else if( !strcmp(argv
[i
], "--standalone") )
350 enable_server
= FALSE
;
351 else if( !strcmp(argv
[i
], "--callback") )
353 else if( !strcmp(argv
[i
], "--blocking") )
355 else if( !strcmp(argv
[i
], "--hid") )
357 else if( !strcmp(argv
[i
], "--shell") || !strcmp( argv
[i
], "-e" ) )
358 { enable_shell
= TRUE
; vm_halt
= FALSE
; }
359 else if( !strcmp(argv
[i
], "--empty") )
361 else if( !strncmp(argv
[i
], "--srate", 7) )
362 srate
= atoi( argv
[i
]+7 ) > 0 ? atoi( argv
[i
]+7 ) : srate
;
363 else if( !strncmp(argv
[i
], "-r", 2) )
364 srate
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : srate
;
365 else if( !strncmp(argv
[i
], "--bufsize", 9) )
366 buffer_size
= atoi( argv
[i
]+9 ) > 0 ? atoi( argv
[i
]+9 ) : buffer_size
;
367 else if( !strncmp(argv
[i
], "-b", 2) )
368 buffer_size
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : buffer_size
;
369 else if( !strncmp(argv
[i
], "--bufnum", 8) )
370 num_buffers
= atoi( argv
[i
]+8 ) > 0 ? atoi( argv
[i
]+8 ) : num_buffers
;
371 else if( !strncmp(argv
[i
], "-n", 2) )
372 num_buffers
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : num_buffers
;
373 else if( !strncmp(argv
[i
], "--dac", 5) )
374 dac
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 0;
375 else if( !strncmp(argv
[i
], "--adc", 5) )
376 adc
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 0;
377 else if( !strncmp(argv
[i
], "--channels", 10) )
378 dac_chans
= adc_chans
= atoi( argv
[i
]+10 ) > 0 ? atoi( argv
[i
]+10 ) : 2;
379 else if( !strncmp(argv
[i
], "-c", 2) )
380 dac_chans
= adc_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
381 else if( !strncmp(argv
[i
], "--out", 5) )
382 dac_chans
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 2;
383 else if( !strncmp(argv
[i
], "-o", 2) )
384 dac_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
385 else if( !strncmp(argv
[i
], "--in", 4) )
386 adc_chans
= atoi( argv
[i
]+4 ) > 0 ? atoi( argv
[i
]+4 ) : 2;
387 else if( !strncmp(argv
[i
], "-i", 2) )
388 adc_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
389 else if( !strncmp(argv
[i
], "--level", 7) )
390 { g_priority
= atoi( argv
[i
]+7 ); set_priority
= TRUE
; }
391 else if( !strncmp(argv
[i
], "--watchdog", 10) )
392 { g_watchdog_timeout
= atof( argv
[i
]+10 );
393 if( g_watchdog_timeout
<= 0 ) g_watchdog_timeout
= 0.5;
394 do_watchdog
= TRUE
; }
395 else if( !strncmp(argv
[i
], "--nowatchdog", 12) )
397 else if( !strncmp(argv
[i
], "--remote", 8) )
398 strcpy( g_host
, argv
[i
]+8 );
399 else if( !strncmp(argv
[i
], "@", 1) )
400 strcpy( g_host
, argv
[i
]+1 );
401 else if( !strncmp(argv
[i
], "--port", 6) )
402 g_port
= atoi( argv
[i
]+6 );
403 else if( !strncmp(argv
[i
], "-p", 2) )
404 g_port
= atoi( argv
[i
]+2 );
405 else if( !strncmp(argv
[i
], "--auto", 6) )
407 else if( !strncmp(argv
[i
], "-u", 2) )
409 else if( !strncmp(argv
[i
], "--log", 5) )
410 log_level
= argv
[i
][5] ? atoi( argv
[i
]+5 ) : CK_LOG_INFO
;
411 else if( !strncmp(argv
[i
], "--verbose", 9) )
412 log_level
= argv
[i
][9] ? atoi( argv
[i
]+9 ) : CK_LOG_INFO
;
413 else if( !strncmp(argv
[i
], "-v", 2) )
414 log_level
= argv
[i
][2] ? atoi( argv
[i
]+2 ) : CK_LOG_INFO
;
415 else if( !strncmp(argv
[i
], "--deprecate", 11) )
418 string arg
= argv
[i
]+11;
419 if( arg
== ":stop" ) deprecate_level
= 0;
420 else if( arg
== ":warn" ) deprecate_level
= 1;
421 else if( arg
== ":ignore" ) deprecate_level
= 2;
425 fprintf( stderr
, "[chuck]: invalid arguments for '--deprecate'...\n" );
426 fprintf( stderr
, "[chuck]: ... (looking for :stop, :warn, or :ignore)\n" );
430 else if( !strcmp( argv
[i
], "--probe" ) )
432 else if( !strcmp( argv
[i
], "--poop" ) )
434 else if( !strcmp(argv
[i
], "--help") || !strcmp(argv
[i
], "-h")
435 || !strcmp(argv
[i
], "--about") )
440 else if( !strcmp( argv
[i
], "--version" ) )
448 g_otf_log
= CK_LOG_CORE
;
452 EM_setlog( log_level
);
454 if( otf_send_cmd( argc
, argv
, i
, g_host
, g_port
, &is_otf
) )
458 if( is_otf
) exit( 1 );
461 fprintf( stderr
, "[chuck]: invalid flag '%s'\n", argv
[i
] );
471 EM_setlog( log_level
);
484 //HidInManager::probeHidIn();
491 buffer_size
= next_power_2( buffer_size
-1 );
492 // check mode and blocking
493 if( !enable_audio
&& !block
) block
= TRUE
;
495 if( !set_priority
&& !block
) g_priority
= g_priority_low
;
496 if( !set_priority
&& !enable_audio
) g_priority
= 0x7fffffff;
498 Chuck_VM::our_priority
= g_priority
;
500 g_do_watchdog
= do_watchdog
;
502 if ( !files
&& vm_halt
&& !enable_shell
)
504 fprintf( stderr
, "[chuck]: no input files... (try --help)\n" );
508 // shell initialization without vm
509 if( enable_shell
&& no_vm
)
512 g_shell
= new Chuck_Shell
;
514 if( !init_shell( g_shell
, new Chuck_Console
, NULL
) )
516 // no vm is needed, just start running the shell now
519 SAFE_DELETE( g_shell
);
527 fprintf( stderr
, "[chuck]: '--empty' can only be used with shell...\n" );
531 // allocate the vm - needs the type system
532 vm
= g_vm
= new Chuck_VM
;
533 if( !vm
->initialize( enable_audio
, vm_halt
, srate
, buffer_size
,
534 num_buffers
, dac
, adc
, dac_chans
, adc_chans
, block
) )
536 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
540 // allocate the compiler
541 compiler
= g_compiler
= new Chuck_Compiler
;
542 // initialize the compiler
543 if( !compiler
->initialize( vm
) )
545 fprintf( stderr
, "[chuck]: error initializing compiler...\n" );
549 compiler
->emitter
->dump
= dump
;
551 compiler
->set_auto_depend( auto_depend
);
553 // vm synthesis subsystem - needs the type system
554 if( !vm
->initialize_synthesis( ) )
556 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
561 if( load_hid
) HidInManager::init();
564 signal( SIGINT
, signal_int
);
565 #ifndef __PLATFORM_WIN32__
567 signal( SIGPIPE
, signal_pipe
);
570 // shell initialization
574 g_shell
= new Chuck_Shell
;
576 if( !init_shell( g_shell
, new Chuck_Console
, vm
) )
581 compiler
->env
->deprecate_level
= deprecate_level
;
587 EM_log( CK_LOG_SEVERE
, "starting compilation..." );
591 // loop through and process each file
592 for( i
= 1; i
< argc
; i
++ )
595 if( argv
[i
][0] == '-' || argv
[i
][0] == '+' )
597 if( !strcmp(argv
[i
], "--dump") || !strcmp(argv
[i
], "+d" ) )
598 compiler
->emitter
->dump
= TRUE
;
599 else if( !strcmp(argv
[i
], "--nodump") || !strcmp(argv
[i
], "-d" ) )
600 compiler
->emitter
->dump
= FALSE
;
602 get_count( argv
[i
], &count
);
607 // parse out command line arguments
608 if( !extract_args( argv
[i
], filename
, args
) )
611 fprintf( stderr
, "[chuck]: malformed filename with argument list...\n" );
612 fprintf( stderr
, " --> '%s'", argv
[i
] );
617 EM_log( CK_LOG_FINE
, "compiling '%s'...", filename
.c_str() );
621 // parse, type-check, and emit
622 if( !compiler
->go( filename
, NULL
) )
626 code
= compiler
->output();
628 code
->name
+= string(argv
[i
]);
631 EM_log( CK_LOG_FINE
, "sporking %d %s...", count
,
632 count
== 1 ? "instance" : "instances" );
638 shred
= vm
->spork( code
, NULL
);
657 if( Chuck_VM::our_priority
!= 0x7fffffff )
660 if( !Chuck_VM::set_priority( Chuck_VM::our_priority
, vm
) )
663 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
672 EM_log( CK_LOG_SYSTEM
, "starting listener on port: %d...", g_port
);
675 g_sock
= ck_tcp_create( 1 );
676 if( !g_sock
|| !ck_bind( g_sock
, g_port
) || !ck_listen( g_sock
, 10 ) )
678 fprintf( stderr
, "[chuck]: cannot bind to tcp port %i...\n", g_port
);
684 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
685 pthread_create( &g_tid_otf
, NULL
, otf_cb
, NULL
);
687 g_tid_otf
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)otf_cb
, NULL
, 0, 0 );
694 EM_log( CK_LOG_SYSTEM
, "OTF server/listener: OFF" );
697 // start shell on separate thread
700 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
701 pthread_create( &g_tid_shell
, NULL
, shell_cb
, g_shell
);
703 g_tid_shell
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)shell_cb
, g_shell
, 0, 0 );
714 vm
= NULL
; SAFE_DELETE( g_vm
);
716 compiler
= NULL
; SAFE_DELETE( g_compiler
);
718 // wait for the shell, if it is running
719 // does the VM reset its priority to normal before exiting?
721 while( g_shell
!= NULL
)