*** empty log message ***
[chuck-blob.git] / exile / v1 / src / chuck_vm.cpp
blob5f1a62a5af27119cd5534d24dca68f11ca388324
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
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_vm.cpp
27 // desc: ...
29 // authors: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // date: Autumn 2002
32 //-----------------------------------------------------------------------------
33 #include "chuck_vm.h"
34 #include "chuck_instr.h"
35 #include "chuck_bbq.h"
36 #include "chuck_errmsg.h"
38 #include <vector>
39 using namespace std;
41 #if defined(__WINDOWS_DS__) && !defined(__WINDOWS_PTHREAD__)
42 #include <windows.h>
43 #else
44 #include <unistd.h>
45 #include <pthread.h>
46 #endif
50 //-----------------------------------------------------------------------------
51 // name: class Chuck_VM_Frame
52 // desc: func frame
53 //-----------------------------------------------------------------------------
54 class Chuck_VM_Frame
56 public:
57 t_CKUINT size;
59 public:
60 Chuck_VM_Frame() { size = 0; }
61 ~Chuck_VM_Frame() { }
67 //-----------------------------------------------------------------------------
68 // name: class Chuck_VM_Func
69 // desc: vm function
70 //-----------------------------------------------------------------------------
71 class Chuck_VM_Func
73 public:
74 Chuck_VM_Code * code;
75 Chuck_VM_Frame * frame;
76 t_CKUINT index;
78 public:
79 Chuck_VM_Func() { code = NULL; frame = NULL; index = 0; }
80 ~Chuck_VM_Func() { }
86 //-----------------------------------------------------------------------------
87 // name: class Chuck_VM_FTable
88 // desc: function table
89 //-----------------------------------------------------------------------------
90 class Chuck_VM_FTable
92 public:
93 Chuck_VM_FTable();
94 ~Chuck_VM_FTable();
96 public:
97 Chuck_VM_Func * get_func( t_CKUINT index );
98 t_CKUINT append( Chuck_VM_Func * f );
99 t_CKBOOL remove( t_CKUINT index );
101 public:
102 vector<Chuck_VM_Func *> func_table;
108 //-----------------------------------------------------------------------------
109 // name: Chuck_VM()
110 // desc: ...
111 //-----------------------------------------------------------------------------
112 Chuck_VM::Chuck_VM()
114 m_shreds = NULL;
115 m_num_shreds = 0;
116 m_shreduler = NULL;
117 m_msg_buffer = NULL;
118 m_shred_id = 0;
119 m_halt = TRUE;
120 m_env = NULL;
121 m_audio = FALSE;
123 m_init = FALSE;
129 //-----------------------------------------------------------------------------
130 // name: ~Chuck_VM()
131 // desc: ...
132 //-----------------------------------------------------------------------------
133 Chuck_VM::~Chuck_VM()
135 if( m_init ) shutdown();
139 // dac tick
140 UGEN_TICK __dac_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
141 { *out = in; return TRUE; }
142 UGEN_TICK __bunghole_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
143 { *out = 0.0f; return TRUE; }
146 // static
147 #ifdef __MACOSX_CORE__
148 t_CKINT Chuck_VM::our_priority = 95;
149 #else
150 t_CKINT Chuck_VM::our_priority = 0x7fffffff;
151 #endif
154 #ifndef __WINDOWS_DS__
155 //-----------------------------------------------------------------------------
156 // name: set_priority()
157 // desc: ...
158 //-----------------------------------------------------------------------------
159 t_CKBOOL Chuck_VM::set_priority( t_CKINT priority, Chuck_VM * vm )
161 struct sched_param param;
162 pthread_t tid = pthread_self();
163 int policy;
164 // get for thread
165 if( pthread_getschedparam( tid, &policy, &param) )
167 if( vm )
168 vm->m_last_error = "could not get current scheduling parameters";
169 return FALSE;
172 // priority
173 param.sched_priority = priority;
174 // policy
175 policy = SCHED_RR;
176 // set for thread
177 if( pthread_setschedparam( tid, policy, &param ) )
179 if( vm )
180 vm->m_last_error = "could not set new scheduling parameters";
181 return FALSE;
184 return TRUE;
186 #else
187 //-----------------------------------------------------------------------------
188 // name: set_priority()
189 // desc: ...
190 //-----------------------------------------------------------------------------
191 t_CKBOOL Chuck_VM::set_priority( t_CKINT priority, Chuck_VM * vm )
193 // if priority is 0, then do nothing
194 if( !priority )
195 return TRUE;
197 // set the priority class of the process
198 // if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
199 // return FALSE;
201 // set the priority the thread
202 if( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ) )
204 if( vm )
205 vm->m_last_error = "could not set new scheduling parameters";
206 return FALSE;
209 return TRUE;
211 #endif
216 //-----------------------------------------------------------------------------
217 // name: initialize()
218 // desc: ...
219 //-----------------------------------------------------------------------------
220 t_CKBOOL Chuck_VM::initialize( t_CKBOOL enable_audio, t_CKBOOL halt, t_CKUINT srate,
221 t_CKUINT buffer_size, t_CKUINT num_buffers,
222 t_CKUINT dac, t_CKUINT adc, t_CKINT priority )
224 if( m_init )
226 m_last_error = "VM already initialized!";
227 return FALSE;
230 //#ifndef __WINDOWS_DS__
231 // boost thread priority
232 if( priority != 0x7fffffff && !set_priority( priority, this ) )
233 return FALSE;
234 //#endif
236 // allocate bbq
237 m_bbq = new BBQ;
238 m_halt = halt;
239 m_audio = enable_audio;
241 // allocate shreduler
242 m_shreduler = new Chuck_VM_Shreduler;
243 m_shreduler->bbq = m_audio ? m_bbq : NULL;
245 // allocate msg buffer
246 m_msg_buffer = new CBuffer;
247 m_msg_buffer->initialize( 1024, sizeof(Chuck_Msg *) );
248 m_reply_buffer = new CBuffer;
249 m_reply_buffer->initialize( 1024, sizeof(Chuck_Msg *) );
251 // allocate dac and adc
252 m_num_dac_channels = 2;
253 m_dac = new Chuck_UGen[2];
254 m_dac[0].tick = __dac_tick;
255 m_dac[1].tick = __dac_tick;
256 m_num_adc_channels = 2;
257 m_adc = new Chuck_UGen[2];
258 m_bunghole = new Chuck_UGen;
259 m_dac[0].add_ref(); m_dac[1].add_ref();
260 m_adc[0].add_ref(); m_adc[1].add_ref();
261 m_bunghole->add_ref();
262 m_shreduler->m_dac = m_dac;
263 m_shreduler->m_adc = m_adc;
264 m_shreduler->m_bunghole = m_bunghole;
265 m_shreduler->m_num_dac_channels = m_num_dac_channels;
266 m_shreduler->m_num_adc_channels = m_num_adc_channels;
268 if( m_audio )
270 // init bbq
271 if( !m_bbq->initialize( 2, srate, 16, buffer_size, num_buffers, dac, adc ) )
273 m_last_error = "cannot initialize audio device (try using --silent/-s)";
274 return FALSE;
277 else
279 // at least set the sample rate and buffer size
280 m_bbq->set_srate( srate );
281 m_bbq->set_bufsize( buffer_size );
284 // m_bbq->midi_out()->open( 0 );
285 // m_bbq->midi_in()->open( 0 );
287 return m_init = TRUE;
293 //-----------------------------------------------------------------------------
294 // name: shutdown()
295 // desc: ...
296 //-----------------------------------------------------------------------------
297 t_CKBOOL Chuck_VM::shutdown()
299 // make sure we are in the initialized state
300 if( !m_init ) return FALSE;
302 // stop
303 this->stop();
304 usleep( 50000 );
306 // dll
307 this->dll_clear();
309 // free the shreduler
310 SAFE_DELETE( m_shreduler );
312 // terminate shreds
313 Chuck_VM_Shred * curr = m_shreds, * prev = NULL;
314 while( curr )
316 prev = curr;
317 curr = curr->next;
318 // delete prev;
320 m_shreds = NULL;
321 m_num_shreds = 0;
323 // shutdown audio
324 if( m_audio )
326 m_bbq->digi_out()->cleanup();
327 m_bbq->digi_in()->cleanup();
328 m_bbq->shutdown();
329 SAFE_DELETE( m_bbq );
330 m_audio = FALSE;
333 m_init = FALSE;
335 return TRUE;
341 //-----------------------------------------------------------------------------
342 // name: run()
343 // desc: ...
344 //-----------------------------------------------------------------------------
345 t_CKBOOL Chuck_VM::run( )
347 m_running = TRUE;
348 Chuck_VM_Shred * shred = NULL;
349 Chuck_Msg * msg = NULL;
351 // audio
352 if( m_audio )
354 if( !m_bbq->digi_out()->initialize( ) )
356 m_last_error = "cannot open audio output (option: use --silent/-s)";
357 return FALSE;
360 m_bbq->digi_in()->initialize( );
361 m_bbq->digi_out()->start();
362 m_bbq->digi_in()->start();
365 while( m_running )
367 // get the shreds queued for 'now'
368 while( shred = m_shreduler->get() )
370 // set the current time of the shred
371 shred->now = shred->wake_time;
373 // run the shred
374 if( !shred->run( this ) )
376 this->free( shred, TRUE );
377 shred = NULL;
378 if( !m_num_shreds && m_halt ) goto vm_stop;
382 // advance the shreduler
383 m_shreduler->advance();
385 // process messages
386 while( m_msg_buffer->get( &msg, 1 ) )
387 process_msg( msg );
390 // vm stop here
391 vm_stop:
392 m_running = FALSE;
394 return TRUE;
400 //-----------------------------------------------------------------------------
401 // name: pause()
402 // desc: ...
403 //-----------------------------------------------------------------------------
404 t_CKBOOL Chuck_VM::pause( )
406 m_running = FALSE;
408 return TRUE;
414 //-----------------------------------------------------------------------------
415 // name: stop()
416 // desc: ...
417 //-----------------------------------------------------------------------------
418 t_CKBOOL Chuck_VM::stop( )
420 m_running = FALSE;
421 Digitalio::m_end = TRUE;
423 return TRUE;
429 //-----------------------------------------------------------------------------
430 // name: gc
431 // desc: ...
432 //-----------------------------------------------------------------------------
433 void Chuck_VM::gc( t_CKUINT amount )
440 //-----------------------------------------------------------------------------
441 // name: gc
442 // desc: ...
443 //-----------------------------------------------------------------------------
444 void Chuck_VM::gc( )
451 //-----------------------------------------------------------------------------
452 // name: queue_msg()
453 // desc: ...
454 //-----------------------------------------------------------------------------
455 t_CKBOOL Chuck_VM::queue_msg( Chuck_Msg * msg, int count )
457 m_msg_buffer->put( &msg, count );
458 return TRUE;
464 //-----------------------------------------------------------------------------
465 // name: get_reply()
466 // desc: ...
467 //-----------------------------------------------------------------------------
468 Chuck_Msg * Chuck_VM::get_reply( )
470 Chuck_Msg * msg = NULL;
471 m_reply_buffer->get( &msg, 1 );
472 return msg;
478 //-----------------------------------------------------------------------------
479 // name: process_msg()
480 // desc: ...
481 //-----------------------------------------------------------------------------
482 t_CKUINT Chuck_VM::process_msg( Chuck_Msg * msg )
484 t_CKUINT retval = 0xfffffff0;
486 if( msg->type == MSG_REPLACE )
488 Chuck_VM_Shred * out = m_shreduler->lookup( msg->param );
489 if( !out )
491 EM_error3( "[chuck](VM): error replacing shred: no shred with id %i...",
492 msg->param );
493 retval = 0;
494 goto done;
497 Chuck_VM_Shred * shred = msg->shred;
498 if( !shred )
500 shred = new Chuck_VM_Shred;
501 shred->initialize( msg->code );
502 shred->name = msg->code->name;
504 // set the current time
505 shred->start = m_shreduler->now_system;
506 // set the id
507 shred->id = msg->param;
509 // replace
510 if( m_shreduler->replace( out, shred ) )
512 EM_error3( "[chuck](VM): replacing shred %i (%s) with %i (%s)...",
513 out->id, mini(out->name.c_str()), shred->id, mini(shred->name.c_str()) );
514 this->free( out, TRUE, FALSE );
515 retval = shred->id;
516 goto done;
518 else
520 EM_error3( "[chuck](VM): shreduler ERROR replacing shred %i...",
521 out->id );
522 delete shred;
523 retval = 0;
524 goto done;
527 else if( msg->type == MSG_REMOVE )
529 if( msg->param == 0xffffffff )
531 if( !this->m_num_shreds)
533 EM_error3( "[chuck](VM): no shreds to remove..." );
534 retval = 0;
535 goto done;
538 t_CKUINT id = m_shred_id;
539 Chuck_VM_Shred * shred = NULL;
540 while( id >= 0 && m_shreduler->remove( shred = m_shreduler->lookup( id ) ) == 0 )
541 id--;
542 if( id >= 0 )
544 EM_error3( "[chuck](VM): removing recent shred: %i (%s)...",
545 id, mini(shred->name.c_str()) );
546 this->free( shred, TRUE );
547 retval = id;
549 else
551 EM_error3( "[chuck](VM): no shreds removed..." );
552 retval = 0;
553 goto done;
556 else
558 Chuck_VM_Shred * shred = m_shreduler->lookup( msg->param );
559 if( !shred )
561 EM_error3( "[chuck](VM): cannot remove: no shred with id %i...",
562 msg->param );
563 retval = 0;
564 goto done;
566 if( !m_shreduler->remove( m_shreduler->lookup( msg->param ) ) )
568 EM_error3( "[chuck](VM): shreduler: cannot remove shred %i...",
569 msg->param );
570 retval = 0;
571 goto done;
573 EM_error3( "[chuck](VM): removing shred: %i (%s)...",
574 msg->param, mini(shred->name.c_str()) );
575 this->free( shred, TRUE );
576 retval = msg->param;
579 else if( msg->type == MSG_REMOVEALL )
581 t_CKUINT id = m_shred_id;
582 EM_error3( "[chuck](VM): removing all (%i) shreds...", m_num_shreds );
583 Chuck_VM_Shred * shred = NULL;
585 while( m_num_shreds && id >= 0 )
587 if( m_shreduler->remove( shred = m_shreduler->lookup( id ) ) )
588 delete shred;
589 id--;
592 m_shred_id = 0;
593 m_num_shreds = 0;
595 else if( msg->type == MSG_ADD )
597 t_CKUINT id = 0;
598 if( msg->shred ) id = this->spork( msg->shred )->id;
599 else id = this->spork( msg->code, NULL )->id;
601 const char * s = ( msg->shred ? msg->shred->name.c_str() : msg->code->name.c_str() );
602 EM_error3( "[chuck](VM): sporking incoming shred: %i (%s)...", id, mini(s) );
603 retval = id;
604 goto done;
606 else if( msg->type == MSG_KILL )
608 EM_error3( "[chuck](VM): KILL received...." );
609 exit( 1 );
611 else if( msg->type == MSG_STATUS )
613 m_shreduler->status();
615 else if( msg->type == MSG_TIME )
617 float srate = (float)Digitalio::sampling_rate();
618 fprintf( stderr, "[chuck](VM): the values of now:\n" );
619 fprintf( stderr, " now = %i (samp)\n", m_shreduler->now_system );
620 fprintf( stderr, " = %.6f (second)\n", m_shreduler->now_system / srate );
621 fprintf( stderr, " = %.6f (minute)\n", m_shreduler->now_system / srate / 60.0f );
622 fprintf( stderr, " = %.6f (hour)\n", m_shreduler->now_system / srate / 60.0f / 60.0f );
623 fprintf( stderr, " = %.6f (day)\n", m_shreduler->now_system / srate / 60.0f / 60.0f / 24.0f );
624 fprintf( stderr, " = %.6f (week)\n", m_shreduler->now_system / srate / 60.0f / 60.0f / 24.0f / 7.0f );
627 done:
629 if( msg->reply )
631 msg->replyA = retval;
632 m_reply_buffer->put( &msg, 1 );
634 else
635 SAFE_DELETE(msg);
637 return retval;
643 //-----------------------------------------------------------------------------
644 // name: next_id()
645 // desc: ...
646 //-----------------------------------------------------------------------------
647 t_CKUINT Chuck_VM::next_id( )
649 return ++m_shred_id;
655 //-----------------------------------------------------------------------------
656 // name: shreduler()
657 // desc: ...
658 //-----------------------------------------------------------------------------
659 Chuck_VM_Shreduler * Chuck_VM::shreduler( ) const
661 return m_shreduler;
667 //-----------------------------------------------------------------------------
668 // name: bbq()
669 // desc: ...
670 //-----------------------------------------------------------------------------
671 BBQ * Chuck_VM::bbq( ) const
673 return m_bbq;
679 //-----------------------------------------------------------------------------
680 // name: srate()
681 // desc: ...
682 //-----------------------------------------------------------------------------
683 t_CKUINT Chuck_VM::srate() const
685 return (t_CKUINT)Digitalio::sampling_rate();
691 //-----------------------------------------------------------------------------
692 // name: fork()
693 // desc: ...
694 //-----------------------------------------------------------------------------
695 Chuck_VM_Shred * Chuck_VM::fork( Chuck_VM_Code * code )
697 return NULL;
703 //-----------------------------------------------------------------------------
704 // name: spork()
705 // desc: ...
706 //-----------------------------------------------------------------------------
707 Chuck_VM_Shred * Chuck_VM::spork( Chuck_VM_Code * code, Chuck_VM_Shred * parent )
709 // allocate a new shred
710 Chuck_VM_Shred * shred = new Chuck_VM_Shred;
711 // initialize the shred (default stack size)
712 shred->initialize( code );
713 // set the name
714 shred->name = code->name;
715 // set the parent
716 shred->parent = parent;
717 // spork it
718 this->spork( shred );
720 return shred;
726 //-----------------------------------------------------------------------------
727 // name: spork()
728 // desc: ...
729 //-----------------------------------------------------------------------------
730 Chuck_VM_Shred * Chuck_VM::spork( Chuck_VM_Shred * shred )
732 // set the current time
733 shred->start = m_shreduler->now_system;
734 // set the now
735 shred->now = shred->wake_time = m_shreduler->now_system;
736 // set the id
737 shred->id = next_id();
738 // add it to the parent
739 if( shred->parent )
740 shred->parent->children[shred->id] = shred;
741 // shredule it
742 m_shreduler->shredule( shred );
743 // count
744 m_num_shreds++;
746 return shred;
752 //-----------------------------------------------------------------------------
753 // name: free()
754 // desc: ...
755 //-----------------------------------------------------------------------------
756 t_CKBOOL Chuck_VM::free( Chuck_VM_Shred * shred, t_CKBOOL cascade, t_CKBOOL dec )
758 assert( cascade );
760 // mark this done
761 shred->is_done = TRUE;
763 // free the children
764 t_CKINT size = shred->children.size();
765 if( size )
767 vector<Chuck_VM_Shred *> list; list.resize( size );
768 map<t_CKUINT, Chuck_VM_Shred *>::iterator iter; t_CKINT i = 0;
769 for( iter = shred->children.begin(); iter != shred->children.end(); iter++ )
770 list[i++] = (*iter).second;
771 for( i = 0; i < size; i++ )
772 this->free( list[i], cascade );
775 // make sure it's done
776 assert( shred->children.size() == 0 );
778 // tell parent
779 if( shred->parent )
780 shred->parent->children.erase( shred->id );
782 // free!
783 m_shreduler->remove( shred );
784 SAFE_DELETE( shred );
785 if( dec ) m_num_shreds--;
786 if( !m_num_shreds ) m_shred_id = 0;
788 return TRUE;
794 //-----------------------------------------------------------------------------
795 // name: dll_load()
796 // desc: ...
797 //-----------------------------------------------------------------------------
798 Chuck_DLL * Chuck_VM::dll_load( const char * path, const char * id )
800 Chuck_DLL * dll = m_dlls[path];
801 if( !dll )
803 dll = new Chuck_DLL(id);
804 if( !dll ) return NULL;
806 // load the dll
807 if( !dll->load( path ) )
809 m_last_error = dll->last_error();
810 delete dll;
811 return NULL;
814 m_dlls[path] = dll;
817 return dll;
823 //-----------------------------------------------------------------------------
824 // name: dll_unload()
825 // desc: ...
826 //-----------------------------------------------------------------------------
827 t_CKBOOL Chuck_VM::dll_unload( Chuck_DLL *& dll )
829 if( !dll ) return TRUE;
831 // deallocate
832 dll->unload();
833 delete dll;
834 dll = NULL;
836 return TRUE;
842 //-----------------------------------------------------------------------------
843 // name: dll_clear()
844 // desc: ...
845 //-----------------------------------------------------------------------------
846 void Chuck_VM::dll_clear()
848 map<string, Chuck_DLL *>::iterator iter;
849 for( iter = m_dlls.begin(); iter != m_dlls.end(); iter++ )
851 (*iter).second->unload();
852 delete (*iter).second;
855 m_dlls.clear();
861 //-----------------------------------------------------------------------------
862 // name: Chuck_VM_Stack()
863 // desc: ...
864 //-----------------------------------------------------------------------------
865 Chuck_VM_Stack::Chuck_VM_Stack()
867 stack = sp = sp_max = NULL;
868 prev = next = NULL;
869 m_is_init = FALSE;
875 //-----------------------------------------------------------------------------
876 // name: ~Chuck_VM_Stack()
877 // desc: ...
878 //-----------------------------------------------------------------------------
879 Chuck_VM_Stack::~Chuck_VM_Stack()
881 this->shutdown();
887 //-----------------------------------------------------------------------------
888 // name: Chuck_VM_Code()
889 // desc: ...
890 //-----------------------------------------------------------------------------
891 Chuck_VM_Code::Chuck_VM_Code()
893 instr = NULL;
894 num_instr = 0;
900 //-----------------------------------------------------------------------------
901 // name: ~Chuck_VM_Code()
902 // desc: ...
903 //-----------------------------------------------------------------------------
904 Chuck_VM_Code::~Chuck_VM_Code()
906 if( instr )
907 delete [] instr;
909 num_instr = 0;
915 //-----------------------------------------------------------------------------
916 // name: initialize()
917 // desc: ...
918 //-----------------------------------------------------------------------------
919 t_CKBOOL Chuck_VM_Stack::initialize( t_CKUINT size )
921 if( m_is_init )
922 return FALSE;
924 // allocate stack
925 stack = new t_CKBYTE[size];
926 if( !stack )
927 return FALSE;
929 // zero
930 memset( stack, 0, size );
932 // set the sp
933 sp = stack;
934 sp_max = sp + size;
936 // set flag and return
937 return m_is_init = TRUE;
943 //-----------------------------------------------------------------------------
944 // name: shutdown()
945 // desc: ...
946 //-----------------------------------------------------------------------------
947 t_CKBOOL Chuck_VM_Stack::shutdown()
949 if( !m_is_init )
950 return FALSE;
952 // free the stack
953 SAFE_DELETE_ARRAY( stack );
954 sp = sp_max = NULL;
956 // set the flag to false
957 m_is_init = FALSE;
959 return TRUE;
965 //-----------------------------------------------------------------------------
966 // name: Chuck_VM_Shred()
967 // desc: ...
968 //-----------------------------------------------------------------------------
969 Chuck_VM_Shred::Chuck_VM_Shred()
971 mem = new Chuck_VM_Stack;
972 reg = new Chuck_VM_Stack;
973 code = NULL;
974 next = prev = NULL;
975 instr = NULL;
976 parent = NULL;
982 //-----------------------------------------------------------------------------
983 // name: ~Chuck_VM_Shred()
984 // desc: ...
985 //-----------------------------------------------------------------------------
986 Chuck_VM_Shred::~Chuck_VM_Shred()
988 this->shutdown();
994 //-----------------------------------------------------------------------------
995 // name: initialize()
996 // desc: ...
997 //-----------------------------------------------------------------------------
998 t_CKBOOL Chuck_VM_Shred::initialize( Chuck_VM_Code * c,
999 t_CKUINT mem_stack_size,
1000 t_CKUINT reg_stack_size )
1002 // allocate mem and reg
1003 if( !mem->initialize( mem_stack_size ) ) return FALSE;
1004 if( !reg->initialize( reg_stack_size ) ) return FALSE;
1006 // program counter
1007 pc = 0;
1008 next_pc = 1;
1009 // code pointer
1010 code = c;
1011 // shred done
1012 is_done = FALSE;
1013 // shred running
1014 is_running = FALSE;
1015 // set the instr
1016 instr = c->instr;
1017 // zero out the id
1018 id = 0;
1020 return TRUE;
1026 //-----------------------------------------------------------------------------
1027 // name: shutdown()
1028 // desc: ...
1029 //-----------------------------------------------------------------------------
1030 t_CKBOOL Chuck_VM_Shred::shutdown()
1032 // get iterator to our map
1033 map<Chuck_UGen *, Chuck_UGen *>::iterator iter = m_ugen_map.begin();
1034 while( iter != m_ugen_map.end() )
1036 (*iter).first->disconnect( TRUE );
1037 iter++;
1039 m_ugen_map.clear();
1041 SAFE_DELETE( mem );
1042 SAFE_DELETE( reg );
1044 // TODO: is this right?
1045 code = NULL;
1046 // what to do with next and prev?
1048 return TRUE;
1054 //-----------------------------------------------------------------------------
1055 // name: add()
1056 // desc: ...
1057 //-----------------------------------------------------------------------------
1058 t_CKBOOL Chuck_VM_Shred::add( Chuck_UGen * ugen )
1060 if( m_ugen_map[ugen] )
1061 return FALSE;
1063 m_ugen_map[ugen] = ugen;
1064 return TRUE;
1070 //-----------------------------------------------------------------------------
1071 // name: remove()
1072 // desc: ...
1073 //-----------------------------------------------------------------------------
1074 t_CKBOOL Chuck_VM_Shred::remove( Chuck_UGen * ugen )
1076 if( !m_ugen_map[ugen] )
1077 return FALSE;
1079 // remove it
1080 m_ugen_map.erase( ugen );
1081 return TRUE;
1087 //-----------------------------------------------------------------------------
1088 // name: run()
1089 // desc: ...
1090 //-----------------------------------------------------------------------------
1091 t_CKBOOL Chuck_VM_Shred::run( Chuck_VM * vm )
1093 // get the code
1094 instr = code->instr;
1095 is_running = TRUE;
1097 // go!
1098 while( is_running )
1100 // execute the instruction
1101 instr[pc]->execute( vm, this );
1103 // set to next_pc;
1104 pc = next_pc;
1105 next_pc++;
1108 // is the shred finished
1109 return !is_done;
1115 //-----------------------------------------------------------------------------
1116 // name: Chuck_VM_Shreduler()
1117 // desc: ...
1118 //-----------------------------------------------------------------------------
1119 Chuck_VM_Shreduler::Chuck_VM_Shreduler()
1121 shred_list = NULL;
1122 now_system = 0;
1128 //-----------------------------------------------------------------------------
1129 // name: ~Chuck_VM_Shreduler()
1130 // desc: ...
1131 //-----------------------------------------------------------------------------
1132 Chuck_VM_Shreduler::~Chuck_VM_Shreduler()
1134 this->shutdown();
1140 //-----------------------------------------------------------------------------
1141 // name: initialize()
1142 // desc: ...
1143 //-----------------------------------------------------------------------------
1144 t_CKBOOL Chuck_VM_Shreduler::initialize()
1146 return TRUE;
1152 //-----------------------------------------------------------------------------
1153 // name: shutdown()
1154 // desc: ...
1155 //-----------------------------------------------------------------------------
1156 t_CKBOOL Chuck_VM_Shreduler::shutdown()
1158 return TRUE;
1164 //-----------------------------------------------------------------------------
1165 // name: shredule()
1166 // desc: ...
1167 //-----------------------------------------------------------------------------
1168 t_CKBOOL Chuck_VM_Shreduler::shredule( Chuck_VM_Shred * shred )
1170 return this->shredule( shred, now_system );
1176 //-----------------------------------------------------------------------------
1177 // name: shredule()
1178 // desc: ...
1179 //-----------------------------------------------------------------------------
1180 t_CKBOOL Chuck_VM_Shreduler::shredule( Chuck_VM_Shred * shred,
1181 t_CKTIME wake_time )
1183 // sanity check
1184 if( shred->prev || shred->next )
1186 // something is really wrong here - no shred can be
1187 // shreduled more than once
1188 return FALSE;
1191 // sanity check
1192 if( wake_time < this->now_system )
1194 // trying to enqueue on a time that is less than now
1195 return FALSE;
1198 shred->wake_time = wake_time;
1200 // list empty
1201 if( !shred_list )
1202 shred_list = shred;
1203 else
1205 // pointers to the shred queue
1206 Chuck_VM_Shred * curr = shred_list;
1207 Chuck_VM_Shred * prev = NULL;
1209 while( curr )
1211 // found the place to insert
1212 if( curr->wake_time > wake_time )
1213 break;
1215 prev = curr;
1216 curr = curr->next;
1219 if( !prev )
1221 shred->next = shred_list;
1222 if( shred_list ) shred_list->prev = shred;
1223 shred_list = shred;
1225 else
1227 // insert the shred in sorted order
1228 shred->next = prev->next;
1229 shred->prev = prev;
1230 if( prev->next ) prev->next->prev = shred;
1231 prev->next = shred;
1235 return TRUE;
1240 //-----------------------------------------------------------------------------
1241 // name: advance()
1242 // desc: ...
1243 //-----------------------------------------------------------------------------
1244 void Chuck_VM_Shreduler::advance( )
1246 // advance system 'now'
1247 this->now_system += 1;
1249 // tick the dac
1250 SAMPLE l, r;
1251 BBQ * audio = this->bbq;
1253 // tick in
1254 if( audio )
1256 audio->digi_in()->tick_in( &l, &r );
1257 m_adc[0].m_current = .5f * ( l + r ) * m_adc[0].m_gain;
1258 // m_adc[1].m_current = r * m_adc[1].m_gain;
1261 // dac
1262 m_dac[0].system_tick( this->now_system );
1263 //m_dac[1].system_tick( this->now_system );
1264 l = m_dac[0].m_current;
1265 //r = m_dac[1].m_current;
1266 l *= .5f;
1268 // suck samples
1269 m_bunghole->system_tick( this->now_system );
1271 // tick
1272 if( audio )
1273 audio->digi_out()->tick_out( l, l );
1279 //-----------------------------------------------------------------------------
1280 // name: get()
1281 // desc: ...
1282 //-----------------------------------------------------------------------------
1283 Chuck_VM_Shred * Chuck_VM_Shreduler::get( )
1285 Chuck_VM_Shred * shred = shred_list;
1287 // list empty
1288 if( !shred )
1289 return NULL;
1291 // TODO: should this be <=?
1292 if( shred->wake_time <= ( this->now_system + .5 ) )
1294 // if( shred->wake_time < this->now_system )
1295 // assert( false );
1297 shred_list = shred->next;
1298 shred->next = NULL;
1299 shred->prev = NULL;
1301 if( shred_list )
1302 shred_list->prev = NULL;
1304 return shred;
1307 return NULL;
1312 //-----------------------------------------------------------------------------
1313 // name: replace()
1314 // desc: ...
1315 //-----------------------------------------------------------------------------
1316 t_CKBOOL Chuck_VM_Shreduler::replace( Chuck_VM_Shred * out, Chuck_VM_Shred * in )
1318 // sanity check
1319 if( !out || !in )
1320 return FALSE;
1322 if( !out->prev )
1323 shred_list = in;
1324 else
1325 out->prev->next = in;
1327 if( out->next )
1328 out->next->prev = in;
1330 in->next = out->next;
1331 in->prev = out->prev;
1333 out->next = out->prev = NULL;
1335 in->wake_time = out->wake_time;
1336 in->start = in->wake_time;
1338 return TRUE;
1344 //-----------------------------------------------------------------------------
1345 // name: remove()
1346 // desc: ...
1347 //-----------------------------------------------------------------------------
1348 t_CKBOOL Chuck_VM_Shreduler::remove( Chuck_VM_Shred * out )
1350 // sanity check
1351 if( !out || ( !out->prev && !out->prev && out != shred_list ) )
1352 return FALSE;
1354 if( !out->prev )
1355 shred_list = out->next;
1356 else
1357 out->prev->next = out->next;
1359 if( out->next )
1360 out->next->prev = out->prev;
1362 out->next = out->prev = NULL;
1364 return TRUE;
1370 //-----------------------------------------------------------------------------
1371 // name: get()
1372 // desc: ...
1373 //-----------------------------------------------------------------------------
1374 Chuck_VM_Shred * Chuck_VM_Shreduler::lookup( t_CKUINT id )
1376 Chuck_VM_Shred * shred = shred_list;
1378 // list empty
1379 if( !shred )
1380 return NULL;
1382 while( shred )
1384 if( shred->id == id )
1385 return shred;
1387 shred = shred->next;
1390 return NULL;
1396 //-----------------------------------------------------------------------------
1397 // name: status()
1398 // desc: ...
1399 //-----------------------------------------------------------------------------
1400 void Chuck_VM_Shreduler::status( )
1402 Chuck_VM_Shred * shred = shred_list;
1404 t_CKUINT srate = Digitalio::sampling_rate();
1405 t_CKUINT s = (t_CKUINT)now_system;
1406 t_CKUINT h = s/(srate*3600);
1407 s = s - (h*(srate*3600));
1408 t_CKUINT m = s / (srate*60);
1409 s = s - (m*(srate*60));
1410 t_CKUINT sec = s / srate;
1411 s = s - (sec*(srate));
1412 float millisecond = s / (float)(srate) * 1000.0f;
1413 fprintf( stdout, "[chuck](VM): status (now == %ih%im%is, %.1f samps) ...\n",
1414 h, m, sec, now_system );
1416 char buffer[1024];
1417 while( shred )
1419 char * s = buffer, * ss = buffer;
1420 strcpy( buffer, shred->name.c_str() );
1421 while( *s++ ) if( *s == '/' ) { ss = s+1; }
1423 fprintf( stdout,
1424 " [shred id]: %i [source]: %s [spork time]: %.2fs ago\n",
1425 shred->id, mini( shred->name.c_str() ),
1426 (now_system-shred->start)/(float)Digitalio::sampling_rate() );
1427 shred = shred->next;