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_math.h"
52 #include "util_string.h"
53 #include "util_thread.h"
54 #include "util_network.h"
55 #include "hidio_sdl.h"
58 #ifndef __PLATFORM_WIN32__
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
66 #if defined(__MACOSX_CORE__)
67 t_CKINT g_priority
= 80;
68 t_CKINT g_priority_low
= 60;
69 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
70 t_CKINT g_priority
= THREAD_PRIORITY_HIGHEST
;
71 t_CKINT g_priority_low
= THREAD_PRIORITY_HIGHEST
;
73 t_CKINT g_priority
= 0x7fffffff;
74 t_CKINT g_priority_low
= 0x7fffffff;
77 // thread id for otf thread
78 CHUCK_THREAD g_tid_otf
= 0;
79 // thread id for shell
80 CHUCK_THREAD g_tid_shell
= 0;
82 // default destination host name
83 char g_host
[256] = "127.0.0.1";
88 //-----------------------------------------------------------------------------
91 //-----------------------------------------------------------------------------
92 extern "C" void signal_int( int sig_num
)
94 fprintf( stderr
, "[chuck]: cleaning up...\n" );
100 Chuck_Compiler
* compiler
= g_compiler
;
101 // flag the global one
113 // things don't work so good on windows...
114 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
115 // pthread_kill( g_tid_otf, 2 );
116 if( g_tid_otf
) pthread_cancel( g_tid_otf
);
117 if( g_tid_whatever
) pthread_cancel( g_tid_whatever
);
118 // if( g_tid_otf ) usleep( 50000 );
121 if( g_tid_otf
) CloseHandle( g_tid_otf
);
123 // will this work for windows?
125 SAFE_DELETE( compiler
);
127 // ck_close( g_sock );
130 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
131 // pthread_join( g_tid_otf, NULL );
140 //-----------------------------------------------------------------------------
143 //-----------------------------------------------------------------------------
146 // TODO: play white noise and/or sound effects
147 srand( time( NULL
) );
150 int n
= (int)(rand() / (float)RAND_MAX
* poop_size
);
151 printf( "%s\n", poop
[n
] );
152 usleep( (unsigned long)(rand() / (float)RAND_MAX
* 2000000) );
159 //-----------------------------------------------------------------------------
160 // name: init_shell()
162 //-----------------------------------------------------------------------------
163 static t_CKBOOL
init_shell( Chuck_Shell
* shell
, Chuck_Shell_UI
* ui
, Chuck_VM
* vm
)
165 // initialize shell UI
168 fprintf( stderr
, "[chuck]: error starting shell UI...\n" );
173 if( !shell
->init( vm
, ui
) )
175 fprintf( stderr
, "[chuck]: error starting shell...\n" );
185 //-----------------------------------------------------------------------------
188 //-----------------------------------------------------------------------------
189 static t_CKBOOL
get_count( const char * arg
, t_CKUINT
* out
)
192 if( !strncmp( arg
, "--", 2 ) ) arg
+= 2;
193 else if( !strncmp( arg
, "-", 1 ) ) arg
+= 1;
197 if( *arg
== '\0' ) return FALSE
;
199 if( *arg
< '0' || *arg
> '9' ) return FALSE
;
202 *out
= (t_CKUINT
)atoi( arg
);
210 //-----------------------------------------------------------------------------
213 //-----------------------------------------------------------------------------
214 static void version()
216 fprintf( stderr
, "\n" );
217 fprintf( stderr
, "chuck version: %s\n", CK_VERSION
);
218 #if defined(__PLATFORM_WIN32__)
219 fprintf( stderr
, " exe target: microsoft win32\n" );
220 #elif defined(__WINDOWS_DS__)
221 fprintf( stderr
, " exe target: microsoft win32 + cygwin\n" );
222 #elif defined(__LINUX_ALSA__)
223 fprintf( stderr
, " exe target: linux (alsa)\n" );
224 #elif defined(__LINUX_OSS__)
225 fprintf( stderr
, " exe target: linux (oss)\n" );
226 #elif defined(__LINUX_JACK__)
227 fprintf( stderr
, " exe target: linux (jack)\n" );
228 #elif defined(__MACOSX_UB__)
229 fprintf( stderr
, " exe target: mac os x : universal binary\n" );
230 #elif defined(__MACOSX_CORE__) && defined(__LITTLE_ENDIAN__)
231 fprintf( stderr
, " exe target: mac os x : intel\n" );
232 #elif defined(__MACOSX_CORE__)
233 fprintf( stderr
, " exe target: mac os x : powerpc\n" );
235 fprintf( stderr
, " exe target: uh... unknown\n" );
237 fprintf( stderr
, " http://chuck.cs.princeton.edu/\n\n" );
243 //-----------------------------------------------------------------------------
246 //-----------------------------------------------------------------------------
249 fprintf( stderr
, "usage: chuck --[options|commands] [+-=^] file1 file2 file3 ...\n" );
250 fprintf( stderr
, " [options] = halt|loop|audio|silent|dump|nodump|server|about|\n" );
251 fprintf( stderr
, " srate<N>|bufsize<N>|bufnum<N>|dac<N>|adc<N>|\n" );
252 fprintf( stderr
, " remote<hostname>|port<N>|verbose<N>|probe|\n" );
253 fprintf( stderr
, " channels<N>|out<N>|in<N>|shell|empty|level<N>|\n" );
254 fprintf( stderr
, " blocking|callback|deprecate:{stop|warn|ignore}\n" );
255 fprintf( stderr
, " [commands] = add|remove|replace|remove.all|status|time|kill\n" );
256 fprintf( stderr
, " [+-=^] = shortcuts for add, remove, replace, status\n" );
263 //-----------------------------------------------------------------------------
266 //-----------------------------------------------------------------------------
267 int main( int argc
, char ** argv
)
269 Chuck_Compiler
* compiler
= NULL
;
270 Chuck_VM
* vm
= NULL
;
271 Chuck_VM_Code
* code
= NULL
;
272 Chuck_VM_Shred
* shred
= NULL
;
274 t_CKBOOL enable_audio
= TRUE
;
275 t_CKBOOL vm_halt
= TRUE
;
276 t_CKUINT srate
= SAMPLING_RATE_DEFAULT
;
277 t_CKUINT buffer_size
= BUFFER_SIZE_DEFAULT
;
278 t_CKUINT num_buffers
= NUM_BUFFERS_DEFAULT
;
281 t_CKUINT dac_chans
= 2;
282 t_CKUINT adc_chans
= 2;
283 t_CKBOOL dump
= FALSE
;
284 t_CKBOOL probe
= FALSE
;
285 t_CKBOOL set_priority
= FALSE
;
286 t_CKBOOL auto_depend
= FALSE
;
287 t_CKBOOL block
= FALSE
;
288 t_CKBOOL enable_shell
= FALSE
;
289 t_CKBOOL no_vm
= FALSE
;
290 t_CKBOOL load_hid
= FALSE
;
291 t_CKBOOL enable_server
= TRUE
;
292 t_CKBOOL do_watchdog
= TRUE
;
293 t_CKINT log_level
= CK_LOG_CORE
;
294 t_CKINT deprecate_level
= 1; // warn
296 string filename
= "";
299 #if defined(__MACOSX_CORE__)
301 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
312 EM_setlog( log_level
);
314 // parse command line args
315 for( i
= 1; i
< argc
; i
++ )
317 if( argv
[i
][0] == '-' || argv
[i
][0] == '+' ||
318 argv
[i
][0] == '=' || argv
[i
][0] == '^' || argv
[i
][0] == '@' )
320 if( !strcmp(argv
[i
], "--dump") || !strcmp(argv
[i
], "+d")
321 || !strcmp(argv
[i
], "--nodump") || !strcmp(argv
[i
], "-d") )
323 else if( get_count( argv
[i
], &count
) )
325 else if( !strcmp(argv
[i
], "--audio") || !strcmp(argv
[i
], "-a") )
327 else if( !strcmp(argv
[i
], "--silent") || !strcmp(argv
[i
], "-s") )
328 enable_audio
= FALSE
;
329 else if( !strcmp(argv
[i
], "--halt") || !strcmp(argv
[i
], "-t") )
331 else if( !strcmp(argv
[i
], "--loop") || !strcmp(argv
[i
], "-l") )
332 { vm_halt
= FALSE
; enable_server
= TRUE
; }
333 else if( !strcmp(argv
[i
], "--server") )
334 enable_server
= TRUE
;
335 else if( !strcmp(argv
[i
], "--standalone") )
336 enable_server
= FALSE
;
337 else if( !strcmp(argv
[i
], "--callback") )
339 else if( !strcmp(argv
[i
], "--blocking") )
341 else if( !strcmp(argv
[i
], "--hid") )
343 else if( !strcmp(argv
[i
], "--shell") || !strcmp( argv
[i
], "-e" ) )
344 { enable_shell
= TRUE
; vm_halt
= FALSE
; }
345 else if( !strcmp(argv
[i
], "--empty") )
347 else if( !strncmp(argv
[i
], "--srate", 7) )
348 srate
= atoi( argv
[i
]+7 ) > 0 ? atoi( argv
[i
]+7 ) : srate
;
349 else if( !strncmp(argv
[i
], "-r", 2) )
350 srate
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : srate
;
351 else if( !strncmp(argv
[i
], "--bufsize", 9) )
352 buffer_size
= atoi( argv
[i
]+9 ) > 0 ? atoi( argv
[i
]+9 ) : buffer_size
;
353 else if( !strncmp(argv
[i
], "-b", 2) )
354 buffer_size
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : buffer_size
;
355 else if( !strncmp(argv
[i
], "--bufnum", 8) )
356 num_buffers
= atoi( argv
[i
]+8 ) > 0 ? atoi( argv
[i
]+8 ) : num_buffers
;
357 else if( !strncmp(argv
[i
], "-n", 2) )
358 num_buffers
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : num_buffers
;
359 else if( !strncmp(argv
[i
], "--dac", 5) )
360 dac
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 0;
361 else if( !strncmp(argv
[i
], "--adc", 5) )
362 adc
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 0;
363 else if( !strncmp(argv
[i
], "--channels", 10) )
364 dac_chans
= adc_chans
= atoi( argv
[i
]+10 ) > 0 ? atoi( argv
[i
]+10 ) : 2;
365 else if( !strncmp(argv
[i
], "-c", 2) )
366 dac_chans
= adc_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
367 else if( !strncmp(argv
[i
], "--out", 5) )
368 dac_chans
= atoi( argv
[i
]+5 ) > 0 ? atoi( argv
[i
]+5 ) : 2;
369 else if( !strncmp(argv
[i
], "-o", 2) )
370 dac_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
371 else if( !strncmp(argv
[i
], "--in", 4) )
372 adc_chans
= atoi( argv
[i
]+4 ) > 0 ? atoi( argv
[i
]+4 ) : 2;
373 else if( !strncmp(argv
[i
], "-i", 2) )
374 adc_chans
= atoi( argv
[i
]+2 ) > 0 ? atoi( argv
[i
]+2 ) : 2;
375 else if( !strncmp(argv
[i
], "--level", 7) )
376 { g_priority
= atoi( argv
[i
]+7 ); set_priority
= TRUE
; }
377 else if( !strncmp(argv
[i
], "--watchdog", 10) )
378 { g_watchdog_timeout
= atof( argv
[i
]+10 );
379 if( g_watchdog_timeout
<= 0 ) g_watchdog_timeout
= 0.5;
380 do_watchdog
= TRUE
; }
381 else if( !strncmp(argv
[i
], "--nowatchdog", 12) )
383 else if( !strncmp(argv
[i
], "--remote", 8) )
384 strcpy( g_host
, argv
[i
]+8 );
385 else if( !strncmp(argv
[i
], "@", 1) )
386 strcpy( g_host
, argv
[i
]+1 );
387 else if( !strncmp(argv
[i
], "--port", 6) )
388 g_port
= atoi( argv
[i
]+6 );
389 else if( !strncmp(argv
[i
], "-p", 2) )
390 g_port
= atoi( argv
[i
]+2 );
391 else if( !strncmp(argv
[i
], "--auto", 6) )
393 else if( !strncmp(argv
[i
], "-u", 2) )
395 else if( !strncmp(argv
[i
], "--log", 5) )
396 log_level
= argv
[i
][5] ? atoi( argv
[i
]+5 ) : CK_LOG_INFO
;
397 else if( !strncmp(argv
[i
], "--verbose", 9) )
398 log_level
= argv
[i
][9] ? atoi( argv
[i
]+9 ) : CK_LOG_INFO
;
399 else if( !strncmp(argv
[i
], "-v", 2) )
400 log_level
= argv
[i
][2] ? atoi( argv
[i
]+2 ) : CK_LOG_INFO
;
401 else if( !strncmp(argv
[i
], "--deprecate", 11) )
404 string arg
= argv
[i
]+11;
405 if( arg
== ":stop" ) deprecate_level
= 0;
406 else if( arg
== ":warn" ) deprecate_level
= 1;
407 else if( arg
== ":ignore" ) deprecate_level
= 2;
411 fprintf( stderr
, "[chuck]: invalid arguments for '--deprecate'...\n" );
412 fprintf( stderr
, "[chuck]: ... (looking for :stop, :warn, or :ignore)\n" );
416 else if( !strcmp( argv
[i
], "--probe" ) )
418 else if( !strcmp( argv
[i
], "--poop" ) )
420 else if( !strcmp(argv
[i
], "--help") || !strcmp(argv
[i
], "-h")
421 || !strcmp(argv
[i
], "--about") )
426 else if( !strcmp( argv
[i
], "--version" ) )
434 g_otf_log
= CK_LOG_CORE
;
438 EM_setlog( log_level
);
440 if( otf_send_cmd( argc
, argv
, i
, g_host
, g_port
, &is_otf
) )
444 if( is_otf
) exit( 1 );
447 fprintf( stderr
, "[chuck]: invalid flag '%s'\n", argv
[i
] );
457 EM_setlog( log_level
);
470 //HidInManager::probeHidIn();
477 buffer_size
= ensurepow2( buffer_size
);
478 // check mode and blocking
479 if( !enable_audio
&& !block
) block
= TRUE
;
481 if( !set_priority
&& !block
) g_priority
= g_priority_low
;
482 if( !set_priority
&& !enable_audio
) g_priority
= 0x7fffffff;
484 Chuck_VM::our_priority
= g_priority
;
486 g_do_watchdog
= do_watchdog
;
488 if ( !files
&& vm_halt
&& !enable_shell
)
490 fprintf( stderr
, "[chuck]: no input files... (try --help)\n" );
494 // shell initialization without vm
495 if( enable_shell
&& no_vm
)
498 g_shell
= new Chuck_Shell
;
500 if( !init_shell( g_shell
, new Chuck_Console
, NULL
) )
502 // no vm is needed, just start running the shell now
505 SAFE_DELETE( g_shell
);
513 fprintf( stderr
, "[chuck]: '--empty' can only be used with shell...\n" );
517 // allocate the vm - needs the type system
518 vm
= g_vm
= new Chuck_VM
;
519 if( !vm
->initialize( enable_audio
, vm_halt
, srate
, buffer_size
,
520 num_buffers
, dac
, adc
, dac_chans
, adc_chans
, block
) )
522 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
526 // allocate the compiler
527 compiler
= g_compiler
= new Chuck_Compiler
;
528 // initialize the compiler
529 if( !compiler
->initialize( vm
) )
531 fprintf( stderr
, "[chuck]: error initializing compiler...\n" );
535 compiler
->emitter
->dump
= dump
;
537 compiler
->set_auto_depend( auto_depend
);
539 // vm synthesis subsystem - needs the type system
540 if( !vm
->initialize_synthesis( ) )
542 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
547 if( load_hid
) HidInManager::init();
550 signal( SIGINT
, signal_int
);
551 #ifndef __PLATFORM_WIN32__
553 signal( SIGPIPE
, signal_pipe
);
556 // shell initialization
560 g_shell
= new Chuck_Shell
;
562 if( !init_shell( g_shell
, new Chuck_Console
, vm
) )
567 compiler
->env
->deprecate_level
= deprecate_level
;
573 EM_log( CK_LOG_SEVERE
, "starting compilation..." );
577 // loop through and process each file
578 for( i
= 1; i
< argc
; i
++ )
581 if( argv
[i
][0] == '-' || argv
[i
][0] == '+' )
583 if( !strcmp(argv
[i
], "--dump") || !strcmp(argv
[i
], "+d" ) )
584 compiler
->emitter
->dump
= TRUE
;
585 else if( !strcmp(argv
[i
], "--nodump") || !strcmp(argv
[i
], "-d" ) )
586 compiler
->emitter
->dump
= FALSE
;
588 get_count( argv
[i
], &count
);
593 // parse out command line arguments
594 if( !extract_args( argv
[i
], filename
, args
) )
597 fprintf( stderr
, "[chuck]: malformed filename with argument list...\n" );
598 fprintf( stderr
, " --> '%s'", argv
[i
] );
603 EM_log( CK_LOG_FINE
, "compiling '%s'...", filename
.c_str() );
607 // parse, type-check, and emit
608 if( !compiler
->go( filename
, NULL
) )
612 code
= compiler
->output();
614 code
->name
+= string(argv
[i
]);
617 EM_log( CK_LOG_FINE
, "sporking %d %s...", count
,
618 count
== 1 ? "instance" : "instances" );
624 shred
= vm
->spork( code
, NULL
);
643 if( Chuck_VM::our_priority
!= 0x7fffffff )
646 if( !Chuck_VM::set_priority( Chuck_VM::our_priority
, vm
) )
649 fprintf( stderr
, "[chuck]: %s\n", vm
->last_error() );
658 EM_log( CK_LOG_SYSTEM
, "starting listener on port: %d...", g_port
);
661 g_sock
= ck_tcp_create( 1 );
662 if( !g_sock
|| !ck_bind( g_sock
, g_port
) || !ck_listen( g_sock
, 10 ) )
664 fprintf( stderr
, "[chuck]: cannot bind to tcp port %i...\n", g_port
);
670 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
671 pthread_create( &g_tid_otf
, NULL
, otf_cb
, NULL
);
673 g_tid_otf
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)otf_cb
, NULL
, 0, 0 );
680 EM_log( CK_LOG_SYSTEM
, "OTF server/listener: OFF" );
683 // start shell on separate thread
686 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
687 pthread_create( &g_tid_shell
, NULL
, shell_cb
, g_shell
);
689 g_tid_shell
= CreateThread( NULL
, 0, (LPTHREAD_START_ROUTINE
)shell_cb
, g_shell
, 0, 0 );
700 vm
= NULL
; SAFE_DELETE( g_vm
);
702 compiler
= NULL
; SAFE_DELETE( g_compiler
);
704 // wait for the shell, if it is running
705 // does the VM reset its priority to normal before exiting?
707 while( g_shell
!= NULL
)