bdcb26ac72
Added is_connected_to_source_proc(), var_is_source() and is_source_var().
1668 lines
52 KiB
C++
1668 lines
52 KiB
C++
#include "cwCommon.h"
|
|
#include "cwLog.h"
|
|
#include "cwCommonImpl.h"
|
|
#include "cwMem.h"
|
|
#include "cwText.h"
|
|
#include "cwObject.h"
|
|
#include "cwVectOps.h"
|
|
#include "cwMtx.h"
|
|
#include "cwDspTypes.h" // real_t, sample_t
|
|
#include "cwTime.h"
|
|
#include "cwMidiDecls.h"
|
|
#include "cwFlowDecl.h"
|
|
#include "cwFlow.h"
|
|
#include "cwFlowTypes.h"
|
|
|
|
|
|
namespace cw
|
|
{
|
|
namespace flow
|
|
{
|
|
idLabelPair_t typeLabelFlagsA[] = {
|
|
|
|
{ kBoolTFl, "bool" },
|
|
{ kUIntTFl, "uint" },
|
|
{ kIntTFl, "int", },
|
|
{ kFloatTFl, "float"},
|
|
{ kDoubleTFl,"double"},
|
|
|
|
{ kBoolMtxTFl, "bool_mtx" },
|
|
{ kUIntMtxTFl, "uint_mtx" },
|
|
{ kIntMtxTFl, "int_mtx" },
|
|
{ kFloatMtxTFl, "float_mtx" },
|
|
{ kDoubleMtxTFl,"double_mtx" },
|
|
|
|
{ kABufTFl, "audio" },
|
|
{ kFBufTFl, "spectrum" },
|
|
{ kMBufTFl, "midi" },
|
|
{ kStringTFl, "string" },
|
|
{ kTimeTFl, "time" },
|
|
{ kCfgTFl, "cfg" },
|
|
|
|
// alias types to map to cwDspTypes.h
|
|
{ kFloatTFl, "srate"},
|
|
{ kFloatTFl, "sample"},
|
|
{ kFloatTFl, "coeff"},
|
|
{ kDoubleTFl, "ftime" },
|
|
|
|
{ kInvalidTFl, nullptr }
|
|
};
|
|
|
|
const char* _typeFlagToLabel( unsigned flag )
|
|
{
|
|
for(unsigned i=0; typeLabelFlagsA[i].id != kInvalidTFl; ++i)
|
|
if( typeLabelFlagsA[i].id == flag )
|
|
return typeLabelFlagsA[i].label;
|
|
|
|
return "<unknown-type>";
|
|
}
|
|
|
|
|
|
void _value_release( value_t* v )
|
|
{
|
|
if( v == nullptr )
|
|
return;
|
|
|
|
switch( v->flags & kTypeMask )
|
|
{
|
|
case kInvalidTFl:
|
|
break;
|
|
|
|
case kBoolTFl:
|
|
case kUIntTFl:
|
|
case kIntTFl:
|
|
case kFloatTFl:
|
|
case kDoubleTFl:
|
|
break;
|
|
|
|
case kABufTFl:
|
|
abuf_destroy( v->u.abuf );
|
|
break;
|
|
|
|
case kFBufTFl:
|
|
fbuf_destroy( v->u.fbuf );
|
|
break;
|
|
|
|
case kMBufTFl:
|
|
mbuf_destroy( v->u.mbuf );
|
|
break;
|
|
|
|
case kBoolMtxTFl:
|
|
case kUIntMtxTFl:
|
|
case kIntMtxTFl:
|
|
case kFloatMtxTFl:
|
|
case kDoubleMtxTFl:
|
|
assert(0); // not implemeneted
|
|
break;
|
|
|
|
case kStringTFl:
|
|
mem::release( v->u.s );
|
|
break;
|
|
|
|
case kTimeTFl:
|
|
assert(0);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
v->flags = kInvalidTFl;
|
|
}
|
|
|
|
void _value_duplicate( value_t& dst, const value_t& src )
|
|
{
|
|
switch( src.flags & kTypeMask )
|
|
{
|
|
case kInvalidTFl:
|
|
break;
|
|
|
|
case kBoolTFl:
|
|
case kUIntTFl:
|
|
case kIntTFl:
|
|
case kFloatTFl:
|
|
case kDoubleTFl:
|
|
dst = src;
|
|
break;
|
|
|
|
case kABufTFl:
|
|
|
|
dst.u.abuf = src.u.abuf == nullptr ? nullptr : abuf_duplicate(src.u.abuf);
|
|
dst.flags = src.flags;
|
|
break;
|
|
|
|
case kFBufTFl:
|
|
dst.u.fbuf = src.u.fbuf == nullptr ? nullptr : fbuf_duplicate(src.u.fbuf);
|
|
dst.flags = src.flags;
|
|
break;
|
|
|
|
case kMBufTFl:
|
|
dst.u.mbuf = src.u.mbuf == nullptr ? nullptr : mbuf_duplicate(src.u.mbuf);
|
|
dst.flags = src.flags;
|
|
break;
|
|
|
|
case kBoolMtxTFl:
|
|
case kUIntMtxTFl:
|
|
case kIntMtxTFl:
|
|
case kFloatMtxTFl:
|
|
case kDoubleMtxTFl:
|
|
assert(0); // not implemeneted
|
|
break;
|
|
|
|
case kStringTFl:
|
|
dst.u.s = mem::duplStr( dst.u.s );
|
|
dst.flags = src.flags;
|
|
break;
|
|
|
|
case kTimeTFl:
|
|
assert(0);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void _value_print( const value_t* v )
|
|
{
|
|
if( v == nullptr )
|
|
return;
|
|
|
|
switch( v->flags & kTypeMask )
|
|
{
|
|
case kInvalidTFl:
|
|
break;
|
|
|
|
case kBoolTFl: printf("%s ", v->u.b ? "True" : "False" ); break;
|
|
case kUIntTFl: printf("%i ", v->u.u ); break;
|
|
case kIntTFl: printf("%i ", v->u.i ); break;
|
|
case kFloatTFl: printf("%f ", v->u.f ); break;
|
|
case kDoubleTFl:printf("%f ", v->u.d ); break;
|
|
case kABufTFl:
|
|
if( v->u.abuf == nullptr )
|
|
printf("abuf: <null>");
|
|
else
|
|
printf("abuf: chN:%i frameN:%i srate:%8.1f ", v->u.abuf->chN, v->u.abuf->frameN, v->u.abuf->srate );
|
|
break;
|
|
|
|
case kFBufTFl:
|
|
if( v->u.fbuf == nullptr )
|
|
printf("fbuf: <null>");
|
|
else
|
|
{
|
|
printf("fbuf: chN:%i srate:%8.1f ", v->u.fbuf->chN, v->u.fbuf->srate );
|
|
for(unsigned i=0; i<v->u.fbuf->chN; ++i)
|
|
printf("(binN:%i hopSmpN:%i) ", v->u.fbuf->binN_V[i], v->u.fbuf->hopSmpN_V[i] );
|
|
}
|
|
break;
|
|
|
|
case kMBufTFl:
|
|
if( v->u.mbuf == nullptr )
|
|
printf("mbuf: <null>");
|
|
else
|
|
{
|
|
printf("mbuf: cnt: %i", v->u.mbuf->msgN );
|
|
}
|
|
break;
|
|
|
|
case kBoolMtxTFl:
|
|
case kUIntMtxTFl:
|
|
case kIntMtxTFl:
|
|
case kFloatMtxTFl:
|
|
case kDoubleMtxTFl:
|
|
assert(0); // not implemeneted
|
|
break;
|
|
|
|
case kStringTFl:
|
|
printf("%s ", v->u.s);
|
|
break;
|
|
|
|
case kTimeTFl:
|
|
assert(0);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
rc_t _val_get( const value_t* val, bool& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
switch( val->flags & kTypeMask )
|
|
{
|
|
case kBoolTFl: valRef = val->u.b; break;
|
|
case kUIntTFl: valRef = val->u.u!=0; break;
|
|
case kIntTFl: valRef = val->u.i!=0; break;
|
|
case kFloatTFl: valRef = val->u.f!=0; break;
|
|
case kDoubleTFl: valRef = val->u.d!=0; break;
|
|
default:
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a bool.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( const value_t* val, uint_t& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
switch( val->flags & kTypeMask )
|
|
{
|
|
case kBoolTFl: valRef = val->u.b ? 1 : 0; break;
|
|
case kUIntTFl: valRef = val->u.u; break;
|
|
case kIntTFl: valRef = val->u.i; break;
|
|
case kFloatTFl: valRef = (uint_t)val->u.f; break;
|
|
case kDoubleTFl: valRef = (uint_t)val->u.d; break;
|
|
default:
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a uint_t.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( const value_t* val, int_t& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
switch( val->flags & kTypeMask )
|
|
{
|
|
case kBoolTFl: valRef = val->u.b ? 1 : 0; break;
|
|
case kUIntTFl: valRef = (int_t)val->u.u; break;
|
|
case kIntTFl: valRef = val->u.i; break;
|
|
case kFloatTFl: valRef = (int_t)val->u.f; break;
|
|
case kDoubleTFl: valRef = (int_t)val->u.d; break;
|
|
default:
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a int_t.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( const value_t* val, float& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
switch( val->flags & kTypeMask )
|
|
{
|
|
case kBoolTFl: valRef = val->u.b ? 1 : 0; break;
|
|
case kUIntTFl: valRef = (float)val->u.u; break;
|
|
case kIntTFl: valRef = (float)val->u.i; break;
|
|
case kFloatTFl: valRef = (float)val->u.f; break;
|
|
case kDoubleTFl: valRef = (float)val->u.d; break;
|
|
default:
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a float.", val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( const value_t* val, double& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
switch( val->flags & kTypeMask )
|
|
{
|
|
case kBoolTFl: valRef = val->u.b ? 1 : 0; break;
|
|
case kUIntTFl: valRef = (double)val->u.u; break;
|
|
case kIntTFl: valRef = (double)val->u.i; break;
|
|
case kFloatTFl: valRef = (double)val->u.f; break;
|
|
case kDoubleTFl: valRef = val->u.d; break;
|
|
default:
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a double.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( const value_t* val, const char*& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
if( cwIsFlag(val->flags & kTypeMask, kStringTFl) )
|
|
valRef = val->u.s;
|
|
else
|
|
{
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a string.",val->flags);
|
|
valRef = nullptr;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, abuf_t*& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
if( cwIsFlag(val->flags & kTypeMask, kABufTFl) )
|
|
valRef = val->u.abuf;
|
|
else
|
|
{
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to an abuf_t.",val->flags);
|
|
valRef = nullptr;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, const abuf_t*& valRef )
|
|
{
|
|
abuf_t* non_const_val;
|
|
rc_t rc = kOkRC;
|
|
if((rc = _val_get(val,non_const_val)) == kOkRC )
|
|
valRef = non_const_val;
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, fbuf_t*& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
if( cwIsFlag(val->flags & kTypeMask, kFBufTFl) )
|
|
valRef = val->u.fbuf;
|
|
else
|
|
{
|
|
valRef = nullptr;
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to an fbuf_t.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, const fbuf_t*& valRef )
|
|
{
|
|
fbuf_t* non_const_val;
|
|
rc_t rc = kOkRC;
|
|
if((rc = _val_get(val,non_const_val)) == kOkRC )
|
|
valRef = non_const_val;
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, mbuf_t*& valRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
if( cwIsFlag(val->flags & kTypeMask, kMBufTFl) )
|
|
valRef = val->u.mbuf;
|
|
else
|
|
{
|
|
valRef = nullptr;
|
|
rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to an mbuf_t.",val->flags);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
rc_t _val_get( value_t* val, const mbuf_t*& valRef )
|
|
{
|
|
mbuf_t* non_const_val;
|
|
rc_t rc = kOkRC;
|
|
if((rc = _val_get(val,non_const_val)) == kOkRC )
|
|
valRef = non_const_val;
|
|
return rc;
|
|
}
|
|
|
|
|
|
template< typename T >
|
|
rc_t _val_get_driver( const variable_t* var, T& valRef )
|
|
{
|
|
if( var == nullptr )
|
|
return cwLogError(kInvalidArgRC,"Cannnot get the value of a non-existent variable.");
|
|
|
|
if( var->value == nullptr )
|
|
return cwLogError(kInvalidStateRC,"No value has been assigned to the variable: %s:%i.%s:%i ch:%i.",cwStringNullGuard(var->inst->label),var->inst->label_sfx_id,cwStringNullGuard(var->label),var->label_sfx_id,var->chIdx);
|
|
|
|
return _val_get(var->value,valRef);
|
|
}
|
|
|
|
rc_t _var_find_to_set( instance_t* inst, unsigned vid, unsigned chIdx, unsigned typeFl, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
varRef = nullptr;
|
|
|
|
//
|
|
if((rc = var_find(inst,vid,chIdx,varRef)) == kOkRC )
|
|
{
|
|
// validate the type of the variable against the description
|
|
if( !cwIsFlag(varRef->varDesc->type,typeFl ) )
|
|
rc = cwLogError(kTypeMismatchRC,"Type mismatch. Instance:%s:%i variable:%s:%i with type 0x%x does not match requested type:0x%x.",varRef->inst->label,varRef->inst->label_sfx_id,varRef->label,varRef->label_sfx_id,varRef->varDesc->type,typeFl);
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
// Variable lookup: Exact match on vid and chIdx
|
|
rc_t _var_find_on_vid_and_ch( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef )
|
|
{
|
|
varRef = nullptr;
|
|
|
|
for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link)
|
|
{
|
|
// the variable vid and chIdx should form a unique pair
|
|
if( var->vid==vid && var->chIdx == chIdx )
|
|
{
|
|
varRef = var;
|
|
return kOkRC;
|
|
}
|
|
}
|
|
return cwLogError(kInvalidIdRC,"The variable matching id:%i ch:%i on instance '%s:%i' could not be found.", vid, chIdx, inst->label, inst->label_sfx_id);
|
|
}
|
|
|
|
// Variable lookup: Exact match on label and chIdx
|
|
variable_t* _var_find_on_label_and_ch( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx )
|
|
{
|
|
for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link)
|
|
{
|
|
// the variable vid and chIdx should form a unique pair
|
|
if( var->label_sfx_id==sfx_id && textCompare(var->label,var_label)==0 && var->chIdx == chIdx )
|
|
return var;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
rc_t _validate_var_assignment( variable_t* var, unsigned typeFl )
|
|
{
|
|
if( cwIsFlag(var->varDesc->flags, kSrcVarFl ) )
|
|
return cwLogError(kInvalidStateRC, "The variable '%s:%i' on instance '%s:%i' cannot be set because it is a 'src' variable.", var->label, var->label_sfx_id, var->inst->label,var->inst->label_sfx_id);
|
|
|
|
if( !cwIsFlag(var->varDesc->type, typeFl ) )
|
|
return cwLogError(kTypeMismatchRC, "The variable '%s:%i' on instance '%s:%i' is not a '%s'.", var->label, var->label_sfx_id, var->inst->label, var->inst->label_sfx_id, _typeFlagToLabel( typeFl ));
|
|
|
|
return kOkRC;
|
|
}
|
|
|
|
rc_t _var_broadcast_new_value( variable_t* var )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
// notify each connected var that the value has changed
|
|
for(variable_t* con_var = var->connect_link; con_var!=nullptr; con_var=con_var->connect_link)
|
|
{
|
|
// the var->local_value[] slot used by the source variable may have changed - update the destination variable
|
|
// so that it points to the correct value.
|
|
con_var->value = var->value;
|
|
|
|
//if((rc = con_var->inst->class_desc->members->value( con_var->inst, con_var )) != kOkRC )
|
|
// break;
|
|
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
template< typename T >
|
|
void _var_setter( variable_t* var, unsigned local_value_idx, T val )
|
|
{
|
|
cwLogError(kAssertFailRC,"Unimplemented variable setter.");
|
|
assert(0);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<bool>( variable_t* var, unsigned local_value_idx, bool val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.b = val;
|
|
var->local_value[ local_value_idx ].flags = kBoolTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %i (bool).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<unsigned>( variable_t* var, unsigned local_value_idx, unsigned val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.u = val;
|
|
var->local_value[ local_value_idx ].flags = kUIntTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %i (uint).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<int>( variable_t* var, unsigned local_value_idx, int val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.i = val;
|
|
var->local_value[ local_value_idx ].flags = kIntTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %i (int).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<float>( variable_t* var, unsigned local_value_idx, float val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.f = val;
|
|
var->local_value[ local_value_idx ].flags = kFloatTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %f (float).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<double>( variable_t* var, unsigned local_value_idx, double val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.d = val;
|
|
var->local_value[ local_value_idx ].flags = kDoubleTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %f (double).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<const char*>( variable_t* var, unsigned local_value_idx, const char* val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.s = mem::duplStr(val);
|
|
var->local_value[ local_value_idx ].flags = kStringTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %s (string).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,val);
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<abuf_t*>( variable_t* var, unsigned local_value_idx, abuf_t* val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.abuf = val;
|
|
var->local_value[ local_value_idx ].flags = kABufTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %s (abuf).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,abuf==nullptr ? "null" : "valid");
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<mbuf_t*>( variable_t* var, unsigned local_value_idx, mbuf_t* val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.mbuf = val;
|
|
var->local_value[ local_value_idx ].flags = kMBufTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %s (abuf).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,mbuf==nullptr ? "null" : "valid");
|
|
}
|
|
|
|
template<>
|
|
void _var_setter<fbuf_t*>( variable_t* var, unsigned local_value_idx, fbuf_t* val )
|
|
{
|
|
var->local_value[ local_value_idx ].u.fbuf = val;
|
|
var->local_value[ local_value_idx ].flags = kFBufTFl;
|
|
cwLogMod("%s:%i.%s:%i ch:%i %s (fbuf).",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,var->chIdx,fbuf==nullptr ? "null" : "valid");
|
|
}
|
|
|
|
template< typename T >
|
|
rc_t _var_set_template( variable_t* var, unsigned typeFlag, T val )
|
|
{
|
|
rc_t rc;
|
|
|
|
unsigned next_local_value_idx = (var->local_value_idx + 1) % kLocalValueN;
|
|
|
|
// store the pointer to the current value of this variable
|
|
value_t* original_value = var->value;
|
|
unsigned original_value_idx = var->local_value_idx;
|
|
|
|
// verify that this is a legal assignment
|
|
if((rc = _validate_var_assignment( var, typeFlag )) != kOkRC )
|
|
{
|
|
goto errLabel;
|
|
}
|
|
|
|
// release the previous value in the next slot
|
|
_value_release(&var->local_value[next_local_value_idx]);
|
|
|
|
// set the new local value
|
|
_var_setter(var,next_local_value_idx,val);
|
|
|
|
// make the new local value current
|
|
var->value = var->local_value + next_local_value_idx;
|
|
var->local_value_idx = next_local_value_idx;
|
|
|
|
// If the instance is fully initialized ...
|
|
if( var->inst->varMapA != nullptr )
|
|
{
|
|
// ... then inform the proc. that the value changed
|
|
// Note 1: We don't want to this call to occur if we are inside or prior to 'proc.create()'
|
|
// call because calls' to 'proc.value()' will see the instance in a incomplete state)
|
|
// Note 2: If this call returns an error then the value assignment is cancelled
|
|
// and the value does not change.
|
|
rc = var->inst->class_desc->members->value( var->inst, var );
|
|
}
|
|
|
|
if( rc == kOkRC )
|
|
{
|
|
// send the value to connected downstream proc's
|
|
rc = _var_broadcast_new_value( var );
|
|
}
|
|
else
|
|
{
|
|
// cancel the assignment and restore the original value
|
|
var->value = original_value;
|
|
var->local_value_idx = original_value_idx;
|
|
}
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
|
|
bool is_connected_to_source_proc( const variable_t* var )
|
|
{
|
|
// if this var does not have a 'src_ptr' then it can't be connected to an external proc
|
|
if( var->src_var == nullptr || var->value == nullptr )
|
|
return false;
|
|
|
|
// if this var is using a local value then it can't be connected to an external proc
|
|
for(unsigned i=0; i<kLocalValueN; ++i)
|
|
if( var->value == var->local_value + i )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool is_a_source_var( const variable_t* var )
|
|
{ return var->connect_link != nullptr; }
|
|
|
|
template< typename T >
|
|
rc_t _var_set_driver( variable_t* var, unsigned typeFlag, T value )
|
|
{
|
|
rc_t rc;
|
|
|
|
// if this variable is fed from the output of an external proc - then it's local value cannot be set
|
|
if(is_connected_to_source_proc(var) )
|
|
return kOkRC;
|
|
|
|
|
|
// if this assignment targets a specific channel ...
|
|
if( var->chIdx != kAnyChIdx )
|
|
{
|
|
rc = _var_set_template( var, typeFlag, value ); // ... then set it alone
|
|
}
|
|
else // ... otherwise set all channels.
|
|
{
|
|
for(; var!=nullptr; var=var->ch_link)
|
|
if((rc = _var_set_template( var, typeFlag, value )) != kOkRC)
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, abuf_t* abuf )
|
|
{
|
|
rc_t rc;
|
|
variable_t* var = nullptr;
|
|
if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC )
|
|
return rc;
|
|
|
|
if( var != nullptr )
|
|
_var_set_driver( var, kABufTFl, abuf );
|
|
|
|
return rc;
|
|
}
|
|
|
|
rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, mbuf_t* mbuf )
|
|
{
|
|
rc_t rc;
|
|
variable_t* var = nullptr;
|
|
if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC )
|
|
return rc;
|
|
|
|
if( var != nullptr )
|
|
_var_set_driver( var, kMBufTFl, mbuf );
|
|
|
|
return rc;
|
|
}
|
|
|
|
rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, fbuf_t* fbuf )
|
|
{
|
|
rc_t rc;
|
|
variable_t* var = nullptr;
|
|
if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC )
|
|
return rc;
|
|
|
|
if( var != nullptr )
|
|
_var_set_driver( var, kFBufTFl, fbuf );
|
|
|
|
return rc;
|
|
}
|
|
|
|
rc_t _set_var_value_from_cfg( variable_t* var, const object_t* value )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
// get the variable type - note that the value type (value->flags) may be differnt
|
|
unsigned typeFlag = var->varDesc->type & kTypeMask;
|
|
|
|
switch( typeFlag )
|
|
{
|
|
case kBoolTFl:
|
|
{
|
|
bool v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
case kUIntTFl:
|
|
{
|
|
unsigned v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
case kIntTFl:
|
|
{
|
|
int v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
case kFloatTFl:
|
|
{
|
|
float v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
case kDoubleTFl:
|
|
{
|
|
double v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
case kStringTFl:
|
|
{
|
|
const char* v;
|
|
if((rc = value->value(v)) == kOkRC )
|
|
rc = _var_set_driver( var, typeFlag, v );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rc = cwLogError(kOpFailRC,"The variable type 0x%x cannot yet be set via a preset.", var->varDesc->type );
|
|
goto errLabel;
|
|
}
|
|
|
|
errLabel:
|
|
if( rc != kOkRC )
|
|
rc = cwLogError(kSyntaxErrorRC,"The %s:%i.%s:%i could not extract a type:%s from a configuration value.",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,_typeFlagToLabel(var->varDesc->type & kTypeMask));
|
|
return rc;
|
|
|
|
}
|
|
|
|
rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef )
|
|
{
|
|
unsigned idx = vid * inst->varMapChN + (chIdx == kAnyChIdx ? 0 : (chIdx+1));
|
|
|
|
// verify that the map idx is valid
|
|
if( idx >= inst->varMapN )
|
|
return cwLogError(kAssertFailRC,"The variable map positioning location %i is out of the range %i on instance '%s:%i' vid:%i ch:%i.", idx, inst->varMapN, inst->label,inst->label_sfx_id,vid,chIdx);
|
|
|
|
idxRef = idx;
|
|
|
|
return kOkRC;
|
|
}
|
|
|
|
rc_t _var_map_label_to_index( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, unsigned& idxRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
idxRef = kInvalidIdx;
|
|
if((rc = var_find(inst, var_label, sfx_id, chIdx, var )) == kOkRC)
|
|
rc = _var_map_id_to_index( inst, var->vid, chIdx, idxRef );
|
|
|
|
return rc;
|
|
}
|
|
|
|
rc_t _var_add_to_ch_list( instance_t* inst, variable_t* new_var )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
variable_t* base_var = nullptr;
|
|
variable_t* v0 = nullptr;
|
|
variable_t* v1 = nullptr;
|
|
|
|
if( new_var->chIdx == kAnyChIdx )
|
|
return kOkRC;
|
|
|
|
if((base_var = _var_find_on_label_and_ch( inst, new_var->label, new_var->label_sfx_id, kAnyChIdx )) == nullptr )
|
|
{
|
|
rc = cwLogError(kInvalidStateRC,"The base channel variable does not exist for '%s:%i.%s:%i'. This is an illegal state.", inst->label, inst->label_sfx_id, new_var->label, new_var->label_sfx_id );
|
|
goto errLabel;
|
|
}
|
|
|
|
// insert v0 in order by channel number
|
|
for(v0=base_var,v1=base_var->ch_link; v1!=nullptr; v1=v1->ch_link)
|
|
{
|
|
if( v1->chIdx > new_var->chIdx )
|
|
break;
|
|
v0 = v1;
|
|
}
|
|
|
|
// the new var channel index should never match the previous or next channel index
|
|
assert( v0->chIdx != new_var->chIdx && (v1==nullptr || v1->chIdx != new_var->chIdx ) );
|
|
|
|
new_var->ch_link = v1;
|
|
v0->ch_link = new_var;
|
|
|
|
|
|
errLabel:
|
|
return rc;
|
|
|
|
}
|
|
|
|
// Create a variable and set it's value from 'value_cfg'.
|
|
// If 'value_cfg' is null then use the value from var->varDesc->val_cfg.
|
|
rc_t _var_create( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned id, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
var_desc_t* vd = nullptr;
|
|
|
|
varRef = nullptr;
|
|
|
|
// if this var already exists - it can't be created again
|
|
if((var = _var_find_on_label_and_ch(inst,var_label, sfx_id, chIdx)) != nullptr )
|
|
{
|
|
rc = cwLogError(kInvalidStateRC,"The variable '%s:%i' ch:%i has already been created on the instance: '%s:%i'.",var_label,sfx_id,chIdx,inst->label,inst->label_sfx_id);
|
|
goto errLabel;
|
|
}
|
|
|
|
// locate the var desc
|
|
if((vd = var_desc_find( inst->class_desc, var_label)) == nullptr )
|
|
{
|
|
rc = cwLogError(kInvalidIdRC,"Unable to locate the variable '%s:%i' in class '%s'.", var_label, sfx_id, inst->class_desc->label );
|
|
goto errLabel;
|
|
}
|
|
|
|
// create the var
|
|
var = mem::allocZ<variable_t>();
|
|
|
|
var->varDesc = vd;
|
|
var->inst = inst;
|
|
var->label = mem::duplStr(var_label);
|
|
var->label_sfx_id = sfx_id;
|
|
var->vid = id;
|
|
var->chIdx = chIdx;
|
|
var->value = nullptr;
|
|
|
|
// if no value was given then set the value to the value given in the class
|
|
if( value_cfg == nullptr )
|
|
value_cfg = var->varDesc->val_cfg;
|
|
|
|
// if value_cfg is valid set the variable value
|
|
if( value_cfg != nullptr )
|
|
if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
var->var_link = inst->varL;
|
|
inst->varL = var;
|
|
|
|
// link the new var into the ch_link list
|
|
if((rc = _var_add_to_ch_list(inst, var )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
|
|
errLabel:
|
|
if( rc != kOkRC )
|
|
{
|
|
_var_destroy(var);
|
|
cwLogError(kOpFailRC,"Variable creation failed on '%s:%i.%s:%i' ch:%i.", inst->label, inst->label_sfx_id, var_label, sfx_id, chIdx );
|
|
}
|
|
else
|
|
{
|
|
varRef = var;
|
|
cwLogMod("Created var: %s:%i.%s:%i ch:%i.", inst->label, inst->label_sfx_id, var_label, sfx_id, chIdx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void _var_print( const variable_t* var )
|
|
{
|
|
const char* conn_label = is_connected_to_source_proc(var) ? "extern" : " ";
|
|
|
|
printf(" %20s:%5i id:%4i ch:%3i : %s : ", var->label, var->label_sfx_id, var->vid, var->chIdx, conn_label );
|
|
|
|
if( var->value == nullptr )
|
|
_value_print( &var->local_value[0] );
|
|
else
|
|
_value_print( var->value );
|
|
|
|
if( var->src_var != nullptr )
|
|
printf(" src:%s:%i.%s:%i",var->src_var->inst->label,var->src_var->inst->label_sfx_id,var->src_var->label,var->src_var->label_sfx_id);
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
rc_t _preset_set_var_value( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, const object_t* value )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
// get the variable
|
|
if((rc = var_find( inst, var_label, sfx_id, chIdx, var )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
rc = _set_var_value_from_cfg( var, value );
|
|
|
|
errLabel:
|
|
if( rc != kOkRC )
|
|
rc = cwLogError(rc,"The value of instance:%s:%i variable:%s:%i could not be set via a preset.", inst->label, inst->label_sfx_id, var_label, sfx_id );
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
cw::flow::abuf_t* cw::flow::abuf_create( srate_t srate, unsigned chN, unsigned frameN )
|
|
{
|
|
abuf_t* a = mem::allocZ<abuf_t>();
|
|
a->srate = srate;
|
|
a->chN = chN;
|
|
a->frameN = frameN;
|
|
a->buf = mem::allocZ<sample_t>( chN*frameN );
|
|
|
|
return a;
|
|
}
|
|
|
|
void cw::flow::abuf_destroy( abuf_t*& abuf )
|
|
{
|
|
if( abuf == nullptr )
|
|
return;
|
|
|
|
mem::release(abuf->buf);
|
|
mem::release(abuf);
|
|
}
|
|
|
|
cw::flow::abuf_t* cw::flow::abuf_duplicate( const abuf_t* src )
|
|
{
|
|
return abuf_create( src->srate, src->chN, src->frameN );
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::abuf_set_channel( abuf_t* abuf, unsigned chIdx, const sample_t* v, unsigned vN )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
if( vN > abuf->frameN )
|
|
rc = cwLogError(kInvalidArgRC,"Cannot copy source vector of length %i into an abuf of length %i.", vN, abuf->frameN);
|
|
else
|
|
if( chIdx > abuf->chN )
|
|
rc = cwLogError(kInvalidArgRC,"The abuf destination channel %i is out of range.", chIdx);
|
|
else
|
|
vop::copy( abuf->buf + (chIdx*abuf->frameN), v, vN);
|
|
|
|
return rc;
|
|
}
|
|
|
|
const cw::flow::sample_t* cw::flow::abuf_get_channel( abuf_t* abuf, unsigned chIdx )
|
|
{
|
|
assert( abuf->buf != nullptr );
|
|
return abuf->buf + (chIdx*abuf->frameN);
|
|
}
|
|
|
|
cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_sample_t** magV, const fd_sample_t** phsV, const fd_sample_t** hzV )
|
|
{
|
|
for(unsigned i=0; i<chN; ++i)
|
|
if( binN_V[i] > maxBinN_V[i] )
|
|
{
|
|
cwLogError(kInvalidArgRC,"A channel bin count (%i) execeeds the max bin count (%i).",binN_V[i],maxBinN_V[i]);
|
|
return nullptr;;
|
|
}
|
|
|
|
fbuf_t* f = mem::allocZ<fbuf_t>();
|
|
|
|
f->srate = srate;
|
|
f->chN = chN;
|
|
f->maxBinN_V = mem::allocZ<unsigned>(chN);
|
|
f->binN_V = mem::allocZ<unsigned>(chN);
|
|
f->hopSmpN_V = mem::allocZ<unsigned>(chN);
|
|
f->magV = mem::allocZ<fd_sample_t*>(chN);
|
|
f->phsV = mem::allocZ<fd_sample_t*>(chN);
|
|
f->hzV = mem::allocZ<fd_sample_t*>(chN);
|
|
f->readyFlV = mem::allocZ<bool>(chN);
|
|
|
|
vop::copy( f->binN_V, binN_V, chN );
|
|
vop::copy( f->maxBinN_V, maxBinN_V, chN );
|
|
vop::copy( f->hopSmpN_V, hopSmpN_V, chN );
|
|
|
|
if( magV != nullptr || phsV != nullptr || hzV != nullptr )
|
|
{
|
|
for(unsigned chIdx=0; chIdx<chN; ++chIdx)
|
|
{
|
|
f->magV[ chIdx ] = (fd_sample_t*)magV[chIdx];
|
|
f->phsV[ chIdx ] = (fd_sample_t*)phsV[chIdx];
|
|
f->hzV[ chIdx ] = (fd_sample_t*)hzV[chIdx];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned maxTotalBinsN = vop::sum( maxBinN_V, chN );
|
|
|
|
fd_sample_t* buf = mem::allocZ<fd_sample_t>( kFbufVectN * maxTotalBinsN );
|
|
fd_sample_t* m = buf;
|
|
for(unsigned chIdx=0; chIdx<chN; ++chIdx)
|
|
{
|
|
f->magV[chIdx] = m + 0 * f->binN_V[chIdx];
|
|
f->phsV[chIdx] = m + 1 * f->binN_V[chIdx];
|
|
f->hzV[ chIdx] = m + 2 * f->binN_V[chIdx];
|
|
m += f->maxBinN_V[chIdx];
|
|
assert( m <= buf + kFbufVectN * maxTotalBinsN );
|
|
}
|
|
|
|
f->buf = buf;
|
|
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
|
|
cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_sample_t** magV, const fd_sample_t** phsV, const fd_sample_t** hzV )
|
|
{
|
|
unsigned maxBinN_V[ chN ];
|
|
unsigned binN_V[ chN ];
|
|
unsigned hopSmpN_V[ chN ];
|
|
|
|
vop::fill( maxBinN_V, chN, maxBinN );
|
|
vop::fill( binN_V, chN, binN );
|
|
vop::fill( hopSmpN_V, chN, binN );
|
|
return fbuf_create( srate, chN, maxBinN_V, binN_V, hopSmpN_V, magV, phsV, hzV );
|
|
|
|
}
|
|
|
|
|
|
|
|
void cw::flow::fbuf_destroy( fbuf_t*& fbuf )
|
|
{
|
|
if( fbuf == nullptr )
|
|
return;
|
|
|
|
mem::release( fbuf->maxBinN_V );
|
|
mem::release( fbuf->binN_V );
|
|
mem::release( fbuf->hopSmpN_V);
|
|
mem::release( fbuf->magV);
|
|
mem::release( fbuf->phsV);
|
|
mem::release( fbuf->hzV);
|
|
mem::release( fbuf->buf);
|
|
mem::release( fbuf->readyFlV);
|
|
mem::release( fbuf);
|
|
}
|
|
|
|
cw::flow::fbuf_t* cw::flow::fbuf_duplicate( const fbuf_t* src )
|
|
{
|
|
fbuf_t* fbuf = fbuf_create( src->srate, src->chN, src->maxBinN_V, src->binN_V, src->hopSmpN_V );
|
|
|
|
for(unsigned i=0; i<fbuf->chN; ++i)
|
|
{
|
|
fbuf->maxBinN_V[i] = src->maxBinN_V[i];
|
|
fbuf->binN_V[i] = src->binN_V[i];
|
|
fbuf->hopSmpN_V[i] = src->hopSmpN_V[i];
|
|
|
|
vop::copy( fbuf->magV[i], src->magV[i], fbuf->binN_V[i] );
|
|
vop::copy( fbuf->phsV[i], src->phsV[i], fbuf->binN_V[i] );
|
|
vop::copy( fbuf->hzV[i], src->hzV[i], fbuf->binN_V[i] );
|
|
}
|
|
return fbuf;
|
|
}
|
|
|
|
|
|
cw::flow::mbuf_t* cw::flow::mbuf_create( const midi::ch_msg_t* msgA, unsigned msgN )
|
|
{
|
|
mbuf_t* m = mem::allocZ<mbuf_t>();
|
|
m->msgA = msgA;
|
|
m->msgN = msgN;
|
|
return m;
|
|
}
|
|
|
|
void cw::flow::mbuf_destroy( mbuf_t*& buf )
|
|
{
|
|
mem::release(buf);
|
|
}
|
|
|
|
cw::flow::mbuf_t* cw::flow::mbuf_duplicate( const mbuf_t* src )
|
|
{
|
|
return mbuf_create(src->msgA,src->msgN);
|
|
}
|
|
|
|
|
|
unsigned cw::flow::value_type_label_to_flag( const char* s )
|
|
{
|
|
unsigned flags = labelToId(typeLabelFlagsA,s,kInvalidTFl);
|
|
if( flags == kInvalidTFl )
|
|
cwLogError(kInvalidArgRC,"Invalid type flag: '%s'",cwStringNullGuard(s));
|
|
|
|
return flags;
|
|
}
|
|
|
|
|
|
cw::flow::class_desc_t* cw::flow::class_desc_find( flow_t* p, const char* label )
|
|
{
|
|
for(unsigned i=0; i<p->classDescN; ++i)
|
|
if( textCompare(p->classDescA[i].label,label) == 0 )
|
|
return p->classDescA + i;
|
|
return nullptr;
|
|
}
|
|
|
|
cw::flow::var_desc_t* cw::flow::var_desc_find( class_desc_t* cd, const char* label )
|
|
{
|
|
var_desc_t* vd = cd->varDescL;
|
|
|
|
for(; vd != nullptr; vd=vd->link )
|
|
if( textCompare(vd->label,label) == 0 )
|
|
return vd;
|
|
return nullptr;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef )
|
|
{
|
|
if((vdRef = var_desc_find(cd,label)) == nullptr )
|
|
return cwLogError(kInvalidArgRC,"The variable desc. named '%s' could not be found on the class '%s'.",label,cd->label);
|
|
return kOkRC;
|
|
}
|
|
|
|
|
|
void cw::flow::class_dict_print( flow_t* p )
|
|
{
|
|
for(unsigned i=0; i<p->classDescN; ++i)
|
|
{
|
|
class_desc_t* cd = p->classDescA + i;
|
|
var_desc_t* vd = cd->varDescL;
|
|
printf("%s\n",cwStringNullGuard(cd->label));
|
|
|
|
for(; vd!=nullptr; vd=vd->link)
|
|
{
|
|
const char* srcFlStr = vd->flags & kSrcVarFl ? "src" : " ";
|
|
const char* srcOptFlStr = vd->flags & kSrcOptVarFl ? "srcOpt" : " ";
|
|
const char* plyMltFlStr = vd->flags & kMultVarFl ? "mult" : " ";
|
|
|
|
printf(" %10s 0x%08x %s %s %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, srcOptFlStr, plyMltFlStr, cwStringNullGuard(vd->docText) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void cw::flow::network_print( const network_t& net )
|
|
{
|
|
// for each instance in the network
|
|
for(unsigned i=0; i<net.proc_arrayN; ++i)
|
|
{
|
|
instance_t* inst = net.proc_array[i];
|
|
instance_print(inst);
|
|
|
|
// if this instance has an internal network
|
|
if( inst->internal_net != nullptr )
|
|
{
|
|
printf("------- Begin Nested Network: %s -------\n",cwStringNullGuard(inst->label));
|
|
network_print(*(inst->internal_net));
|
|
printf("------- End Nested Network: %s -------\n",cwStringNullGuard(inst->label));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
cw::flow::instance_t* cw::flow::instance_find( network_t& net, const char* inst_label, unsigned sfx_id )
|
|
{
|
|
for(unsigned i=0; i<net.proc_arrayN; ++i)
|
|
if( net.proc_array[i]->label_sfx_id==sfx_id && textIsEqual(inst_label,net.proc_array[i]->label) )
|
|
return net.proc_array[i];
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
cw::rc_t cw::flow::instance_find( network_t& net, const char* inst_label, unsigned sfx_id, instance_t*& instPtrRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
if((instPtrRef = instance_find(net,inst_label,sfx_id)) != nullptr )
|
|
return rc;
|
|
|
|
return cwLogError(kInvalidArgRC,"The instance '%s:%i' was not found.", inst_label, sfx_id );
|
|
}
|
|
|
|
cw::flow::external_device_t* cw::flow::external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl, const char* midiPortLabel )
|
|
{
|
|
for(unsigned i=0; i<p->deviceN; ++i)
|
|
if( (device_label==nullptr || cw::textIsEqual(p->deviceA[i].devLabel,device_label))
|
|
&& p->deviceA[i].typeId==typeId
|
|
&& cwIsFlag(p->deviceA[i].flags,inOrOutFl)
|
|
&& (midiPortLabel==nullptr || cw::textIsEqual(p->deviceA[i].portLabel,midiPortLabel)) )
|
|
return p->deviceA + i;
|
|
|
|
cwLogError(kInvalidArgRC,"The %s device named '%s' could not be found.", cwIsFlag(inOrOutFl,kInFl) ? "in" : "out", device_label );
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void cw::flow::instance_print( instance_t* inst )
|
|
{
|
|
printf("%s:%i\n", inst->label,inst->label_sfx_id);
|
|
for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link)
|
|
if( var->chIdx == kAnyChIdx )
|
|
for(variable_t* v0 = var; v0!=nullptr; v0=v0->ch_link)
|
|
_var_print(v0);
|
|
|
|
if( inst->class_desc->members->report )
|
|
inst->class_desc->members->report( inst );
|
|
}
|
|
|
|
|
|
|
|
void cw::flow::_var_destroy( variable_t* var )
|
|
{
|
|
if( var != nullptr )
|
|
{
|
|
for(unsigned i=0; i<kLocalValueN; ++i)
|
|
_value_release(var->local_value+i);
|
|
mem::release(var->label);
|
|
mem::release(var);
|
|
}
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::var_create( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned id, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
|
|
rc = _var_create( inst, var_label, sfx_id, id, chIdx, value_cfg, varRef );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
variable_t* base_var = nullptr;
|
|
varRef = nullptr;
|
|
|
|
if((base_var = _var_find_on_label_and_ch( inst, var_label, sfx_id, kAnyChIdx)) == nullptr)
|
|
{
|
|
rc = cwLogError(kInvalidStateRC,"The base ('any') channel variable could not be located on '%s:%i.%s:%i'.",inst->label,inst->label_sfx_id,var_label,sfx_id);
|
|
goto errLabel;
|
|
}
|
|
|
|
// locate the variable with the stated chIdx
|
|
var = _var_find_on_label_and_ch( inst, var_label, sfx_id, chIdx );
|
|
|
|
// 'src' variables cannot be channelized
|
|
if( cwIsFlag(base_var->varDesc->flags,kSrcVarFl) )
|
|
{
|
|
rc = cwLogError(rc,"'src' variables cannot be channelized.");
|
|
goto errLabel;
|
|
}
|
|
|
|
// if the requested var was not found then create a new variable with the requested channel index
|
|
if( var == nullptr && chIdx != kAnyChIdx )
|
|
{
|
|
// create the channelized var
|
|
if((rc = _var_create( inst, var_label, sfx_id, vid, chIdx, value_cfg, var )) != kOkRC )
|
|
goto errLabel;
|
|
|
|
// if no value was set then set the value from the 'any' channel
|
|
if( value_cfg == nullptr )
|
|
{
|
|
// Set the value of the new variable to the value of the 'any' channel
|
|
_value_duplicate( var->local_value[ var->local_value_idx], base_var->local_value[ base_var->local_value_idx ] );
|
|
|
|
// If the 'any' channel value was set to point to it's local value then do same with this value
|
|
if( base_var->local_value + base_var->local_value_idx == base_var->value )
|
|
var->value = var->local_value + var->local_value_idx;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// a correctly channelized var was found - but we still may need to set the value
|
|
if( value_cfg != nullptr )
|
|
{
|
|
//cwLogInfo("%s ch:%i",var_label,chIdx);
|
|
rc = _set_var_value_from_cfg( var, value_cfg );
|
|
}
|
|
else
|
|
{
|
|
cwLogWarning("An existing var (%s:i.%s:i ch:%i) was specified for channelizing but no value was provided.", inst->label, inst->label_sfx_id, var_label, sfx_id, chIdx );
|
|
}
|
|
}
|
|
|
|
assert( var != nullptr );
|
|
varRef = var;
|
|
|
|
errLabel:
|
|
if( rc != kOkRC )
|
|
rc = cwLogError(rc,"Channelize failed for variable '%s:%i' on instance '%s:%i' ch:%i.", var_label, sfx_id, inst->label, inst->label_sfx_id, chIdx );
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx )
|
|
{ return _var_find_on_label_and_ch(inst,label,sfx_id,chIdx) != nullptr; }
|
|
|
|
bool cw::flow::var_has_value( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx )
|
|
{
|
|
variable_t* varPtr = nullptr;
|
|
rc_t rc;
|
|
|
|
if((rc = var_find( inst, label, sfx_id, chIdx, varPtr )) != kOkRC )
|
|
return false;
|
|
|
|
return varPtr->value != nullptr;
|
|
}
|
|
|
|
bool cw::flow::var_is_a_source( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx )
|
|
{
|
|
rc_t rc;
|
|
variable_t* varPtr = nullptr;
|
|
if((rc = var_find( inst, label, sfx_id, chIdx, varPtr)) != kOkRC )
|
|
{
|
|
cwLogError(kEleNotFoundRC,"The variable '%s:%i' was not found on proc:'%s:%i'. 'source' state query is invalid.",cwStringNullGuard(label),sfx_id,cwStringNullGuard(inst->label),inst->label_sfx_id);
|
|
return false;
|
|
}
|
|
|
|
return is_a_source_var(varPtr);
|
|
}
|
|
|
|
bool cw::flow::var_is_a_source( instance_t* inst, unsigned vid, unsigned chIdx )
|
|
{
|
|
rc_t rc;
|
|
variable_t* varPtr = nullptr;
|
|
if((rc = var_find( inst, vid, chIdx, varPtr)) != kOkRC )
|
|
{
|
|
cwLogError(kEleNotFoundRC,"The variable with vid '%i' was not found on proc:'%s:%i'. 'source' state query is invalid.",vid,cwStringNullGuard(inst->label),inst->label_sfx_id);
|
|
return false;
|
|
}
|
|
|
|
return is_a_source_var(varPtr);
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
unsigned idx = kInvalidIdx;
|
|
variable_t* var = nullptr;
|
|
|
|
varRef = nullptr;
|
|
|
|
// if the varMapA[] has not yet been formed (we are inside the instance constructor) then do a slow lookup of the variable
|
|
if( inst->varMapA == nullptr )
|
|
{
|
|
if((rc = _var_find_on_vid_and_ch(inst,vid,chIdx,var)) != kOkRC )
|
|
goto errLabel;
|
|
}
|
|
else
|
|
{
|
|
// otherwise do a fast lookup using inst->varMapA[]
|
|
if((rc = _var_map_id_to_index(inst, vid, chIdx, idx )) == kOkRC && (idx != kInvalidIdx ))
|
|
var = inst->varMapA[idx];
|
|
else
|
|
{
|
|
rc = cwLogError(kInvalidIdRC,"The index of variable vid:%i chIdx:%i on instance '%s:%i' could not be calculated and the variable value could not be retrieved.", vid, chIdx, inst->label,inst->label_sfx_id);
|
|
goto errLabel;
|
|
}
|
|
}
|
|
|
|
// if we get here var must be non-null
|
|
assert( var != nullptr && rc == kOkRC );
|
|
varRef = var;
|
|
|
|
errLabel:
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::flow::var_find( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx, variable_t*& vRef )
|
|
{
|
|
variable_t* var;
|
|
vRef = nullptr;
|
|
|
|
if((var = _var_find_on_label_and_ch(inst,label,sfx_id,chIdx)) != nullptr )
|
|
{
|
|
vRef = var;
|
|
return kOkRC;
|
|
}
|
|
|
|
return cwLogError(kInvalidIdRC,"The instance '%s:%i' does not have a variable named '%s:%i'.", inst->label, inst->label_sfx_id, label, sfx_id );
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_find( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx, const variable_t*& vRef )
|
|
{
|
|
variable_t* v = nullptr;
|
|
rc_t rc = var_find(inst,label,sfx_id,chIdx,v);
|
|
vRef = v;
|
|
return rc;
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::var_channel_count( instance_t* inst, const char* label, unsigned sfx_id, unsigned& chCntRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
const variable_t* var= nullptr;
|
|
if((rc = var_find(inst,label,sfx_id,kAnyChIdx,var)) != kOkRC )
|
|
return cwLogError(rc,"Channel count was not available because the variable '%s:%i.%s:%i' does not exist.",cwStringNullGuard(inst->label),inst->label_sfx_id,cwStringNullGuard(label),sfx_id);
|
|
|
|
return var_channel_count(var,chCntRef);
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_channel_count( const variable_t* var, unsigned& chCntRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
const variable_t* v;
|
|
|
|
chCntRef = 0;
|
|
|
|
if((rc = var_find( var->inst, var->label, var->label_sfx_id, kAnyChIdx, v )) != kOkRC )
|
|
{
|
|
rc = cwLogError(kInvalidStateRC,"The base channel variable instance could not be found for the variable '%s:%i.%s:%i'.",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id);
|
|
goto errLabel;
|
|
}
|
|
|
|
for(v = v->ch_link; v!=nullptr; v=v->ch_link)
|
|
chCntRef += 1;
|
|
|
|
errLabel:
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
varRef = nullptr;
|
|
|
|
// TODO: check for duplicate 'vid'-'chIdx' pairs on this instance
|
|
// The concatenation of 'vid' and 'chIdx' should be unique
|
|
|
|
// if an exact match to label/chIdx was found
|
|
if((var = _var_find_on_label_and_ch(inst,var_label,sfx_id,chIdx)) != nullptr )
|
|
{
|
|
// if a value was given - then update the value
|
|
if( value_cfg != nullptr )
|
|
if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC )
|
|
goto errLabel;
|
|
}
|
|
else // an exact match was not found - channelize the variable
|
|
{
|
|
if((rc = var_channelize(inst,var_label,sfx_id,chIdx,value_cfg,vid,var)) != kOkRC )
|
|
goto errLabel;
|
|
}
|
|
|
|
var->vid = vid;
|
|
varRef = var;
|
|
|
|
if((var = _var_find_on_label_and_ch(inst,var_label,sfx_id,kAnyChIdx)) != nullptr )
|
|
var->vid = vid;
|
|
else
|
|
rc = cwLogError(kInvalidStateRC,"The variable '%s:%i' instance '%s:%i' has no base channel.", var_label, sfx_id, inst->label, inst->label_sfx_id, chIdx);
|
|
|
|
errLabel:
|
|
if( rc != kOkRC )
|
|
rc = cwLogError(rc,"Registration failed on variable '%s:%i' instance '%s:%i' ch: %i.", var_label, sfx_id, inst->label, inst->label_sfx_id, chIdx);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, variable_t*& varRef )
|
|
{
|
|
return var_register( inst, var_label, sfx_id, vid, chIdx, nullptr, varRef );
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
abuf_t* abuf;
|
|
|
|
if((abuf = abuf_create( srate, chN, frameN )) == nullptr )
|
|
return cwLogError(kOpFailRC,"abuf create failed on instance:'%s:%i' variable:'%s:%i'.", inst->label, inst->label_sfx_id, var_label,sfx_id);
|
|
|
|
if((rc = _var_register_and_set( inst, var_label, sfx_id, vid, chIdx, abuf )) != kOkRC )
|
|
abuf_destroy(abuf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_sample_t** magV, const fd_sample_t** phsV, const fd_sample_t** hzV )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
fbuf_t* fbuf;
|
|
if((fbuf = fbuf_create( srate, chN, maxBinN_V, binN_V, hopSmpN_V, magV, phsV, hzV )) == nullptr )
|
|
return cwLogError(kOpFailRC,"fbuf create failed on instance:'%s:%i' variable:'%s:%i'.", inst->label, inst->label_sfx_id, var_label,sfx_id);
|
|
|
|
if((rc = _var_register_and_set( inst, var_label, sfx_id, vid, chIdx, fbuf )) != kOkRC )
|
|
fbuf_destroy(fbuf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, midi::ch_msg_t* msgA, unsigned msgN )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
mbuf_t* mbuf;
|
|
|
|
if((mbuf = mbuf_create(msgA,msgN)) == nullptr )
|
|
return cwLogError(kOpFailRC,"mbuf create failed on instance:'%s:%i' variable:'%s:%i'.", inst->label, inst->label_sfx_id, var_label, sfx_id);
|
|
|
|
if((rc = _var_register_and_set( inst, var_label, sfx_id, vid, chIdx, mbuf )) != kOkRC )
|
|
mbuf_destroy(mbuf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_sample_t** magV, const fd_sample_t** phsV, const fd_sample_t** hzV )
|
|
{
|
|
unsigned maxBinN_V[ chN ];
|
|
unsigned binN_V[ chN ];
|
|
unsigned hopSmpN_V[ chN ];
|
|
vop::fill(maxBinN_V,chN,maxBinN);
|
|
vop::fill(binN_V,chN,binN);
|
|
vop::fill(hopSmpN_V,chN, hopSmpN );
|
|
return var_register_and_set(inst,var_label,sfx_id,vid,chIdx,srate, chN, maxBinN_V, binN_V, hopSmpN_V, magV, phsV, hzV);
|
|
}
|
|
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, bool& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, uint_t& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, int_t& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, float& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, double& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, const char*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, const abuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( variable_t* var, abuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, const fbuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( variable_t* var, fbuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( const variable_t* var, const mbuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
cw::rc_t cw::flow::var_get( variable_t* var, mbuf_t*& valRef )
|
|
{ return _val_get_driver(var,valRef); }
|
|
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kBoolTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kBoolTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint_t val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kUIntTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kUIntTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_t val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kIntTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kIntTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, float val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kFloatTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kFloatTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, double val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kDoubleTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kDoubleTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, const char* val )
|
|
{
|
|
rc_t rc = kOkRC;
|
|
variable_t* var = nullptr;
|
|
|
|
if((rc = _var_find_to_set(inst, vid, chIdx, kStringTFl, var )) == kOkRC )
|
|
_var_set_driver( var, kStringTFl, val );
|
|
|
|
return rc;
|
|
}
|
|
|
|
const cw::flow::preset_t* cw::flow::class_preset_find( class_desc_t* cd, const char* preset_label )
|
|
{
|
|
const preset_t* pr;
|
|
for(pr=cd->presetL; pr!=nullptr; pr=pr->link)
|
|
if( textCompare(pr->label,preset_label) == 0 )
|
|
return pr;
|
|
|
|
return nullptr;
|
|
}
|
|
|