libcw/cwFlowTypes.cpp

1404 lines
40 KiB
C++
Raw Normal View History

#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 "cwFlow.h"
#include "cwFlowTypes.h"
namespace cw
{
namespace flow
{
idLabelPair_t typeLabelFlagsA[] = {
{ kBoolTFl, "bool" },
{ kUIntTFl, "uint" },
{ kIntTFl, "int", },
{ kFloatTFl, "float"},
{ kRealTFl, "real"},
{ kDoubleTFl, "double"},
{ kBoolMtxTFl, "bool_mtx" },
{ kUIntMtxTFl, "uint_mtx" },
{ kIntMtxTFl, "int_mtx" },
{ kFloatMtxTFl, "float_mtx" },
{ kDoubleMtxTFl, "double_mtx" },
{ kABufTFl, "audio" },
{ kFBufTFl, "spectrum" },
{ kStringTFl, "string" },
{ kTimeTFl, "time" },
{ 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 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 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 binN:%i hopSmpN:%i srate:%8.1f", v->u.fbuf->chN, v->u.fbuf->binN, v->u.fbuf->hopSmpN, v->u.fbuf->srate );
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.");
}
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.");
}
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.");
}
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.");
}
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.");
}
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.");
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.");
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.");
}
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 _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 variable:%s with type 0x%x does not match requested type:0x%x.",varRef->inst->label,varRef->label,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' could not be found.", vid, chIdx, inst->label);
}
// Variable lookup: Exact match on label and chIdx
variable_t* _var_find_on_label_and_ch( instance_t* inst, const char* var_label, 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( textCompare(var->label,var_label)==0 && var->chIdx == chIdx )
return var;
}
return nullptr;
}
// Find a variable: If an exact match on label,chIdx is found this is returned.
// Otherwise if the arg 'chIdx' is a numeric channel idx the 'any' var is returned.
// if the arg 'chIdx' is 'any' then the 'any' or the lowest numeric channel is returned
variable_t* _var_find_best( instance_t* inst, const char* label, unsigned chIdx )
{
/*
variable_t* v0 = nullptr;
variable_t* var = inst->varL;
for(; var!=nullptr; var=var->var_link)
if( textCompare(var->label,label) == 0 )
{
// if the channel matches exactly - return this var
if( var->chIdx == chIdx )
return var;
// if we encounter a var with 'any' channel - store this we will keep looking because we may still find an exact match
if( var->chIdx == kAnyChIdx )
v0 = var;
else
// if 'any' was requested then try to get ch==0 but a non-zero channel will suffice otherwise
if( chIdx == kAnyChIdx )
if( v0 == nullptr || var->chIdx < v0->chIdx )
v0 = var;
}
return v0;
*/
return _var_find_on_label_and_ch(inst,label,chIdx);
}
rc_t _validate_var_assignment( variable_t* var, unsigned typeFl )
{
if( cwIsFlag(var->varDesc->flags, kSrcVarFl ) )
return cwLogError(kInvalidStateRC, "The variable '%s' on instance '%s' cannot be set because it is a 'src' variable.", var->label, var->inst->label);
if( !cwIsFlag(var->varDesc->type, typeFl ) )
return cwLogError(kTypeMismatchRC, "The variable '%s' on instance '%s' is not a '%s'.", var->label, var->inst->label, _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)
if((rc = con_var->inst->class_desc->members->value( con_var->inst, con_var )) != kOkRC )
break;
return rc;
}
rc_t _var_set( variable_t* var, bool val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kBoolTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.b = val;
var->local_value.flags = kBoolTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val);
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, unsigned val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kUIntTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.u = val;
var->local_value.flags = kUIntTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %i (uint_t).",var->inst->label,var->label,var->chIdx,val);
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, int val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kIntTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.i = val;
var->local_value.flags = kIntTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %i (int_t).",var->inst->label,var->label,var->chIdx,val);
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, float val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kFloatTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.f = val;
var->local_value.flags = kFloatTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %f (float).",var->inst->label,var->label,var->chIdx,val);
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, double val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kDoubleTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.d = val;
var->local_value.flags = kDoubleTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %f (double).",var->inst->label,var->label,var->chIdx,val);
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, const char* val )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kStringTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.s = mem::duplStr(val);
var->local_value.flags = kStringTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %s (string).",var->inst->label,var->label,var->chIdx,cwStringNullGuard(val));
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, abuf_t* abuf )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kABufTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.abuf = abuf;
var->local_value.flags = kABufTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %s (abuf).",var->inst->label,var->label,var->chIdx,abuf==nullptr ? "null" : "valid");
return _var_broadcast_new_value( var );
}
rc_t _var_set( variable_t* var, fbuf_t* fbuf )
{
rc_t rc;
if((rc = _validate_var_assignment( var, kFBufTFl )) != kOkRC )
return rc;
_value_release(&var->local_value);
var->local_value.u.fbuf = fbuf;
var->local_value.flags = kFBufTFl;
var->value = &var->local_value;
cwLogMod("%s.%s ch:%i %s (fbuf).",var->inst->label,var->label,var->chIdx,fbuf==nullptr ? "null" : "valid");
return _var_broadcast_new_value( var );
}
template< typename T >
rc_t _var_set_driver( variable_t* var, T value )
{
rc_t rc;
// if this assignment targets a specific channel ...
if( var->chIdx != kAnyChIdx )
{
rc = _var_set(var,value); // ... then set it alone
}
else // ... otherwise set all channels.
{
for(; var!=nullptr; var=var->ch_link)
if((rc = _var_set(var,value)) != kOkRC )
break;
}
return rc;
}
rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, abuf_t* abuf )
{
rc_t rc;
variable_t* var = nullptr;
if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) != kOkRC )
return rc;
if( var != nullptr )
_var_set_driver( var, abuf );
return rc;
}
rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, fbuf_t* fbuf )
{
rc_t rc;
variable_t* var = nullptr;
if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) != kOkRC )
return rc;
if( var != nullptr )
_var_set_driver( var, fbuf );
return rc;
}
rc_t _set_var_value_from_cfg( variable_t* var, const object_t* value )
{
rc_t rc = kOkRC;
switch( var->varDesc->type & kTypeMask )
{
case kBoolTFl:
{
bool v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, v );
}
break;
case kUIntTFl:
{
unsigned v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, v );
}
break;
case kIntTFl:
{
int v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, v );
}
break;
case kFloatTFl:
{
float v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, v );
}
break;
case kDoubleTFl:
{
double v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, v );
}
break;
case kStringTFl:
{
const char* v;
if((rc = value->value(v)) == kOkRC )
rc = _var_set_driver( var, 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.%s could not extract a type:%s from a configuration value.",var->inst->label,var->label,_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);
// 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 % on instance '%s' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx);
idxRef = idx;
return kOkRC;
}
rc_t _var_map_label_to_index( instance_t* inst, const char* var_label, unsigned chIdx, unsigned& idxRef )
{
rc_t rc = kOkRC;
variable_t* var = nullptr;
idxRef = kInvalidIdx;
if((rc = var_find(inst, var_label, 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, kAnyChIdx )) == nullptr )
{
rc = cwLogError(kInvalidStateRC,"The base channel variable does not exist for '%s.%s'. This is an illegal state.", inst->label, new_var->label );
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 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,chIdx)) != nullptr )
{
rc = cwLogError(kInvalidStateRC,"The variable '%s' ch:%i has already been created on the instance: '%s'.",var_label,chIdx,inst->label);
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' in class '%s'.", var_label, 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->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.%s' ch:%i.", inst->label, var_label, chIdx );
}
else
{
varRef = var;
cwLogMod("Created var: %s.%s ch:%i.", inst->label, var_label, chIdx );
}
return rc;
}
void _var_print( const variable_t* var )
{
const char* local_label = var->value==nullptr || var->value == &var->local_value ? "local" : " ";
printf(" %20s id:%4i ch:%3i : %s : ", var->label, var->vid, var->chIdx, local_label );
if( var->value == nullptr )
_value_print( &var->local_value );
else
_value_print( var->value );
printf("\n");
}
rc_t _preset_set_var_value( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value )
{
rc_t rc = kOkRC;
variable_t* var = nullptr;
// get the variable
if((rc = var_find( inst, var_label, 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 variable:%s could not be set via a preset.", inst->label, var_label );
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, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV )
{
fbuf_t* f = mem::allocZ<fbuf_t>();
f->srate = srate;
f->chN = chN;
f->binN = binN;
f->hopSmpN = hopSmpN;
f->magV = mem::allocZ<sample_t*>(chN);
f->phsV = mem::allocZ<sample_t*>(chN);
f->hzV = mem::allocZ<sample_t*>(chN);
f->readyFlV= mem::allocZ<bool>(chN);
if( magV != nullptr || phsV != nullptr || hzV != nullptr )
{
for(unsigned chIdx=0; chIdx<chN; ++chIdx)
{
f->magV[ chIdx ] = (sample_t*)magV[chIdx];
f->phsV[ chIdx ] = (sample_t*)phsV[chIdx];
f->hzV[ chIdx ] = (sample_t*)hzV[chIdx];
}
}
else
{
sample_t* buf = mem::allocZ<sample_t>( chN * kFbufVectN * binN );
for(unsigned chIdx=0,j=0; chIdx<chN; ++chIdx,j+=kFbufVectN*binN)
{
f->magV[chIdx] = buf + j + 0 * binN;
f->phsV[chIdx] = buf + j + 1 * binN;
f->hzV[ chIdx] = buf + j + 2 * binN;
}
f->buf = buf;
}
return f;
}
void cw::flow::fbuf_destroy( fbuf_t* fbuf )
{
if( fbuf == nullptr )
return;
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->binN, src->hopSmpN );
for(unsigned i=0; i<fbuf->chN; ++i)
{
vop::copy( fbuf->magV[i], src->magV[i], fbuf->binN );
vop::copy( fbuf->phsV[i], src->phsV[i], fbuf->binN );
vop::copy( fbuf->hzV[i], src->hzV[i], fbuf->binN );
}
return fbuf;
}
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" : " ";
printf(" %10s 0x%08x %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, cwStringNullGuard(vd->docText) );
}
}
}
void cw::flow::network_print( flow_t* p )
{
for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link)
instance_print(inst);
}
cw::flow::instance_t* cw::flow::instance_find( flow_t* p, const char* inst_label )
{
for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link )
if( textCompare(inst_label,inst->label) == 0 )
return inst;
return nullptr;
}
cw::rc_t cw::flow::instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef )
{
rc_t rc = kOkRC;
if((instPtrRef = instance_find(p,inst_label)) != nullptr )
return rc;
return cwLogError(kInvalidArgRC,"The instance '%s' was not found.", inst_label );
}
cw::flow::external_device_t* cw::flow::external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl )
{
for(unsigned i=0; i<p->deviceN; ++i)
if( cw::textIsEqual(p->deviceA[i].label,device_label) && p->deviceA[i].typeId==typeId && cwIsFlag(p->deviceA[i].flags,inOrOutFl ))
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\n", inst->label);
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 )
{
_value_release(&var->local_value);
mem::release(var->label);
mem::release(var);
}
}
cw::rc_t cw::flow::var_create( instance_t* inst, const char* var_label, unsigned id, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef )
{
rc_t rc = kOkRC;
rc = _var_create( inst, var_label, id, chIdx, value_cfg, varRef );
return rc;
}
cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, 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, kAnyChIdx)) == nullptr)
{
rc = cwLogError(kInvalidStateRC,"The base ('any') channel variable could not be located on '%s.%s'.",inst->label,var_label);
goto errLabel;
}
// locate the variable with the stated chIdx
var = _var_find_on_label_and_ch( inst, var_label, 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, kInvalidId, 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, base_var->local_value );
// 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->value )
var->value = &var->local_value;
}
}
else
{
// a correctly channelized var was found - but we still may need to set the value
if( value_cfg != nullptr )
{
rc = _set_var_value_from_cfg( var, value_cfg );
}
else
{
cwLogWarning("An existing var (%s.%s ch:%i) was specified for channelizing but no value was provided.", inst->label, var_label, chIdx );
}
}
assert( var != nullptr );
varRef = var;
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"Channelize failed for variable '%s' on instance '%s' ch:%i.", var_label, inst->label, chIdx );
return rc;
}
bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx )
{ return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; }
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' could not be calculated and the variable value could not be retrieved.", vid, chIdx, inst->label);
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 chIdx, variable_t*& vRef )
{
variable_t* var;
vRef = nullptr;
if((var = _var_find_best(inst,label,chIdx)) != nullptr )
{
vRef = var;
return kOkRC;
}
return cwLogError(kInvalidIdRC,"The instance '%s' does not have a variable named '%s'.", inst->label, label );
}
cw::rc_t cw::flow::var_find( instance_t* inst, const char* label, unsigned chIdx, const variable_t*& vRef )
{
variable_t* v = nullptr;
rc_t rc = var_find(inst,label,chIdx,v);
vRef = v;
return rc;
}
cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, 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,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,chIdx,value_cfg,var)) != kOkRC )
goto errLabel;
}
var->vid = vid;
varRef = var;
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"Registration failed on variable '%s' instance '%s' ch: %i.", var_label, inst->label, chIdx);
return rc;
}
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, variable_t*& varRef )
{
return var_register( inst, var_label, vid, chIdx, nullptr, varRef );
}
cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, 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' variable:'%s'.", inst->label, var_label);
if((rc = _var_register_and_set( inst, var_label, 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 vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV )
{
rc_t rc = kOkRC;
fbuf_t* fbuf;
if((fbuf = fbuf_create( srate, chN, binN, hopSmpN, magV, phsV, hzV )) == nullptr )
return cwLogError(kOpFailRC,"fbuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label);
if((rc = _var_register_and_set( inst, var_label, vid, chIdx, fbuf )) != kOkRC )
fbuf_destroy(fbuf);
return rc;
}
cw::rc_t cw::flow::var_get( const variable_t* var, bool& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, uint_t& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, int_t& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, float& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, double& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, const char*& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, const abuf_t*& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( variable_t* var, abuf_t*& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( const variable_t* var, const fbuf_t*& valRef )
{ return _val_get(var->value,valRef); }
cw::rc_t cw::flow::var_get( variable_t* var, fbuf_t*& valRef )
{ return _val_get(var->value,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, 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, 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, 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, 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, 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, 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;
}