Ge Wangfile permissions99bc19d5 years agoHistory
5631 lines · 172.0 KB · C++
RawDownload
/*----------------------------------------------------------------------------  ChucK Concurrent, On-the-fly Audio Programming Language    Compiler and Virtual Machine   Copyright (c) 2004 Ge Wang and Perry R. Cook.  All rights reserved.    http://chuck.stanford.edu/    http://chuck.cs.princeton.edu/   This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.   This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.   You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// file: chuck_vm.cpp// desc: chuck virtual machine//// author: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)// date: Autumn 2002//-----------------------------------------------------------------------------#include "chuck_vm.h"#include "chuck_instr.h"#include "chuck_lang.h"#include "chuck_type.h"#include "chuck_dl.h" #ifndef __DISABLE_SERIAL__#include "chuck_io.h"#endif #include "chuck_errmsg.h"#include "ugen_xxx.h" #ifndef __DISABLE_HID__#include "hidio_sdl.h"  // 1.4.0.0#endif #ifndef __DISABLE_MIDI__#include "midiio_rtmidi.h"  // 1.4.0.2#endif #include <algorithm>using namespace std; #if defined(__PLATFORM_WIN32__)  #include <windows.h>#else  #include <unistd.h>  #include <pthread.h>#endif // uncomment to compile VM debug messages#define CK_VM_DEBUG_ENABLE (0) #if CK_VM_DEBUG_ENABLE#define CK_VM_DEBUG(x) x#include <typeinfo>#else#define CK_VM_DEBUG(x)#endif // CK_VM_DEBUG_ENABLE    //-----------------------------------------------------------------------------// name: struct Chuck_VM_Frame// desc: func frame//-----------------------------------------------------------------------------struct Chuck_VM_Frame{public:    t_CKUINT size; public:    Chuck_VM_Frame() { size = 0; }    ~Chuck_VM_Frame() { }};    //-----------------------------------------------------------------------------// name: struct Chuck_VM_Func// desc: vm function//-----------------------------------------------------------------------------struct Chuck_VM_Func{public:    Chuck_VM_Code * code;    Chuck_VM_Frame * frame;    t_CKUINT index; public:    Chuck_VM_Func() { code = NULL; frame = NULL; index = 0; }    ~Chuck_VM_Func() { }};    //-----------------------------------------------------------------------------// name: struct Chuck_VM_FTable// desc: function table//-----------------------------------------------------------------------------struct Chuck_VM_FTable{public:    Chuck_VM_FTable();    ~Chuck_VM_FTable(); public:    Chuck_VM_Func * get_func( t_CKUINT index );    t_CKUINT append( Chuck_VM_Func * f );    t_CKBOOL remove( t_CKUINT index ); public:    vector<Chuck_VM_Func *> func_table;};    //-----------------------------------------------------------------------------// name: Chuck_VM()// desc: ...//-----------------------------------------------------------------------------Chuck_VM::Chuck_VM(){    // REFACTOR-2017: refs    m_carrier = NULL;        // data    m_shreds = NULL;    m_num_shreds = 0;    m_shreduler = NULL;    m_num_dumped_shreds = 0;    m_globals_manager = NULL; // 1.4.0.2 (jack)    m_msg_buffer = NULL;    m_reply_buffer = NULL;    m_event_buffer = NULL;    m_shred_id = 0;    m_halt = TRUE;     m_dac = NULL;    m_adc = NULL;    m_bunghole = NULL;    m_srate = 0;    m_num_dac_channels = 0;    m_num_adc_channels = 0;    m_init = FALSE;    m_input_ref = NULL;    m_output_ref = NULL;    m_current_buffer_frames = 0;}    //-----------------------------------------------------------------------------// name: ~Chuck_VM()// desc: ...//-----------------------------------------------------------------------------Chuck_VM::~Chuck_VM(){    // check if init    if( m_init )    {        // cleanup        shutdown();    }}    //-----------------------------------------------------------------------------// name: initialize()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::initialize( t_CKUINT srate, t_CKUINT dac_chan,                               t_CKUINT adc_chan, t_CKUINT adaptive, t_CKBOOL halt ){    if( m_init )    {        m_last_error = "VM already initialized!";        return FALSE;    }     // log    EM_log( CK_LOG_SYSTEM, "initializing virtual machine..." );    EM_pushlog(); // push stack     m_halt = halt;    m_num_adc_channels = adc_chan;    m_num_dac_channels = dac_chan;    m_srate = srate;     // lockdown    Chuck_VM_Object::lock_all();     // log    EM_log( CK_LOG_SYSTEM, "allocating shreduler..." );    // allocate shreduler    m_shreduler = new Chuck_VM_Shreduler;    m_shreduler->vm_ref = this;    m_shreduler->set_adaptive( adaptive > 0 ? adaptive : 0 );     // log    EM_log( CK_LOG_SYSTEM, "allocating messaging buffers..." );    // allocate msg buffer    m_msg_buffer = new CBufferSimple;    m_msg_buffer->initialize( 1024, sizeof(Chuck_Msg *) );    //m_msg_buffer->join(); // this should return 0    m_reply_buffer = new CBufferSimple;    m_reply_buffer->initialize( 1024, sizeof(Chuck_Msg *) );    //m_reply_buffer->join(); // this should return 0 too    m_event_buffer = new CBufferSimple;    m_event_buffer->initialize( 1024, sizeof(Chuck_Event *) );    //m_event_buffer->join(); // this should also return 0     // 1.4.0.2 (jack): added globals manager    EM_log( CK_LOG_SYSTEM, "allocating globals manager..." );    m_globals_manager = new Chuck_Globals_Manager( this );     // pop log    EM_poplog();     // TODO: clean up all the dynamic objects here on failure    //       and in the shutdown function!     return m_init = TRUE;}    //-----------------------------------------------------------------------------// name: initialize_synthesis()// desc: requires type system//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::initialize_synthesis( ){    if( !m_init )    {        m_last_error = "VM initialize_synthesis() called on raw VM";        return FALSE;    }     if( !env()->t_dac || !env()->t_adc )    {        m_last_error = "VM initialize_synthesis() called before type system initialized";        return FALSE;    }     if( m_dac != NULL )    {        m_last_error = "VM synthesis already initialized";        return FALSE;    }     // log    EM_log( CK_LOG_SYSTEM, "initializing synthesis engine..." );    // push indent    EM_pushlog();     // log    EM_log( CK_LOG_SEVERE, "initializing 'dac'..." );    // allocate dac and adc (REFACTOR-2017: g_t_dac changed to env()->t_dac)    env()->t_dac->ugen_info->num_outs =        env()->t_dac->ugen_info->num_ins = m_num_dac_channels;    m_dac = (Chuck_UGen *)instantiate_and_initialize_object( env()->t_dac, this );    // Chuck_DL_Api::Api::instance() added 1.3.0.0    object_ctor( m_dac, NULL, this, NULL, Chuck_DL_Api::Api::instance() ); // TODO: this can't be the place to do this    stereo_ctor( m_dac, NULL, this, NULL, Chuck_DL_Api::Api::instance() ); // TODO: is the NULL shred a problem?    multi_ctor( m_dac, NULL, this, NULL, Chuck_DL_Api::Api::instance() );  // TODO: remove and let type system do this    m_dac->add_ref();    // lock it    m_dac->lock();     // log    EM_log( CK_LOG_SEVERE, "initializing 'adc'..." );    // (REFACTOR-2017: g_t_adc changed to env()->t_adc)    env()->t_adc->ugen_info->num_ins =        env()->t_adc->ugen_info->num_outs = m_num_adc_channels;    m_adc = (Chuck_UGen *)instantiate_and_initialize_object( env()->t_adc, this );    // Chuck_DL_Api::Api::instance() added 1.3.0.0    object_ctor( m_adc, NULL, this, NULL, Chuck_DL_Api::Api::instance() ); // TODO: this can't be the place to do this    stereo_ctor( m_adc, NULL, this, NULL, Chuck_DL_Api::Api::instance() );    multi_ctor( m_adc, NULL, this, NULL, Chuck_DL_Api::Api::instance() ); // TODO: remove and let type system do this    m_adc->add_ref();    // lock it    m_adc->lock();     // log    EM_log( CK_LOG_SEVERE, "initializing 'blackhole'..." );    m_bunghole = new Chuck_UGen;    m_bunghole->add_ref();    m_bunghole->lock();    initialize_object( m_bunghole, env()->t_ugen );    m_bunghole->tick = NULL;    m_bunghole->alloc_v( m_shreduler->m_max_block_size );    m_shreduler->m_dac = m_dac;    m_shreduler->m_adc = m_adc;    m_shreduler->m_bunghole = m_bunghole;    m_shreduler->m_num_dac_channels = m_num_dac_channels;    m_shreduler->m_num_adc_channels = m_num_adc_channels;     // pop indent    EM_poplog();     return TRUE;}    //-----------------------------------------------------------------------------// name: shutdown()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::shutdown(){    // make sure we are in the initialized state    if( !m_init ) return FALSE;     // log    EM_log( CK_LOG_SYSTEM, "shutting down virtual machine..." );    // push indent    EM_pushlog();        // unlockdown    // REFACTOR-2017: TODO: don't unlock all objects for all VMs? see relockdown below    Chuck_VM_Object::unlock_all();        // REFACTOR-2017: clean up after my global variables    m_globals_manager->cleanup_global_variables();    SAFE_DELETE( m_globals_manager );     // log    EM_log( CK_LOG_SYSTEM, "freeing shreduler..." );    // free the shreduler    SAFE_DELETE( m_shreduler );        #ifndef __DISABLE_HID__    // log    EM_log( CK_LOG_SYSTEM, "unregistering VM from HID manager..." );    // clean up this vm    HidInManager::cleanup_buffer( this );    #endif        #ifndef __DISABLE_MIDI__    EM_log( CK_LOG_SYSTEM, "unregistering VM from MIDI manager..." );    MidiInManager::cleanup_buffer( this );    #endif     // log    EM_log( CK_LOG_SYSTEM, "freeing msg/reply/event buffers..." );    // free the msg buffer    SAFE_DELETE( m_msg_buffer );    // free the reply buffer    SAFE_DELETE( m_reply_buffer );    // free the event buffer    SAFE_DELETE( m_event_buffer );     // log    EM_log( CK_LOG_SEVERE, "clearing shreds..." );    // terminate shreds    Chuck_VM_Shred * curr = m_shreds, * prev = NULL;    while( curr )    {        prev = curr;        curr = curr->next;        // release shred        prev->release();    }    m_shreds = NULL;    m_num_shreds = 0;     // log    EM_pushlog();    EM_log( CK_LOG_SEVERE, "freeing dumped shreds..." );    // do it    this->release_dump();    EM_poplog();     // log    EM_log( CK_LOG_SYSTEM, "freeing special ugens..." );    // go    SAFE_RELEASE( m_dac );    SAFE_RELEASE( m_adc );    SAFE_RELEASE( m_bunghole );        // set state    m_init = FALSE;        // relockdown (added 1.3.6.0)    // REFACTOR-2017: TODO -- remove once made per-VM    Chuck_VM_Object::lock_all();     // log    EM_log( CK_LOG_SYSTEM, "virtual machine shutdown complete." );     // pop indent    EM_poplog();     return TRUE;}    //-----------------------------------------------------------------------------// name: start()// desc: run start (can be called before or after init)//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::start(){    // already running?    if( m_is_running) return FALSE;    // set state    m_is_running = TRUE;    // done    return TRUE;}    //-----------------------------------------------------------------------------// name: running()// desc: get run state//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::running(){    return m_is_running;}    //-----------------------------------------------------------------------------// name: stop()// desc: run stop//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::stop(){    // running?    if( !m_is_running ) return FALSE;    // set state    m_is_running = FALSE;    // done    return TRUE;}    //-----------------------------------------------------------------------------// name: compute()// desc: compute all shreds at one instance in ChucK time//-----------------------------------------------------------------------------t_CKBOOL Chuck_VM::compute(){    Chuck_VM_Shred *& shred = m_shreduler->m_current_shred;    Chuck_Msg * msg = NULL;    Chuck_Event * event = NULL;    t_CKBOOL iterate = TRUE;        // REFACTOR-2017: spork queued shreds, handle global messages    // global manager added 1.4.0.2 (jack)    m_globals_manager->handle_global_queue_messages();     // iteration until no more shreds/events/messages    while( iterate )    {        // get the shreds queued for 'now'        while(( shred = m_shreduler->get() ))        {            // set the current time of the shred            shred->now = shred->wake_time;             // track shred activation            CK_TRACK( Chuck_Stats::instance()->activate_shred( shred ) );             // run the shred            if( !shred->run( this ) )            {                // track shred deactivation                CK_TRACK( Chuck_Stats::instance()->deactivate_shred( shred ) );

Lines 1–500 of 5631.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t