Skip to content

Commit

Permalink
modify => semantics for array of UGens
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Mar 16, 2024
1 parent 3b8b588 commit d070fa8
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 33 deletions.
15 changes: 15 additions & 0 deletions VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ ChucK VERSIONS log
- (added) OSC wildcard examples
examples/osc/wildcards/r-wildcards.ck
examples/osc/wildcards/s-multi.ck
- (modified) semantics for connecting (=>) arrays of UGens;
1) LHS[X] => RHS: each elements in LHS => to RHS
// Gain A[3] => Gain B;
2) LHS[X] => RHS[X]: one to one mapping
// Gain C[3] => Gain D[3];
3) LHS[X] => RHS[Y]: one to one mapping up to min(X,Y), after
which elements in the smaller array will modulo to the beginning
and connect to remaining elements in larger array
// Gain E[2] => Gain F[3];
4) LHS => RHS[X]: LHS => to each element in RHS
// Gain G => Gain H[3];
- (added) connecting (=^) arrays of Unit Analyzers (UAnae)
- (added) examples/array/array_ugen.ck
- (added) Math.min( int, int ) and Math.max( int, int )
NOTE: these overload the existing (float,float) min/max functions
- (fixed) error reporting for =^ =v --> --< operators
- (fixed) all oscillators Osc( freq, phase ) constructors; previously the phase
was not set correctly
Expand Down
24 changes: 24 additions & 0 deletions examples/array/array_ugens.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// connecting => with arrays of UGens
// (requires chuck-1.5.2.2 or higher)
// there are several possibilities...

// 1) LHS[X] => RHS: each elements in LHS => to RHS
Gain A[3] => Gain B;
for( UGen a : A ) <<< "1) connected:", a.isConnectedTo(B) >>>;

// 2) LHS[X] => RHS[X]: one to one mapping
Gain C[3] => Gain D[3];
for( int i; i < C.size(); i++ )
<<< "2) connected:", C[i].isConnectedTo(D[i]) >>>;

// 3) LHS[X] => RHS[Y]: one to one mapping up to min(X,Y), after
// which elements in the smaller array will modulo to the beginning
// and connect to remaining elements in larger array
Gain E[2] => Gain F[3];
Math.max(E.size(), F.size()) => int greater;
for( int i; i < greater; i++ )
<<< "3) connected:", E[i%E.size()].isConnectedTo(F[i%F.size()]) >>>;

