1626 lines · 44.9 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_ugen.cpp// desc: chuck unit generator interface//// authors: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)//          Rebecca Fiebrink (fiebrink@cs.princeton.edu)//          Spencer Salazar (spencer@ccrma.stanford.edu)// date: spring 2004 - 1.1//       spring 2005 - 1.2//       spring 2007 - UAna//-----------------------------------------------------------------------------#include "chuck_ugen.h"#include "chuck_instr.h"#include "chuck_type.h"#include "chuck_vm.h"#include "chuck_lang.h"#include "chuck_errmsg.h"using namespace std;    //-----------------------------------------------------------------------------// fast array//-----------------------------------------------------------------------------void fa_init( Chuck_UGen ** & base, t_CKUINT & capacity );void fa_done( Chuck_UGen ** & base, t_CKUINT & capacity );void fa_resize( Chuck_UGen ** & base, t_CKUINT & capacity );void fa_push_back( Chuck_UGen ** & base, t_CKUINT & capacity,                   t_CKUINT size, Chuck_UGen * value );t_CKBOOL fa_lookup( Chuck_UGen ** base, t_CKUINT size,                    const Chuck_UGen * value );   //-----------------------------------------------------------------------------// name: fa_init()// desc: ...//-----------------------------------------------------------------------------void fa_init( Chuck_UGen ** & base, t_CKUINT & capacity ){    base = NULL;    capacity = 0;}    //-----------------------------------------------------------------------------// name: fa_done()// desc: ...//-----------------------------------------------------------------------------void fa_done( Chuck_UGen ** & base, t_CKUINT & capacity ){    if( base ) delete [] base;    base = NULL;    capacity = 0;}    //-----------------------------------------------------------------------------// name: fa_resize()// desc: ...//-----------------------------------------------------------------------------void fa_resize( Chuck_UGen ** & base, t_CKUINT & capacity ){    // initial    if( capacity == 0 )        capacity = 8;    else        capacity *= 2;     // allocate    Chuck_UGen ** new_base = new Chuck_UGen *[capacity];    // delete    if( base )    {        // copy        memcpy( new_base, base, capacity / 2 * sizeof(Chuck_UGen *) );        // delete        delete [] base;    }     // done    base = new_base;}    //-----------------------------------------------------------------------------// name: fa_push_back()// desc: ...//-----------------------------------------------------------------------------void fa_push_back( Chuck_UGen ** & base, t_CKUINT & capacity,                   t_CKUINT size, Chuck_UGen * value ){    // resize    if( size == capacity ) fa_resize( base, capacity );    // add    base[size] = value;}    //-----------------------------------------------------------------------------// name: fa_lookup()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL fa_lookup( Chuck_UGen ** base, t_CKUINT size, const Chuck_UGen * value ){    // loop    for( t_CKUINT i = 0; i < size; i++ )        if( base[i] == value )            return TRUE;     // not found    return FALSE;}    //-----------------------------------------------------------------------------// name: Chuck_UGen()// desc: constructor//-----------------------------------------------------------------------------Chuck_UGen::Chuck_UGen(){    this->init();}    //-----------------------------------------------------------------------------// name: ~Chuck_UGen()// desc: ...//-----------------------------------------------------------------------------Chuck_UGen::~Chuck_UGen(){    this->done();}    //-----------------------------------------------------------------------------// name: init()// desc: ...//-----------------------------------------------------------------------------void Chuck_UGen::init(){    tick = NULL;    tickf = NULL; // added 1.3.0.0    pmsg = NULL;    m_multi_chan = NULL;    m_multi_chan_size = 0;    m_num_ins = 1;    m_num_outs = 1;     fa_init( m_src_list, m_src_cap );    fa_init( m_dest_list, m_dest_cap );    fa_init( m_src_uana_list, m_src_uana_cap );    fa_init( m_dest_uana_list, m_dest_uana_cap );    m_num_src = 0;    m_num_dest = 0;    m_num_uana_src = 0;    m_num_uana_dest = 0;    m_max_src = CK_NO_VALUE;    m_time = 0;    m_valid = TRUE;    m_sum = 0.0f;    m_current = 0.0f;    m_last = 0.0f;    m_op = UGEN_OP_TICK;    m_gain = 1.0f;    m_next = 0.0f;    m_use_next = FALSE;    m_max_block_size = -1;    // if this is part of a stereo UGen, this parameter will be initialized    // according to the underly panning law (1.4.1.0)    m_pan = 1.0f;     m_sum_v = NULL;    m_current_v = NULL;     shred = NULL;    owner = NULL;     // what a hack    m_is_uana = FALSE;     // what another hack (added 1.3.0.0)    m_is_subgraph = FALSE;    m_inlet = m_outlet = NULL;    m_multi_in_v = m_multi_out_v = NULL;     // 1.4.1.0 (jack): yes more hacks. buffered flag allows    // global ugens' samples to be gotten    m_is_buffered = FALSE;    // buffer empty for any ugen that is not buffered    m_buffer.resize( 0 );}    //-----------------------------------------------------------------------------// name: done()// desc: ...//-----------------------------------------------------------------------------void Chuck_UGen::done(){    if( this->shred )        shred->remove( this );     assert( this->m_ref_count == 0 );     // disconnect    this->disconnect( TRUE );    m_valid = FALSE;     fa_done( m_src_list, m_src_cap );    fa_done( m_dest_list, m_dest_cap );    fa_done( m_src_uana_list, m_src_uana_cap );    fa_done( m_dest_uana_list, m_dest_uana_cap );     // reclaim    SAFE_DELETE_ARRAY( m_sum_v );    SAFE_DELETE_ARRAY( m_current_v );     // more reclaim (added 1.3.0.0)    SAFE_DELETE_ARRAY( m_multi_chan );    // TODO: m_multi_chan, break ref count loop     // SPENCERTODO: is this okay??? (added 1.3.0.0)    SAFE_DELETE( m_inlet );    SAFE_DELETE( m_outlet );     // clean up array (added 1.3.0.0)    SAFE_DELETE_ARRAY( m_multi_in_v );    SAFE_DELETE_ARRAY( m_multi_out_v );}    //-----------------------------------------------------------------------------// name: alloc_v()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_UGen::alloc_v( t_CKUINT size ){    // reclaim    SAFE_DELETE_ARRAY( m_sum_v );    SAFE_DELETE_ARRAY( m_current_v );     // save block size as max block size (added 1.3.0.0)    m_max_block_size = size;     // go    if( size > 0 )    {        m_sum_v = new SAMPLE[size];        m_current_v = new SAMPLE[size];         return ( m_sum_v != NULL && m_current_v != NULL );    }     return TRUE;}    //-----------------------------------------------------------------------------// name: alloc_multi_chan()// desc: ...//-----------------------------------------------------------------------------void Chuck_UGen::alloc_multi_chan( t_CKUINT num_ins, t_CKUINT num_outs ){    // get max of num_ins and num_outs    m_multi_chan_size = ( num_ins > num_outs ? num_ins : num_outs );     // allocate    m_multi_chan = new Chuck_UGen *[m_multi_chan_size];    // zero it out, whoever call this will fill in    memset( m_multi_chan, 0, m_multi_chan_size * sizeof(Chuck_UGen *) );     // mono    if( m_multi_chan_size == 1 )    {        // zero out        m_multi_chan_size = 0;        // self        m_multi_chan[0] = this;    }     // if there tick-frame (i.e., has multi-channel tick function; added 1.3.0.0)    if( m_multi_chan_size && tickf )    {        // m_max_block_size needs to be set via alloc_v() first (added 1.3.0.0)        assert(m_max_block_size >= 0);        t_CKINT block_size = m_max_block_size == 0 ? 1 : m_max_block_size;         SAFE_DELETE_ARRAY(m_multi_in_v);        SAFE_DELETE_ARRAY(m_multi_out_v);        // allocate a frame for input and output from the tick function (add 1.3.0.0)        m_multi_in_v = new SAMPLE[m_multi_chan_size*block_size];        m_multi_out_v = new SAMPLE[m_multi_chan_size*block_size];    }     // remember    m_num_ins = num_ins;    m_num_outs = num_outs;}    //-----------------------------------------------------------------------------// name: set_max_src()// dsec: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_UGen::set_max_src( t_CKUINT num ){    m_max_src = num;    return TRUE;}    //-----------------------------------------------------------------------------// name: get_num_src()// desc: ...//-----------------------------------------------------------------------------t_CKUINT Chuck_UGen::get_num_src(){    return m_num_src;}    //-----------------------------------------------------------------------------// name: set_is_buffered()// dsec: set whether we should store our old samples//-----------------------------------------------------------------------------t_CKBOOL Chuck_UGen::set_is_buffered( t_CKBOOL buffered ){    // check if value is really changing. if not, return    if( ( buffered && m_is_buffered ) || ( !buffered && !m_is_buffered ) )    {        return TRUE;    }     if( buffered )    {        // alloc        // (TODO: smarter way of maximum size of my buffer)        m_buffer.resize( 8192 );    }    else    {        // dealloc        m_buffer.resize( 0 );    }     // store flag    m_is_buffered = buffered;     return TRUE; }    //-----------------------------------------------------------------------------// name: get_buffer()// dsec: get the most recent buffer of samples//-----------------------------------------------------------------------------void Chuck_UGen::get_buffer( SAMPLE * buffer, t_CKINT num_elem ){    if( m_is_buffered )    {        // if we actually store our samples, give them num_elem of them        m_buffer.get_most_recent( buffer, num_elem );    }    else    {        // otherwise, give them 0        memset( buffer, 0, sizeof( SAMPLE ) * num_elem );    }}     //-----------------------------------------------------------------------------// name: src_chan()// desc: added 1.3.3.1//       destination ugen for a given source channel//-----------------------------------------------------------------------------Chuck_UGen * Chuck_UGen::src_chan( t_CKUINT chan ){    if( this->m_num_outs == 1)        return this;    return m_multi_chan[chan%m_num_outs];}    //-----------------------------------------------------------------------------// name: dst_for_src_chan()// desc: added 1.3.3.1//       destination ugen for a given source channel//-----------------------------------------------------------------------------Chuck_UGen * Chuck_UGen::dst_for_src_chan( t_CKUINT chan ){    if( this->m_num_ins == 1)        return this;    if( chan < this->m_num_ins )        return m_multi_chan[chan];    return NULL;}    //-----------------------------------------------------------------------------// name: add()// dsec: from point of view of destination (RHS) Ugen, add source (LHS) ugen//       i.e., src => this//-----------------------------------------------------------------------------t_CKBOOL Chuck_UGen::add( Chuck_UGen * src, t_CKBOOL isUpChuck ){    // spencer 2012: chubgraph handling (added 1.3.0.0)    if( m_is_subgraph )    {        // sanity check        assert( inlet() != NULL );        // add src to this inlet        return inlet()->add( src, isUpChuck );    }    else if( src->m_is_subgraph ) // (added 1.3.0.0)    {        // sanity check        assert( src->outlet() != NULL );        // call add on the src's outlet instead        return add( src->outlet(), isUpChuck );    }     // examine ins and outs    t_CKUINT outs = src->m_num_outs;    t_CKUINT ins = this->m_num_ins;    t_CKUINT i;     // map output channels to inputs    if( outs >= 1 && ins == 1 )    {        // check if already connected        // if( fa_lookup( m_src_list, m_num_src, src ) )        //     return FALSE;         // check for limit        if( m_num_src >= m_max_src )            return FALSE; 

Lines 1–500 of 1626.

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