From 1b649124a6ae7094962e8f5988da5bd7ed32aa08 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 22 Apr 2024 16:02:40 -0400 Subject: [PATCH] cwFlow*,cwPresetSel.cpp: Many changes to implement 'poly' networks. cwFlowNet.h/cpp : Initial commit. --- Makefile.am | 4 +- cwFlow.cpp | 1665 ++-------------------------------- cwFlow.h | 62 +- cwFlowDecl.h | 61 ++ cwFlowNet.cpp | 2279 +++++++++++++++++++++++++++++++++++++++++++++++ cwFlowNet.h | 82 ++ cwFlowProc.cpp | 617 ++++++++++--- cwFlowProc.h | 3 + cwFlowTypes.cpp | 220 ++--- cwFlowTypes.h | 104 ++- cwPresetSel.cpp | 3 +- 11 files changed, 3183 insertions(+), 1917 deletions(-) create mode 100644 cwFlowNet.cpp create mode 100644 cwFlowNet.h diff --git a/Makefile.am b/Makefile.am index ac568fd..a94f6e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,8 +34,8 @@ libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwDspTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwDspTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp -libcwHDR += src/libcw/cwFlow.h src/libcw/cwFlowDecl.h src/libcw/cwFlowTypes.h src/libcw/cwFlowProc.h src/libcw/cwFlowCross.h -libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp +libcwHDR += src/libcw/cwFlow.h src/libcw/cwFlowDecl.h src/libcw/cwFlowTypes.h src/libcw/cwFlowNet.h src/libcw/cwFlowProc.h src/libcw/cwFlowCross.h +libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowNet.cpp src/libcw/cwFlowProc.cpp src/libcw/cwFlowCross.cpp if cwWEBSOCK libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h diff --git a/cwFlow.cpp b/cwFlow.cpp index 8f61939..ceea17f 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -3,7 +3,9 @@ #include "cwCommonImpl.h" #include "cwMem.h" #include "cwText.h" +#include "cwNumericConvert.h" #include "cwObject.h" + #include "cwAudioFile.h" #include "cwVectOps.h" #include "cwMtx.h" @@ -13,6 +15,7 @@ #include "cwFlowDecl.h" #include "cwFlow.h" #include "cwFlowTypes.h" +#include "cwFlowNet.h" #include "cwFlowProc.h" namespace cw @@ -26,6 +29,7 @@ namespace cw } library_t; library_t g_library[] = { + { "poly", &poly::members }, { "midi_in", &midi_in::members }, { "midi_out", &midi_out::members }, { "audio_in", &audio_in::members }, @@ -48,6 +52,8 @@ namespace cw { "balance", &balance::members }, { "audio_meter", &audio_meter::members }, { "audio_marker", &audio_marker::members }, + { "xfade_ctl", &xfade_ctl::members }, + { "poly_mixer", &poly_mixer::members }, { nullptr, nullptr } }; @@ -113,7 +119,8 @@ namespace cw // get the variable description if((rc = cd->cfg->getv_opt("vars", varD, - "presets", presetD )) != kOkRC ) + "presets", presetD, + "poly_limit_cnt", cd->polyLimitN)) != kOkRC ) { rc = cwLogError(rc,"Parsing failed while parsing class desc:'%s'", cwStringNullGuard(cd->label) ); goto errLabel; @@ -229,19 +236,9 @@ namespace cw return rc; } - void _connect_vars( variable_t* src_var, variable_t* in_var ) - { - // connect in_var into src_var's outgoing var chain - in_var->connect_link = src_var->connect_link; - src_var->connect_link = in_var; - assert( src_var->value != nullptr ); - - in_var->value = src_var->value; - in_var->src_var = src_var; - } - - rc_t _setup_input( flow_t* p, instance_t* in_inst, const char* in_var_label, const char* src_label_arg ) + /* + rc_t _setup_input( flow_t* p, instance_t* in_inst, const char* in_var_label, const char* src_proc_label, const char* src_var_label ) { rc_t rc = kOkRC; unsigned src_charN = textLength(src_label_arg); @@ -267,21 +264,21 @@ namespace cw } // locate source instance - if((rc = instance_find(p, sbuf, src_inst )) != kOkRC ) + if((rc = instance_find(p, sbuf, kBaseSfxId, src_inst )) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"The source instance '%s' was not found.", cwStringNullGuard(sbuf) ); goto errLabel; } // locate source value - if((rc = var_find( src_inst, suffix, kAnyChIdx, src_var)) != kOkRC ) + if((rc = var_find( src_inst, suffix, kBaseSfxId, kAnyChIdx, src_var)) != kOkRC ) { rc = cwLogError(rc,"The source var '%s' was not found on the source instance '%s'.", cwStringNullGuard(suffix), cwStringNullGuard(sbuf)); goto errLabel; } // locate input value - if((rc = var_find( in_inst, in_var_label, kAnyChIdx, in_var )) != kOkRC ) + if((rc = var_find( in_inst, in_var_label, kBaseSfxId, kAnyChIdx, in_var )) != kOkRC ) { rc = cwLogError(rc,"The input value '%s' was not found on the instance '%s'.", cwStringNullGuard(in_var_label), cwStringNullGuard(in_inst->label)); goto errLabel; @@ -307,853 +304,12 @@ namespace cw errLabel: return rc; } + */ - void _destroy_inst( instance_t* inst ) - { - if( inst == nullptr ) - return; - - if( inst->class_desc->members->destroy != nullptr && inst->userPtr != nullptr ) - inst->class_desc->members->destroy( inst ); - // destroy the instance variables - variable_t* var0 = inst->varL; - variable_t* var1 = nullptr; - while( var0 != nullptr ) - { - var1 = var0->var_link; - _var_destroy(var0); - var0 = var1; - } - - - mem::release(inst->varMapA); - mem::release(inst); - } - - rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ); - - rc_t _create_instance_var_map( instance_t* inst ) - { - rc_t rc = kOkRC; - unsigned max_vid = kInvalidId; - unsigned max_chIdx = 0; - variable_t* var = inst->varL; - //variable_t* v0 = nullptr; - - // determine the max variable vid and max channel index value among all variables - for(; var!=nullptr; var = var->var_link ) - { - if( var->vid != kInvalidId ) - { - if( max_vid == kInvalidId || var->vid > max_vid ) - max_vid = var->vid; - - if( var->chIdx != kAnyChIdx && (var->chIdx+1) > max_chIdx ) - max_chIdx = (var->chIdx + 1); - - } - } - - // If there are any variables - if( max_vid != kInvalidId ) - { - // create the variable map array - inst->varMapChN = max_chIdx + 1; - inst->varMapIdN = max_vid + 1; - inst->varMapN = inst->varMapIdN * inst->varMapChN; - inst->varMapA = mem::allocZ( inst->varMapN ); - - // assign each variable to a location in the map - for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) - if( var->vid != kInvalidId ) - { - unsigned idx = kInvalidIdx; - - if((rc = _var_map_id_to_index( inst, var->vid, var->chIdx, idx )) != kOkRC ) - goto errLabel; - - - // verify that there are not multiple variables per map position - if( inst->varMapA[ idx ] != nullptr ) - { - variable_t* v0 = inst->varMapA[idx]; - rc = cwLogError(kInvalidStateRC,"The variable '%s' id:%i ch:%i and '%s' id:%i ch:%i share the same variable map position on instance: %s. This is usually cased by duplicate variable id's.", - v0->label,v0->vid,v0->chIdx, var->label,var->vid,var->chIdx,inst->label); - - goto errLabel; - } - - // assign this variable to a map position - inst->varMapA[ idx ] = var; - - if( var->chIdx != kAnyChIdx && var->value == nullptr ) - { - rc = cwLogError(kInvalidStateRC,"The value of the variable '%s' ch:%i on instance:'%s' has not been set.",var->label,var->chIdx,inst->label); - goto errLabel; - } - - } - - } - - errLabel: - return rc; - - } - - void _complete_input_connections( instance_t* inst ) - { - for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) - if(var->chIdx == kAnyChIdx && is_connected_to_external_proc(var) ) - { - - variable_t* base_src_var = var->src_var; - - // since 'var' is on the 'any' channel the 'src' var must also be on the 'any' channel - assert( base_src_var->chIdx == kAnyChIdx ); - - //printf("%s %s\n",inst->label,var->label); - - // for each var channel in the input var - for(variable_t* in_var = var->ch_link; in_var != nullptr; in_var=in_var->ch_link) - { - // locate the matching channel on the 'src' var - variable_t* svar = base_src_var; - for(; svar!=nullptr; svar=svar->ch_link) - if( svar->chIdx == in_var->chIdx ) - break; - - // connect the src->input var - _connect_vars( svar==nullptr ? base_src_var : svar, in_var); - } - } - } - rc_t _call_value_func_on_all_variables( instance_t* inst ) - { - rc_t rc = kOkRC; - rc_t rc1 = kOkRC; - - for(unsigned i=0; ivarMapN; ++i) - if( inst->varMapA[i] != nullptr && inst->varMapA[i]->vid != kInvalidId ) - { - variable_t* var = inst->varMapA[i]; - - if((rc = var->inst->class_desc->members->value( var->inst, var )) != kOkRC ) - rc1 = cwLogError(rc,"The proc instance '%s' reported an invalid valid on variable:%s chIdx:%i.", var->inst->label, var->label, var->chIdx ); - } - - return rc1; - } - - rc_t _var_channelize( instance_t* inst, const char* preset_label, const char* type_src_label, const char* value_label, const object_t* value ) - { - rc_t rc = kOkRC; - - variable_t* dummy = nullptr; - - // verify that a valid value exists - if( value == nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"Unexpected missig value on %s preset '%s' instance '%s' variable '%s'.", type_src_label, preset_label, inst->label, cwStringNullGuard(value_label) ); - goto errLabel; - } - - // if a list of values was given - if( value->is_list() ) - { - for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) - if((rc = var_channelize( inst, value_label, chIdx, value->child_ele(chIdx), kInvalidId, dummy )) != kOkRC ) - goto errLabel; - } - else // otherwise a single value was given - { - if((rc = var_channelize( inst, value_label, kAnyChIdx, value, kInvalidId, dummy )) != kOkRC ) - goto errLabel; - } - - errLabel: - return rc; - } - rc_t _preset_channelize_vars( instance_t* inst, const char* type_src_label, const char* preset_label, const object_t* preset_cfg ) - { - rc_t rc = kOkRC; - - //cwLogInfo("Channelizing '%s' preset %i vars for '%s'.",type_src_label, preset_cfg==nullptr ? 0 : preset_cfg->child_count(), inst->label ); - - // validate the syntax of the preset record - if( !preset_cfg->is_dict() ) - { - rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on %s '%s' is not a dictionary.", preset_label, type_src_label, inst->class_desc->label ); - goto errLabel; - } - - - // for each preset variable - for(unsigned i=0; ichild_count(); ++i) - { - const object_t* value = preset_cfg->child_ele(i)->pair_value(); - const char* value_label = preset_cfg->child_ele(i)->pair_label(); - if((rc = _var_channelize( inst, preset_label, type_src_label, value_label, value )) != kOkRC ) - goto errLabel; - - - } - - errLabel: - if( rc != kOkRC ) - rc = cwLogError(rc,"Apply %s preset failed on instance:%s class:%s preset:%s.", type_src_label, inst->label, inst->class_desc->label, preset_label ); - - return rc; - } - - - template< typename T > - T _interp_dual_value( T v0, T v1, double coeff ) - { - T y; - if( v0 == v1 ) - y = v0; - else - y = (T)(v0 + (v1-v0)*coeff ); - - //printf("%f %f -> %f\n",(double)v0,(double)v1,(double)y); - return y; - } - - rc_t _set_var_from_dual_preset_scalar_scalar( instance_t* inst, const char* var_label, const object_t* scalar_0, const object_t* scalar_1, double coeff, unsigned chIdx ) - { - rc_t rc = kOkRC; - object_t interped_value; - variable_t* dummy = nullptr; - - // one of the input values must exist - if( scalar_0==nullptr && scalar_1==nullptr ) - { - rc = cwLogError(kInvalidArgRC,"The numeric types of both operands of a dual value are null."); - goto errLabel; - } - - // It's possible that one or the other input value does not exist - if( scalar_0 == nullptr ) - scalar_0 = scalar_1; - else - { - if( scalar_1 == nullptr ) - scalar_1 = scalar_0; - } - - // verify that the input values are the same type - if( scalar_0->type->id != scalar_1->type->id ) - { - rc = cwLogError(kInvalidArgRC,"The numeric types of both operands of a dual value preset must match. (%s != %s).",cwStringNullGuard(scalar_0->type->label),cwStringNullGuard(scalar_1->type->label)); - goto errLabel; - } - - printf("%s:%s :",inst->label,var_label); - - switch( scalar_0->type->id ) - { - case kInt32TId: - interped_value.set_value( _interp_dual_value(scalar_0->u.i32,scalar_1->u.i32,coeff) ); - break; - case kUInt32TId: - interped_value.set_value( _interp_dual_value(scalar_0->u.u32,scalar_1->u.u32,coeff) ); - break; - case kInt64TId: - assert(0); - //interped_value.set_value( _interp_dual_value(scalar_0->u.i64,scalar_1->u.i64,coeff) ); - break; - case kUInt64TId: - assert(0); - //interped_value.set_value( _interp_dual_value(scalar_0->u.u64,scalar_1->u.u64,coeff) ); - break; - case kFloatTId: - interped_value.set_value( _interp_dual_value(scalar_0->u.f,scalar_1->u.f,coeff) ); - break; - case kDoubleTId: - interped_value.set_value( _interp_dual_value(scalar_0->u.d,scalar_1->u.d,coeff) ); - break; - - default: - rc = cwLogError(kInvalidStateRC,"Preset dual values of type '%s' cannot be interpolated.",cwStringNullGuard(scalar_0->type->label)); - goto errLabel; - } - - - if((rc = var_channelize( inst, var_label, chIdx, &interped_value, kInvalidId, dummy )) != kOkRC ) - { - rc = cwLogError(kInvalidArgRC,"Dual value preset application failed."); - goto errLabel; - } - - errLabel: - return rc; - } - - rc_t _set_var_from_dual_preset_list_list( instance_t* inst, const char* var_label, const object_t* list_0, const object_t* list_1, double coeff ) - { - rc_t rc = kOkRC; - - if( list_0->child_count() != list_1->child_count() ) - return cwLogError(kInvalidArgRC,"If two lists are to be applied as a dual preset they must be the same length."); - - for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) - if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,list_0->child_ele(chIdx),list_1->child_ele(chIdx),coeff,chIdx)) != kOkRC ) - goto errLabel; - - errLabel: - return rc; - } - - rc_t _set_var_from_dual_preset_scalar_list( instance_t* inst, const char* var_label, const object_t* scalar, const object_t* list, double coeff ) - { - rc_t rc = kOkRC; - for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) - if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,scalar,list->child_ele(chIdx),coeff,chIdx)) != kOkRC ) - goto errLabel; - - errLabel: - return rc; - } - - rc_t _set_var_from_dual_preset_list_scalar( instance_t* inst, const char* var_label, const object_t* list, const object_t* scalar, double coeff ) - { - rc_t rc = kOkRC; - for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) - if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,list->child_ele(chIdx),scalar,coeff,chIdx)) != kOkRC ) - goto errLabel; - - errLabel: - return rc; - } - - rc_t _set_var_from_dual_preset_scalar_scalar( instance_t* inst, const char* var_label, const object_t* scalar_0, const object_t* scalar_1, double coeff ) - { - return _set_var_from_dual_preset_scalar_scalar(inst,var_label,scalar_0,scalar_1,coeff,kAnyChIdx); - } - - - rc_t _is_legal_dual_value( const object_t* value ) - { - rc_t rc = kOkRC; - - if( value->is_list() ) - { - if( value->child_count() == 0 ) - { - rc = cwLogError(kInvalidArgRC,"Empty lists values cannot be applied as part of a dual value preset."); - goto errLabel; - } - - } - else - { - switch( value->type->id ) - { - case kInt32TId: - case kUInt32TId: - case kInt64TId: - case kUInt64TId: - case kFloatTId: - case kDoubleTId: - break; - default: - rc = cwLogError(kInvalidArgRC,"Objects of type '%s' cannot be applied as part of a dual value preset.",cwStringNullGuard(value->type->label)); - } - } - - errLabel: - return rc; - - } - - rc_t _set_var_from_dual_preset( instance_t* inst, const char* var_label, const object_t* value_0, const object_t* value_1, double coeff ) - { - rc_t rc = kOkRC; - - // dual values must be either numeric scalars or lists - if((rc = _is_legal_dual_value(value_0)) != kOkRC || (rc = _is_legal_dual_value(value_1)) != kOkRC) - goto errLabel; - - - // if both values are lists then they must be the same length - if( value_0->is_list() && value_1->is_list() ) - { - rc = _set_var_from_dual_preset_list_list( inst, var_label, value_0, value_1, coeff ); - goto errLabel; - } - else - { - // if value_0 is a list and value_1 is a scalar - if( value_0->is_list() ) - { - rc = _set_var_from_dual_preset_list_scalar( inst, var_label, value_0, value_1, coeff ); - goto errLabel; - } - else - { - // if value_1 is a list and value_0 is a scalar - if( value_1->is_list() ) - { - rc = _set_var_from_dual_preset_scalar_list( inst, var_label, value_0, value_1, coeff ); - goto errLabel; - } - else // both values are scalars - { - rc = _set_var_from_dual_preset_scalar_scalar( inst, var_label, value_0, value_1, coeff ); - goto errLabel; - } - } - } - - errLabel: - return rc; - } - - rc_t _multi_preset_channelize_vars( instance_t* inst, const char* type_src_label, const char** presetLabelA, const object_t** preset_cfgA, unsigned presetN, double coeff ) - { - rc_t rc = kOkRC; - - const char* preset_label_0 = ""; - const char* preset_label_1 = ""; - - //cwLogInfo("Channelizing '%s' preset %i vars for '%s'.",type_src_label, preset_cfg==nullptr ? 0 : preset_cfg->child_count(), inst->label ); - - if( presetN < 2 ) - { - rc = cwLogError(kInvalidArgRC,"There must be at least 2 presets selected to interpolate between preset variable dictionaries."); - goto errLabel; - } - - if( presetN > 2 ) - { - cwLogWarning("More than two presets dictionaries were specified for interpolation. Only the first two will be used."); - goto errLabel; - } - - preset_label_0 = presetLabelA[0]; - preset_label_1 = presetLabelA[1]; - - // validate each of the preset records is a dict - for(unsigned i=0; iis_dict() ) - { - rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on %s '%s' is not a dictionary.", presetLabelA[i], type_src_label, inst->class_desc->label ); - goto errLabel; - } - - - // for each preset variable in the first preset var dict - for(unsigned i=0; ichild_count(); ++i) - { - const char* var_label = preset_cfgA[0]->child_ele(i)->pair_label(); - const object_t* value_0 = preset_cfgA[0]->child_ele(i)->pair_value(); - - const object_t* value_1 = preset_cfgA[1]->find_child(var_label); - - if( value_0 == nullptr && value_1 == nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"Unexpected missig values on %s preset '%s' instance '%s' variable '%s'.", type_src_label, presetLabelA[0], inst->label, cwStringNullGuard(var_label) ); - goto errLabel; - } - - if( value_0 == nullptr ) - { - cwLogWarning("The preset variable '%s' was not found for the preset: '%s'. Falling back to single value assign.",cwStringNullGuard(var_label),cwStringNullGuard(presetLabelA[0])); - - rc = _var_channelize( inst, preset_label_1, "dual class", var_label, value_1 ); - goto errLabel; - } - - if( value_1 == nullptr ) - { - cwLogWarning("The preset variable '%s' was not found for the preset: '%s'. Falling back to single value assign.",cwStringNullGuard(var_label),cwStringNullGuard(presetLabelA[1])); - - rc = _var_channelize( inst, preset_label_0, "dual class", var_label, value_0 ); - goto errLabel; - } - - - if((rc = _set_var_from_dual_preset( inst, var_label, value_0, value_1, coeff )) != kOkRC ) - { - rc = cwLogError(rc,"Multi preset application failed on variable:%s.",cwStringNullGuard(var_label)); - goto errLabel; - } - } - - errLabel: - if( rc != kOkRC ) - rc = cwLogError(rc,"Apply %s multi-preset failed on instance:%s class:%s presetA:%s presetB:%s.", type_src_label, inst->label, inst->class_desc->label, preset_label_0, preset_label_1 ); - - return rc; - } - - - rc_t _class_multi_preset_channelize_vars(instance_t* inst, const char** class_preset_labelA, unsigned presetN, double coeff ) - { - rc_t rc = kOkRC; - const object_t* presetCfgA[ presetN ]; - const char* presetLabelA[ presetN ]; - unsigned presetCfgN = 0; - - for(unsigned i=0; iclass_desc, class_preset_labelA[i])) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The preset '%s' could not be found for the instance '%s'.", class_preset_labelA[i], inst->label); - goto errLabel; - } - - if( pr->cfg == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The value of preset '%s' was empty in instance '%s'.", class_preset_labelA[i], inst->label); - goto errLabel; - } - - presetCfgA[ presetCfgN] = pr->cfg; - presetLabelA[presetCfgN] = class_preset_labelA[i]; - presetCfgN++; - } - } - - // dispatch based on the count of presets located - switch( presetCfgN ) - { - case 0: - rc = cwLogError(kInvalidArgRC,"No valid class preset records were found while attempting apply a multi-preset."); - break; - - case 1: - // only one valid preset was located - apply it directly - rc = _preset_channelize_vars( inst, "class", presetLabelA[0], presetCfgA[0]); - break; - - default: - // more than one preset was located - apply it's interpolated values - rc = _multi_preset_channelize_vars( inst, "class", presetLabelA, presetCfgA, presetCfgN, coeff); - } - - - errLabel: - return rc; - - } - - rc_t _class_preset_channelize_vars( instance_t* inst, const char* preset_label ) - { - rc_t rc = kOkRC; - const preset_t* pr; - - if( preset_label == nullptr ) - return kOkRC; - - // locate the requestd preset record - if((pr = class_preset_find(inst->class_desc, preset_label)) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The preset '%s' could not be found for the instance '%s'.", preset_label, inst->label); - goto errLabel; - } - - rc = _preset_channelize_vars( inst, "class", preset_label, pr->cfg); - - errLabel: - return rc; - } - - - rc_t _class_apply_presets( instance_t* inst, const object_t* preset_labels ) - { - rc_t rc = kOkRC; - const char* s = nullptr; - - // if preset_labels is a string - if( preset_labels->is_string() && preset_labels->value(s)==kOkRC ) - return _class_preset_channelize_vars(inst,s); - - // if the preset_labels is not a list - if( !preset_labels->is_list() ) - rc = cwLogError(kSyntaxErrorRC,"The preset list on instance '%s' is neither a list nor a string.",inst->label); - else - { - // preset_labels is a list. - - // for each label listed in the preset label list - for(unsigned i=0; ichild_count(); ++i) - { - const object_t* label_obj = preset_labels->child_ele(i); - - // verify that the label is a strng - if( !label_obj->is_string() || label_obj->value(s) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"The preset list does not contain string on instance '%s'.",inst->label); - goto errLabel; - } - - // apply a preset label - if((rc = _class_preset_channelize_vars( inst, s)) != kOkRC ) - goto errLabel; - } - } - - errLabel: - return rc; - } - - - - - rc_t _inst_args_channelize_vars( instance_t* inst, const char* arg_label, const object_t* arg_cfg ) - { - rc_t rc = kOkRC; - - if( arg_cfg == nullptr ) - return rc; - - return _preset_channelize_vars( inst, "instance", arg_label, arg_cfg ); - - } - - typedef struct inst_parse_vars_str - { - const char* inst_label; - const char* inst_clas_label; - const object_t* in_dict; - const char* arg_label; - const object_t* preset_labels; - const object_t* arg_cfg; - } inst_parse_vars_t; - - rc_t _parse_instance_cfg( flow_t* p, const object_t* inst_cfg, inst_parse_vars_t& pvars ) - { - rc_t rc = kOkRC; - const object_t* arg_dict = nullptr; - - // validate the syntax of the inst_cfg pair - if( inst_cfg == nullptr || !inst_cfg->is_pair() || inst_cfg->pair_label()==nullptr || inst_cfg->pair_value()==nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"The instance cfg. is not a valid pair. No instance label could be parsed."); - goto errLabel; - } - - pvars.inst_label = inst_cfg->pair_label(); - - // verify that the instance label is unique - if( instance_find(p,pvars.inst_label) != nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"The instance label '%s' has already been used.",pvars.inst_label); - goto errLabel; - } - - // get the instance class label - if((rc = inst_cfg->pair_value()->getv("class",pvars.inst_clas_label)) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",pvars.inst_label); - goto errLabel; - } - - // parse the optional args - if((rc = inst_cfg->pair_value()->getv_opt("args", arg_dict, - "in", pvars.in_dict, - "argLabel", pvars.arg_label, - "preset", pvars.preset_labels)) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",pvars.inst_label); - goto errLabel; - } - - // if an argument dict was given in the instanec cfg - if( arg_dict != nullptr ) - { - bool rptErrFl = true; - - // verify the arg. dict is actually a dict. - if( !arg_dict->is_dict() ) - { - cwLogError(kSyntaxErrorRC,"The instance argument dictionary on instance '%s' is not a dictionary.",pvars.inst_label); - goto errLabel; - } - - // if no label was given then try 'default' - if( pvars.arg_label == nullptr) - { - pvars.arg_label = "default"; - rptErrFl = false; - } - - // locate the specified argument record - if((pvars.arg_cfg = arg_dict->find_child(pvars.arg_label)) == nullptr ) - { - - // if an explicit arg. label was given but it was not found - if( rptErrFl ) - { - rc = cwLogError(kSyntaxErrorRC,"The argument cfg. '%s' was not found on instance cfg. '%s'.",pvars.arg_label,pvars.inst_label); - goto errLabel; - } - - // no explicit arg. label was given - make arg_dict the instance arg cfg. - pvars.arg_cfg = arg_dict; - pvars.arg_label = nullptr; - } - } - - errLabel: - if( rc != kOkRC ) - rc = cwLogError(kSyntaxErrorRC,"Configuration parsing failed on instance: '%s'.", cwStringNullGuard(pvars.inst_label) ); - - return rc; - } - - rc_t _create_instance( flow_t* p, const object_t* inst_cfg ) - { - rc_t rc = kOkRC; - inst_parse_vars_t pvars = {}; - instance_t* inst = nullptr; - class_desc_t* class_desc = nullptr; - - // parse the instance configuration - if((rc = _parse_instance_cfg( p, inst_cfg, pvars )) != kOkRC ) - goto errLabel; - - // locate the class desc - if(( class_desc = class_desc_find(p,pvars.inst_clas_label)) == nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(pvars.inst_clas_label)); - goto errLabel; - } - - // instantiate the instance - inst = mem::allocZ(); - - inst->ctx = p; - inst->label = pvars.inst_label; - inst->inst_cfg = inst_cfg; - inst->arg_label = pvars.arg_label; - inst->arg_cfg = pvars.arg_cfg; - inst->class_desc = class_desc; - - // Instantiate all the variables in the class description - for(var_desc_t* vd=class_desc->varDescL; vd!=nullptr; vd=vd->link) - { - variable_t* var = nullptr; - if((rc = var_create( inst, vd->label, kInvalidId, kAnyChIdx, vd->val_cfg, var )) != kOkRC ) - goto errLabel; - } - - // All the variables that can be used by this instance have now been created - // and the chIdx of each variable is set to 'any'. - - // If a 'preset' field was included in the instance cfg then apply the specified class preset - if( pvars.preset_labels != nullptr ) - if((rc = _class_apply_presets(inst, pvars.preset_labels )) != kOkRC ) - goto errLabel; - - // All the class presets values have now been set and those variables - // that were expressed with a list have numeric channel indexes assigned. - - // Apply the instance preset values. - if( pvars.arg_cfg != nullptr ) - if((rc = _inst_args_channelize_vars( inst, pvars.arg_label, pvars.arg_cfg )) != kOkRC ) - goto errLabel; - - // All the instance arg values have now been set and those variables - // that were expressed with a list have numeric channel indexes assigned. - - - // TODO: Should the 'all' variable be removed for variables that have numeric channel indexes? - - // connect the variable lists in the instance 'in' dictionary - if( pvars.in_dict != nullptr ) - { - if( !pvars.in_dict->is_dict() ) - { - cwLogError(kSyntaxErrorRC,"The 'in' dict in instance '%s' is not a valid dictionary.",inst->label); - goto errLabel; - } - - // for each input variable in the 'in' set - for(unsigned i=0; ichild_count(); ++i) - { - const object_t* in_pair = pvars.in_dict->child_ele(i); - const char* in_var_label = in_pair->pair_label(); - const char* src_label = nullptr; - const var_desc_t* vd = nullptr; - - // locate the var desc of the associated variable - if((vd = var_desc_find( class_desc, in_var_label)) == nullptr ) - { - cwLogError(kSyntaxErrorRC,"The value description for the 'in' value '%s' was not found on instance '%s'. Maybe '%s' is not marked as a 'src' attribute in the class variable descripiton.",in_var_label,inst->label,in_var_label); - goto errLabel; - } - - // Note that all variable's found by the above call to var_desc_find() should be 'src' variables. - //assert( cwIsFlag(vd->flags,kSrcVarFl) ); - - // if this value is a 'src' value then it must be setup prior to the instance being instantiated - //if( cwIsFlag(vd->flags,kSrcVarFl) ) - //{ - in_pair->pair_value()->value(src_label); - - // locate the pointer to the referenced output abuf and store it in inst->srcABuf[i] - if((rc = _setup_input( p, inst, in_var_label, src_label )) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"The 'in' variable at index %i is not valid on instance '%s'.", i, inst->label ); - goto errLabel; - } - //} - } - } - - // Complete the instantiation - - // Call the custom instance create() function. - if((rc = class_desc->members->create( inst )) != kOkRC ) - { - rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s'.", inst->label ); - goto errLabel; - } - - // Create the instance->varMap[] lookup array - if((rc =_create_instance_var_map( inst )) != kOkRC ) - goto errLabel; - - // - _complete_input_connections(inst); - - // call the 'value()' function to inform the instance of the current value of all of it's variables. - if((rc = _call_value_func_on_all_variables( inst )) != kOkRC ) - goto errLabel; - - // insert an instance in the network - if( p->network_tail == nullptr ) - { - p->network_head = inst; - p->network_tail = inst; - } - else - { - p->network_tail->link = inst; - p->network_tail = inst; - } - - - errLabel: - if( rc != kOkRC ) - _destroy_inst(inst); - - return rc; - } - - rc_t _destroy( flow_t* p) { rc_t rc = kOkRC; @@ -1161,17 +317,8 @@ namespace cw if( p == nullptr ) return rc; - instance_t* i0=p->network_head; - instance_t* i1=nullptr; - - // destroy the instances - while(i0!=nullptr) - { - i1 = i0->link; - _destroy_inst(i0); - i0 = i1; - } - + network_destroy(p->net); + // release the class records for(unsigned i=0; iclassDescN; ++i) { @@ -1199,350 +346,14 @@ namespace cw } mem::release(p->classDescA); + + mem::release(p); return rc; } - const object_t* _find_network_preset( flow_t* p, const char* presetLabel ) - { - const object_t* preset_value = nullptr; - - if( p->presetCfg != nullptr ) - { - rc_t rc; - - if((rc = p->presetCfg->getv_opt( presetLabel, preset_value )) != kOkRC ) - cwLogError(rc,"Search for network preset named '%s' failed.", cwStringNullGuard(presetLabel)); - } - - return preset_value; - - } - - rc_t _exec_cycle( flow_t* p ) - { - rc_t rc = kOkRC; - - for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) - { - if((rc = inst->class_desc->members->exec(inst)) != kOkRC ) - { - break; - } - } - - return rc; - } - - rc_t _get_variable( flow_t* p, const char* inst_label, const char* var_label, unsigned chIdx, instance_t*& instPtrRef, variable_t*& varPtrRef ) - { - rc_t rc = kOkRC; - instance_t* inst = nullptr; - variable_t* var = nullptr; - - varPtrRef = nullptr; - instPtrRef = nullptr; - - // locate the proc instance - if((inst = instance_find(p,inst_label)) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"Unknown proc instance label '%s'.", cwStringNullGuard(inst_label)); - goto errLabel; - } - - // locate the variable - if((rc = var_find( inst, var_label, chIdx, var)) != kOkRC ) - { - rc = cwLogError(kInvalidArgRC,"The variable '%s' could not be found on the proc instance '%s'.",cwStringNullGuard(var_label),cwStringNullGuard(inst_label)); - goto errLabel; - } - - instPtrRef = inst; - varPtrRef = var; - - errLabel: - return rc; - } - template< typename T > - rc_t _set_variable_value( flow_t* p, const char* inst_label, const char* var_label, unsigned chIdx, T value ) - { - rc_t rc = kOkRC; - instance_t* inst = nullptr; - variable_t* var = nullptr; - - // get the variable - if((rc = _get_variable(p,inst_label,var_label,chIdx,inst,var)) != kOkRC ) - goto errLabel; - - // set the variable value - if((rc = var_set( inst, var->vid, chIdx, value )) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"The variable set failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label)); - goto errLabel; - } - - errLabel: - return rc; - } - - template< typename T > - rc_t _get_variable_value( flow_t* p, const char* inst_label, const char* var_label, unsigned chIdx, T& valueRef ) - { - rc_t rc = kOkRC; - instance_t* inst = nullptr; - variable_t* var = nullptr; - - // get the variable - if((rc = _get_variable(p,inst_label,var_label,chIdx,inst,var)) != kOkRC ) - goto errLabel; - - // get the variable value - if((rc = var_get( inst, var->vid, chIdx, valueRef )) != kOkRC ) - { - rc = cwLogError(kOpFailRC,"The variable get failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label)); - goto errLabel; - } - - errLabel: - return rc; - } - - unsigned _select_ranked_ele_by_rank_prob( const preset_order_t* presetA, const bool* selV , unsigned presetN ) - { - - // get a count of the candidate presets - unsigned rankN = selV==nullptr ? presetN : std::count_if(selV,selV+presetN,[](const bool& x){ return x; }); - - if( rankN == 0 ) - { - cwLogWarning("All preset candidates have been eliminated."); - return kInvalidIdx; - } - - unsigned rankV[ rankN ]; - unsigned idxMapA[ rankN ]; - - // fill rankV[] with candidates 'order' value - for(unsigned i=0,j=0; i 1 ); - - unsigned threshV[ rankN ]; - unsigned uniqueRankV[ rankN ]; - unsigned uniqueRankN = 0; - unsigned sel_idx = rankN - 1; // - - // for each possible rank value - for(unsigned i=0; ichild_count(); ++i) - { - const object_t* inst_pair; - if((inst_pair = net_preset_pair->child_ele(i)) != nullptr && inst_pair->is_pair() && textIsEqual(inst_pair->pair_label(),instance_label) ) - { - - preset_val_ref = inst_pair->pair_value(); - - goto errLabel; - } - } - - rc = cwLogError(kInvalidArgRC,"The preset instance label '%s' was not found.",cwStringNullGuard(preset_label)); - - errLabel: - return rc; - } } } @@ -1560,14 +371,15 @@ void cw::flow::print_external_device( const external_device_t* dev ) } + cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, - const object_t& networkCfg, + const object_t& flowCfg, external_device_t* deviceA, unsigned deviceN ) { rc_t rc = kOkRC; - const object_t* network = nullptr; + const object_t* networkCfg = nullptr; bool printClassDictFl = false; bool printNetworkFl = false; @@ -1575,7 +387,7 @@ cw::rc_t cw::flow::create( handle_t& hRef, return rc; flow_t* p = mem::allocZ(); - p->networkCfg = &networkCfg; // TODO: duplicate cfg? + p->flowCfg = &flowCfg; // TODO: duplicate cfg? p->deviceA = deviceA; p->deviceN = deviceN; @@ -1587,21 +399,20 @@ cw::rc_t cw::flow::create( handle_t& hRef, } // parse the main audio file processor cfg record - if((rc = networkCfg.getv("framesPerCycle", p->framesPerCycle, - "multiPriPresetProbFl", p->multiPriPresetProbFl, - "multiSecPresetProbFl", p->multiSecPresetProbFl, - "multiPresetInterpFl", p->multiPresetInterpFl, - "network", network)) != kOkRC ) + if((rc = flowCfg.getv("framesPerCycle", p->framesPerCycle, + "multiPriPresetProbFl", p->multiPriPresetProbFl, + "multiSecPresetProbFl", p->multiSecPresetProbFl, + "multiPresetInterpFl", p->multiPresetInterpFl, + "network", networkCfg)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the required flow configuration parameters."); goto errLabel; } // parse the optional args - if((rc = networkCfg.getv_opt("maxCycleCount", p->maxCycleCount, - "printClassDictFl", printClassDictFl, - "printNetworkFl", printNetworkFl, - "presets", p->presetCfg)) != kOkRC ) + if((rc = flowCfg.getv_opt("maxCycleCount", p->maxCycleCount, + "printClassDictFl", printClassDictFl, + "printNetworkFl", printNetworkFl)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters."); goto errLabel; @@ -1624,22 +435,15 @@ cw::rc_t cw::flow::create( handle_t& hRef, if( printClassDictFl ) class_dict_print( p ); - // build the network - for(unsigned i=0; ichild_count(); ++i) + // instantiate the network + if((rc = network_create(p,networkCfg,p->net)) != kOkRC ) { - const object_t* inst_cfg = network->child_ele(i); - - // create the instance - if( (rc= _create_instance( p, inst_cfg ) ) != kOkRC ) - { - rc = cwLogError(rc,"The instantiation at proc index %i is invalid.",i); - goto errLabel; - - } + rc = cwLogError(rc,"Network creation failed."); + goto errLabel; } if( printNetworkFl ) - network_print(p); + network_print(p->net); hRef.set(p); @@ -1689,7 +493,7 @@ unsigned cw::flow::preset_cfg_flags( handle_t h ) cw::rc_t cw::flow::exec_cycle( handle_t h ) { - return _exec_cycle(_handleToPtr(h)); + return exec_cycle(_handleToPtr(h)->net); } cw::rc_t cw::flow::exec( handle_t h ) @@ -1699,7 +503,7 @@ cw::rc_t cw::flow::exec( handle_t h ) while( true ) { - rc = _exec_cycle(p); + rc = exec_cycle(p->net); if( rc == kEofRC ) { @@ -1720,418 +524,53 @@ cw::rc_t cw::flow::exec( handle_t h ) cw::rc_t cw::flow::apply_preset( handle_t h, const char* presetLabel ) { - rc_t rc = kOkRC; flow_t* p = _handleToPtr(h); - const object_t* net_preset_value; - const object_t* preset_pair; - - // locate the cfg of the requested preset - if((net_preset_value = _find_network_preset(p, presetLabel )) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The network preset '%s' could not be found.", presetLabel ); - goto errLabel; - } - - // for each instance in the preset - for(unsigned i=0; ichild_count(); ++i) - { - // get the instance label/value pair - if((preset_pair = net_preset_value->child_ele(i)) != nullptr && preset_pair->is_pair() ) - { - const char* inst_label = preset_pair->pair_label(); - const object_t* preset_value_cfg = preset_pair->pair_value(); - instance_t* inst; - - // locate the instance - if((inst = instance_find(p,inst_label)) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The network instance '%s' refered to in network preset '%s' could not be found.",inst_label,presetLabel); - goto errLabel; - } - - // if the preset value is a string then look it up in the class dictionary - if( preset_value_cfg->is_string() ) - { - const char* class_preset_label; - preset_value_cfg->value(class_preset_label); - _class_preset_channelize_vars(inst, class_preset_label ); - } - else - { - // if the preset value is a dict then apply it directly - if( preset_value_cfg->is_dict() ) - { - if((rc = _preset_channelize_vars( inst, "network", presetLabel, preset_value_cfg )) != kOkRC ) - { - rc = cwLogError(rc,"The preset '%s' application failed on instance '%s'.", presetLabel, inst_label ); - goto errLabel; - } - - } - else - { - rc = cwLogError(kSyntaxErrorRC,"The network preset '%s' instance '%s' does not have a string or dictionary value.", presetLabel, inst_label ); - goto errLabel; - } - } - } - else - { - rc = cwLogError(kSyntaxErrorRC,"The network preset '%s' is malformed.",presetLabel); - goto errLabel; - } - } - - cwLogInfo("Activated preset:%s",presetLabel); - errLabel: - return rc; + return network_apply_preset(p->net,presetLabel); } cw::rc_t cw::flow::apply_dual_preset( handle_t h, const char* presetLabel_0, const char* presetLabel_1, double coeff ) { - rc_t rc = kOkRC; flow_t* p = _handleToPtr(h); - const object_t* net_preset_value_0; - - cwLogInfo("*** Applying dual: %s %s : %f",presetLabel_0, presetLabel_1, coeff ); - - // locate the cfg of the requested preset - if((net_preset_value_0 = _find_network_preset(p, presetLabel_0 )) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The network preset '%s' could not be found.", presetLabel_0 ); - goto errLabel; - } - - // for each instance in the preset - for(unsigned i=0; ichild_count(); ++i) - { - const object_t* preset_pair_0 = net_preset_value_0->child_ele(i); - const char* inst_label = preset_pair_0->pair_label(); - const object_t* preset_value_cfg_0 = preset_pair_0->pair_value(); - instance_t* inst = nullptr; - const object_t* preset_value_cfg_1 = nullptr; - const int two = 2; - const char* class_preset_labelA[two]; - - // get the instance label/value pair - if((preset_pair_0 = net_preset_value_0->child_ele(i)) == nullptr || !preset_pair_0->is_pair() ) - { - rc = cwLogError(kSyntaxErrorRC,"An invalid preset value pair was encountered in '%s'.",presetLabel_0); - goto errLabel; - } - - // verify that the preset value is a string or dict - if( preset_pair_0->pair_value()==nullptr || (!preset_value_cfg_0->is_dict() && !preset_value_cfg_0->is_string() )) - { - rc = cwLogError(kSyntaxErrorRC,"The preset value pair for instance '%s' in '%s' is not a 'dict' or 'string'.",inst_label,presetLabel_0); - goto errLabel; - } - - // locate the instance associated with the primary and secondary preset - if((inst = instance_find(p,inst_label)) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"The network instance '%s' refered to in network preset '%s' could not be found.",cwStringNullGuard(inst_label),cwStringNullGuard(presetLabel_0)); - goto errLabel; - } - - // locate the second instance/preset value pair - if((rc = _find_network_preset_instance_pair( p, presetLabel_1, inst_label, preset_value_cfg_1 )) != kOkRC ) - { - rc = cwLogError(kInvalidIdRC,"The second network instance '%s' refered to in network preset '%s' could not be found.",inst_label,presetLabel_1); - goto errLabel; - } - - // TODO: We require that the instance presets both be of the same type: string or dict. - // There's no good reason for this, as string's resolve to class dict presets anyway. - // Fix this! - if( !(preset_value_cfg_0->is_dict() == preset_value_cfg_1->is_dict() && preset_value_cfg_0->is_string() == preset_value_cfg_1->is_string()) ) - { - rc = cwLogError(kInvalidIdRC,"The value type (string or dict) of dual network presets must match. (%s != %s)",preset_value_cfg_0->type->label,preset_value_cfg_1->type->label); - goto errLabel; - } - - preset_value_cfg_0->value(class_preset_labelA[0]); - preset_value_cfg_1->value(class_preset_labelA[1]); - - - // if the preset value is a string then look it up in the class dictionary - if( preset_value_cfg_0->is_string() ) - { - rc = _class_multi_preset_channelize_vars(inst, class_preset_labelA, two, coeff ); - } - else - { - assert( preset_value_cfg_1->is_dict() ); - - const object_t* preset_value_cfgA[] = { preset_value_cfg_0, preset_value_cfg_1}; - - if((rc = _multi_preset_channelize_vars( inst, "network", class_preset_labelA, preset_value_cfgA, two, coeff )) != kOkRC ) - { - rc = cwLogError(rc,"The dual preset '%s':'%s' application failed on instance '%s'.", cwStringNullGuard(class_preset_labelA[0]), cwStringNullGuard(class_preset_labelA[1]), inst_label ); - goto errLabel; - } - } - } - - - errLabel: - - if( rc != kOkRC ) - rc = cwLogError(rc,"The dual preset '%s':'%s' application failed.", cwStringNullGuard(presetLabel_0), cwStringNullGuard(presetLabel_1) ); - - return rc; + return network_apply_dual_preset(p->net,presetLabel_0, presetLabel_1, coeff ); } cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& mps ) { - rc_t rc = kOkRC; - const char* label0 = nullptr; - const char* label1 = nullptr; - bool priProbFl = cwIsFlag(mps.flags, kPriPresetProbFl ); - bool secProbFl = cwIsFlag(mps.flags, kSecPresetProbFl ); - bool interpFl = cwIsFlag(mps.flags, kInterpPresetFl ); - - //printf("preset flags: pri:%i sec:%i interp:%i\n",priProbFl,secProbFl,interpFl); - - // verify that the set of candidate presets is not empty - if( mps.presetN == 0 ) - { - cwLogError(kInvalidArgRC,"A multi-preset application was requested but no presets were provided."); - goto errLabel; - } - - // if only a single candidate preset exists or needs to be selected - if( interpFl==false || mps.presetN==1 ) - { - // if only a single candidate preset is available or pri. probablity is not enabled - if( mps.presetN == 1 || priProbFl==false ) - label0 = mps.presetA[0].preset_label; - else - { - if( priProbFl ) - label0 = _select_ranked_ele_label_by_rank_prob( mps.presetA, nullptr, mps.presetN ); - else - label0 = mps.presetA[0].preset_label; - } - } - else // interpolation has been selected and at least 2 presets exist - { - unsigned pri_sel_idx = 0; - - // select the primary preset - if( priProbFl ) - pri_sel_idx = _select_ranked_ele_by_rank_prob( mps.presetA, nullptr, mps.presetN ); - else - { - // select all presets assigned to order == 1 - bool selA[ mps.presetN ]; - for(unsigned i=0; inet,mps); } -/* -cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel ) -{ - rc_t rc = kOkRC; - const char* label0 = nullptr; - const char* label1 = nullptr; - const char* prob_label = nullptr; - bool multiPriPresetProbFl = cwIsFlag(multi_preset_sel.flags, kPriPresetProbFl ); - bool multiSecPresetProbFl = cwIsFlag(multi_preset_sel.flags, kSecPresetProbFl ); - bool multiPresetInterpFl = cwIsFlag(multi_preset_sel.flags, kInterpPresetFl ); - - // verify that the set of presets to select from is not empty - if( multi_preset_sel.presetN == 0 ) - { - cwLogError(kInvalidArgRC,"A multi-preset application was requested but no presets were provided."); - goto errLabel; - } - - // if probabistic selection was requested and is possible - if( multiPresetProbFl && multi_preset_sel.presetN > 1 ) - { - auto presetA = multi_preset_sel.presetA; - auto presetN = multi_preset_sel.presetN; - - // if we are interpolating then the base preset is always the first one in presetA[] - // so do not include it as a candidate for probabilistic selection - if( multiPresetInterpFl ) - { - presetA += 1; - presetN -= 1; - - // if only one preset remains in the list then prob. selection is not possible - if( presetN == 1 ) - prob_label = presetA[0].preset_label; - } - - // select a preset based using the ranked-prob. algorithm. - if( prob_label == nullptr ) - { - unsigned prob_sel_idx; - - if((prob_sel_idx = _select_ranked_ele_by_rank_prob( presetA, presetN )) == kInvalidIdx ) - rc = cwLogWarning("The multi-preset select function failed. Selecting preset 0."); - else - { - prob_label = presetA[prob_sel_idx].preset_label; - - cwLogInfo("Multi-preset prob. select:%s : %i from %i", - cwStringNullGuard(prob_label), - prob_sel_idx, - multi_preset_sel.presetN ); - - } - } - } - - // prob_label now holds a probablistically selected preset label - // or null if prob. sel. was not requested or failed - - switch( multi_preset_sel.presetN ) - { - case 0: - assert(0); // we avoided this case at the top of the function - break; - - case 1: - // if there is only one preset to select from - label0 = multi_preset_sel.presetA[0].preset_label; - break; - - default: - // There are at least two presets ... - // ... and prob. select was not requested or failed - if( prob_label == nullptr ) - { - label0 = multi_preset_sel.presetA[0].preset_label; - label1 = multiPresetInterpFl ? multi_preset_sel.presetA[1].preset_label : nullptr; - } - else // ... and a prob. selection exists - { - // if we need two presets - if( multiPresetInterpFl ) - { - label0 = multi_preset_sel.presetA[0].preset_label; - label1 = prob_label; - } - else // otherwise we need only one - { - label0 = prob_label; - label1 = nullptr; - } - } - } - - if( label0 == nullptr ) - { - rc = cwLogError(kInvalidStateRC,"The selected multi-preset label is empty."); - goto errLabel; - } - - if( label1 == nullptr ) - { - rc = apply_preset( h, label0 ); - } - else - { - double coeff = _calc_multi_preset_dual_coeff(multi_preset_sel); - rc = apply_dual_preset( h, label0, label1, coeff ); - } - -errLabel: - return rc; -} -*/ cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool value ) -{ return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } +{ return set_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, value ); } cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, int value ) -{ return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } +{ return set_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, value ); } cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, unsigned value ) -{ return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } +{ return set_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, value ); } cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, float value ) -{ return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } +{ return set_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, value ); } cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, double value ) -{ return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } +{ return set_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, value ); } cw::rc_t cw::flow::get_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool& valueRef ) -{ return _get_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, valueRef ); } +{ return get_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, valueRef ); } cw::rc_t cw::flow::get_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, int& valueRef ) -{ return _get_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, valueRef ); } +{ return get_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, valueRef ); } cw::rc_t cw::flow::get_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, unsigned& valueRef ) -{ return _get_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, valueRef ); } +{ return get_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, valueRef ); } cw::rc_t cw::flow::get_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, float& valueRef ) -{ return _get_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, valueRef ); } +{ return get_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, valueRef ); } cw::rc_t cw::flow::get_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, double& valueRef ) -{ return _get_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, valueRef ); } +{ return get_variable_value( _handleToPtr(h)->net, inst_label, var_label, chIdx, valueRef ); } @@ -2148,7 +587,7 @@ void cw::flow::print_network( handle_t h ) for(unsigned i=0; ideviceN; ++i) print_external_device( p->deviceA + i ); - network_print(p); + network_print(p->net); } diff --git a/cwFlow.h b/cwFlow.h index 945840b..51a767c 100644 --- a/cwFlow.h +++ b/cwFlow.h @@ -8,64 +8,6 @@ namespace cw typedef handle handle_t; - enum - { - kAudioDevTypeId, - kMidiDevTypeId, - kSerialDevTypeId, - kSocketDevTypeId - }; - - enum - { - kInFl = 0x01, - kOutFl = 0x02 - }; - - - struct abuf_str; - - typedef struct audio_dev_cfg_str - { - struct abuf_str* abuf; // Buffer to receive incoming or send outgoing audio for this device - // The audio_in/audio_out proc's locate and use these buffers. - } audio_dev_cfg_t; - - struct external_device_str; - - typedef rc_t (*send_midi_triple_func_t)( struct external_device_str* dev, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 ); - - typedef struct midi_dev_cfg_str - { - // msgArray[] contains the current msgs for all devices NOT just the device that this record is embedded in. - // We do this so that the order of messages as they arrived is maintained. Otherwise, to achieve this ordering, - // the messages for all devices would need to be collected and sorted by time. - const midi::ch_msg_t* msgArray; - unsigned msgCnt; - - unsigned maxMsgCnt; // max possible value of msgCnt - send_midi_triple_func_t sendTripleFunc; - } midi_dev_cfg_t; - - // Generate external device record - typedef struct external_device_str - { - void* reserved; - const char* devLabel; // IO framework device label - const char* portLabel; // IO framework MIDI port label (only used by MIDI devices) - unsigned typeId; // see ???DevTypeId above - unsigned flags; // see ???Fl above - - unsigned ioDevIdx; // IO framework device index - unsigned ioPortIdx; // IO framework MIDI port index (only used by MIDI devices) - - union - { - audio_dev_cfg_t a; // audio devices use this record - midi_dev_cfg_t m; // MIDI " " " " - } u; - - } external_device_t; void print_abuf( const struct abuf_str* abuf ); @@ -86,11 +28,11 @@ namespace cw rc_t exec_cycle( handle_t h ); // Run the network to completion. - rc_t exec( handle_t h ); + rc_t exec( handle_t h ); rc_t apply_preset( handle_t h, const char* presetLabel ); - rc_t apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel ); rc_t apply_dual_preset( handle_t h, const char* presetLabel_0, const char* presetLabel_1, double coeff ); + rc_t apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel ); rc_t set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool value ); diff --git a/cwFlowDecl.h b/cwFlowDecl.h index 7303f99..044cf24 100644 --- a/cwFlowDecl.h +++ b/cwFlowDecl.h @@ -5,6 +5,67 @@ namespace cw { namespace flow { + + enum + { + kAudioDevTypeId, + kMidiDevTypeId, + kSerialDevTypeId, + kSocketDevTypeId + }; + + enum + { + kInFl = 0x01, + kOutFl = 0x02 + }; + + + struct abuf_str; + + typedef struct audio_dev_cfg_str + { + struct abuf_str* abuf; // Buffer to receive incoming or send outgoing audio for this device + // The audio_in/audio_out proc's locate and use these buffers. + } audio_dev_cfg_t; + + struct external_device_str; + + typedef rc_t (*send_midi_triple_func_t)( struct external_device_str* dev, uint8_t ch, uint8_t status, uint8_t d0, uint8_t d1 ); + + typedef struct midi_dev_cfg_str + { + // msgArray[] contains the current msgs for all devices NOT just the device that this record is embedded in. + // We do this so that the order of messages as they arrived is maintained. Otherwise, to achieve this ordering, + // the messages for all devices would need to be collected and sorted by time. + const midi::ch_msg_t* msgArray; + unsigned msgCnt; + + unsigned maxMsgCnt; // max possible value of msgCnt + send_midi_triple_func_t sendTripleFunc; + } midi_dev_cfg_t; + + // Generate external device record + typedef struct external_device_str + { + void* reserved; + const char* devLabel; // IO framework device label + const char* portLabel; // IO framework MIDI port label (only used by MIDI devices) + unsigned typeId; // see ???DevTypeId above + unsigned flags; // see ???Fl above + + unsigned ioDevIdx; // IO framework device index + unsigned ioPortIdx; // IO framework MIDI port index (only used by MIDI devices) + + union + { + audio_dev_cfg_t a; // audio devices use this record + midi_dev_cfg_t m; // MIDI " " " " + } u; + + } external_device_t; + + enum { kPriPresetProbFl = 0x01, kSecPresetProbFl = 0x02, diff --git a/cwFlowNet.cpp b/cwFlowNet.cpp new file mode 100644 index 0000000..19be4ec --- /dev/null +++ b/cwFlowNet.cpp @@ -0,0 +1,2279 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwText.h" +#include "cwNumericConvert.h" +#include "cwObject.h" + +#include "cwAudioFile.h" +#include "cwVectOps.h" +#include "cwMtx.h" +#include "cwDspTypes.h" // real_t, sample_t +#include "cwTime.h" +#include "cwMidiDecls.h" +#include "cwFlowDecl.h" +#include "cwFlowTypes.h" +#include "cwFlowNet.h" +#include "cwFlowProc.h" + +namespace cw +{ + namespace flow + { + + void _destroy_inst( instance_t* inst ) + { + if( inst == nullptr ) + return; + + if( inst->class_desc->members->destroy != nullptr && inst->userPtr != nullptr ) + inst->class_desc->members->destroy( inst ); + + // destroy the instance variables + variable_t* var0 = inst->varL; + variable_t* var1 = nullptr; + while( var0 != nullptr ) + { + var1 = var0->var_link; + _var_destroy(var0); + var0 = var1; + } + + inst->varL = nullptr; + + mem::release(inst->label); + mem::release(inst->varMapA); + mem::release(inst); + } + + rc_t _network_destroy( network_t& net ) + { + rc_t rc = kOkRC; + + for(unsigned i=0; iconnect_link = src_var->connect_link; + src_var->connect_link = in_var; + + assert( src_var->value != nullptr ); + + in_var->value = src_var->value; + in_var->src_var = src_var; + } + + rc_t _create_instance_var_map( instance_t* inst ) + { + rc_t rc = kOkRC; + unsigned max_vid = kInvalidId; + unsigned max_chIdx = 0; + variable_t* var = inst->varL; + //variable_t* v0 = nullptr; + + // determine the max variable vid and max channel index value among all variables + for(; var!=nullptr; var = var->var_link ) + { + if( var->vid != kInvalidId ) + { + if( max_vid == kInvalidId || var->vid > max_vid ) + max_vid = var->vid; + + if( var->chIdx != kAnyChIdx && (var->chIdx+1) > max_chIdx ) + max_chIdx = (var->chIdx + 1); + + } + } + + // If there are any variables + if( max_vid != kInvalidId ) + { + // create the variable map array + inst->varMapChN = max_chIdx + 1; + inst->varMapIdN = max_vid + 1; + inst->varMapN = inst->varMapIdN * inst->varMapChN; + inst->varMapA = mem::allocZ( inst->varMapN ); + + // assign each variable to a location in the map + for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) + if( var->vid != kInvalidId ) + { + unsigned idx = kInvalidIdx; + + if((rc = _var_map_id_to_index( inst, var->vid, var->chIdx, idx )) != kOkRC ) + goto errLabel; + + + // verify that there are not multiple variables per map position + if( inst->varMapA[ idx ] != nullptr ) + { + variable_t* v0 = inst->varMapA[idx]; + rc = cwLogError(kInvalidStateRC,"The variable '%s' id:%i ch:%i and '%s' id:%i ch:%i share the same variable map position on instance: %s. This is usually cased by duplicate variable id's.", + v0->label,v0->vid,v0->chIdx, var->label,var->vid,var->chIdx,inst->label); + + goto errLabel; + } + + // assign this variable to a map position + inst->varMapA[ idx ] = var; + + if( var->chIdx != kAnyChIdx && var->value == nullptr ) + { + rc = cwLogError(kInvalidStateRC,"The value of the variable '%s' ch:%i on instance:'%s' has not been set.",var->label,var->chIdx,inst->label); + goto errLabel; + } + + } + + } + + errLabel: + return rc; + + } + + void _complete_input_connections( instance_t* inst ) + { + for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) + if(var->chIdx == kAnyChIdx && is_connected_to_external_proc(var) ) + { + + variable_t* base_src_var = var->src_var; + + // since 'var' is on the 'any' channel the 'src' var must also be on the 'any' channel + assert( base_src_var->chIdx == kAnyChIdx ); + + //printf("%s %s\n",inst->label,var->label); + + // for each var channel in the input var + for(variable_t* in_var = var->ch_link; in_var != nullptr; in_var=in_var->ch_link) + { + // locate the matching channel on the 'src' var + variable_t* svar = base_src_var; + for(; svar!=nullptr; svar=svar->ch_link) + if( svar->chIdx == in_var->chIdx ) + break; + + // connect the src->input var + _connect_vars( svar==nullptr ? base_src_var : svar, in_var); + } + } + } + + rc_t _call_value_func_on_all_variables( instance_t* inst ) + { + rc_t rc = kOkRC; + rc_t rc1 = kOkRC; + + for(unsigned i=0; ivarMapN; ++i) + if( inst->varMapA[i] != nullptr && inst->varMapA[i]->vid != kInvalidId ) + { + variable_t* var = inst->varMapA[i]; + + if((rc = var->inst->class_desc->members->value( var->inst, var )) != kOkRC ) + rc1 = cwLogError(rc,"The proc instance '%s:%i' reported an invalid valid on variable:%s chIdx:%i.", var->inst->label, var->inst->label_sfx_id, var->label, var->chIdx ); + } + + return rc1; + } + + rc_t _var_channelize( instance_t* inst, const char* preset_label, const char* type_src_label, const char* value_label, const object_t* value ) + { + rc_t rc = kOkRC; + + variable_t* dummy = nullptr; + + // verify that a valid value exists + if( value == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"Unexpected missig value on %s preset '%s' instance '%s' variable '%s'.", type_src_label, preset_label, inst->label, cwStringNullGuard(value_label) ); + goto errLabel; + } + + // if a list of values was given + if( value->is_list() ) + { + for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) + if((rc = var_channelize( inst, value_label, kBaseSfxId, chIdx, value->child_ele(chIdx), kInvalidId, dummy )) != kOkRC ) + goto errLabel; + } + else // otherwise a single value was given + { + if((rc = var_channelize( inst, value_label, kBaseSfxId, kAnyChIdx, value, kInvalidId, dummy )) != kOkRC ) + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t _preset_channelize_vars( instance_t* inst, const char* type_src_label, const char* preset_label, const object_t* preset_cfg ) + { + rc_t rc = kOkRC; + + //cwLogInfo("Channelizing '%s' preset %i vars for '%s'.",type_src_label, preset_cfg==nullptr ? 0 : preset_cfg->child_count(), inst->label ); + + // validate the syntax of the preset record + if( !preset_cfg->is_dict() ) + { + rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on %s '%s' is not a dictionary.", preset_label, type_src_label, inst->class_desc->label ); + goto errLabel; + } + + + // for each preset variable + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* value = preset_cfg->child_ele(i)->pair_value(); + const char* value_label = preset_cfg->child_ele(i)->pair_label(); + if((rc = _var_channelize( inst, preset_label, type_src_label, value_label, value )) != kOkRC ) + goto errLabel; + + + } + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(rc,"Apply %s preset failed on instance:%s class:%s preset:%s.", type_src_label, inst->label, inst->class_desc->label, preset_label ); + + return rc; + } + + + template< typename T > + T _interp_dual_value( T v0, T v1, double coeff ) + { + T y; + if( v0 == v1 ) + y = v0; + else + y = (T)(v0 + (v1-v0)*coeff ); + + //printf("%f %f -> %f\n",(double)v0,(double)v1,(double)y); + return y; + } + + rc_t _set_var_from_dual_preset_scalar_scalar( instance_t* inst, const char* var_label, const object_t* scalar_0, const object_t* scalar_1, double coeff, unsigned chIdx ) + { + rc_t rc = kOkRC; + object_t interped_value; + variable_t* dummy = nullptr; + + // one of the input values must exist + if( scalar_0==nullptr && scalar_1==nullptr ) + { + rc = cwLogError(kInvalidArgRC,"The numeric types of both operands of a dual value are null."); + goto errLabel; + } + + // It's possible that one or the other input value does not exist + if( scalar_0 == nullptr ) + scalar_0 = scalar_1; + else + { + if( scalar_1 == nullptr ) + scalar_1 = scalar_0; + } + + // verify that the input values are the same type + if( scalar_0->type->id != scalar_1->type->id ) + { + rc = cwLogError(kInvalidArgRC,"The numeric types of both operands of a dual value preset must match. (%s != %s).",cwStringNullGuard(scalar_0->type->label),cwStringNullGuard(scalar_1->type->label)); + goto errLabel; + } + + printf("%s:%s :",inst->label,var_label); + + switch( scalar_0->type->id ) + { + case kInt32TId: + interped_value.set_value( _interp_dual_value(scalar_0->u.i32,scalar_1->u.i32,coeff) ); + break; + case kUInt32TId: + interped_value.set_value( _interp_dual_value(scalar_0->u.u32,scalar_1->u.u32,coeff) ); + break; + case kInt64TId: + assert(0); + //interped_value.set_value( _interp_dual_value(scalar_0->u.i64,scalar_1->u.i64,coeff) ); + break; + case kUInt64TId: + assert(0); + //interped_value.set_value( _interp_dual_value(scalar_0->u.u64,scalar_1->u.u64,coeff) ); + break; + case kFloatTId: + interped_value.set_value( _interp_dual_value(scalar_0->u.f,scalar_1->u.f,coeff) ); + break; + case kDoubleTId: + interped_value.set_value( _interp_dual_value(scalar_0->u.d,scalar_1->u.d,coeff) ); + break; + + default: + rc = cwLogError(kInvalidStateRC,"Preset dual values of type '%s' cannot be interpolated.",cwStringNullGuard(scalar_0->type->label)); + goto errLabel; + } + + + if((rc = var_channelize( inst, var_label, kBaseSfxId, chIdx, &interped_value, kInvalidId, dummy )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"Dual value preset application failed."); + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t _set_var_from_dual_preset_list_list( instance_t* inst, const char* var_label, const object_t* list_0, const object_t* list_1, double coeff ) + { + rc_t rc = kOkRC; + + if( list_0->child_count() != list_1->child_count() ) + return cwLogError(kInvalidArgRC,"If two lists are to be applied as a dual preset they must be the same length."); + + for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) + if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,list_0->child_ele(chIdx),list_1->child_ele(chIdx),coeff,chIdx)) != kOkRC ) + goto errLabel; + + errLabel: + return rc; + } + + rc_t _set_var_from_dual_preset_scalar_list( instance_t* inst, const char* var_label, const object_t* scalar, const object_t* list, double coeff ) + { + rc_t rc = kOkRC; + for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) + if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,scalar,list->child_ele(chIdx),coeff,chIdx)) != kOkRC ) + goto errLabel; + + errLabel: + return rc; + } + + rc_t _set_var_from_dual_preset_list_scalar( instance_t* inst, const char* var_label, const object_t* list, const object_t* scalar, double coeff ) + { + rc_t rc = kOkRC; + for(unsigned chIdx=0; chIdxchild_count(); ++chIdx) + if((rc = _set_var_from_dual_preset_scalar_scalar(inst,var_label,list->child_ele(chIdx),scalar,coeff,chIdx)) != kOkRC ) + goto errLabel; + + errLabel: + return rc; + } + + rc_t _set_var_from_dual_preset_scalar_scalar( instance_t* inst, const char* var_label, const object_t* scalar_0, const object_t* scalar_1, double coeff ) + { + return _set_var_from_dual_preset_scalar_scalar(inst,var_label,scalar_0,scalar_1,coeff,kAnyChIdx); + } + + + rc_t _is_legal_dual_value( const object_t* value ) + { + rc_t rc = kOkRC; + + if( value->is_list() ) + { + if( value->child_count() == 0 ) + { + rc = cwLogError(kInvalidArgRC,"Empty lists values cannot be applied as part of a dual value preset."); + goto errLabel; + } + + } + else + { + switch( value->type->id ) + { + case kInt32TId: + case kUInt32TId: + case kInt64TId: + case kUInt64TId: + case kFloatTId: + case kDoubleTId: + break; + default: + rc = cwLogError(kInvalidArgRC,"Objects of type '%s' cannot be applied as part of a dual value preset.",cwStringNullGuard(value->type->label)); + } + } + + errLabel: + return rc; + + } + + rc_t _set_var_from_dual_preset( instance_t* inst, const char* var_label, const object_t* value_0, const object_t* value_1, double coeff ) + { + rc_t rc = kOkRC; + + // dual values must be either numeric scalars or lists + if((rc = _is_legal_dual_value(value_0)) != kOkRC || (rc = _is_legal_dual_value(value_1)) != kOkRC) + goto errLabel; + + + // if both values are lists then they must be the same length + if( value_0->is_list() && value_1->is_list() ) + { + rc = _set_var_from_dual_preset_list_list( inst, var_label, value_0, value_1, coeff ); + goto errLabel; + } + else + { + // if value_0 is a list and value_1 is a scalar + if( value_0->is_list() ) + { + rc = _set_var_from_dual_preset_list_scalar( inst, var_label, value_0, value_1, coeff ); + goto errLabel; + } + else + { + // if value_1 is a list and value_0 is a scalar + if( value_1->is_list() ) + { + rc = _set_var_from_dual_preset_scalar_list( inst, var_label, value_0, value_1, coeff ); + goto errLabel; + } + else // both values are scalars + { + rc = _set_var_from_dual_preset_scalar_scalar( inst, var_label, value_0, value_1, coeff ); + goto errLabel; + } + } + } + + errLabel: + return rc; + } + + rc_t _multi_preset_channelize_vars( instance_t* inst, const char* type_src_label, const char** presetLabelA, const object_t** preset_cfgA, unsigned presetN, double coeff ) + { + rc_t rc = kOkRC; + + const char* preset_label_0 = ""; + const char* preset_label_1 = ""; + + //cwLogInfo("Channelizing '%s' preset %i vars for '%s'.",type_src_label, preset_cfg==nullptr ? 0 : preset_cfg->child_count(), inst->label ); + + if( presetN < 2 ) + { + rc = cwLogError(kInvalidArgRC,"There must be at least 2 presets selected to interpolate between preset variable dictionaries."); + goto errLabel; + } + + if( presetN > 2 ) + { + cwLogWarning("More than two presets dictionaries were specified for interpolation. Only the first two will be used."); + goto errLabel; + } + + preset_label_0 = presetLabelA[0]; + preset_label_1 = presetLabelA[1]; + + // validate each of the preset records is a dict + for(unsigned i=0; iis_dict() ) + { + rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on %s '%s' is not a dictionary.", presetLabelA[i], type_src_label, inst->class_desc->label ); + goto errLabel; + } + + + // for each preset variable in the first preset var dict + for(unsigned i=0; ichild_count(); ++i) + { + const char* var_label = preset_cfgA[0]->child_ele(i)->pair_label(); + const object_t* value_0 = preset_cfgA[0]->child_ele(i)->pair_value(); + + const object_t* value_1 = preset_cfgA[1]->find_child(var_label); + + if( value_0 == nullptr && value_1 == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"Unexpected missig values on %s preset '%s' instance '%s' variable '%s'.", type_src_label, presetLabelA[0], inst->label, cwStringNullGuard(var_label) ); + goto errLabel; + } + + if( value_0 == nullptr ) + { + cwLogWarning("The preset variable '%s' was not found for the preset: '%s'. Falling back to single value assign.",cwStringNullGuard(var_label),cwStringNullGuard(presetLabelA[0])); + + rc = _var_channelize( inst, preset_label_1, "dual class", var_label, value_1 ); + goto errLabel; + } + + if( value_1 == nullptr ) + { + cwLogWarning("The preset variable '%s' was not found for the preset: '%s'. Falling back to single value assign.",cwStringNullGuard(var_label),cwStringNullGuard(presetLabelA[1])); + + rc = _var_channelize( inst, preset_label_0, "dual class", var_label, value_0 ); + goto errLabel; + } + + + if((rc = _set_var_from_dual_preset( inst, var_label, value_0, value_1, coeff )) != kOkRC ) + { + rc = cwLogError(rc,"Multi preset application failed on variable:%s.",cwStringNullGuard(var_label)); + goto errLabel; + } + } + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(rc,"Apply %s multi-preset failed on instance:%s class:%s presetA:%s presetB:%s.", type_src_label, inst->label, inst->class_desc->label, preset_label_0, preset_label_1 ); + + return rc; + } + + + rc_t _class_multi_preset_channelize_vars(instance_t* inst, const char** class_preset_labelA, unsigned presetN, double coeff ) + { + rc_t rc = kOkRC; + const object_t* presetCfgA[ presetN ]; + const char* presetLabelA[ presetN ]; + unsigned presetCfgN = 0; + + for(unsigned i=0; iclass_desc, class_preset_labelA[i])) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The preset '%s' could not be found for the instance '%s'.", class_preset_labelA[i], inst->label); + goto errLabel; + } + + if( pr->cfg == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The value of preset '%s' was empty in instance '%s'.", class_preset_labelA[i], inst->label); + goto errLabel; + } + + presetCfgA[ presetCfgN] = pr->cfg; + presetLabelA[presetCfgN] = class_preset_labelA[i]; + presetCfgN++; + } + } + + // dispatch based on the count of presets located + switch( presetCfgN ) + { + case 0: + rc = cwLogError(kInvalidArgRC,"No valid class preset records were found while attempting apply a multi-preset."); + break; + + case 1: + // only one valid preset was located - apply it directly + rc = _preset_channelize_vars( inst, "class", presetLabelA[0], presetCfgA[0]); + break; + + default: + // more than one preset was located - apply it's interpolated values + rc = _multi_preset_channelize_vars( inst, "class", presetLabelA, presetCfgA, presetCfgN, coeff); + } + + + errLabel: + return rc; + + } + + rc_t _class_preset_channelize_vars( instance_t* inst, const char* preset_label ) + { + rc_t rc = kOkRC; + const preset_t* pr; + + if( preset_label == nullptr ) + return kOkRC; + + // locate the requestd preset record + if((pr = class_preset_find(inst->class_desc, preset_label)) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The preset '%s' could not be found for the instance '%s'.", preset_label, inst->label); + goto errLabel; + } + + rc = _preset_channelize_vars( inst, "class", preset_label, pr->cfg); + + errLabel: + return rc; + } + + + rc_t _class_apply_presets( instance_t* inst, const object_t* preset_labels ) + { + rc_t rc = kOkRC; + const char* s = nullptr; + + // if preset_labels is a string + if( preset_labels->is_string() && preset_labels->value(s)==kOkRC ) + return _class_preset_channelize_vars(inst,s); + + // if the preset_labels is not a list + if( !preset_labels->is_list() ) + rc = cwLogError(kSyntaxErrorRC,"The preset list on instance '%s' is neither a list nor a string.",inst->label); + else + { + // preset_labels is a list. + + // for each label listed in the preset label list + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* label_obj = preset_labels->child_ele(i); + + // verify that the label is a strng + if( !label_obj->is_string() || label_obj->value(s) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The preset list does not contain string on instance '%s'.",inst->label); + goto errLabel; + } + + // apply a preset label + if((rc = _class_preset_channelize_vars( inst, s)) != kOkRC ) + goto errLabel; + } + } + + errLabel: + return rc; + } + + + + + rc_t _proc_inst_args_channelize_vars( instance_t* inst, const char* arg_label, const object_t* arg_cfg ) + { + rc_t rc = kOkRC; + + if( arg_cfg == nullptr ) + return rc; + + return _preset_channelize_vars( inst, "instance", arg_label, arg_cfg ); + + } + + + //======================================================================================================= + // + // network creation + // + + enum { + kInVarTypeId = 0x01, + kSrcProcTypeId = 0x02, + kSrcVarTypeId = 0x04 + }; + + typedef struct in_ele_str + { + unsigned typeId; // See k???_InFl above + char* label; // label of in or src id + unsigned base_sfx_id; // literal base_sfx_id or kInvalidId if the base_sfx_id was not given or 'is_iter_fl' is false + unsigned sfx_id_count; // literal sfx_id_count or kInvalidCnt if not given + unsigned is_iter_fl; // this id included an '_' + } in_ele_t; + + typedef struct in_stmt_str + { + in_ele_t in_var_ele; // in-var element + char* src_net_label; // src-net label (null=in-var net, '_'=root net, string=named net) + network_t* src_net; // network containing the src-proc + in_ele_t src_proc_ele; // src-proc element + in_ele_t src_var_ele; // src-var element + var_desc_t* in_var_desc; // Pointer to the in-var var_desc. + bool create_in_fl; // True if the in_var needs to be created with an sfx_id, false create the var by the default process (w/o sfx_id) + in_ele_t* iter_cnt_ctl_ele; // Pointer to the ele which is controlling the iteration count (or null if in-var is non-iterating) + unsigned iter_cnt; // Count of iterations or 0 if in-var is non-iterating. + } in_stmt_t; + + typedef struct proc_inst_parse_statestr + { + const char* inst_label; // + const char* inst_clas_label; // + const char* arg_label; // + const object_t* preset_labels; // + const object_t* arg_cfg; // + const object_t* in_dict; // cfg. node to the in-list + in_stmt_t* in_array; // in_array[ in_arrayN ] in-stmt array + unsigned in_arrayN; // count of in-stmt's in the in-list. + } proc_inst_parse_state_t; + + bool _is_non_null_pair( const object_t* cfg ) + { return cfg != nullptr && cfg->is_pair() && cfg->pair_label()!=nullptr && cfg->pair_value()!=nullptr; } + + + rc_t _parse_in_ele( const char* id_str, in_ele_t& r ) + { + rc_t rc = kOkRC; + unsigned bufN; + + r.base_sfx_id = kInvalidId; + r.sfx_id_count = kInvalidCnt; + + if((bufN = textLength(id_str)) == 0 ) + { + rc = cwLogError(kSyntaxErrorRC,"A blank connection id string was encountered."); + goto errLabel; + } + else + { + char* underscore = nullptr; + char* digit = nullptr; + char buf[ bufN+1 ]; + + // copy the id string into a non-const scratch buffer + textCopy(buf,bufN+1,id_str); + + // locate the last underscore + if((underscore = lastMatchChar(buf,'_')) != nullptr ) + { + *underscore = 0; // terminate the string prior to the underscore + + for(digit = underscore + 1; *digit; digit++) + if( !isdigit(*digit) ) + break; + + // if the underscore was followed by a number + // or if the underscore was the last char + // in the string - then digit will point to + // the terminating zero - otherwise the + // underscore did not indicate an iterating id + if( *digit != 0 ) + { + *underscore = '_'; // replace the underscore - its part of the label + underscore = nullptr; + } + else + { + r.is_iter_fl = true; + + // if there is a number following the underscore then this is the secInt + if( textLength(underscore + 1) ) + { + // a literal iteration count was given - parse it into an integer + if((rc = string_to_number(underscore + 1,r.sfx_id_count)) != kOkRC ) + { + rc = cwLogError(rc,"Unable to parse the secondary integer in the connection label '%s'.",cwStringNullGuard(id_str)); + goto errLabel; + } + } + } + } + + // verify that some content remains in the id string + if( textLength(buf) == 0 ) + { + rc = cwLogError(kSyntaxErrorRC,"Unable to parse the connection id string '%s'.",cwStringNullGuard(id_str)); + goto errLabel; + } + + // go backward from the last char until the begin-of-string or a non-digit is found + for(digit=buf + textLength(buf)-1; digit>buf; --digit) + if(!isdigit(*digit) ) + { + ++digit; // advance to the first digit in the number + break; + } + + // if a digit was found then this is the 'priInt' + if( textLength(digit) ) + { + assert( buf <= digit-1 && digit-1 <= buf + bufN ); + + // a literal base-sfx-id was given - parse it into an integer + if((rc = string_to_number(digit,r.base_sfx_id)) != kOkRC ) + { + rc = cwLogError(rc,"Unable to parse the primary integer in the connection label '%s'.",cwStringNullGuard(id_str)); + goto errLabel; + } + + *digit = 0; // zero terminate the label + + } + + // verify that some content remains in the id string + if( textLength(buf) == 0 ) + { + rc = cwLogError(kSyntaxErrorRC,"Unexpected invalid connection id string '%s'.",cwStringNullGuard(id_str)); + goto errLabel; + + } + else + { + // store the label + r.label = mem::duplStr(buf); + } + } + + + errLabel: + return rc; + } + + rc_t _calc_src_proc_ele_count(network_t& net, in_ele_t& src_proc_ele, unsigned& cnt_ref) + { + rc_t rc = kOkRC; + cnt_ref = 0; + + // if a literal proc sfx_id was given then use it otherwise use the default base-sfx-id (0) + unsigned sfx_id = src_proc_ele.base_sfx_id==kInvalidCnt ? kBaseSfxId : src_proc_ele.base_sfx_id; + unsigned n; + for(n=0; instance_find(net, src_proc_ele.label, sfx_id ) != nullptr; ++n ) + sfx_id += 1; + + if( n == 0 ) + { + rc = cwLogError(kSyntaxErrorRC,"The src-proc '%s:%i' was not found.",cwStringNullGuard(src_proc_ele.label),sfx_id); + goto errLabel; + } + + cnt_ref = n; + errLabel: + return rc; + } + + rc_t _calc_src_var_ele_count(network_t& net, const in_ele_t& src_proc_ele, const in_ele_t& src_var_ele, unsigned& cnt_ref) + { + rc_t rc = kOkRC; + instance_t* src_proc = nullptr; + unsigned proc_sfx_id = src_proc_ele.base_sfx_id==kInvalidCnt ? kBaseSfxId : src_proc_ele.base_sfx_id; + + cnt_ref = 0; + + // locate the parent proc of this var + if((src_proc = instance_find(net,src_proc_ele.label,proc_sfx_id)) == nullptr ) + { + cwLogError(kSyntaxErrorRC,"The src-proc instance '%s:%i' could not be found.",cwStringNullGuard(src_proc_ele.label),proc_sfx_id); + goto errLabel; + } + else + { + // if a starting var sfx_id was given by the id then use it otherwise use the default base-sfx-id (0) + unsigned sfx_id = src_var_ele.base_sfx_id==kInvalidCnt ? kBaseSfxId : src_var_ele.base_sfx_id; + unsigned n; + for(n=0; var_exists(src_proc,src_var_ele.label, sfx_id, kAnyChIdx ); ++n ) + sfx_id += 1; + + + if( n == 0 ) + { + cwLogError(kSyntaxErrorRC,"The src-var '%s:%i' was not found.",cwStringNullGuard(src_var_ele.label),sfx_id); + goto errLabel; + } + + cnt_ref = n; + + } + + errLabel: + return rc; + } + + // If the in-var is iterating then the count of iterations must be controlled by exactly one + // of the 3 parts of the in-stmt: in-var,src_proc, or src_var. This function determines + // which element is used to determine the iteration count. + rc_t _determine_in_stmt_iter_count_ctl_ele(network_t& net, instance_t* inst, in_stmt_t& in_stmt ) + { + assert( in_stmt.in_var_ele.is_iter_fl ); + rc_t rc = kOkRC; + + in_ele_t* iter_cnt_ctl_ele = nullptr; + + // if the in-var gives a literal count - then it determines the count + if( in_stmt.in_var_ele.sfx_id_count != kInvalidCnt ) + { + // if the in-var gives a literal count then the src-proc cannot give one + if( in_stmt.src_proc_ele.sfx_id_count != kInvalidCnt ) + { + rc = cwLogError(kSyntaxErrorRC,"The in-var provided a literal iteration count therefore the src-proc cannot."); + goto errLabel; + } + + // if the in-var gives a literal count then the src-var cannot give one + if( in_stmt.src_var_ele.sfx_id_count != kInvalidCnt ) + { + rc = cwLogError(kSyntaxErrorRC,"The in-var provided a literal iteration count therefore the src-var cannot."); + goto errLabel; + } + + iter_cnt_ctl_ele = &in_stmt.in_var_ele; + + } + else // the src-proc or src-var must control the iter count + { + // if the src-proc gives a literal count - then it determines th count + if( in_stmt.src_proc_ele.sfx_id_count != kInvalidCnt ) + { + // then the src-var cannot give a literal count + if( in_stmt.src_var_ele.sfx_id_count != kInvalidCnt ) + { + rc = cwLogError(kSyntaxErrorRC,"The src-proc provided a literal iteration count therefore the src-var cannot."); + goto errLabel; + } + + iter_cnt_ctl_ele = &in_stmt.src_proc_ele; + + } + else + { + // if the src-var gives a literal count - then it determines the count + if( in_stmt.src_var_ele.sfx_id_count != kInvalidCnt ) + { + iter_cnt_ctl_ele = &in_stmt.src_var_ele; + } + else // no literal count was given - we need to get the implied count + { + // if the src-proc is iterating then it will provide the count + if( in_stmt.src_proc_ele.is_iter_fl ) + { + // the src-var cannot be iterating if the src-proc is iterating + if( in_stmt.src_var_ele.is_iter_fl ) + { + rc = cwLogError(kSyntaxErrorRC,"The src-proc is iterating therefore the src-var cannot."); + goto errLabel; + } + + iter_cnt_ctl_ele = &in_stmt.src_proc_ele; + } + else // the src-proc isn't iterating check the src-var + { + if( in_stmt.src_var_ele.is_iter_fl ) + { + iter_cnt_ctl_ele = &in_stmt.src_var_ele; + } + else // no iteration count control was found + { + rc = cwLogError(kSyntaxErrorRC,"No iteration count control was specified."); + goto errLabel; + } + } + } + } + } + + errLabel: + + if( rc == kOkRC ) + in_stmt.iter_cnt_ctl_ele = iter_cnt_ctl_ele; + + return rc; + } + + rc_t _determine_in_stmt_iter_count( network_t& net,instance_t* inst, in_stmt_t& in_stmt ) + { + rc_t rc = kOkRC; + + // it has already been determined that this an iterating in-stmt + // and a iteration count control element has been identified. + assert( in_stmt.in_var_ele.is_iter_fl ); + assert( in_stmt.iter_cnt_ctl_ele != nullptr ); + + switch( in_stmt.iter_cnt_ctl_ele->typeId ) + { + case kInVarTypeId: + + assert( in_stmt.iter_cnt_ctl_ele->sfx_id_count != kInvalidCnt ); + + if((in_stmt.iter_cnt = in_stmt.iter_cnt_ctl_ele->sfx_id_count) == 0 ) + rc = cwLogError(rc,"The literal in-var iteration count on '%s:%i' must be greater than zero.", cwStringNullGuard(in_stmt.iter_cnt_ctl_ele->label),in_stmt.iter_cnt_ctl_ele->base_sfx_id); + break; + + case kSrcProcTypeId: + if((rc = _calc_src_proc_ele_count( *in_stmt.src_net, in_stmt.src_proc_ele, in_stmt.iter_cnt )) != kOkRC ) + rc = cwLogError(rc,"Unable to determine the in-stmt iteration count based on the iteration control src-proc '%s'.",cwStringNullGuard(in_stmt.src_proc_ele.label)); + break; + + case kSrcVarTypeId: + if((rc = _calc_src_var_ele_count( *in_stmt.src_net, in_stmt.src_proc_ele, in_stmt.src_var_ele, in_stmt.iter_cnt )) != kOkRC ) + rc = cwLogError(rc,"Unable to determine the in-stmt iteration count based on the iteration control src-var '%s'.",cwStringNullGuard(in_stmt.src_var_ele.label)); + + break; + + default: + rc = cwLogError(kInvalidStateRC,"An unknown in-stmt element type was encountered."); + } + + return rc; + } + + void _destroy_in_stmt( in_stmt_t& s ) + { + mem::release(s.in_var_ele.label); + mem::release(s.src_net_label); + mem::release(s.src_proc_ele.label); + mem::release(s.src_var_ele.label); + } + + rc_t _parse_in_stmt_src_net_proc_var_string( char* str, char*& src_net_label, const char*& src_proc_label, const char*& src_var_label ) + { + rc_t rc = kOkRC; + char* period0 = nullptr; + char* period1 = nullptr; + + // locate the separator period on the src proc/var id + if((period0 = firstMatchChar(str,'.')) == nullptr ) + { + cwLogError(kSyntaxErrorRC,"No period separator was found in the src net/proc/var for the src specifier:%s.",str); + goto errLabel; + } + + *period0 = 0; + + if((period1 = firstMatchChar(period0+1,'.')) != nullptr ) + { + *period1 = 0; + src_var_label = period1 + 1; // Set a pointer to the src var label + src_proc_label = period0 + 1; + src_net_label = mem::duplStr(str); + } + else + { + src_var_label = period0 + 1; + src_proc_label = str; + src_net_label = nullptr; + } + + if( textLength(src_var_label) == 0 ) + rc = cwLogError(kSyntaxErrorRC,"The 'src-var' label has length 0."); + + if( textLength(src_proc_label) == 0 ) + rc = cwLogError(kSyntaxErrorRC,"The 'src-proc' label has length 0."); + + + errLabel: + return rc; + } + + + // Recursively search the tree of networks rooted on 'net' for the + // network named 'net_inst_label'. + network_t* _find_labeled_network( network_t& net, const char* net_inst_label ) + { + network_t* labeled_net = nullptr; + + // for each instance in the network + for(unsigned i=0; iinternal_net != nullptr ) + { + // if the name of the network matches the key ... + if( textIsEqual(inst->label,net_inst_label) ) + labeled_net = inst->internal_net; // .. we are done + else + { + // ... otherwise recurse + labeled_net = _find_labeled_network(*inst->internal_net,net_inst_label); + } + } + + } + return labeled_net; + } + + // Set 'in_stmt.src_net' based on 'in_stmt.src_net_label' + rc_t _locate_src_net(network_t& net,instance_t* inst, in_stmt_t& in_stmt) + { + rc_t rc = kOkRC; + network_t* src_net = nullptr; + + in_stmt.src_net = nullptr; + + if( in_stmt.src_net_label == nullptr ) + src_net = &net; + else + { + if( textIsEqual(in_stmt.src_net_label,"_") ) + src_net = &inst->ctx->net; + else + { + if((src_net = _find_labeled_network(inst->ctx->net,in_stmt.src_net_label)) == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The source net '%s' was not found.",cwStringNullGuard(in_stmt.src_net_label)); + goto errLabel; + } + } + } + errLabel: + in_stmt.src_net = src_net; + + if( in_stmt.src_net == nullptr ) + rc = cwLogError(kSyntaxErrorRC,"No source net was found."); + + return rc; + } + + + rc_t _create_in_stmt( network_t& net, instance_t* inst, in_stmt_t& in_stmt, const char* in_var_str, const char* src_proc_var_str ) + { + rc_t rc = kOkRC; + unsigned src_char_cnt = 0; + + in_stmt.in_var_ele.typeId = kInVarTypeId; + in_stmt.src_proc_ele.typeId = kSrcProcTypeId; + in_stmt.src_var_ele.typeId = kSrcVarTypeId; + + // verify the src proc/var string is valid + if( (src_char_cnt = textLength(src_proc_var_str)) == 0 ) + { + cwLogError(kSyntaxErrorRC,"No source variable was found for the input variable '%s'.",cwStringNullGuard(in_var_str)); + goto errLabel; + } + else + { + const char* src_proc_label = nullptr; + const char* src_var_label = nullptr; + + char str[ src_char_cnt+1 ]; + + // put the src proc/var string into a non-const scratch buffer + textCopy(str,src_char_cnt+1,src_proc_var_str); + + // parse the src part into it's 3 parts + if((rc = _parse_in_stmt_src_net_proc_var_string(str, in_stmt.src_net_label, src_proc_label, src_var_label )) != kOkRC ) + { + cwLogError(rc,"Unable to parse the 'src' part of an 'in-stmt'."); + goto errLabel; + } + + // parse the in-var + if((rc = _parse_in_ele( in_var_str, in_stmt.in_var_ele )) != kOkRC ) + { + rc = cwLogError(rc,"Unable to parse the in-var from '%s'.",cwStringNullGuard(in_var_str)); + goto errLabel; + } + + // parse the src-proc + if((rc = _parse_in_ele( src_proc_label, in_stmt.src_proc_ele )) != kOkRC ) + { + rc = cwLogError(rc,"Unable to parse the in-var from '%s'.",cwStringNullGuard(in_var_str)); + goto errLabel; + } + + // parse the src-var + if((rc = _parse_in_ele( src_var_label, in_stmt.src_var_ele )) != kOkRC ) + { + rc = cwLogError(rc,"Unable to parse the in-var from '%s'.",cwStringNullGuard(in_var_str)); + goto errLabel; + } + + // get the var class desc. for the in-var + if(( in_stmt.in_var_desc = var_desc_find(inst->class_desc,in_stmt.in_var_ele.label)) == nullptr ) + { + rc = cwLogError(rc,"Unable to locate the var class desc for the in-var from '%s'.",cwStringNullGuard(in_stmt.in_var_ele.label)); + goto errLabel; + } + + // get the src net + if((rc = _locate_src_net(net,inst,in_stmt)) != kOkRC ) + { + rc = cwLogError(rc,"Unable to locate the src-net '%s'.",cwStringNullGuard(in_stmt.src_net_label)); + goto errLabel; + } + + // if the in-var has an sfx_id, or is iterating, then the var needs to be created (the dflt creation process assumes no sfx id) + if( in_stmt.in_var_ele.base_sfx_id != kInvalidId || in_stmt.in_var_ele.is_iter_fl ) + { + in_stmt.create_in_fl = true; + if( in_stmt.in_var_ele.base_sfx_id == kInvalidId ) + in_stmt.in_var_ele.base_sfx_id = kBaseSfxId; + } + + // if the src-proc is not iterating and the src-proc was not given a literal sfx-id + if( in_stmt.src_proc_ele.is_iter_fl==false && in_stmt.src_proc_ele.base_sfx_id==kInvalidId && in_stmt.src_net==&net) + in_stmt.src_proc_ele.base_sfx_id = inst->label_sfx_id; + + // if this is not an iterating in-stmt ... + if( !in_stmt.in_var_ele.is_iter_fl ) + { + in_stmt.iter_cnt = 1; // ... then it must be a simple 1:1 connection + } + else + { + // if the in-stmt is iterating then determine the in-stmt element which controls the iteration count + if((rc = _determine_in_stmt_iter_count_ctl_ele(net,inst,in_stmt)) != kOkRC || in_stmt.iter_cnt_ctl_ele==nullptr) + { + rc = cwLogError(rc,"Unable to determine the iter count control ele."); + goto errLabel; + } + + // if the in-stmt is iterating then determine the iteration count + if((rc = _determine_in_stmt_iter_count(net,inst,in_stmt)) != kOkRC ) + { + cwLogError(rc,"Unable to determine the in-stmt iteration count."); + goto errLabel; + } + } + } + + errLabel: + if( rc != kOkRC ) + _destroy_in_stmt(in_stmt); + + return rc; + } + + rc_t _parse_in_list( network_t& net, instance_t* inst, proc_inst_parse_state_t& pstate ) + { + rc_t rc = kOkRC; + + if( pstate.in_dict == nullptr ) + goto errLabel; + + if( !pstate.in_dict->is_dict() ) + { + cwLogError(kSyntaxErrorRC,"The 'in' dict in instance '%s' is not a valid dictionary.",inst->label); + goto errLabel; + } + + if( pstate.in_dict->child_count() == 0 ) + goto errLabel; + + pstate.in_arrayN = pstate.in_dict->child_count(); + pstate.in_array = mem::allocZ(pstate.in_arrayN); + + // for each input variable in the 'in' set + for(unsigned i=0; ichild_ele(i); // in:src pair + const char* in_var_str = in_pair->pair_label(); // 'in' var string + const char* src_proc_var_str = nullptr; + + // get the src net/proc/var string + if((rc = in_pair->pair_value()->value(src_proc_var_str)) != kOkRC ) + { + cwLogError(rc,"Unable to access the source proc/var string for the input var '%s'.",cwStringNullGuard(in_var_str)); + goto errLabel; + } + + // + if((rc= _create_in_stmt(net, inst, in_stmt, in_var_str, src_proc_var_str )) != kOkRC ) + { + cwLogError(rc,"Parse failed on the in-connection '%s:%s'.",cwStringNullGuard(in_var_str),cwStringNullGuard(src_proc_var_str)); + goto errLabel; + } + + // create the var + if( in_stmt.create_in_fl ) + { + for(unsigned i=0; ilabel, + in_stmt.in_var_ele.base_sfx_id + i, + kInvalidId, + kAnyChIdx, + in_stmt.in_var_desc->val_cfg, + dum )) != kOkRC ) + { + rc = cwLogError(rc,"in-stmt var create failed on '%s:%s'.",cwStringNullGuard(in_var_str),cwStringNullGuard(src_proc_var_str)); + goto errLabel; + } + } + } + + } + + errLabel: + + return rc; + + } + + bool _is_var_inst_already_created( const char* var_label, const proc_inst_parse_state_t& pstate ) + { + for(unsigned i=0; ivarDesc->type, src_var->varDesc->type) ) + { + rc = cwLogError(kSyntaxErrorRC,"The type flags don't match on input:%s:%i source:%s:%i.%s:%i .", in_var_label, in_var_sfx_id, src_proc_label, src_proc_sfx_id, src_var_label, src_var_sfx_id); + goto errLabel; + } + + // verify that the source exists + if( src_var->value == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The source value is null on the connection input::%s:%i source:%s:%i.%s:%i .", in_var_label, in_var_sfx_id, src_proc_label, src_proc_sfx_id, src_var_label, src_var_sfx_id); + goto errLabel; + } + + // + _connect_vars( src_var, in_var ); + } + } + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(rc,"Connection failed on proc '%s:%i'.",inst->label,inst->label_sfx_id); + return rc; + } + + + rc_t _parse_proc_inst_cfg( network_t& net, const object_t* proc_inst_cfg, unsigned sfx_id, proc_inst_parse_state_t& pstate ) + { + rc_t rc = kOkRC; + const object_t* arg_dict = nullptr; + + // validate the syntax of the proc_inst_cfg pair + if( !_is_non_null_pair(proc_inst_cfg)) + { + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. is not a valid pair. No instance label could be parsed."); + goto errLabel; + } + + pstate.inst_label = proc_inst_cfg->pair_label(); + + // verify that the instance label is unique + if( instance_find(net,pstate.inst_label,sfx_id) != nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The proc instance label '%s:%i' has already been used.",pstate.inst_label,sfx_id); + goto errLabel; + } + + // get the instance class label + if((rc = proc_inst_cfg->pair_value()->getv("class",pstate.inst_clas_label)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",pstate.inst_label); + goto errLabel; + } + + // parse the optional args + if((rc = proc_inst_cfg->pair_value()->getv_opt("args", arg_dict, + "in", pstate.in_dict, + "argLabel", pstate.arg_label, + "preset", pstate.preset_labels)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",pstate.inst_label); + goto errLabel; + } + + // if an argument dict was given in the instance cfg + if( arg_dict != nullptr ) + { + bool rptErrFl = true; + + // verify the arg. dict is actually a dict. + if( !arg_dict->is_dict() ) + { + cwLogError(kSyntaxErrorRC,"The instance argument dictionary on instance '%s' is not a dictionary.",pstate.inst_label); + goto errLabel; + } + + // if no label was given then try 'default' + if( pstate.arg_label == nullptr) + { + pstate.arg_label = "default"; + rptErrFl = false; + } + + // locate the specified argument record + if((pstate.arg_cfg = arg_dict->find_child(pstate.arg_label)) == nullptr ) + { + + // if an explicit arg. label was given but it was not found + if( rptErrFl ) + { + rc = cwLogError(kSyntaxErrorRC,"The argument cfg. '%s' was not found on instance cfg. '%s'.",pstate.arg_label,pstate.inst_label); + goto errLabel; + } + + // no explicit arg. label was given - make arg_dict the instance arg cfg. + pstate.arg_cfg = arg_dict; + pstate.arg_label = nullptr; + } + } + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(kSyntaxErrorRC,"Configuration parsing failed on instance: '%s'.", cwStringNullGuard(pstate.inst_label) ); + + return rc; + } + + void _destroy_pstate( proc_inst_parse_state_t pstate ) + { + for(unsigned i=0; iclass_desc->label,proc_clas_label) ) + ++n; + return n; + } + + rc_t _create_instance( flow_t* p, const object_t* proc_inst_cfg, unsigned sfx_id, network_t& net, instance_t*& inst_ref ) + { + rc_t rc = kOkRC; + proc_inst_parse_state_t pstate = {}; + instance_t* inst = nullptr; + class_desc_t* class_desc = nullptr; + + inst_ref = nullptr; + + // parse the instance configuration + if((rc = _parse_proc_inst_cfg( net, proc_inst_cfg, sfx_id, pstate )) != kOkRC ) + goto errLabel; + + // locate the class desc + if(( class_desc = class_desc_find(p,pstate.inst_clas_label)) == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(pstate.inst_clas_label)); + goto errLabel; + } + + // if the poly instance count has been exceeded for this proc inst class ... + if(class_desc->polyLimitN > 0 && _poly_copy_count(net,pstate.inst_clas_label) >= class_desc->polyLimitN ) + { + // ... then silently skip this instantiation + cwLogDebug("The poly class copy count has been exceeded for '%s' - skipping instantiation of sfx_id:%i.",pstate.inst_label,sfx_id); + goto errLabel; + } + + // instantiate the instance + inst = mem::allocZ(); + + inst->ctx = p; + inst->label = mem::duplStr(pstate.inst_label); + inst->label_sfx_id = sfx_id; + inst->proc_cfg = proc_inst_cfg->pair_value(); + inst->arg_label = pstate.arg_label; + inst->arg_cfg = pstate.arg_cfg; + inst->class_desc = class_desc; + inst->net = &net; + + // parse the in-list ,fill in pstate.in_array, and create var instances for var's referenced by in-list + if((rc = _parse_in_list( net, inst, pstate )) != kOkRC ) + { + rc = cwLogError(rc,"in-list parse failed on proc instance '%s:%i'.",cwStringNullGuard(inst->label),sfx_id); + goto errLabel; + } + + // Instantiate all the variables in the class description - that were not already created in _parse_in_list() + for(var_desc_t* vd=class_desc->varDescL; vd!=nullptr; vd=vd->link) + if( !_is_var_inst_already_created( vd->label, pstate ) ) + { + variable_t* var = nullptr; + if((rc = var_create( inst, vd->label, kBaseSfxId, kInvalidId, kAnyChIdx, vd->val_cfg, var )) != kOkRC ) + goto errLabel; + } + + // All the variables that can be used by this instance have now been created + // and the chIdx of each variable is set to 'any'. + + // If a 'preset' field was included in the class cfg then apply the specified class preset + if( pstate.preset_labels != nullptr ) + if((rc = _class_apply_presets(inst, pstate.preset_labels )) != kOkRC ) + goto errLabel; + + // All the class presets values have now been set and those variables + // that were expressed with a list have numeric channel indexes assigned. + + // Apply the proc instance preset values. + if( pstate.arg_cfg != nullptr ) + if((rc = _proc_inst_args_channelize_vars( inst, pstate.arg_label, pstate.arg_cfg )) != kOkRC ) + goto errLabel; + + // All the instance arg values have now been set and those variables + // that were expressed with a list have numeric channel indexes assigned. + + + // TODO: Should the 'all' variable be removed for variables that have numeric channel indexes? + + // Connect the in-list variables to their sources. + if((rc = _connect_in_vars(net, inst, pstate)) != kOkRC ) + { + rc = cwLogError(rc,"Creation of the proc instance '%s:%i' failed during input connection processing.",cwStringNullGuard(inst->label),inst->label_sfx_id); + goto errLabel; + } + + // Complete the instantiation of the proc instance by calling the custom instance creation function. + + // Call the custom instance create() function. + if((rc = class_desc->members->create( inst )) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s:%i'.", inst->label,inst->label_sfx_id ); + goto errLabel; + } + + // Create the instance->varMap[] lookup array + if((rc =_create_instance_var_map( inst )) != kOkRC ) + goto errLabel; + + // the custom creation function may have added channels to in-list vars fix up those connections here. + _complete_input_connections(inst); + + // call the 'value()' function to inform the instance of the current value of all of it's variables. + if((rc = _call_value_func_on_all_variables( inst )) != kOkRC ) + goto errLabel; + + + inst_ref = inst; + + /* + // insert an instance in the network + if( net.network_tail == nullptr ) + { + net.network_head = inst; + net.network_tail = inst; + } + else + { + net.network_tail->link = inst; + net.network_tail = inst; + } + */ + + errLabel: + if( rc != kOkRC ) + _destroy_inst(inst); + _destroy_pstate(pstate); + + return rc; + } + + //======================================================================================================= + // + // Apply presets + // + + + unsigned _select_ranked_ele_by_rank_prob( const preset_order_t* presetA, const bool* selV , unsigned presetN ) + { + + // get a count of the candidate presets + unsigned rankN = selV==nullptr ? presetN : std::count_if(selV,selV+presetN,[](const bool& x){ return x; }); + + if( rankN == 0 ) + { + cwLogWarning("All preset candidates have been eliminated."); + return kInvalidIdx; + } + + unsigned rankV[ rankN ]; + unsigned idxMapA[ rankN ]; + + // fill rankV[] with candidates 'order' value + for(unsigned i=0,j=0; i 1 ); + + unsigned threshV[ rankN ]; + unsigned uniqueRankV[ rankN ]; + unsigned uniqueRankN = 0; + unsigned sel_idx = rankN - 1; // + + // for each possible rank value + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* inst_pair; + if((inst_pair = net_preset_pair->child_ele(i)) != nullptr && inst_pair->is_pair() && textIsEqual(inst_pair->pair_label(),instance_label) ) + { + + preset_val_ref = inst_pair->pair_value(); + + goto errLabel; + } + } + + rc = cwLogError(kInvalidArgRC,"The preset instance label '%s' was not found.",cwStringNullGuard(preset_label)); + + errLabel: + return rc; + } + + + } +} + +cw::rc_t cw::flow::network_create( flow_t* p, + const object_t* networkCfg, + network_t& net, + unsigned polyCnt, + network_order_id_t orderId ) +{ + rc_t rc = kOkRC; + + // default to kNetFirstPolyOrderId + unsigned outerN = polyCnt; + unsigned innerN = 1; + + if((rc = networkCfg->getv("procs",net.procsCfg)) != kOkRC ) + { + rc = cwLogError(rc,"Failed on parsing required network cfg. elements."); + goto errLabel; + } + + if((rc = networkCfg->getv_opt("presets",net.presetsCfg)) != kOkRC ) + { + rc = cwLogError(rc,"Failed on parsing optional network cfg. elements."); + goto errLabel; + } + + + if( orderId == kProcFirstPolyOrderId ) + { + outerN = 1; + innerN = polyCnt; + } + + net.proc_arrayAllocN = polyCnt * net.procsCfg->child_count(); + net.proc_array = mem::allocZ(net.proc_arrayAllocN); + net.proc_arrayN = 0; + + for(unsigned i=0; ichild_count(); ++j) + { + const object_t* proc_cfg = net.procsCfg->child_ele(j); + + for(unsigned k=0; kgetv_opt( presetLabel, preset_value )) != kOkRC ) + cwLogError(rc,"Search for network preset named '%s' failed.", cwStringNullGuard(presetLabel)); + } + + return preset_value; + +} + +cw::rc_t cw::flow::exec_cycle( network_t& net ) +{ + rc_t rc = kOkRC; + + for(unsigned i=0; iclass_desc->members->exec(net.proc_array[i])) != kOkRC ) + { + break; + } + } + + return rc; +} + +cw::rc_t cw::flow::get_variable( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, instance_t*& instPtrRef, variable_t*& varPtrRef ) +{ + rc_t rc = kOkRC; + instance_t* inst = nullptr; + variable_t* var = nullptr; + + varPtrRef = nullptr; + instPtrRef = nullptr; + + // locate the proc instance + if((inst = instance_find(net,inst_label,kBaseSfxId)) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"Unknown proc instance label '%s'.", cwStringNullGuard(inst_label)); + goto errLabel; + } + + // locate the variable + if((rc = var_find( inst, var_label, kBaseSfxId, chIdx, var)) != kOkRC ) + { + rc = cwLogError(kInvalidArgRC,"The variable '%s' could not be found on the proc instance '%s'.",cwStringNullGuard(var_label),cwStringNullGuard(inst_label)); + goto errLabel; + } + + instPtrRef = inst; + varPtrRef = var; + +errLabel: + return rc; +} + + +cw::rc_t cw::flow::network_apply_preset( network_t& net, const char* presetLabel ) +{ + rc_t rc = kOkRC; + const object_t* net_preset_value; + const object_t* preset_pair; + + // locate the cfg of the requested preset + if((net_preset_value = find_network_preset(net, presetLabel )) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The network preset '%s' could not be found.", presetLabel ); + goto errLabel; + } + + // for each instance in the preset + for(unsigned i=0; ichild_count(); ++i) + { + // get the instance label/value pair + if((preset_pair = net_preset_value->child_ele(i)) != nullptr && preset_pair->is_pair() ) + { + const char* inst_label = preset_pair->pair_label(); + const object_t* preset_value_cfg = preset_pair->pair_value(); + instance_t* inst; + + // locate the instance + if((inst = instance_find(net,inst_label,kBaseSfxId)) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The network instance '%s' refered to in network preset '%s' could not be found.",inst_label,presetLabel); + goto errLabel; + } + + // if the preset value is a string then look it up in the class preset dictionary + if( preset_value_cfg->is_string() ) + { + const char* class_preset_label; + preset_value_cfg->value(class_preset_label); + _class_preset_channelize_vars(inst, class_preset_label ); + } + else + { + // if the preset value is a dict then apply it directly + if( preset_value_cfg->is_dict() ) + { + if((rc = _preset_channelize_vars( inst, "network", presetLabel, preset_value_cfg )) != kOkRC ) + { + rc = cwLogError(rc,"The preset '%s' application failed on instance '%s'.", presetLabel, inst_label ); + goto errLabel; + } + + } + else + { + rc = cwLogError(kSyntaxErrorRC,"The network preset '%s' instance '%s' does not have a string or dictionary value.", presetLabel, inst_label ); + goto errLabel; + } + } + } + else + { + rc = cwLogError(kSyntaxErrorRC,"The network preset '%s' is malformed.",presetLabel); + goto errLabel; + } + } + + cwLogInfo("Activated preset:%s",presetLabel); +errLabel: + return rc; +} + +cw::rc_t cw::flow::network_apply_dual_preset( network_t& net, const char* presetLabel_0, const char* presetLabel_1, double coeff ) +{ + rc_t rc = kOkRC; + + const object_t* net_preset_value_0; + + cwLogInfo("*** Applying dual: %s %s : %f",presetLabel_0, presetLabel_1, coeff ); + + // locate the cfg of the requested preset + if((net_preset_value_0 = find_network_preset(net, presetLabel_0 )) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The network preset '%s' could not be found.", presetLabel_0 ); + goto errLabel; + } + + // for each instance in the preset + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* preset_pair_0 = net_preset_value_0->child_ele(i); + const char* inst_label = preset_pair_0->pair_label(); + const object_t* preset_value_cfg_0 = preset_pair_0->pair_value(); + instance_t* inst = nullptr; + const object_t* preset_value_cfg_1 = nullptr; + const int two = 2; + const char* class_preset_labelA[two]; + + // get the instance label/value pair + if((preset_pair_0 = net_preset_value_0->child_ele(i)) == nullptr || !preset_pair_0->is_pair() ) + { + rc = cwLogError(kSyntaxErrorRC,"An invalid preset value pair was encountered in '%s'.",presetLabel_0); + goto errLabel; + } + + // verify that the preset value is a string or dict + if( preset_pair_0->pair_value()==nullptr || (!preset_value_cfg_0->is_dict() && !preset_value_cfg_0->is_string() )) + { + rc = cwLogError(kSyntaxErrorRC,"The preset value pair for instance '%s' in '%s' is not a 'dict' or 'string'.",inst_label,presetLabel_0); + goto errLabel; + } + + // locate the instance associated with the primary and secondary preset + if((inst = instance_find(net,inst_label,kBaseSfxId)) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"The network instance '%s' refered to in network preset '%s' could not be found.",cwStringNullGuard(inst_label),cwStringNullGuard(presetLabel_0)); + goto errLabel; + } + + // locate the second instance/preset value pair + if((rc = _find_network_preset_instance_pair(net, presetLabel_1, inst_label, preset_value_cfg_1 )) != kOkRC ) + { + rc = cwLogError(kInvalidIdRC,"The second network instance '%s' refered to in network preset '%s' could not be found.",inst_label,presetLabel_1); + goto errLabel; + } + + // TODO: We require that the instance presets both be of the same type: string or dict. + // There's no good reason for this, as string's resolve to class dict presets anyway. + // Fix this! + if( !(preset_value_cfg_0->is_dict() == preset_value_cfg_1->is_dict() && preset_value_cfg_0->is_string() == preset_value_cfg_1->is_string()) ) + { + rc = cwLogError(kInvalidIdRC,"The value type (string or dict) of dual network presets must match. (%s != %s)",preset_value_cfg_0->type->label,preset_value_cfg_1->type->label); + goto errLabel; + } + + preset_value_cfg_0->value(class_preset_labelA[0]); + preset_value_cfg_1->value(class_preset_labelA[1]); + + + // if the preset value is a string then look it up in the class dictionary + if( preset_value_cfg_0->is_string() ) + { + rc = _class_multi_preset_channelize_vars(inst, class_preset_labelA, two, coeff ); + } + else + { + assert( preset_value_cfg_1->is_dict() ); + + const object_t* preset_value_cfgA[] = { preset_value_cfg_0, preset_value_cfg_1}; + + if((rc = _multi_preset_channelize_vars( inst, "network", class_preset_labelA, preset_value_cfgA, two, coeff )) != kOkRC ) + { + rc = cwLogError(rc,"The dual preset '%s':'%s' application failed on instance '%s'.", cwStringNullGuard(class_preset_labelA[0]), cwStringNullGuard(class_preset_labelA[1]), inst_label ); + goto errLabel; + } + } + } + + +errLabel: + + if( rc != kOkRC ) + rc = cwLogError(rc,"The dual preset '%s':'%s' application failed.", cwStringNullGuard(presetLabel_0), cwStringNullGuard(presetLabel_1) ); + + return rc; +} + +cw::rc_t cw::flow::network_apply_preset( network_t& net, const multi_preset_selector_t& mps ) +{ + rc_t rc = kOkRC; + const char* label0 = nullptr; + const char* label1 = nullptr; + bool priProbFl = cwIsFlag(mps.flags, kPriPresetProbFl ); + bool secProbFl = cwIsFlag(mps.flags, kSecPresetProbFl ); + bool interpFl = cwIsFlag(mps.flags, kInterpPresetFl ); + + //printf("preset flags: pri:%i sec:%i interp:%i\n",priProbFl,secProbFl,interpFl); + + // verify that the set of candidate presets is not empty + if( mps.presetN == 0 ) + { + cwLogError(kInvalidArgRC,"A multi-preset application was requested but no presets were provided."); + goto errLabel; + } + + // if only a single candidate preset exists or needs to be selected + if( interpFl==false || mps.presetN==1 ) + { + // if only a single candidate preset is available or pri. probablity is not enabled + if( mps.presetN == 1 || priProbFl==false ) + label0 = mps.presetA[0].preset_label; + else + { + if( priProbFl ) + label0 = _select_ranked_ele_label_by_rank_prob( mps.presetA, nullptr, mps.presetN ); + else + label0 = mps.presetA[0].preset_label; + } + } + else // interpolation has been selected and at least 2 presets exist + { + unsigned pri_sel_idx = 0; + + // select the primary preset + if( priProbFl ) + pri_sel_idx = _select_ranked_ele_by_rank_prob( mps.presetA, nullptr, mps.presetN ); + else + { + // select all presets assigned to order == 1 + bool selA[ mps.presetN ]; + for(unsigned i=0; i + rc_t set_variable_value( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, T value ) + { + rc_t rc = kOkRC; + instance_t* inst = nullptr; + variable_t* var = nullptr; + + // get the variable + if((rc = get_variable(net,inst_label,var_label,chIdx,inst,var)) != kOkRC ) + goto errLabel; + + // set the variable value + if((rc = var_set( inst, var->vid, chIdx, value )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The variable set failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label)); + goto errLabel; + } + + errLabel: + return rc; + } + + template< typename T > + rc_t get_variable_value( network_t& net, const char* inst_label, const char* var_label, unsigned chIdx, T& valueRef ) + { + rc_t rc = kOkRC; + instance_t* inst = nullptr; + variable_t* var = nullptr; + + // get the variable + if((rc = get_variable(net,inst_label,var_label,chIdx,inst,var)) != kOkRC ) + goto errLabel; + + // get the variable value + if((rc = var_get( inst, var->vid, chIdx, valueRef )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The variable get failed on instance:'%s' variable:'%s'.",cwStringNullGuard(inst_label),cwStringNullGuard(var_label)); + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t network_apply_preset( network_t& net, const char* presetLabel ); + rc_t network_apply_dual_preset( network_t& net, const char* presetLabel_0, const char* presetLabel_1, double coeff ); + rc_t network_apply_preset( network_t& net, const multi_preset_selector_t& mps ); + + + } +} + + +#endif diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index 5eff84e..bb23ca1 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -17,6 +17,7 @@ #include "cwFlowDecl.h" #include "cwFlow.h" #include "cwFlowTypes.h" +#include "cwFlowNet.h" #include "cwFlowProc.h" #include "cwFile.h" @@ -89,6 +90,119 @@ namespace cw }; } + + //------------------------------------------------------------------------------------------------------------------ + // + // poly + // + namespace poly + { + enum + { + kCountPId, + kOrderPId, + }; + + typedef struct + { + unsigned count; + network_t net; + network_order_id_t orderId; + } inst_t; + + + rc_t create( instance_t* proc ) + { + rc_t rc = kOkRC; + inst_t* inst = mem::allocZ(); + const object_t* networkCfg = nullptr; + const char* order_label = nullptr; + + proc->userPtr = inst; + + if((rc = var_register_and_get( proc, kAnyChIdx, + kCountPId, "count", kBaseSfxId, inst->count, + kOrderPId, "order", kBaseSfxId, order_label )) != kOkRC ) + goto errLabel; + + if( inst->count == 0 ) + { + cwLogWarning("The 'poly' %s:%i was given a count of 0.",proc->label,proc->label_sfx_id); + goto errLabel; + } + + if((rc = proc->proc_cfg->getv("network",networkCfg)) != kOkRC ) + { + rc = cwLogError(rc,"The 'network' cfg. was not found."); + goto errLabel; + } + + // get the network exec. order type + if( textIsEqual(order_label,"net") ) + inst->orderId = kNetFirstPolyOrderId; + else + { + if( textIsEqual(order_label,"proc") ) + inst->orderId = kProcFirstPolyOrderId; + else + { + rc = cwLogError(kInvalidArgRC,"'%s' is not one of the valid order types (i.e. 'net','proc').",order_label); + goto errLabel; + } + } + + if((rc = network_create(proc->ctx,networkCfg,inst->net,inst->count )) != kOkRC ) + { + rc = cwLogError(rc,"Creation failed on the internal network."); + goto errLabel; + } + + + // Set the internal net pointer in the base proc instance + // so that network based utilities can scan it + proc->internal_net = &inst->net; + + errLabel: + return rc; + } + + rc_t destroy( instance_t* proc ) + { + inst_t* p = (inst_t*)proc->userPtr; + network_destroy(p->net); + + + mem::release( proc->userPtr ); + return kOkRC; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + return kOkRC; + } + + rc_t exec( instance_t* ctx ) + { + inst_t* p = (inst_t*)ctx->userPtr; + rc_t rc = kOkRC; + + if((rc = exec_cycle(p->net)) != kOkRC ) + { + rc = cwLogError(rc,"poly internal network exec failed."); + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = nullptr + }; + + } //------------------------------------------------------------------------------------------------------------------ // @@ -115,12 +229,12 @@ namespace cw real_t in_value = 0.5; ctx->userPtr = mem::allocZ(); - if((rc = var_register_and_get( ctx, kAnyChIdx, kInPId, "in", in_value )) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx, kInPId, "in", kBaseSfxId, in_value )) != kOkRC ) goto errLabel; if((rc = var_register_and_set( ctx, kAnyChIdx, - kOutPId, "out", in_value, - kInvOutPId, "inv_out", (real_t)(1.0-in_value) )) != kOkRC ) + kOutPId, "out", kBaseSfxId, in_value, + kInvOutPId, "inv_out", kBaseSfxId, (real_t)(1.0-in_value) )) != kOkRC ) { goto errLabel; } @@ -205,14 +319,14 @@ namespace cw // Register variable and get their current value if((rc = var_register_and_get( ctx, kAnyChIdx, - kDevLabelPId, "dev_label", dev_label, - kPortLabelPId, "port_label", port_label )) != kOkRC ) + kDevLabelPId, "dev_label", kBaseSfxId, dev_label, + kPortLabelPId, "port_label", kBaseSfxId, port_label )) != kOkRC ) { goto errLabel; } - if((rc = var_register( ctx, kAnyChIdx,kOutPId, "out")) != kOkRC ) + if((rc = var_register( ctx, kAnyChIdx, kOutPId, "out", kBaseSfxId)) != kOkRC ) { goto errLabel; } @@ -246,7 +360,7 @@ namespace cw inst->buf = mem::allocZ( inst->bufN ); // create one output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, nullptr, 0 ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, nullptr, 0 ); errLabel: @@ -349,9 +463,9 @@ namespace cw // Register variables and get their current value if((rc = var_register_and_get( ctx, kAnyChIdx, - kDevLabelPId, "dev_label", dev_label, - kPortLabelPId,"port_label", port_label, - kInPId, "in", mbuf)) != kOkRC ) + kDevLabelPId, "dev_label", kBaseSfxId, dev_label, + kPortLabelPId,"port_label", kBaseSfxId, port_label, + kInPId, "in", kBaseSfxId, mbuf)) != kOkRC ) { goto errLabel; } @@ -444,7 +558,7 @@ namespace cw ctx->userPtr = inst; // Register variable and get their current value - if((rc = var_register_and_get( ctx, kAnyChIdx, kDevLabelPId, "dev_label", inst->dev_label )) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx, kDevLabelPId, "dev_label", kBaseSfxId, inst->dev_label )) != kOkRC ) { goto errLabel; } @@ -457,7 +571,7 @@ namespace cw // create one output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, inst->ext_dev->u.a.abuf->srate, inst->ext_dev->u.a.abuf->chN, ctx->ctx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, inst->ext_dev->u.a.abuf->srate, inst->ext_dev->u.a.abuf->chN, ctx->ctx->framesPerCycle ); errLabel: return rc; @@ -542,8 +656,8 @@ namespace cw // Register variables and get their current value if((rc = var_register_and_get( ctx, kAnyChIdx, - kDevLabelPId, "dev_label", inst->dev_label, - kInPId, "in", src_abuf)) != kOkRC ) + kDevLabelPId, "dev_label", kBaseSfxId, inst->dev_label, + kInPId, "in", kBaseSfxId, src_abuf)) != kOkRC ) { goto errLabel; } @@ -638,16 +752,16 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - if((rc = var_register( ctx, kAnyChIdx, kOnOffFlPId, "on_off" )) != kOkRC ) + if((rc = var_register( ctx, kAnyChIdx, kOnOffFlPId, "on_off", kBaseSfxId)) != kOkRC ) { goto errLabel; } // Register variable and get their current value if((rc = var_register_and_get( ctx, kAnyChIdx, - kFnamePId, "fname", inst->filename, - kSeekSecsPId, "seekSecs", seekSecs, - kEofFlPId, "eofFl", inst->eofFl )) != kOkRC ) + kFnamePId, "fname", kBaseSfxId, inst->filename, + kSeekSecsPId, "seekSecs", kBaseSfxId, seekSecs, + kEofFlPId, "eofFl", kBaseSfxId, inst->eofFl )) != kOkRC ) { goto errLabel; } @@ -669,7 +783,7 @@ namespace cw cwLogInfo("Audio '%s' srate:%f chs:%i frames:%i %f seconds.",inst->filename,info.srate,info.chCnt,info.frameCnt, info.frameCnt/info.srate ); // create one output audio buffer - with the same configuration as the source audio file - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle ); errLabel: return rc; @@ -795,9 +909,9 @@ namespace cw // Register variables and get their current value if((rc = var_register_and_get( ctx, kAnyChIdx, - kFnamePId, "fname", inst->filename, - kBitsPId, "bits", audioFileBits, - kInPId, "in", src_abuf )) != kOkRC ) + kFnamePId, "fname", kBaseSfxId, inst->filename, + kBitsPId, "bits", kBaseSfxId, audioFileBits, + kInPId, "in", kBaseSfxId, src_abuf )) != kOkRC ) { goto errLabel; } @@ -902,16 +1016,16 @@ namespace cw ctx->userPtr = mem::allocZ(); // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,abuf )) != kOkRC ) goto errLabel; // register the gain for(unsigned i=0; ichN; ++i) - if((rc = var_register( ctx, i, kGainPId, "gain" )) != kOkRC ) + if((rc = var_register( ctx, i, kGainPId, "gain", kBaseSfxId )) != kOkRC ) goto errLabel; // create the output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); errLabel: @@ -1021,7 +1135,7 @@ namespace cw ctx->userPtr = inst; // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId, abuf )) != kOkRC ) goto errLabel; if( abuf->chN ) @@ -1030,20 +1144,20 @@ namespace cw inst->chSelMap = mem::allocZ(abuf->chN); - if((rc = var_channel_count(ctx,"select",selChN)) != kOkRC ) + if((rc = var_channel_count(ctx,"select",kBaseSfxId,selChN)) != kOkRC ) goto errLabel; // register the gain for(unsigned i=0; ichN; ++i) { if( i < selChN ) - if((rc = var_register_and_get( ctx, i, kSelectPId, "select", inst->chSelMap[i] )) != kOkRC ) + if((rc = var_register_and_get( ctx, i, kSelectPId, "select", kBaseSfxId, inst->chSelMap[i] )) != kOkRC ) goto errLabel; if( inst->chSelMap[i] ) { // register an output gain control - if((rc = var_register( ctx, inst->outChN, kGainPId, "gain")) != kOkRC ) + if((rc = var_register( ctx, inst->outChN, kGainPId, "gain", kBaseSfxId)) != kOkRC ) goto errLabel; // count the number of selected channels to determine the count of output channels @@ -1055,7 +1169,7 @@ namespace cw if( inst->outChN == 0 ) cwLogWarning("The audio split instance '%s' has no selected channels.",ctx->label); else - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf->srate, inst->outChN, abuf->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf->srate, inst->outChN, abuf->frameN ); } errLabel: @@ -1162,7 +1276,7 @@ namespace cw ctx->userPtr = inst; // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,abuf )) != kOkRC ) goto errLabel; if( abuf->chN ) @@ -1172,13 +1286,13 @@ namespace cw // register the gain for(unsigned i=0; ichN; ++i) { - if((rc = var_register_and_get( ctx, i, kDuplicatePId, "duplicate", inst->chDuplMap[i] )) != kOkRC ) + if((rc = var_register_and_get( ctx, i, kDuplicatePId, "duplicate", kBaseSfxId, inst->chDuplMap[i] )) != kOkRC ) goto errLabel; if( inst->chDuplMap[i] ) { // register an input gain control - if((rc = var_register( ctx, inst->outChN, kGainPId, "gain")) != kOkRC ) + if((rc = var_register( ctx, inst->outChN, kGainPId, "gain", kBaseSfxId)) != kOkRC ) goto errLabel; // count the number of selected channels to determine the count of output channels @@ -1190,7 +1304,7 @@ namespace cw if( inst->outChN == 0 ) cwLogWarning("The audio split instance '%s' has no selected channels.",ctx->label); else - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf->srate, inst->outChN, abuf->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf->srate, inst->outChN, abuf->frameN ); } errLabel: @@ -1309,11 +1423,11 @@ namespace cw // TODO: allow non-contiguous source labels // the source labels must be contiguous - if( !var_has_value( ctx, label, kAnyChIdx ) ) + if( !var_has_value( ctx, label, kBaseSfxId, kAnyChIdx ) ) break; // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInBasePId+i,label,abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInBasePId+i,label,kBaseSfxId, abuf )) != kOkRC ) { goto errLabel; } @@ -1337,11 +1451,11 @@ namespace cw // register the gain for(unsigned i=0; ichN, abuf1->chN); // register the gain - var_register_and_get( ctx, kAnyChIdx, kGain0PId, "gain0", dum ); - var_register_and_get( ctx, kAnyChIdx, kGain1PId, "gain1", dum ); + var_register_and_get( ctx, kAnyChIdx, kGain0PId, "gain0", kBaseSfxId, dum ); + var_register_and_get( ctx, kAnyChIdx, kGain1PId, "gain1", kBaseSfxId, dum ); // create the output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf0->srate, outChN, abuf0->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf0->srate, outChN, abuf0->frameN ); errLabel: return rc; @@ -1601,7 +1715,7 @@ namespace cw ctx->userPtr = inst; // Register variables and get their current value - if((rc = var_register_and_get( ctx, kAnyChIdx, kChCntPid, "chCnt", chCnt)) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx, kChCntPid, "chCnt", kBaseSfxId, chCnt)) != kOkRC ) { goto errLabel; } @@ -1609,15 +1723,15 @@ namespace cw // register each oscillator variable for(unsigned i=0; ictx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srate, chCnt, ctx->ctx->framesPerCycle ); inst->phaseA = mem::allocZ( chCnt ); @@ -1719,7 +1833,7 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", srcBuf )) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", kBaseSfxId, srcBuf )) != kOkRC ) { cwLogError(kInvalidArgRC,"Unable to access the 'src' buffer."); } @@ -1746,10 +1860,10 @@ namespace cw bool hzFl = false; if((rc = var_register_and_get( ctx, i, - kMaxWndSmpNPId, "maxWndSmpN", maxWndSmpN, - kWndSmpNPId, "wndSmpN", wndSmpN, - kHopSmpNPId, "hopSmpN", hopSmpN, - kHzFlPId, "hzFl", hzFl )) != kOkRC ) + kMaxWndSmpNPId, "maxWndSmpN", kBaseSfxId, maxWndSmpN, + kWndSmpNPId, "wndSmpN", kBaseSfxId, wndSmpN, + kHopSmpNPId, "hopSmpN", kBaseSfxId, hopSmpN, + kHzFlPId, "hzFl", kBaseSfxId, hzFl )) != kOkRC ) { goto errLabel; } @@ -1771,7 +1885,7 @@ namespace cw // create the fbuf 'out' - if((rc = var_register_and_set(ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, maxBinNV, binNV, hopNV, magV, phsV, hzV )) != kOkRC ) + if((rc = var_register_and_set(ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, maxBinNV, binNV, hopNV, magV, phsV, hzV )) != kOkRC ) { cwLogError(kOpFailRC,"The output freq. buffer could not be created."); goto errLabel; @@ -1902,7 +2016,7 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", srcBuf)) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", kBaseSfxId, srcBuf)) != kOkRC ) { goto errLabel; } @@ -1925,11 +2039,11 @@ namespace cw } } - if((rc = var_register( ctx, kAnyChIdx, kInPId, "in" )) != kOkRC ) + if((rc = var_register( ctx, kAnyChIdx, kInPId, "in", kBaseSfxId)) != kOkRC ) goto errLabel; // create the abuf 'out' - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); } errLabel: @@ -2035,7 +2149,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -2070,13 +2184,13 @@ namespace cw spec_dist_t* sd = inst->sdA[i]; if((rc = var_register_and_get( ctx, i, - kBypassPId, "bypass", sd->bypassFl, - kCeilingPId, "ceiling", sd->ceiling, - kExpoPId, "expo", sd->expo, - kThreshPId, "thresh", sd->thresh, - kUprSlopePId, "upr", sd->uprSlope, - kLwrSlopePId, "lwr", sd->lwrSlope, - kMixPId, "mix", sd->mix )) != kOkRC ) + kBypassPId, "bypass", kBaseSfxId, sd->bypassFl, + kCeilingPId, "ceiling", kBaseSfxId, sd->ceiling, + kExpoPId, "expo", kBaseSfxId, sd->expo, + kThreshPId, "thresh", kBaseSfxId, sd->thresh, + kUprSlopePId, "upr", kBaseSfxId, sd->uprSlope, + kLwrSlopePId, "lwr", kBaseSfxId, sd->lwrSlope, + kMixPId, "mix", kBaseSfxId, sd->mix )) != kOkRC ) { goto errLabel; } @@ -2084,7 +2198,7 @@ namespace cw } // create the output buffer - if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->maxBinN_V, srcBuf->binN_V, srcBuf->hopSmpN_V, magV, phsV, hzV )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->maxBinN_V, srcBuf->binN_V, srcBuf->hopSmpN_V, magV, phsV, hzV )) != kOkRC ) goto errLabel; } @@ -2223,7 +2337,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -2243,15 +2357,15 @@ namespace cw // get the compressor variable values if((rc = var_register_and_get( ctx, i, - kBypassPId, "bypass", bypassFl, - kInGainPId, "igain", igain, - kThreshPId, "thresh", thresh, - kRatioPId, "ratio", ratio, - kAtkMsPId, "atk_ms", atk_ms, - kRlsMsPId, "rls_ms", rls_ms, - kWndMsPId, "wnd_ms", wnd_ms, - kMaxWndMsPId, "maxWnd_ms", maxWnd_ms, - kOutGainPId, "ogain", ogain )) != kOkRC ) + kBypassPId, "bypass", kBaseSfxId, bypassFl, + kInGainPId, "igain", kBaseSfxId, igain, + kThreshPId, "thresh", kBaseSfxId, thresh, + kRatioPId, "ratio", kBaseSfxId, ratio, + kAtkMsPId, "atk_ms", kBaseSfxId, atk_ms, + kRlsMsPId, "rls_ms", kBaseSfxId, rls_ms, + kWndMsPId, "wnd_ms", kBaseSfxId, wnd_ms, + kMaxWndMsPId, "maxWnd_ms", kBaseSfxId, maxWnd_ms, + kOutGainPId, "ogain", kBaseSfxId, ogain )) != kOkRC ) { goto errLabel; } @@ -2266,7 +2380,7 @@ namespace cw } // create the output audio buffer - if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) goto errLabel; } @@ -2411,7 +2525,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -2431,10 +2545,10 @@ namespace cw // get the limiter variable values if((rc = var_register_and_get( ctx, i, - kBypassPId, "bypass", bypassFl, - kInGainPId, "igain", igain, - kThreshPId, "thresh", thresh, - kOutGainPId, "ogain", ogain )) != kOkRC ) + kBypassPId, "bypass", kBaseSfxId, bypassFl, + kInGainPId, "igain", kBaseSfxId, igain, + kThreshPId, "thresh", kBaseSfxId, thresh, + kOutGainPId, "ogain", kBaseSfxId, ogain )) != kOkRC ) { goto errLabel; } @@ -2449,7 +2563,7 @@ namespace cw } // create the output audio buffer - if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) goto errLabel; } @@ -2585,7 +2699,7 @@ namespace cw ctx->userPtr = inst; // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,abuf )) != kOkRC ) goto errLabel; @@ -2596,8 +2710,8 @@ namespace cw for(unsigned i=0; ichN; ++i) { if((rc = var_register_and_get( ctx, i, - kMaxDelayMsPId, "maxDelayMs", maxDelayMs, - kDelayMsPId, "delayMs", delayMs)) != kOkRC ) + kMaxDelayMsPId, "maxDelayMs", kBaseSfxId, maxDelayMs, + kDelayMsPId, "delayMs", kBaseSfxId, delayMs)) != kOkRC ) { goto errLabel; } @@ -2617,7 +2731,7 @@ namespace cw inst->delayBuf = abuf_create( abuf->srate, abuf->chN, inst->maxDelayFrameN ); // create the output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); errLabel: @@ -2775,7 +2889,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -2795,8 +2909,8 @@ namespace cw // get the dc_filter variable values if((rc = var_register_and_get( ctx, i, - kBypassPId, "bypass", bypassFl, - kGainPId, "gain", gain )) != kOkRC ) + kBypassPId, "bypass", kBaseSfxId, bypassFl, + kGainPId, "gain", kBaseSfxId, gain )) != kOkRC ) { goto errLabel; } @@ -2811,7 +2925,7 @@ namespace cw } // create the output audio buffer - if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) goto errLabel; } @@ -2931,7 +3045,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -2950,18 +3064,18 @@ namespace cw // get the audio_meter variable values if((rc = var_register_and_get( ctx, i, - kDbFlPId, "dbFl", dbFl, - kWndMsPId, "wndMs", wndMs, - kPeakDbPId, "peakDb", peakThreshDb )) != kOkRC ) + kDbFlPId, "dbFl", kBaseSfxId, dbFl, + kWndMsPId, "wndMs", kBaseSfxId, wndMs, + kPeakDbPId, "peakDb", kBaseSfxId, peakThreshDb )) != kOkRC ) { goto errLabel; } // get the audio_meter variable values if((rc = var_register( ctx, i, - kOutPId, "out", - kPeakFlPId, "peakFl", - kClipFlPId, "clipFl" )) != kOkRC ) + kOutPId, "out", kBaseSfxId, + kPeakFlPId, "peakFl", kBaseSfxId, + kClipFlPId, "clipFl", kBaseSfxId )) != kOkRC ) { goto errLabel; } @@ -3075,15 +3189,15 @@ namespace cw ctx->userPtr = mem::allocZ(); // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",abuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",kBaseSfxId,abuf )) != kOkRC ) goto errLabel; // register the marker input - if((rc = var_register_and_set( ctx, kAnyChIdx, kMarkPId, "mark", 0.0f )) != kOkRC ) + if((rc = var_register_and_set( ctx, kAnyChIdx, kMarkPId, "mark", kBaseSfxId, 0.0f )) != kOkRC ) goto errLabel; // create the output audio buffer - rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf->srate, abuf->chN, abuf->frameN ); errLabel: return rc; @@ -3147,6 +3261,307 @@ namespace cw }; } + + //------------------------------------------------------------------------------------------------------------------ + // + // xfade_ctl + // + namespace xfade_ctl + { + enum { + kNetLabelPId, + kNetLabelSfxPId, + kSrateRefPId, + kDurMsPId, + kTriggerPId, + kGainPId, + }; + + typedef struct + { + unsigned xfadeDurMs; // crossfade duration in milliseconds + instance_t* net_proc; // source 'poly' network + network_t net; // internal proxy network + unsigned poly_ch_cnt; // set to 2 (one for 'cur' poly-ch., one for 'next' poly-ch.) + unsigned net_proc_cnt; // count of proc's in a single poly-channel (net_proc->proc_arrayN/poly_cnt) + unsigned cur_poly_ch_idx; // + unsigned next_poly_ch_idx; // + float* target_gainA; // target_gainA[net_proc->poly_cnt] + float* cur_gainA; // cur_gainA[net_proc->poly_cnt] + double srate; + + } inst_t; + + void _trigger_xfade( inst_t* p ) + { + // begin fading out the cur channel + p->target_gainA[ p->cur_poly_ch_idx ] = 0; + + // the next poly-ch become the cur poly-ch + p->cur_poly_ch_idx = p->next_poly_ch_idx; + + // the next poly-ch advances + p->next_poly_ch_idx = p->next_poly_ch_idx+1 >= p->poly_ch_cnt ? 0 : p->next_poly_ch_idx+1; + + // j selects a block of 'net_proc_cnt' slots in the proxy network which will become the 'next' channel + unsigned j = p->next_poly_ch_idx * p->net_proc_cnt; + + // set the [j:j+poly_proc_cnt] pointers in the proxy net to the actual proc instances in the source net + for(unsigned i=0; inet_proc->internal_net->proc_arrayN; ++i) + if( p->net_proc->internal_net->proc_array[i]->label_sfx_id == p->next_poly_ch_idx ) + { + assert( p->next_poly_ch_idx * p->net_proc_cnt <= j + && j < p->next_poly_ch_idx * p->net_proc_cnt + p->net_proc_cnt + && j < p->net.proc_arrayN ); + + p->net.proc_array[j++] = p->net_proc->internal_net->proc_array[i]; + } + + // begin fading in the new cur channel + p->target_gainA[ p->cur_poly_ch_idx ] = 1; + + // if the next channel is not already at 0 send it in that direction + p->target_gainA[ p->next_poly_ch_idx ] = 0; + + } + + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const char* netLabel = nullptr; + unsigned netLabelSfxId = kBaseSfxId; + bool trigFl = false; + variable_t* gainVar = nullptr; + abuf_t* srateSrc = nullptr; + double dum; + + inst_t* p = mem::allocZ(); + + ctx->userPtr = p; + + p->poly_ch_cnt = 2; + + if((rc = var_register_and_get(ctx,kAnyChIdx, + kNetLabelPId, "net", kBaseSfxId, netLabel, + kNetLabelSfxPId, "netSfxId", kBaseSfxId, netLabelSfxId, + kSrateRefPId, "srateSrc", kBaseSfxId, srateSrc, + kDurMsPId, "durMs", kBaseSfxId, p->xfadeDurMs, + kTriggerPId, "trigger", kBaseSfxId, trigFl, + kGainPId, "gain", kBaseSfxId, dum)) != kOkRC ) + { + goto errLabel; + } + + // locate the source poly-network for this xfad-ctl + if((rc = instance_find(*ctx->net,netLabel,netLabelSfxId,p->net_proc)) != kOkRC ) + { + cwLogError(rc,"The xfade_ctl source network proc instance '%s:%i' was not found.",cwStringNullGuard(netLabel),netLabelSfxId); + goto errLabel; + } + + if( p->net_proc->internal_net->poly_cnt < 3 ) + { + cwLogError(rc,"The xfade_ctl source network must have at least 3 poly channels. %i < 3",p->net_proc->internal_net->poly_cnt); + goto errLabel; + } + + + // create the gain output variables - one output for each poly-channel + for(unsigned i=1; inet_proc->internal_net->poly_cnt; ++i) + { + variable_t* dum; + if((rc = var_create(ctx, "gain", i, kGainPId+i, kAnyChIdx, nullptr, dum )) != kOkRC ) + { + cwLogError(rc,"'gain:%i' create failed.",i); + goto errLabel; + } + } + + // count of proc's in one poly-ch of the poly network + p->net_proc_cnt = p->net_proc->internal_net->proc_arrayN / p->net_proc->internal_net->poly_cnt; + + // create the proxy network + p->net.proc_arrayAllocN = p->net_proc_cnt * p->poly_ch_cnt; + p->net.proc_arrayN = p->net.proc_arrayAllocN; + p->net.proc_array = mem::allocZ(p->net.proc_arrayAllocN); + p->target_gainA = mem::allocZ(p->net_proc->internal_net->poly_cnt); + p->cur_gainA = mem::allocZ(p->net_proc->internal_net->poly_cnt); + p->srate = srateSrc->srate; + + // make the proxy network public - xfad_ctl now looks like the source network + // because it has the same proc instances + ctx->internal_net = &p->net; + + // setup the channels such that the first active channel after _trigger_xfade() + // will be channel 0 + p->cur_poly_ch_idx = 1; + p->next_poly_ch_idx = 2; + _trigger_xfade(p); // cur=2 nxt=0 initialize inst ptrs in range: p->net[0:net_proc_cnt] + _trigger_xfade(p); // cur=0 nxt=1 initialize inst ptrs in range: p->net[net_proc_cnt:2*net_proc_cnt] + + + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + inst_t* p = (inst_t*)ctx->userPtr; + mem::release(p->net.proc_array); + mem::release(p->target_gainA); + mem::release(p->cur_gainA); + mem::release(ctx->userPtr); + + return kOkRC; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { return kOkRC; } + + // return sign of expression as a float + float _signum( float v ) { return (0.0f < v) - (v < 0.0f); } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* p = (inst_t*)ctx->userPtr; + bool trigFl = false; + + // check if a cross-fade has been triggered + if((rc = var_get(ctx,kTriggerPId,kAnyChIdx,trigFl)) == kOkRC ) + { + _trigger_xfade(p); + + var_set(ctx,kTriggerPId,kAnyChIdx,false); + } + + // time in sample frames to complete a xfade + double xfade_dur_smp = p->xfadeDurMs * p->srate / 1000.0; + + // fraction of a xfade which will be completed in on exec() cycle + float delta_gain_per_cycle = (float)(ctx->ctx->framesPerCycle / xfade_dur_smp); + + // update the cross-fade gain outputs + for(unsigned i=0; inet_proc->internal_net->poly_cnt; ++i) + { + p->cur_gainA[i] += _signum(p->target_gainA[i] - p->cur_gainA[i]) * delta_gain_per_cycle; + + p->cur_gainA[i] = std::min(1.0f, std::max(0.0f, p->cur_gainA[i])); + + var_set(ctx,kGainPId+i,kAnyChIdx,p->cur_gainA[i]); + } + + errLabel: + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = nullptr + }; + + } + + //------------------------------------------------------------------------------------------------------------------ + // + // poly_mixer + // + namespace poly_mixer + { + enum { + kOutGainPId, + kOutPId, + + }; + + typedef struct + { + unsigned inBaseVId; + unsigned gainBaseVId; + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + /* + const abuf_t* abuf0 = nullptr; // + const abuf_t* abuf1 = nullptr; + unsigned outChN = 0; + double dum; + + // get the source audio buffer + if((rc = var_register_and_get(ctx, kAnyChIdx, + kIn0PId,"in0",kBaseSfxId,abuf0, + kIn1PId,"in1",kBaseSfxId,abuf1 )) != kOkRC ) + { + goto errLabel; + } + + assert( abuf0->frameN == abuf1->frameN ); + + outChN = std::max(abuf0->chN, abuf1->chN); + + // register the gain + var_register_and_get( ctx, kAnyChIdx, kGain0PId, "gain0", kBaseSfxId, dum ); + var_register_and_get( ctx, kAnyChIdx, kGain1PId, "gain1", kBaseSfxId, dum ); + + // create the output audio buffer + rc = var_register_and_set( ctx, "out", kBaseSfxId, kOutPId, kAnyChIdx, abuf0->srate, outChN, abuf0->frameN ); + */ + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { return kOkRC; } + + rc_t value( instance_t* ctx, variable_t* var ) + { return kOkRC; } + + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + /* + abuf_t* obuf = nullptr; + //const abuf_t* ibuf0 = nullptr; + //const abuf_t* ibuf1 = nullptr; + + if((rc = var_get(ctx,kOutPId, kAnyChIdx, obuf)) != kOkRC ) + goto errLabel; + + //if((rc = var_get(ctx,kIn0PId, kAnyChIdx, ibuf0 )) != kOkRC ) + // goto errLabel; + + //if((rc = var_get(ctx,kIn1PId, kAnyChIdx, ibuf1 )) != kOkRC ) + // goto errLabel; + + vop::zero(obuf->buf, obuf->frameN*obuf->chN ); + + _mix( ctx, kIn0PId, kGain0PId, obuf ); + _mix( ctx, kIn1PId, kGain1PId, obuf ); + */ + + errLabel: + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = nullptr + }; + + } } // flow diff --git a/cwFlowProc.h b/cwFlowProc.h index 026bbed..3898cb1 100644 --- a/cwFlowProc.h +++ b/cwFlowProc.h @@ -2,6 +2,7 @@ namespace cw { namespace flow { + namespace poly { extern class_members_t members; } namespace midi_in { extern class_members_t members; } namespace midi_out { extern class_members_t members; } namespace audio_in { extern class_members_t members; } @@ -24,5 +25,7 @@ namespace cw namespace balance { extern class_members_t members; } namespace audio_meter { extern class_members_t members; } namespace audio_marker { extern class_members_t members; } + namespace xfade_ctl { extern class_members_t members; } + namespace poly_mixer { extern class_members_t members; } } } diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 477b5f1..0788edc 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -393,7 +393,7 @@ namespace cw 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.%s ch:%i.",cwStringNullGuard(var->inst->label),cwStringNullGuard(var->label),var->chIdx); + 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); } @@ -408,7 +408,7 @@ namespace cw { // 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); + 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); } @@ -430,16 +430,16 @@ namespace cw return kOkRC; } } - return cwLogError(kInvalidIdRC,"The variable matching id:%i ch:%i on instance '%s' could not be found.", vid, chIdx, inst->label); + 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 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( textCompare(var->label,var_label)==0 && var->chIdx == chIdx ) + if( var->label_sfx_id==sfx_id && textCompare(var->label,var_label)==0 && var->chIdx == chIdx ) return var; } @@ -450,10 +450,10 @@ namespace cw 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); + 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' on instance '%s' is not a '%s'.", var->label, var->inst->label, _typeFlagToLabel( 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; } @@ -482,7 +482,7 @@ namespace cw { var->local_value[ local_value_idx ].u.b = val; var->local_value[ local_value_idx ].flags = kBoolTFl; - cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -490,7 +490,7 @@ namespace cw { var->local_value[ local_value_idx ].u.u = val; var->local_value[ local_value_idx ].flags = kUIntTFl; - cwLogMod("%s.%s ch:%i %i (uint).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -498,7 +498,7 @@ namespace cw { var->local_value[ local_value_idx ].u.i = val; var->local_value[ local_value_idx ].flags = kIntTFl; - cwLogMod("%s.%s ch:%i %i (int).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -506,7 +506,7 @@ namespace cw { var->local_value[ local_value_idx ].u.f = val; var->local_value[ local_value_idx ].flags = kFloatTFl; - cwLogMod("%s.%s ch:%i %f (float).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -514,7 +514,7 @@ namespace cw { var->local_value[ local_value_idx ].u.d = val; var->local_value[ local_value_idx ].flags = kDoubleTFl; - cwLogMod("%s.%s ch:%i %f (double).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -522,7 +522,7 @@ namespace cw { var->local_value[ local_value_idx ].u.s = mem::duplStr(val); var->local_value[ local_value_idx ].flags = kStringTFl; - cwLogMod("%s.%s ch:%i %s (string).",var->inst->label,var->label,var->chIdx,val); + 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<> @@ -530,7 +530,7 @@ namespace cw { var->local_value[ local_value_idx ].u.abuf = val; var->local_value[ local_value_idx ].flags = kABufTFl; - cwLogMod("%s.%s ch:%i %s (abuf).",var->inst->label,var->label,var->chIdx,abuf==nullptr ? "null" : "valid"); + 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<> @@ -538,7 +538,7 @@ namespace cw { var->local_value[ local_value_idx ].u.mbuf = val; var->local_value[ local_value_idx ].flags = kMBufTFl; - cwLogMod("%s.%s ch:%i %s (abuf).",var->inst->label,var->label,var->chIdx,mbuf==nullptr ? "null" : "valid"); + 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<> @@ -546,7 +546,7 @@ namespace cw { var->local_value[ local_value_idx ].u.fbuf = val; var->local_value[ local_value_idx ].flags = kFBufTFl; - cwLogMod("%s.%s ch:%i %s (fbuf).",var->inst->label,var->label,var->chIdx,fbuf==nullptr ? "null" : "valid"); + 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 > @@ -644,11 +644,11 @@ namespace cw } - rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, abuf_t* abuf ) + 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, vid, chIdx, var)) != kOkRC ) + if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC ) return rc; if( var != nullptr ) @@ -657,11 +657,11 @@ namespace cw return rc; } - rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, mbuf_t* mbuf ) + 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, vid, chIdx, var)) != kOkRC ) + if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC ) return rc; if( var != nullptr ) @@ -670,11 +670,11 @@ namespace cw return rc; } - rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, fbuf_t* fbuf ) + 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, vid, chIdx, var)) != kOkRC ) + if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) != kOkRC ) return rc; if( var != nullptr ) @@ -746,7 +746,7 @@ namespace cw 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)); + 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; } @@ -757,20 +757,20 @@ namespace cw // 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' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx); + 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 chIdx, unsigned& idxRef ) + 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, chIdx, var )) == kOkRC) + 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; @@ -787,9 +787,9 @@ namespace cw if( new_var->chIdx == kAnyChIdx ) return kOkRC; - if((base_var = _var_find_on_label_and_ch( inst, new_var->label, kAnyChIdx )) == nullptr ) + 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.%s'. This is an illegal state.", inst->label, new_var->label ); + 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; } @@ -815,7 +815,7 @@ namespace cw // 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 _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; @@ -824,28 +824,29 @@ namespace cw 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 ) + if((var = _var_find_on_label_and_ch(inst,var_label, sfx_id, chIdx)) != nullptr ) { - rc = cwLogError(kInvalidStateRC,"The variable '%s' ch:%i has already been created on the instance: '%s'.",var_label,chIdx,inst->label); + 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' in class '%s'.", var_label, inst->class_desc->label ); + 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(); - var->varDesc = vd; - var->inst = inst; - var->label = mem::duplStr(var_label); - var->vid = id; - var->chIdx = chIdx; - var->value = nullptr; + 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 ) @@ -868,12 +869,12 @@ namespace cw if( rc != kOkRC ) { _var_destroy(var); - cwLogError(kOpFailRC,"Variable creation failed on '%s.%s' ch:%i.", inst->label, var_label, chIdx ); + 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.%s ch:%i.", inst->label, var_label, chIdx ); + cwLogMod("Created var: %s:%i.%s:%i ch:%i.", inst->label, inst->label_sfx_id, var_label, sfx_id, chIdx ); } return rc; @@ -883,31 +884,34 @@ namespace cw { const char* conn_label = is_connected_to_external_proc(var) ? "extern" : " "; - printf(" %20s id:%4i ch:%3i : %s : ", var->label, var->vid, var->chIdx, conn_label ); + 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 chIdx, const object_t* value ) + 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, chIdx, var )) != kOkRC ) + 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 variable:%s could not be set via a preset.", inst->label, var_label ); + 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; } @@ -1136,37 +1140,52 @@ void cw::flow::class_dict_print( flow_t* p ) for(; vd!=nullptr; vd=vd->link) { - const char* srcFlStr = vd->flags & kSrcVarFl ? "src" : " "; - const char* srcOptFlStr = vd->flags & kSrcOptVarFl ? "srcOpt" : " "; + 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\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, srcOptFlStr, cwStringNullGuard(vd->docText) ); + 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( flow_t* p ) + +void cw::flow::network_print( const network_t& net ) { - for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) + // for each instance in the network + for(unsigned i=0; iinternal_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( flow_t* p, const char* inst_label ) +cw::flow::instance_t* cw::flow::instance_find( network_t& net, const char* inst_label, unsigned sfx_id ) { - for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link ) - if( textCompare(inst_label,inst->label) == 0 ) - return inst; + for(unsigned i=0; ilabel_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( flow_t* p, const char* inst_label, instance_t*& instPtrRef ) +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(p,inst_label)) != nullptr ) + if((instPtrRef = instance_find(net,inst_label,sfx_id)) != nullptr ) return rc; - return cwLogError(kInvalidArgRC,"The instance '%s' was not found.", inst_label ); + 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 ) @@ -1185,7 +1204,7 @@ cw::flow::external_device_t* cw::flow::external_device_find( flow_t* p, const ch void cw::flow::instance_print( instance_t* inst ) { - printf("%s\n", inst->label); + 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) @@ -1209,31 +1228,31 @@ void cw::flow::_var_destroy( variable_t* 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 ) +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, id, chIdx, value_cfg, varRef ); + 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 chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef ) +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, kAnyChIdx)) == 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.%s'.",inst->label,var_label); + 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, chIdx ); + var = _var_find_on_label_and_ch( inst, var_label, sfx_id, chIdx ); // 'src' variables cannot be channelized @@ -1247,7 +1266,7 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns if( var == nullptr && chIdx != kAnyChIdx ) { // create the channelized var - if((rc = _var_create( inst, var_label, vid, chIdx, value_cfg, var )) != kOkRC ) + 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 @@ -1272,7 +1291,7 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns } else { - cwLogWarning("An existing var (%s.%s ch:%i) was specified for channelizing but no value was provided.", inst->label, var_label, chIdx ); + 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 ); } } @@ -1281,20 +1300,20 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns errLabel: if( rc != kOkRC ) - rc = cwLogError(rc,"Channelize failed for variable '%s' on instance '%s' ch:%i.", var_label, inst->label, chIdx ); + 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 chIdx ) -{ return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; } +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 chIdx ) +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, chIdx, varPtr )) != kOkRC ) + if((rc = var_find( inst, label, sfx_id, chIdx, varPtr )) != kOkRC ) return false; return varPtr->value != nullptr; @@ -1322,7 +1341,7 @@ cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, var 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); + 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; } } @@ -1338,34 +1357,35 @@ cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, var -cw::rc_t cw::flow::var_find( instance_t* inst, const char* label, unsigned chIdx, variable_t*& vRef ) +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,chIdx)) != 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' does not have a variable named '%s'.", inst->label, label ); + 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 chIdx, const variable_t*& vRef ) +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,chIdx,v); + 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& chCntRef ) + +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,kAnyChIdx,var)) != kOkRC ) - return cwLogError(rc,"Channel count was not available because the variable '%s.%s' does not exist.",cwStringNullGuard(inst->label),cwStringNullGuard(label)); + 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); } @@ -1377,9 +1397,9 @@ cw::rc_t cw::flow::var_channel_count( const variable_t* var, unsigned& chCntRef chCntRef = 0; - if((rc = var_find( var->inst, var->label, kAnyChIdx, v )) != kOkRC ) + 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.%s'.",var->inst->label,var->label); + 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; } @@ -1392,7 +1412,7 @@ cw::rc_t cw::flow::var_channel_count( const variable_t* var, unsigned& chCntRef -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 ) +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; @@ -1403,7 +1423,7 @@ cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsign // 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((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 ) @@ -1412,74 +1432,74 @@ cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsign } else // an exact match was not found - channelize the variable { - if((rc = var_channelize(inst,var_label,chIdx,value_cfg,vid,var)) != kOkRC ) + 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,kAnyChIdx)) != nullptr ) + 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' instance '%s' has no base channel.", var_label, inst->label, chIdx); + 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' instance '%s' ch: %i.", var_label, inst->label, chIdx); + 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 vid, unsigned chIdx, variable_t*& varRef ) +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, vid, chIdx, nullptr, 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 vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ) +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' variable:'%s'.", inst->label, var_label); + 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, vid, chIdx, abuf )) != kOkRC ) + 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 vid, unsigned chIdx, srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_real_t** magV, const fd_real_t** phsV, const fd_real_t** hzV ) +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_real_t** magV, const fd_real_t** phsV, const fd_real_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' variable:'%s'.", inst->label, var_label); + 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, vid, chIdx, fbuf )) != kOkRC ) + 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 vid, unsigned chIdx, midi::ch_msg_t* msgA, unsigned msgN ) +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' variable:'%s'.", inst->label, var_label); + 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, vid, chIdx, mbuf )) != kOkRC ) + 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 vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_real_t** magV, const fd_real_t** phsV, const fd_real_t** hzV ) +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_real_t** magV, const fd_real_t** phsV, const fd_real_t** hzV ) { unsigned maxBinN_V[ chN ]; unsigned binN_V[ chN ]; @@ -1487,7 +1507,7 @@ cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label 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,vid,chIdx,srate, chN, maxBinN_V, binN_V, hopSmpN_V, magV, phsV, hzV); + return var_register_and_set(inst,var_label,sfx_id,vid,chIdx,srate, chN, maxBinN_V, binN_V, hopSmpN_V, magV, phsV, hzV); } diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 0fe4ce5..e111842 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -15,6 +15,7 @@ namespace cw typedef unsigned vid_t; enum { + kBaseSfxId = 0, kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz) kAnyChIdx = kInvalidIdx, kLocalValueN = 2 @@ -127,8 +128,10 @@ namespace cw enum { + kNoVarFl = 0x00, kSrcVarFl = 0x01, - kSrcOptVarFl = 0x02 + kSrcOptVarFl = 0x02, + kMultVarFl = 0x04 }; typedef struct class_members_str @@ -165,6 +168,7 @@ namespace cw var_desc_t* varDescL; // varDescA[varDescN] value description list preset_t* presetL; // presetA[ presetN ] class_members_t* members; // member functions for this class + unsigned polyLimitN; // max. poly copies of this class per network_t or 0 if no limit } class_desc_t; @@ -174,6 +178,7 @@ namespace cw { struct instance_str* inst; // pointer to this variables instance char* label; // this variables label + unsigned label_sfx_id; // the label suffix id of this variable or kInvalidIdx if this has no suffix unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'inst' var_desc_t* varDesc; // the variable description for this variable value_t local_value[ kLocalValueN ]; // the local value instance (actual value if this is not a 'src' variable) @@ -187,15 +192,33 @@ namespace cw } variable_t; + struct instance_str; + + typedef struct network_str + { + const object_t* procsCfg; // network proc list + const object_t* presetsCfg; // presets designed for this network + + unsigned poly_cnt; // count of duplicated networks in the list + + struct instance_str** proc_array; + unsigned proc_arrayAllocN; + unsigned proc_arrayN; + + } network_t; + typedef struct instance_str { struct flow_str* ctx; // global system context + network_t* net; // network which owns this proc class_desc_t* class_desc; // - const char* label; // instance label - const object_t* inst_cfg; // instance configuration + char* label; // instance label + unsigned label_sfx_id; // label suffix id (set to kBaseSfxId (0) unless poly is non-null) + const object_t* proc_cfg; // instance configuration + const char* arg_label; // optional args label const object_t* arg_cfg; // optional args configuration @@ -207,17 +230,16 @@ namespace cw unsigned varMapIdN; // max 'vid' among all variables on this instance unsigned varMapN; // varMapN = varMapIdN * varMapChN variable_t** varMapA; // varMapA[ varMapN ] = allows fast lookup from ('vid','chIdx) to variable + + network_t* internal_net; - struct instance_str* link; } instance_t; - typedef struct flow_str { - const object_t* networkCfg; // complete cfg used to create this network + const object_t* flowCfg; // complete cfg used to create this flow - const object_t* presetCfg; // presets designed for this network unsigned framesPerCycle; // sample frames per cycle (64) bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application @@ -232,8 +254,8 @@ namespace cw external_device_t* deviceA; // deviceA[ deviceN ] external device description array unsigned deviceN; // - struct instance_str* network_head; // first instance - struct instance_str* network_tail; // last insance + network_t net; + } flow_t; //------------------------------------------------------------------------------------------------------------------------ @@ -278,15 +300,16 @@ namespace cw // // Network // - void network_print( flow_t* p ); + void network_print(const network_t& net ); //------------------------------------------------------------------------------------------------------------------------ // // Instance // - instance_t* instance_find( flow_t* p, const char* inst_label ); - rc_t instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef ); + instance_t* instance_find( network_t& net, const char* inst_label, unsigned sfx_id ); + rc_t instance_find( network_t& net, const char* inst_label, unsigned sfx_id, instance_t*& instPtrRef ); + external_device_t* external_device_find( flow_t* p, const char* device_label, unsigned typeId, unsigned inOrOutFl, const char* midiPortLabel=nullptr ); void instance_print( instance_t* inst ); @@ -300,14 +323,14 @@ namespace cw // Create a variable but do not assign it a value. Return a pointer to the new variable. // Note: `value_cfg` is optional. Set it to NULL to ignore - rc_t var_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); + rc_t var_create( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); // Channelizing creates a new var record with an explicit channel index to replace the // automatically generated variable whose channel index is set to 'all'. - rc_t var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef ); + rc_t var_channelize( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, const object_t* value_cfg, unsigned vid, variable_t*& varRef ); // `value_cfg` is optional. Set it to NULL to ignore - rc_t var_register( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); + rc_t var_register( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ); // Returns true if this var is connected to an external proc variable bool is_connected_to_external_proc( const variable_t* var ); @@ -320,11 +343,11 @@ namespace cw inline rc_t _var_reg(cw::flow::instance_t*, unsigned int ) { return kOkRC; } template< typename T0, typename T1, typename... ARGS > - rc_t _var_reg( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, ARGS&&... args ) + rc_t _var_reg( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, ARGS&&... args ) { rc_t rc; variable_t* dummy = nullptr; - if((rc = var_register( inst, var_label, vid, chIdx, nullptr, dummy )) == kOkRC ) + if((rc = var_register( inst, var_label, sfx_id, vid, chIdx, nullptr, dummy )) == kOkRC ) if((rc = _var_reg( inst, chIdx, std::forward(args)...)) != kOkRC ) return rc; return rc; @@ -332,8 +355,8 @@ namespace cw // Call var_register() on a list of variables. template< typename... ARGS > - rc_t var_register( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args ) - { return _var_reg( inst, chIdx, vid, var_label, std::forward(args)...); } + rc_t var_register( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args ) + { return _var_reg( inst, chIdx, vid, var_label, sfx_id, std::forward(args)...); } @@ -345,11 +368,11 @@ namespace cw inline rc_t _var_register_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; } template< typename T> - rc_t var_register_and_get( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, T& valRef ) + rc_t var_register_and_get( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, T& valRef ) { rc_t rc; variable_t* var; - if((rc = var_register(inst,var_label,vid,chIdx,nullptr,var)) == kOkRC ) + if((rc = var_register(inst,var_label,sfx_id,vid,chIdx,nullptr,var)) == kOkRC ) rc = var_get(var,valRef); return rc; } @@ -358,11 +381,11 @@ namespace cw inline rc_t _var_reg_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; } template< typename T0, typename T1, typename T2, typename... ARGS > - rc_t _var_reg_and_get( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2& valRef, ARGS&&... args ) + rc_t _var_reg_and_get( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, T2& valRef, ARGS&&... args ) { rc_t rc; - if((rc = var_register_and_get( inst, var_label, vid, chIdx, valRef )) == kOkRC ) + if((rc = var_register_and_get( inst, var_label, sfx_id, vid, chIdx, valRef )) == kOkRC ) if((rc = _var_reg_and_get( inst, chIdx, std::forward(args)...)) != kOkRC ) return rc; @@ -371,8 +394,8 @@ namespace cw // Call var_register_and_get() on a list of variables. template< typename... ARGS > - rc_t var_register_and_get( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args ) - { return _var_reg_and_get( inst, chIdx, vid, var_label, std::forward(args)...); } + rc_t var_register_and_get( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args ) + { return _var_reg_and_get( inst, chIdx, vid, var_label, sfx_id, std::forward(args)...); } @@ -384,22 +407,22 @@ namespace cw // var_register_and_set(). If the variable has not yet been created then it is created and assigned a value. // If the variable has already been created then 'vid' and the value are updated. // (Note that abuf and fbuf values are not changed by this function only the 'vid' is updated.) - rc_t var_register_and_set( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef ); + rc_t var_register_and_set( instance_t* inst, const char* label, unsigned sfx_id, unsigned vid, unsigned chIdx, variable_t*& varRef ); - rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ); - rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, midi::ch_msg_t* midiA, unsigned midiN ); - rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, const unsigned* maxBinN_V, const unsigned* binN_V, const unsigned* hopSmpN_V, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr ); - rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned maxBinN, unsigned binN, unsigned hopSmpN, const fd_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr ); + rc_t 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 var_register_and_set( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned vid, unsigned chIdx, midi::ch_msg_t* midiA, unsigned midiN ); + rc_t 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_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr ); + rc_t 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_real_t** magV=nullptr, const fd_real_t** phsV=nullptr, const fd_real_t** hzV=nullptr ); inline rc_t _var_register_and_set(cw::flow::instance_t*, unsigned int ) { return kOkRC; } template< typename T0, typename T1, typename T2, typename... ARGS > - rc_t _var_register_and_set( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2 val, ARGS&&... args ) + rc_t _var_register_and_set( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, unsigned sfx_id, T2 val, ARGS&&... args ) { rc_t rc; variable_t* var = nullptr; - if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) == kOkRC ) + if((rc = var_register_and_set( inst, var_label, sfx_id, vid, chIdx, var)) == kOkRC ) { var_set( inst, vid, chIdx, val ); @@ -412,22 +435,23 @@ namespace cw // Call var_register_and_set() on a list of variables. template< typename... ARGS > - rc_t var_register_and_set( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args ) - { return _var_register_and_set( inst, chIdx, vid, var_label, std::forward(args)...); } + rc_t var_register_and_set( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, unsigned sfx_id, ARGS&&... args ) + { return _var_register_and_set( inst, chIdx, vid, var_label, sfx_id, std::forward(args)...); } void _var_destroy( variable_t* var ); - bool var_exists( instance_t* inst, const char* label, unsigned chIdx ); - bool var_has_value( instance_t* inst, const char* label, unsigned chIdx ); + bool var_exists( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx ); + bool var_has_value( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx ); - rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef ); - rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef ); - rc_t var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ); + rc_t var_find( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, const variable_t*& varRef ); + rc_t var_find( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, variable_t*& varRef ); + rc_t var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ); + // Count of numbered channels - does not count the kAnyChIdx variable instance. - rc_t var_channel_count( instance_t* inst, const char* label, unsigned& chCntRef ); + rc_t var_channel_count( instance_t* inst, const char* label, unsigned sfx_idx, unsigned& chCntRef ); rc_t var_channel_count( const variable_t* var, unsigned& chCntRef ); diff --git a/cwPresetSel.cpp b/cwPresetSel.cpp index 0f3a420..2e07769 100644 --- a/cwPresetSel.cpp +++ b/cwPresetSel.cpp @@ -6,11 +6,12 @@ #include "cwObject.h" #include "cwTime.h" #include "cwVectOps.h" +#include "cwMidi.h" +#include "cwMidiDecls.h" #include "cwFlowDecl.h" #include "cwPresetSel.h" #include "cwFile.h" -#include "cwMidi.h" #include "cwDynRefTbl.h" #include "cwScoreParse.h" #include "cwSfScore.h"