// 4) LHS => RHS[X]: LHS => to each element in RHS
Gain G => Gain H[3];
for( UGen h : H ) <<< "4) connected:", G.isConnectedTo(h) >>>;
17 changes: 14 additions & 3 deletions src/core/chuck_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3193,7 +3193,7 @@ t_CKBOOL emit_engine_emit_op_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs,
// ugen => ugen
if( isa( left, emit->env->ckt_ugen ) && isa( right, emit->env->ckt_ugen ) )
{
// link, flag as NOT unchuck
// link, flag as NOT upchuck
emit->append( instr = new Chuck_Instr_UGen_Link( FALSE ) );
instr->set_linepos( lhs->line );
// done
Expand All @@ -3204,8 +3204,8 @@ t_CKBOOL emit_engine_emit_op_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs,
if( ( isa( left, emit->env->ckt_ugen ) || ( isa( left, emit->env->ckt_array ) && isa( left->array_type, emit->env->ckt_ugen ) ) ) &&
( isa( right, emit->env->ckt_ugen ) || ( isa( right, emit->env->ckt_array ) && isa( right->array_type, emit->env->ckt_ugen ) ) ) )
{
// link, flag as NOT unchuck
emit->append( instr = new Chuck_Instr_UGen_Array_Link( isa( left, emit->env->ckt_array ), isa( right, emit->env->ckt_array ) ) );
// link, flag as NOT upchuck
emit->append( instr = new Chuck_Instr_UGen_Array_Link( isa( left, emit->env->ckt_array ), isa( right, emit->env->ckt_array ), FALSE ) );
instr->set_linepos( lhs->line );
// done
return TRUE;
Expand Down Expand Up @@ -3348,6 +3348,17 @@ t_CKBOOL emit_engine_emit_op_upchuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs
emit->append( instr = new Chuck_Instr_UGen_Link( TRUE ) );
instr->set_linepos( lhs->line );
}
// uana[] =^ uana[] (or permutation)
else if( ( isa( left, emit->env->ckt_uana ) || ( isa( left, emit->env->ckt_array ) && isa( left->array_type, emit->env->ckt_uana ) ) ) &&
( isa( right, emit->env->ckt_uana ) || ( isa( right, emit->env->ckt_array ) && isa( right->array_type, emit->env->ckt_uana ) ) ) )
{
// link, flag as upchuck
Chuck_Instr * instr = NULL;
emit->append( instr = new Chuck_Instr_UGen_Array_Link( isa( left, emit->env->ckt_array ), isa( right, emit->env->ckt_array ), TRUE ) );
instr->set_linepos( lhs->line );
// done
return TRUE;
}
else
{
EM_error2( lhs->where,
Expand Down
54 changes: 46 additions & 8 deletions src/core/chuck_instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6508,6 +6508,7 @@ Chuck_Object * do_alloc_array(
// initialize object | 1.5.0.0 (ge) use array type instead of base t_array
// for the object->type_ref to contain more specific information
initialize_object( baseX, type, shred, vm );

// initialize_object( baseX, vm->env()->ckt_array );
return baseX;
}
Expand Down Expand Up @@ -8338,7 +8339,7 @@ void Chuck_Instr_UGen_Array_Link::execute( Chuck_VM * vm, Chuck_VM_Shred * shred
{
Chuck_Object **& sp = (Chuck_Object **&)shred->reg->sp;
Chuck_Object * src_obj = NULL, * dst_obj = NULL;
t_CKINT num_in;
t_CKINT num_out = 1, num_in = 1;

// pop
pop_( sp, 2 );
Expand All @@ -8349,14 +8350,51 @@ void Chuck_Instr_UGen_Array_Link::execute( Chuck_VM * vm, Chuck_VM_Shred * shred
dst_obj = (*(sp + 1));

// go for it
num_in = ugen_generic_num_in(dst_obj, m_dstIsArray);
for( int i = 0; i < num_in; i++ )
// 1.5.2.2 (ge) semantic update: default num_out and num_in to 1,
// only update if actually an array; let ugen->add() sort out channels
num_out = ugen_generic_num_out_nochan( src_obj, m_srcIsArray );
num_in = ugen_generic_num_in_nochan( dst_obj, m_dstIsArray );

// check for different combos, similar to ugen->add() | 1.5.2.2 (ge)
if( num_out == 1 && num_in == 1 )
{
Chuck_UGen *dst_ugen = ugen_generic_get_dst( dst_obj, i, m_dstIsArray );
Chuck_UGen *src_ugen = ugen_generic_get_src( src_obj, i, m_srcIsArray );
if( dst_ugen == NULL || src_ugen == NULL )
goto null_pointer;
dst_ugen->add( src_ugen, FALSE);
Chuck_UGen * dst_ugen = ugen_generic_get_dst_nochan( dst_obj, 0, m_dstIsArray );
Chuck_UGen * src_ugen = ugen_generic_get_src_nochan( src_obj, 0, m_srcIsArray );
if( dst_ugen == NULL || src_ugen == NULL ) goto null_pointer;
dst_ugen->add( src_ugen, m_isUpChuck );
}
else if( num_out == 1 && num_in > 1 )
{
Chuck_UGen * src_ugen = ugen_generic_get_src_nochan( src_obj, 0, m_srcIsArray );
for( t_CKINT i = 0; i < num_in; i++ )
{
Chuck_UGen * dst_ugen = ugen_generic_get_dst_nochan( dst_obj, i, m_dstIsArray );
if( dst_ugen == NULL || src_ugen == NULL ) goto null_pointer;
dst_ugen->add( src_ugen, m_isUpChuck );
}
}
else if( num_out > 1 && num_in == 1 )
{
Chuck_UGen * dst_ugen = ugen_generic_get_dst_nochan( dst_obj, 0, m_dstIsArray );
for( t_CKINT i = 0; i < num_out; i++ )
{
Chuck_UGen * src_ugen = ugen_generic_get_src_nochan( src_obj, i, m_srcIsArray );
if( dst_ugen == NULL || src_ugen == NULL ) goto null_pointer;
dst_ugen->add( src_ugen, m_isUpChuck );
}
}
else if( num_out > 1 && num_in > 1 )
{
// find greater
t_CKINT greater = ck_max( num_out, num_in );
// map one to one, up to greater (lesser should modulo)
for( t_CKINT i = 0; i < greater; i++ )
{
Chuck_UGen * src_ugen = ugen_generic_get_src_nochan( src_obj, i, m_srcIsArray );
Chuck_UGen * dst_ugen = ugen_generic_get_dst_nochan( dst_obj, i, m_dstIsArray );
if( dst_ugen == NULL || src_ugen == NULL ) goto null_pointer;
dst_ugen->add( src_ugen, m_isUpChuck );
}
}

// push the second
Expand Down
6 changes: 3 additions & 3 deletions src/core/chuck_instr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4072,14 +4072,14 @@ struct Chuck_Instr_UGen_Link : public Chuck_Instr
struct Chuck_Instr_UGen_Array_Link : public Chuck_Instr
{
public:
Chuck_Instr_UGen_Array_Link( t_CKBOOL srcIsArray, t_CKBOOL dstIsArray ) :
m_srcIsArray(srcIsArray), m_dstIsArray(dstIsArray)
Chuck_Instr_UGen_Array_Link( t_CKBOOL srcIsArray, t_CKBOOL dstIsArray, t_CKBOOL isUpChuck = FALSE ) :
m_srcIsArray(srcIsArray), m_dstIsArray(dstIsArray), m_isUpChuck(isUpChuck)
{ }

virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );

protected:
t_CKBOOL m_srcIsArray, m_dstIsArray;
t_CKBOOL m_srcIsArray, m_dstIsArray, m_isUpChuck;
};


Expand Down
4 changes: 2 additions & 2 deletions src/core/chuck_lang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ t_CKBOOL init_class_ugen( Chuck_Env * env, Chuck_Type * type )

// add isConnectedTo
func = make_new_mfun( "int", "isConnectedTo", ugen_connected );
func->add_arg( "UGen", "right" );
func->doc = "return true if this UGen's output is connected to the input of the argument; return false otherwise.";
func->add_arg( "UGen", "rhs" );
func->doc = "return true if this UGen's output is connected to the input of rhs; if either this UGen or rhs has more than one channel, this function returns true if any connections exist between the channels; return false if there are no connections.";
if( !type_engine_import_mfun( env, func ) ) goto error;

// add buffered
Expand Down
130 changes: 120 additions & 10 deletions src/core/chuck_ugen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,8 +844,27 @@ t_CKBOOL Chuck_UGen::disconnect( t_CKBOOL recursive )
//-----------------------------------------------------------------------------
t_CKBOOL Chuck_UGen::is_connected_from( Chuck_UGen * src )
{
if( m_src_list != NULL && fa_lookup( m_src_list, m_num_src, src ) )
return TRUE;
// check for NULL
if( !src ) return FALSE;

// if we have src list
if( m_src_list != NULL )
{
// check if src in src list
if( fa_lookup( m_src_list, m_num_src, src ) )
return TRUE;

// if src is multichannel
if( src->m_multi_chan )
{
for( t_CKUINT i = 0; i < src->m_multi_chan_size; i++ )
{
// check if src multi-chan in src list
if( fa_lookup( m_src_list, m_num_src, src->m_multi_chan[i] ) )
return TRUE;
}
}
}

// multichannel
if( m_multi_chan != NULL )
Expand All @@ -855,6 +874,19 @@ t_CKBOOL Chuck_UGen::is_connected_from( Chuck_UGen * src )
if( fa_lookup( m_multi_chan[i]->m_src_list,
m_multi_chan[i]->m_num_src, src ) )
return TRUE;

// if src is multichannel
if( src->m_multi_chan )
{
for( t_CKUINT j = 0; j < src->m_multi_chan_size; j++ )
{
// check if src multi-chan in src list
if( fa_lookup( m_multi_chan[i]->m_src_list,
m_multi_chan[i]->m_num_src,
src->m_multi_chan[j] ) )
return TRUE;
}
}
}
}

Expand Down Expand Up @@ -1604,25 +1636,37 @@ t_CKBOOL Chuck_UAna::system_tock( t_CKTIME now )
//-----------------------------------------------------------------------------
t_CKINT ugen_generic_num_in( Chuck_Object * obj, t_CKBOOL isArray )
{
if(isArray)
return ((Chuck_ArrayInt *) obj)->size();
else
return ((Chuck_UGen *) obj)->m_num_ins;
if( isArray ) return ((Chuck_ArrayInt *)obj)->size();
else return ((Chuck_UGen *)obj)->m_num_ins;
}




//-----------------------------------------------------------------------------
// name: ugen_generic_num_out()
// dsec: get number of output channels for ugen or ugen array | 1.5.2.2 (ge)
//-----------------------------------------------------------------------------
t_CKINT ugen_generic_num_out( Chuck_Object * obj, t_CKBOOL isArray )
{
if( isArray ) return ((Chuck_ArrayInt *)obj)->size();
else return ((Chuck_UGen *)obj)->m_num_outs;
}




//-----------------------------------------------------------------------------
// name: ugen_generic_get_src()
// dsec: get source channel given a ugen or ugen array
//-----------------------------------------------------------------------------
Chuck_UGen *ugen_generic_get_src( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
Chuck_UGen * ugen_generic_get_src( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
{
if( isArray )
{
Chuck_ArrayInt *arr = (Chuck_ArrayInt *) obj;
Chuck_UGen *src = NULL;
arr->get( chan%arr->size(), (t_CKUINT *) &src );
arr->get( chan%arr->size(), (t_CKUINT *)(&src) );
return src;
}
else
Expand All @@ -1637,13 +1681,13 @@ Chuck_UGen *ugen_generic_get_src( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isA
// name: ugen_generic_get_dst()
// dsec: get destination channel given a ugen or array object
//-----------------------------------------------------------------------------
Chuck_UGen *ugen_generic_get_dst( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
Chuck_UGen * ugen_generic_get_dst( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
{
if( isArray )
{
Chuck_ArrayInt *arr = (Chuck_ArrayInt *) obj;
Chuck_UGen *dst = NULL;
( (Chuck_ArrayInt *) obj )->get( chan%arr->size(), (t_CKUINT *) &dst );
((Chuck_ArrayInt *)obj)->get( chan%arr->size(), (t_CKUINT *)(&dst) );
return dst;
}
else
Expand All @@ -1654,3 +1698,69 @@ Chuck_UGen *ugen_generic_get_dst( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isA




//-----------------------------------------------------------------------------
// name: ugen_generic_num_in_nochan()
// dsec: get number of input channels for ugen or ugen array
//-----------------------------------------------------------------------------
t_CKINT ugen_generic_num_in_nochan( Chuck_Object * obj, t_CKBOOL isArray )
{
if( isArray ) return ((Chuck_ArrayInt *)obj)->size();
else return 1;
}




//-----------------------------------------------------------------------------
// name: ugen_generic_num_out_nochan()
// dsec: get number of output channels for ugen or ugen array | 1.5.2.2 (ge)
//-----------------------------------------------------------------------------
t_CKINT ugen_generic_num_out_nochan( Chuck_Object * obj, t_CKBOOL isArray )
{
if( isArray ) return ((Chuck_ArrayInt *)obj)->size();
else return 1;
}




//-----------------------------------------------------------------------------
// name: ugen_generic_get_src_nochan()
// dsec: get source channel given a ugen or ugen array
//-----------------------------------------------------------------------------
Chuck_UGen * ugen_generic_get_src_nochan( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
{
if( isArray )
{
Chuck_ArrayInt *arr = (Chuck_ArrayInt *) obj;
Chuck_UGen *src = NULL;
arr->get( chan%arr->size(), (t_CKUINT *)(&src) );
return src;
}
else
{
return ((Chuck_UGen *)obj);
}
}



//-----------------------------------------------------------------------------
// name: ugen_generic_get_dst_nochan()
// dsec: get destination channel given a ugen or array object
//-----------------------------------------------------------------------------
Chuck_UGen * ugen_generic_get_dst_nochan( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray )
{
if( isArray )
{
Chuck_ArrayInt *arr = (Chuck_ArrayInt *) obj;
Chuck_UGen *dst = NULL;
((Chuck_ArrayInt *)obj)->get( chan%arr->size(), (t_CKUINT *)(&dst) );
return dst;
}
else
{
return ((Chuck_UGen *)obj);
}
}
16 changes: 11 additions & 5 deletions src/core/chuck_ugen.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,17 @@ struct Chuck_UAna : public Chuck_UGen
};



t_CKINT ugen_generic_num_in( Chuck_Object * obj, t_CKBOOL isArray );
Chuck_UGen *ugen_generic_get_src( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );
Chuck_UGen *ugen_generic_get_dst( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );

// helper functions for abstracting input/output between arrays and multichan
//t_CKINT ugen_generic_num_out( Chuck_Object * obj, t_CKBOOL isArray );
//t_CKINT ugen_generic_num_in( Chuck_Object * obj, t_CKBOOL isArray );
//Chuck_UGen *ugen_generic_get_src( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );
//Chuck_UGen *ugen_generic_get_dst( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );

// helper functions for abstracting input/output between arrays and ugen (no channel distinction)
t_CKINT ugen_generic_num_out_nochan( Chuck_Object * obj, t_CKBOOL isArray );
t_CKINT ugen_generic_num_in_nochan( Chuck_Object * obj, t_CKBOOL isArray );
Chuck_UGen *ugen_generic_get_src_nochan( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );
Chuck_UGen *ugen_generic_get_dst_nochan( Chuck_Object * obj, t_CKINT chan, t_CKBOOL isArray );


#endif
Loading

0 comments on commit d070fa8

Please sign in to comment.