From 040d902c6b81f6fdec028e7fc70916d4bd8a3148 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 2 May 2024 13:59:19 -0400 Subject: [PATCH] Initial working version of poly_merge and xfade_ctl. cwFlowNet._connect_vars() changed to cwFlowTypes.var_connect(). cwFlowTest._set_var_value_from_cfg() to cwFlowTypes.var_set_from_preset(). var_channelize() now connects matching channels when they are available. Added type 'numeric'. Updated proc_template() to automatically allocate and extract inst_t. Added a system sample rate. --- cwFlow.cpp | 90 +-------- cwFlowNet.cpp | 27 +-- cwFlowProc.cpp | 445 ++++++++++++++++++++++++++++------------ cwFlowProc.h | 2 +- cwFlowTypes.cpp | 525 +++++++++++++++++++++++++----------------------- cwFlowTypes.h | 50 +++-- 6 files changed, 637 insertions(+), 502 deletions(-) diff --git a/cwFlow.cpp b/cwFlow.cpp index 078ff79..16e0f73 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -53,7 +53,7 @@ namespace cw { "audio_meter", &audio_meter::members }, { "audio_marker", &audio_marker::members }, { "xfade_ctl", &xfade_ctl::members }, - { "poly_mixer", &poly_mixer::members }, + { "poly_merge", &poly_merge::members }, { "sample_hold", &sample_hold::members }, { "number", &number::members }, { "timer", &timer::members }, @@ -244,78 +244,6 @@ namespace cw } - /* - 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); - variable_t* src_var = nullptr; - instance_t* src_inst = nullptr; - variable_t* in_var = nullptr; - - char sbuf[ src_charN+1 ]; - - // copy the id into the buf - strncpy(sbuf,src_label_arg,src_charN+1); - - // advance suffix to the '.' - char* suffix = sbuf; - while( *suffix && *suffix != '.') - ++suffix; - - // if a '.' suffix was found - if( *suffix ) - { - *suffix = 0; - ++suffix; - } - - // locate source instance - 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, 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, 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; - } - - // verify that the src_value type is included in the in_value type flags - if( cwIsNotFlag(in_var->varDesc->type, src_var->varDesc->type) ) - { - rc = cwLogError(kSyntaxErrorRC,"The type flags don't match on input:%s %s source:%s %s .", in_inst->label, in_var_label, src_inst->label, suffix); - goto errLabel; - } - - if( src_var->value == nullptr ) - { - rc = cwLogError(kSyntaxErrorRC,"The source value is null on the connection input:'%s' %s source:'%s' '%s' .", in_inst->label, in_var_label, src_inst->label, suffix); - goto errLabel; - } - - _connect_vars( src_var, in_var ); - - //cwLogInfo("'%s:%s' connected to source '%s:%s' %p.", in_inst->label, in_var_label, src_inst->label, suffix, in_var->value ); - - errLabel: - return rc; - } - */ - - - - rc_t _destroy( flow_t* p) { @@ -406,20 +334,24 @@ cw::rc_t cw::flow::create( handle_t& hRef, } // parse the main audio file processor cfg record - if((rc = flowCfg.getv("framesPerCycle", p->framesPerCycle, - "network", networkCfg)) != kOkRC ) + if((rc = flowCfg.getv("network", networkCfg)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the required flow configuration parameters."); goto errLabel; } + p->framesPerCycle = kDefaultFramesPerCycle; + p->sample_rate = kDefaultSampleRate; + // parse the optional args - if((rc = flowCfg.getv_opt("maxCycleCount", p->maxCycleCount, + if((rc = flowCfg.getv_opt("framesPerCycle", p->framesPerCycle, + "sample_rate", p->sample_rate, + "maxCycleCount", p->maxCycleCount, "multiPriPresetProbFl", p->multiPriPresetProbFl, "multiSecPresetProbFl", p->multiSecPresetProbFl, - "multiPresetInterpFl", p->multiPresetInterpFl, - "printClassDictFl", printClassDictFl, - "printNetworkFl", printNetworkFl)) != kOkRC ) + "multiPresetInterpFl", p->multiPresetInterpFl, + "printClassDictFl", printClassDictFl, + "printNetworkFl", printNetworkFl)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters."); goto errLabel; diff --git a/cwFlowNet.cpp b/cwFlowNet.cpp index 01f2cd8..cc1402c 100644 --- a/cwFlowNet.cpp +++ b/cwFlowNet.cpp @@ -63,20 +63,6 @@ namespace cw rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ); - void _connect_vars( variable_t* src_var, variable_t* in_var ) - { - // connect in_var into src_var's outgoing var chain - in_var->dst_link = src_var->dst_tail; - src_var->dst_tail = in_var; - if( src_var->dst_head == nullptr ) - src_var->dst_head = 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; @@ -146,6 +132,7 @@ namespace cw } + /* void _complete_input_connections( instance_t* inst ) { for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link) @@ -173,7 +160,8 @@ namespace cw } } } - + */ + rc_t _set_log_flags(instance_t* proc, const object_t* log_labels) { rc_t rc = kOkRC; @@ -1223,7 +1211,7 @@ namespace cw // 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)); + rc = cwLogError(kEleNotFoundRC,"Unable to locate the var class desc for the in-var from '%s'.",cwStringNullGuard(in_stmt.in_var_ele.label)); goto errLabel; } @@ -1446,7 +1434,7 @@ namespace cw } // - _connect_vars( src_var, in_var ); + var_connect( src_var, in_var ); } } @@ -1661,7 +1649,7 @@ namespace cw } // the custom creation function may have added channels to in-list vars fix up those connections here. - _complete_input_connections(inst); + //_complete_input_connections(inst); // set the log flags again so that vars created by the instance can be included in the log output if((rc = _set_log_flags(inst,pstate.log_labels)) != kOkRC ) @@ -2033,7 +2021,8 @@ cw::rc_t cw::flow::exec_cycle( network_t& net ) for(unsigned i=0; iclass_desc->members->exec(net.proc_array[i])) != kOkRC ) - { + { + rc = cwLogError(rc,"Execution failed on the proc:%s:%i.",cwStringNullGuard(net.proc_array[i]->label),net.proc_array[i]->label_sfx_id); break; } } diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index e9f640a..7dbb49c 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -31,6 +31,39 @@ namespace cw namespace flow { + + template< typename inst_t > + rc_t std_destroy( instance_t* proc ) + { + inst_t* p = (inst_t*)proc->userPtr; + rc_t rc = _destroy(proc,p); + mem::release(proc->userPtr); + return rc; + } + + template< typename inst_t > + rc_t std_create( instance_t* proc ) + { + rc_t rc = kOkRC; + proc->userPtr = mem::allocZ(); + if((rc = _create(proc,(inst_t*)proc->userPtr)) != kOkRC ) + std_destroy(proc); + return rc; + } + + template< typename inst_t > + rc_t std_value( instance_t* proc, variable_t* var ) + { return _value(proc,(inst_t*)proc->userPtr, var); } + + template< typename inst_t > + rc_t std_exec( instance_t* proc ) + { return _exec(proc,(inst_t*)proc->userPtr); } + + template< typename inst_t > + rc_t std_report( instance_t* proc ) + { return _report(proc,(inst_t*)proc->userPtr); } + + //------------------------------------------------------------------------------------------------------------------ // // Template @@ -43,50 +76,46 @@ namespace cw } inst_t; - rc_t create( instance_t* proc ) + rc_t _create( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - inst_t* p = mem::allocZ(); - proc->userPtr = p; // Custom create code goes here return rc; } - rc_t destroy( instance_t* proc ) + rc_t _destroy( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - inst_t* p = (inst_t*)proc->userPtr; - // Custom clean-up code goes here - mem::release(p); - return rc; } - rc_t value( instance_t* proc, variable_t* var ) + rc_t _value( instance_t* proc, inst_t* p, variable_t* var ) { rc_t rc = kOkRC; return rc; } - rc_t exec( instance_t* proc ) + rc_t _exec( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - //inst_t* p = (inst_t*)proc->userPtr; return rc; } + rc_t _report( instance_t* proc, inst_t* p ) + { return kOkRC; } + class_members_t members = { - .create = create, - .destroy = destroy, - .value = value, - .exec = exec, - .report = nullptr + .create = std_create, + .destroy = std_destroy, + .value = std_value, + .exec = std_exec, + .report = std_report }; } @@ -972,7 +1001,7 @@ namespace cw // print a minutes counter inst->durSmpN += src_abuf->frameN; - if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 ) + if( src_abuf->srate!=0 && inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 ) printf("audio file out: %5.1f min\n", inst->durSmpN/(src_abuf->srate*60)); } @@ -1720,15 +1749,29 @@ namespace cw ctx->userPtr = inst; // Register variables and get their current value - if((rc = var_register_and_get( ctx, kAnyChIdx, kChCntPid, "chCnt", kBaseSfxId, chCnt)) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx, + kChCntPid, "chCnt", kBaseSfxId, chCnt, + kSratePId, "srate", kBaseSfxId, srate)) != kOkRC ) { goto errLabel; } + // Sample rate logic: + // The sample rate may be set directly, or sourced. + // If the srate is 0 then this indicates that the system sample rate should be used. + // if the sample rate is sourced and 0 it is a configuration error. + + // if no sample rate was given then use the system sample rate. + if( srate == 0 ) + srate = ctx->ctx->sample_rate; + // 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 ); @@ -3286,22 +3336,25 @@ namespace cw kSrateRefPId, kDurMsPId, kTriggerPId, + kPresetPId, kGainPId, }; typedef struct { - unsigned xfadeDurMs; // crossfade duration in milliseconds - instance_t* net_proc; // source 'poly' network - network_t net; // internal proxy network + 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 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; - + bool preset_delta_fl; + bool trigFl; + bool trigVal; } inst_t; void _trigger_xfade( inst_t* p ) @@ -3333,16 +3386,17 @@ namespace cw 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; + p->target_gainA[ p->next_poly_ch_idx ] = 0; + + //printf("xfad:%i %i : %i\n",p->cur_poly_ch_idx, p->next_poly_ch_idx,p->poly_ch_cnt); } - - rc_t create( instance_t* ctx ) { rc_t rc = kOkRC; const char* netLabel = nullptr; + const char* presetLabel = nullptr; unsigned netLabelSfxId = kBaseSfxId; bool trigFl = false; variable_t* gainVar = nullptr; @@ -3353,15 +3407,15 @@ namespace cw 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_dbl)) != kOkRC ) + kTriggerPId, "trigger", kBaseSfxId, p->trigVal, + kPresetPId, "preset", kBaseSfxId, presetLabel, + kGainPId, "gain", kBaseSfxId, dum_dbl)) != kOkRC ) { goto errLabel; } @@ -3378,7 +3432,9 @@ namespace cw 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; } - + + p->poly_ch_cnt = p->net_proc->internal_net->poly_cnt; + // create the gain output variables - one output for each poly-channel for(unsigned i=1; inet_proc->internal_net->poly_cnt; ++i) @@ -3396,11 +3452,11 @@ namespace cw // 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; + 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 @@ -3431,7 +3487,27 @@ namespace cw } rc_t value( instance_t* ctx, variable_t* var ) - { return kOkRC; } + { + rc_t rc = kOkRC; + inst_t* p = (inst_t*)ctx->userPtr; + + if(var->vid == kTriggerPId ) + { + bool v; + if((rc = var_get(var,v)) == kOkRC ) + { + if( !p->trigFl ) + p->trigFl = p->trigVal != v; + + p->trigVal = v; + } + //printf("tr:%i %i %i\n",v,p->trigVal,p->trigFl); + + + } + + return kOkRC; + } // return sign of expression as a float float _signum( float v ) { return (0.0f < v) - (v < 0.0f); } @@ -3440,14 +3516,12 @@ namespace cw { 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 ) + if(p->trigFl ) { + p->trigFl = false; _trigger_xfade(p); - - var_set(ctx,kTriggerPId,kAnyChIdx,false); } // time in sample frames to complete a xfade @@ -3482,95 +3556,181 @@ namespace cw //------------------------------------------------------------------------------------------------------------------ // - // poly_mixer + // poly_merge // - namespace poly_mixer + + namespace poly_merge { - enum { + enum + { kOutGainPId, kOutPId, - + kInBasePId, }; - + typedef struct { - unsigned inBaseVId; - unsigned gainBaseVId; + unsigned inAudioVarCnt; + unsigned gainVarCnt; + unsigned baseGainPId; } inst_t; - rc_t create( instance_t* ctx ) + rc_t _create( instance_t* proc, inst_t* p ) { - rc_t rc = kOkRC; - /* - const abuf_t* abuf0 = nullptr; // - const abuf_t* abuf1 = nullptr; - unsigned outChN = 0; - double dum; + rc_t rc = kOkRC; + + unsigned inAudioChCnt = 0; + srate_t srate = 0; + unsigned audioFrameN = 0; + unsigned sfxIdAllocN = instance_var_count(proc); + unsigned sfxIdA[ sfxIdAllocN ]; + + + // register the output gain variable + if((rc = var_register(proc,kAnyChIdx,kOutGainPId,"out_gain",kBaseSfxId)) != kOkRC ) + goto errLabel; + - // get the source audio buffer - if((rc = var_register_and_get(ctx, kAnyChIdx, - kIn0PId,"in0",kBaseSfxId,abuf0, - kIn1PId,"in1",kBaseSfxId,abuf1 )) != kOkRC ) + // get the the sfx_id's of the input audio variables + if((rc = var_mult_sfx_id_array(proc, "in", sfxIdA, sfxIdAllocN, p->inAudioVarCnt )) != kOkRC ) + goto errLabel; + + // for each input audio variable + for(unsigned i=0; iinAudioVarCnt; ++i) { + abuf_t* abuf; + + // register the input audio variable + if((rc = var_register_and_get(proc,kAnyChIdx,kInBasePId+i,"in",sfxIdA[i],abuf)) != kOkRC ) + goto errLabel; + + + // the sample rate of off input audio signals must be the same + if( srate != 0 && abuf->srate != srate ) + { + rc = cwLogError(kInvalidArgRC,"All signals on a poly merge must have the same sample rate."); + goto errLabel; + } + + srate = abuf->srate; + + // the count of frames in all audio signals must be the same + if( audioFrameN != 0 && abuf->frameN != audioFrameN ) + { + rc = cwLogError(kInvalidArgRC,"All signals on a poly merge must have the same frame count."); + goto errLabel; + } + + audioFrameN = abuf->frameN; + + inAudioChCnt += abuf->chN; + } + + // Get the sfx-id's of the input gain variables + if((rc = var_mult_sfx_id_array(proc, "gain", sfxIdA, sfxIdAllocN, p->gainVarCnt )) != kOkRC ) + goto errLabel; + + + // There must be one gain variable for each audio input or exactly one gain variable + if( p->gainVarCnt != p->inAudioVarCnt && p->gainVarCnt != 1 ) + { + rc = cwLogError(kInvalidArgRC,"The count of gain variables must be the same as the count of audio variables are there must be one gain variable."); goto errLabel; } - assert( abuf0->frameN == abuf1->frameN ); + // set the baseInGainPId + p->baseGainPId = kInBasePId + p->inAudioVarCnt; - outChN = std::max(abuf0->chN, abuf1->chN); + // register each of the input gain variables + for(unsigned i=0; igainVarCnt; ++i) + { + coeff_t dum; + if((rc = var_register(proc,kAnyChIdx,p->baseGainPId + i,"gain",sfxIdA[i])) != kOkRC ) + goto errLabel; + + } - // register the gain - var_register_and_get( ctx, kAnyChIdx, kGain0PId, "gain0", kBaseSfxId, dum ); - var_register_and_get( ctx, kAnyChIdx, kGain1PId, "gain1", kBaseSfxId, dum ); + rc = var_register_and_set( proc, "out", kBaseSfxId, kOutPId, kAnyChIdx, srate, inAudioChCnt, audioFrameN ); - // 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 _destroy( instance_t* proc, inst_t* p ) + { + return kOkRC; + } - rc_t value( instance_t* ctx, variable_t* var ) - { return kOkRC; } + rc_t _value( instance_t* proc, inst_t* p, variable_t* var ) + { + return kOkRC; + } + unsigned _merge_in_one_audio_var( instance_t* proc, const abuf_t* ibuf, abuf_t* obuf, unsigned outChIdx, coeff_t gain ) + { + // for each channel + for(unsigned i=0; ichN && outChIdxchN; ++i) + { + sample_t* isig = ibuf->buf + i * ibuf->frameN; + sample_t* osig = obuf->buf + outChIdx * obuf->frameN; + + // apply the gain + for(unsigned j=0; jframeN; ++j) + osig[j] = gain * isig[j]; + + outChIdx += 1; + } + + return outChIdx; + } - rc_t exec( instance_t* ctx ) + rc_t _exec( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - /* abuf_t* obuf = nullptr; - //const abuf_t* ibuf0 = nullptr; - //const abuf_t* ibuf1 = nullptr; + unsigned oChIdx = 0; + coeff_t igain = 1; + coeff_t ogain = 1; - if((rc = var_get(ctx,kOutPId, kAnyChIdx, obuf)) != kOkRC ) + // get the output audio buffer + if((rc = var_get(proc,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; + // get the output audio gain + if((rc = var_get(proc,kOutGainPId, kAnyChIdx, ogain)) != kOkRC ) + goto errLabel; + + // for each audio input variable + for(unsigned i=0; iinAudioVarCnt; ++i) + { + const abuf_t* ibuf = nullptr; + + // get the input audio buffer + if((rc = var_get(proc,kInBasePId+i, kAnyChIdx, ibuf )) != kOkRC ) + goto errLabel; + + // get the input gain + if( i < p->gainVarCnt ) + var_get(proc,p->baseGainPId+i,kAnyChIdx,igain); + + // merge the input audio signal into the output audio buffer + oChIdx = _merge_in_one_audio_var( proc, ibuf, obuf, oChIdx, igain * ogain ); + } - vop::zero(obuf->buf, obuf->frameN*obuf->chN ); - - _mix( ctx, kIn0PId, kGain0PId, obuf ); - _mix( ctx, kIn1PId, kGain1PId, obuf ); - */ - errLabel: return rc; } + rc_t _report( instance_t* proc, inst_t* p ) + { return kOkRC; } + class_members_t members = { - .create = create, - .destroy = destroy, - .value = value, - .exec = exec, - .report = nullptr + .create = std_create, + .destroy = std_destroy, + .value = std_value, + .exec = std_exec, + .report = std_report }; } @@ -3878,6 +4038,9 @@ namespace cw goto errLabel; } + if( srate == 0 ) + var_set(proc,kSratePId,kAnyChIdx,proc->ctx->sample_rate); + if((rc = var_register_and_set(proc,kAnyChIdx, kOutPId, "out", kBaseSfxId,false)) != kOkRC ) { @@ -4745,12 +4908,14 @@ namespace cw }; } + //------------------------------------------------------------------------------------------------------------------ // // preset // namespace preset { + enum { kInPId }; enum { kPresetLabelCharN=255 }; @@ -4758,101 +4923,113 @@ namespace cw typedef struct { char preset_label[ kPresetLabelCharN+1]; + bool delta_fl; } inst_t; - rc_t _set_preset( instance_t* proc, inst_t* p, const char* preset_label ) + rc_t _set_preset( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; + unsigned presetLabelCharN = 0; + const char* preset_label = nullptr; - if( preset_label == nullptr ) + // get the preset label + if((rc = var_get(proc, kInPId, kAnyChIdx, preset_label)) != kOkRC ) { - if((rc = var_get(proc, kInPId, kAnyChIdx, preset_label)) != kOkRC ) - { - rc = cwLogError(rc,"The variable 'in read failed."); - goto errLabel; - } + rc = cwLogError(rc,"The variable 'in read failed."); + goto errLabel; } - if( preset_label == nullptr ) + // at this point a valid preset-label must exist + if( preset_label == nullptr || (presetLabelCharN=textLength(preset_label))==0 ) { rc = cwLogError(kInvalidArgRC,"Preset application failed due to blank preset label."); goto errLabel; } + // if the preset-label has not changed since the last preset application - then there is nothing to do + if( textIsEqual(preset_label,p->preset_label) ) + goto errLabel; + + + // verify the preset-label is not too long + if( presetLabelCharN > kPresetLabelCharN ) + { + rc = cwLogError(kBufTooSmallRC,"The preset label '%s' is to long.",cwStringNullGuard(preset_label)); + goto errLabel; + } + + cwRuntimeCheck(proc->net != nullptr ); + + // apply the preset if((rc = network_apply_preset(*proc->net, preset_label)) != kOkRC ) { rc = cwLogError(rc,"Appy preset '%s' failed.",cwStringNullGuard(preset_label)); goto errLabel; } - - if( textLength(preset_label) >= kPresetLabelCharN ) - strncpy(p->preset_label,preset_label,kPresetLabelCharN); - else - { - rc = cwLogError(kBufTooSmallRC,"The preset label '%s' is to long.",cwStringNullGuard(preset_label)); - goto errLabel; - } + + // store the applied preset-label + textCopy(p->preset_label,kPresetLabelCharN,preset_label,presetLabelCharN); errLabel: return rc; } - - rc_t create( instance_t* proc ) + + rc_t _create( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - inst_t* p = mem::allocZ(); - proc->userPtr = p; + + // Custom create code goes here const char* label = nullptr; p->preset_label[0] = 0; + p->delta_fl = true; if((rc = var_register_and_get(proc,kAnyChIdx,kInPId,"in",kBaseSfxId,label)) != kOkRC ) goto errLabel; + // we can't apply a preset here because the network is not yet constructed errLabel: return rc; } - rc_t destroy( instance_t* proc ) + rc_t _destroy( instance_t* proc, inst_t* p ) + { return kOkRC; } + + rc_t _value( instance_t* proc, inst_t* p, variable_t* var ) { rc_t rc = kOkRC; - - inst_t* p = (inst_t*)proc->userPtr; - - // Custom clean-up code goes here - - mem::release(p); + if( var->vid == kInPId ) + p->delta_fl = true; return rc; } - rc_t value( instance_t* proc, variable_t* var ) - { - rc_t rc = kOkRC; - return rc; - } - - rc_t exec( instance_t* proc ) + rc_t _exec( instance_t* proc, inst_t* p ) { rc_t rc = kOkRC; - //inst_t* p = (inst_t*)proc->userPtr; + + if( p->delta_fl ) + rc = _set_preset(proc,p); return rc; } + rc_t _report( instance_t* proc, inst_t* p ) + { return kOkRC; } + + class_members_t members = { - .create = create, - .destroy = destroy, - .value = value, - .exec = exec, - .report = nullptr + .create = std_create, + .destroy = std_destroy, + .value = std_value, + .exec = std_exec, + .report = std_report }; } - } // flow } // cw diff --git a/cwFlowProc.h b/cwFlowProc.h index 30e3588..64921e3 100644 --- a/cwFlowProc.h +++ b/cwFlowProc.h @@ -26,7 +26,7 @@ namespace cw 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; } + namespace poly_merge { extern class_members_t members; } namespace sample_hold { extern class_members_t members; } namespace number { extern class_members_t members; } namespace timer { extern class_members_t members; } diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 6474233..df43567 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -46,7 +46,7 @@ namespace cw { kFloatTFl, "coeff"}, { kDoubleTFl, "ftime" }, - { kUIntTFl | kIntTFl | kFloatTFl | kDoubleTFl, "numeric" }, + { kBoolTFl | kUIntTFl | kIntTFl | kFloatTFl | kDoubleTFl, "numeric" }, { kRuntimeTFl, "runtime" }, @@ -473,7 +473,6 @@ namespace cw val->u.s = mem::duplStr(v); val->tflag = kStringTFl; break; - default: rc = cwLogError(kTypeMismatchRC,"A string could not be converted to a %s (0x%x).",_typeFlagToLabel(val->tflag),val->tflag); } @@ -662,30 +661,8 @@ namespace cw return _val_get(var->value,valRef); -} - rc_t _var_find_to_set( instance_t* inst, unsigned vid, unsigned chIdx, unsigned typeFl, variable_t*& varRef ) - { - rc_t rc = kOkRC; - varRef = nullptr; - - // - if((rc = var_find(inst,vid,chIdx,varRef)) == kOkRC ) - { - // validate the type of the variable against the description - /* - if( !cwIsFlag(varRef->varDesc->type,typeFl ) ) - rc = cwLogError(kTypeMismatchRC,"Type mismatch. Instance:%s:%i variable:%s:%i with type %s (0x%x) does not match requested type: %s (0x%x).", - varRef->inst->label,varRef->inst->label_sfx_id, - varRef->label, - varRef->label_sfx_id,_typeFlagToLabel(varRef->varDesc->type),varRef->varDesc->type, - _typeFlagToLabel(typeFl),typeFl); - */ - - } - - return rc; } - + // Variable lookup: Exact match on vid and chIdx rc_t _var_find_on_vid_and_ch( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ) @@ -737,6 +714,9 @@ namespace cw return kOkRC; } + void _var_print_addr( const char* title, const variable_t* v ) + { printf("%s:%s:%i.%s:%i ",title,v->inst->label,v->inst->label_sfx_id,v->label,v->label_sfx_id); } + void _var_print( const variable_t* var ) { const char* conn_label = is_connected_to_source_proc(var) ? "extern" : " "; @@ -751,6 +731,12 @@ namespace cw 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); + if( var->dst_head != nullptr ) + { + for(variable_t* v = var->dst_head; v!=nullptr; v=v->dst_link) + printf(" dst:%s:%i.%s:%i",v->inst->label,v->inst->label_sfx_id,v->label,v->label_sfx_id); + } + printf("\n"); } @@ -766,7 +752,7 @@ namespace cw // so that it points to the correct value. con_var->value = var->value; - cwLogMod("%s:%i %s:%i -> %s:%i %s:%i\n", + cwLogMod("%s:%i %s:%i -> %s:%i %s:%i", var->inst->label,var->inst->label_sfx_id, var->label,var->label_sfx_id, con_var->inst->label,con_var->inst->label_sfx_id, @@ -782,23 +768,28 @@ namespace cw - // 'typeFlag' is the type (tflag) of 'val'. + // 'argTypeFlag' is the type (tflag) of 'val'. template< typename T > rc_t _var_set_template( variable_t* var, unsigned argTypeFlag, T val ) { - rc_t rc; + rc_t rc = kOkRC; + + // it is not legal to set the value of a variable that is connected to a 'source' variable. + if( var->src_var != nullptr ) + return cwLogError(kInvalidStateRC, "The variable '%s:%i %s:%i' cannot be set because it is connected to a source variable.", var->inst->label,var->inst->label_sfx_id, var->label, var->label_sfx_id); + + // var->type is the allowable type for this var's value. + // It may be set to kInvalidTFl if the type has not yet been determined. unsigned value_type_flag = var->type; + // Pick the slot in local_value[] that we will use to try out this new value. unsigned next_local_value_idx = (var->local_value_idx + 1) % kLocalValueN; // store the pointer to the current value of this variable value_t* original_value = var->value; unsigned original_value_idx = var->local_value_idx; - // verify that this is a legal assignment - if((rc = _validate_var_assignment( var, argTypeFlag )) != kOkRC ) - goto errLabel; // release the previous value in the next slot _value_release(&var->local_value[next_local_value_idx]); @@ -808,9 +799,13 @@ namespace cw { // if the var desc is a single type then use that .... if( math::isPowerOfTwo(var->varDesc->type) ) + { value_type_flag = var->varDesc->type; + } else // ... Otherwise select a type from the one of the possible flags given by the var desc + { value_type_flag = var->varDesc->type & argTypeFlag; + } // if the incoming type is not in the set of allowable types then it is an error if( value_type_flag == 0 ) @@ -824,7 +819,7 @@ namespace cw // set the type of the LHS to force the incoming value to be coerced to this type var->local_value[ next_local_value_idx ].tflag = value_type_flag; - // set the new local value + // set the new local value in var->local_value[next_local_value_idx] if((rc = _val_set(var->local_value + next_local_value_idx, val )) != kOkRC ) { rc = cwLogError(rc,"Value set failed on '%s:%i %s:%i",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id); @@ -843,7 +838,7 @@ namespace cw // call because calls' to 'proc.value()' will see the instance in a incomplete state) // Note 2: If this call returns an error then the value assignment is cancelled // and the value does not change. - var_call_custom_value_func( var ); + rc = var_call_custom_value_func( var ); } //printf("%p set: %s:%s 0x%x\n",var->value, var->inst->label,var->label,var->value->tflag); @@ -875,8 +870,9 @@ namespace cw // if this variable is fed from the output of an external proc - then it's local value cannot be set if(is_connected_to_source_proc(var) ) - return kOkRC; - + { + return cwLogError(kInvalidStateRC,"Cannot set the value on a connected variables."); + } // if this assignment targets a specific channel ... if( var->chIdx != kAnyChIdx ) @@ -936,137 +932,6 @@ namespace cw return rc; } - rc_t _set_var_value_from_cfg( variable_t* var, const object_t* value ) - { - rc_t rc = kOkRC; - - // Determine the flow variable type of cfg. argument 'value'. - unsigned value_flag = 0; - - switch( value->type->id ) - { - case kCharTId: - case kUInt8TId: - case kUInt16TId: - case kUInt32TId: - value_flag = kUIntTFl; - break; - - case kInt8TId: - case kInt16TId: - case kInt32TId: - value_flag = kIntTFl; - break; - - case kInt64TId: - case kUInt64TId: - rc = cwLogError(kInvalidArgRC,"The flow system does not currently implement 64bit integers."); - goto errLabel; - break; - - case kFloatTId: - value_flag = kFloatTFl; - break; - - case kDoubleTId: - value_flag = kDoubleTFl; - break; - - case kBoolTId: - value_flag = kBoolTFl; - break; - - case kStringTId: - case kCStringTId: - value_flag = kStringTFl; - break; - - default: - value_flag = kCfgTFl; - - } - - /* - if( !cwIsFlag(var->varDesc->type & kTypeMask, value_flag) ) - { - rc = cwLogError(kTypeMismatchRC,"The var desc class type 0x%x does not permit the var to be instantiated with the type %s (0x%x).",var->varDesc->type,_typeFlagToLabel(value_flag),value_flag); - goto errLabel; - } - */ - - switch( value_flag ) - { - case kBoolTFl: - { - bool v; - // assign the value of 'value' to to 'v' (do type conversion if necessary) - if((rc = value->value(v)) == kOkRC ) - // set the value of 'var' where 'v' is the new value and 'value_flag' is the type of 'v'. - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kUIntTFl: - { - unsigned v; - if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kIntTFl: - { - int v; - if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kFloatTFl: - { - float v; - if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kDoubleTFl: - { - double v; - if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kStringTFl: - { - const char* v; - if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, v ); - } - break; - - case kCfgTFl: - { - //const object_t* v; - //if((rc = value->value(v)) == kOkRC ) - rc = _var_set_driver( var, value_flag, value ); - } - break; - - default: - rc = cwLogError(kOpFailRC,"The variable type 0x%x cannot yet be set via a cfg.", var->varDesc->type ); - goto errLabel; - } - - errLabel: - if( rc != kOkRC ) - rc = cwLogError(kSyntaxErrorRC,"The %s:%i.%s:%i could not extract a type:%s from a configuration value.",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,_typeFlagToLabel(var->varDesc->type & kTypeMask)); - - return rc; - - } - rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ) { @@ -1130,22 +995,6 @@ namespace cw } - /* - void _var_set_value_to_typed_null( variable_t* var, unsigned type_flag ) - { - for(unsigned i=0; ilocal_value[i].tflag == kInvalidTFl ); - - // set the var-value to a typed null value - this will force later settings to be coerced to this type - set_null( var->local_value[i], type_flag ); - } - - var->value = var->local_value; - - } - */ - rc_t _var_set_type( variable_t* var, unsigned type_flag ) { rc_t rc = kOkRC; @@ -1155,7 +1004,8 @@ namespace cw rc = cwLogError(kOpFailRC,"It is invalid to change the type of a statically (non-runtime) type variable."); goto errLabel; } - + + // Duplicate the varDesc with the 'type' field set to type_flag if( var->localVarDesc == nullptr ) { var->localVarDesc = mem::allocZ(); @@ -1165,8 +1015,6 @@ namespace cw var->localVarDesc->type = type_flag; var->varDesc = var->localVarDesc; - - //_var_set_value_to_typed_null(var,type_flag); errLabel: return rc; @@ -1215,10 +1063,10 @@ namespace cw // if no value was given then set the value to the value given in the class if( value_cfg == nullptr ) value_cfg = var->varDesc->val_cfg; - + // if value_cfg is valid set the variable value if( value_cfg != nullptr && cwIsNotFlag(vd->type,kRuntimeTFl)) - if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC ) + if((rc = var_set_from_preset( var, value_cfg )) != kOkRC ) goto errLabel; var->var_link = inst->varL; @@ -1244,28 +1092,9 @@ namespace cw return rc; } - - rc_t _preset_set_var_value( instance_t* inst, const char* var_label, unsigned sfx_id, unsigned chIdx, const object_t* value ) - { - rc_t rc = kOkRC; - variable_t* var = nullptr; - - // get the variable - if((rc = var_find( inst, var_label, sfx_id, chIdx, var )) != kOkRC ) - goto errLabel; - - rc = _set_var_value_from_cfg( var, value ); - - errLabel: - if( rc != kOkRC ) - rc = cwLogError(rc,"The value of instance:%s:%i variable:%s:%i could not be set via a preset.", inst->label, inst->label_sfx_id, var_label, sfx_id ); - - return rc; - } } } - cw::flow::abuf_t* cw::flow::abuf_create( srate_t srate, unsigned chN, unsigned frameN ) { abuf_t* a = mem::allocZ(); @@ -1455,6 +1284,7 @@ cw::flow::class_desc_t* cw::flow::class_desc_find( flow_t* p, const char* label return nullptr; } + cw::flow::var_desc_t* cw::flow::var_desc_find( class_desc_t* cd, const char* label ) { var_desc_t* vd = cd->varDescL; @@ -1472,6 +1302,15 @@ cw::rc_t cw::flow::var_desc_find( class_desc_t* cd, const char* label, var_desc_ return kOkRC; } +const cw::flow::preset_t* cw::flow::class_preset_find( class_desc_t* cd, const char* preset_label ) +{ + const preset_t* pr; + for(pr=cd->presetL; pr!=nullptr; pr=pr->link) + if( textCompare(pr->label,preset_label) == 0 ) + return pr; + + return nullptr; +} void cw::flow::class_dict_print( flow_t* p ) { @@ -1530,16 +1369,19 @@ cw::rc_t cw::flow::instance_validate( instance_t* inst ) continue; } + // the assigned value must have exactly one type if(!math::isPowerOfTwo( var->value->tflag ) ) { rc = cwLogError(kInvalidStateRC,"The var '%s:%i' has the invalid type flag:0x%x",var->label,var->label_sfx_id,var->value->tflag); continue; } - if( !(var->varDesc->type & var->value->tflag) ) + // if var is using a local value (not connected to a source variable) then the type of the value must be valid with the variable class + if( !is_connected_to_source_proc(var) && !(var->varDesc->type & var->value->tflag) ) { - rc = cwLogError(kInvalidStateRC, "The value type flag '%s' (0x%x) of the var '%s:%i' is not found in the variable class type flags: '%s' (0x%x)", + rc = cwLogError(kInvalidStateRC, "The value type flag '%s' (0x%x) of '%s:%i-%s:%i' is not found in the variable class type flags: '%s' (0x%x)", _typeFlagToLabel(var->value->tflag),var->value->tflag, + var->inst->label,var->inst->label_sfx_id, var->label,var->label_sfx_id, _typeFlagToLabel(var->varDesc->type),var->varDesc->type); continue; @@ -1651,12 +1493,14 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns var = _var_find_on_label_and_ch( inst, var_label, sfx_id, chIdx ); // 'src' variables cannot be channelized + /* if( cwIsFlag(base_var->varDesc->flags,kSrcVarFl) ) { rc = cwLogError(rc,"'src' variables cannot be channelized."); goto errLabel; } - + */ + // if the requested var was not found then create a new variable with the requested channel index if( var == nullptr && chIdx != kAnyChIdx ) { @@ -1667,12 +1511,46 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns // if no value was set then set the value from the 'any' channel if( value_cfg == nullptr ) { - // Set the value of the new variable to the value of the 'any' channel - _value_duplicate( var->local_value[ var->local_value_idx], base_var->local_value[ base_var->local_value_idx ] ); + // if the base-var is connected to a source ... + if( is_connected_to_source_proc(base_var) ) + { + // ... then connect the new var to a source also + + // Attempt to find a matching channel on the source + variable_t* src_ch_var = base_var->src_var; + variable_t* last_src_ch_var = base_var->src_var; + unsigned src_ch_cnt = 0; + + for(; src_ch_var!=nullptr; src_ch_var=src_ch_var->ch_link) + { + last_src_ch_var = src_ch_var; + if( src_ch_var->chIdx == var->chIdx ) + break; - // If the 'any' channel value was set to point to it's local value then do same with this value - if( base_var->local_value + base_var->local_value_idx == base_var->value ) - var->value = var->local_value + var->local_value_idx; + src_ch_cnt += 1; + } + + // if there is more than one channel available and the src and dst var's do not have matching ch indexes + // then there is a possibility that this is an unexpected connection between different channels. + if( src_ch_var == nullptr && src_ch_cnt>1 && last_src_ch_var->chIdx != var->chIdx ) + cwLogWarning("A connection is being made where channel src and dst. channels don't match and more than one src channel is available."); + + // if no matching channel is found connect to the last valid source channel + // (Connecting to the last valid source is better than connecting to base_var->src_var + // because if a var has more than a base var it is unlikely to update the base_var.) + var_connect( last_src_ch_var, var ); + + } + else + { + + // Set the value of the new variable to the value of the 'any' channel + _value_duplicate( var->local_value[ var->local_value_idx], base_var->local_value[ base_var->local_value_idx ] ); + + // If the 'any' channel value was set to point to it's local value then do same with this value + if( base_var->local_value + base_var->local_value_idx == base_var->value ) + var->value = var->local_value + var->local_value_idx; + } } } @@ -1683,7 +1561,7 @@ cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, uns if( value_cfg != nullptr ) { //cwLogInfo("%s ch:%i",var_label,chIdx); - rc = _set_var_value_from_cfg( var, value_cfg ); + rc = var_set_from_preset( var, value_cfg ); } else { @@ -1708,9 +1586,18 @@ cw::rc_t cw::flow::var_call_custom_value_func( variable_t* var ) goto errLabel; if( var->flags & kLogVarFl ) - { + { printf("%10s:%5i", var->inst->label,var->inst->label_sfx_id); - _var_print(var); + + if( var->chIdx == kAnyChIdx ) + _var_print(var); + else + { + printf("\n"); + for(variable_t* ch_var = var; ch_var!=nullptr; ch_var=ch_var->ch_link) + _var_print(ch_var); + + } } errLabel: @@ -1761,24 +1648,6 @@ cw::rc_t cw::flow::var_clr_flags( instance_t* inst, unsigned chIdx, const char* errLabel: return rc; } -/* -cw::rc_t cw::flow::var_set_type( instance_t* inst, unsigned chIdx, const char* var_label, unsigned sfx_id, unsigned type_flag ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_find_on_label_and_ch(inst,var_label,sfx_id,chIdx,var)) != kOkRC ) - goto errLabel; - - rc = _var_set_type(var,type_flag); - -errLabel: - if( rc != kOkRC ) - rc = cwLogError(rc,"Type set failed on the variable:'%s:%i",cwStringNullGuard(var_label),sfx_id); - - return rc; -} -*/ bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned sfx_id, unsigned chIdx ) { return _var_find_on_label_and_ch(inst,label,sfx_id,chIdx) != nullptr; } @@ -1846,7 +1715,7 @@ cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, var } } - // if we get here var must be non-null + // if we get here var must be non-null - (was the var registered?) assert( var != nullptr && rc == kOkRC ); varRef = var; @@ -1927,7 +1796,7 @@ cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsign { // if a value was given - then update the value if( value_cfg != nullptr ) - if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC ) + if((rc = var_set_from_preset( var, value_cfg )) != kOkRC ) goto errLabel; } else // an exact match was not found - channelize the variable @@ -1968,6 +1837,37 @@ bool cw::flow::is_connected_to_source_proc( const variable_t* var ) bool cw::flow::is_a_source_var( const variable_t* var ) { return var->dst_head != nullptr; } + +void cw::flow::var_connect( variable_t* src_var, variable_t* in_var ) +{ + assert( in_var->dst_link == nullptr ); + + // connect in_var into src_var's outgoing var chain + if( src_var->dst_head == nullptr ) + src_var->dst_head = in_var; + else + src_var->dst_tail->dst_link = in_var; + + src_var->dst_tail = in_var; + + in_var->value = src_var->value; + in_var->src_var = src_var; + + //printf("Connect: "); + //_var_print_addr("src",src_var); + //_var_print_addr("dst",in_var); + //_var_print_addr("HEAD",src_var->dst_head); + + //if( src_var->dst_head->dst_link != nullptr ) + // _var_print_addr("LINK",src_var->dst_head->dst_link); + + //_var_print_addr("TAIL",src_var->dst_tail); + //printf("\n"); + + +} + + cw::rc_t cw::flow::var_mult_sfx_id_array( instance_t* inst, const char* var_label, unsigned* idA, unsigned idAllocN, unsigned& idN_ref ) { rc_t rc = kOkRC; @@ -2104,6 +2004,132 @@ cw::rc_t cw::flow::var_get( variable_t* var, mbuf_t*& valRef ) cw::rc_t cw::flow::var_get( const variable_t* var, const object_t*& valRef ) { return _val_get_driver(var,valRef); } +cw::rc_t cw::flow::var_set_from_preset( variable_t* var, const object_t* value ) +{ + rc_t rc = kOkRC; + + // + // Determine the flow variable type of cfg. argument 'value'. + // + unsigned value_flag = 0; + + switch( value->type->id ) + { + case kCharTId: + case kUInt8TId: + case kUInt16TId: + case kUInt32TId: + value_flag = kUIntTFl; + break; + + case kInt8TId: + case kInt16TId: + case kInt32TId: + value_flag = kIntTFl; + break; + + case kInt64TId: + case kUInt64TId: + rc = cwLogError(kInvalidArgRC,"The flow system does not currently implement 64bit integers."); + goto errLabel; + break; + + case kFloatTId: + value_flag = kFloatTFl; + break; + + case kDoubleTId: + value_flag = kDoubleTFl; + break; + + case kBoolTId: + value_flag = kBoolTFl; + break; + + case kStringTId: + case kCStringTId: + value_flag = kStringTFl; + break; + + default: + value_flag = kCfgTFl; + + } + + // + // Convert the cfg value to a c++ typed value and then call _var_set_driver() with the c++ value. + // + switch( value_flag ) + { + case kBoolTFl: + { + bool v; + // assign the value of 'value' to to 'v' (do type conversion if necessary) + if((rc = value->value(v)) == kOkRC ) + // set the value of 'var' where 'v' is the new value and 'value_flag' is the type of 'v'. + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kUIntTFl: + { + unsigned v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kIntTFl: + { + int v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kFloatTFl: + { + float v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kDoubleTFl: + { + double v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kStringTFl: + { + const char* v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, value_flag, v ); + } + break; + + case kCfgTFl: + { + rc = _var_set_driver( var, value_flag, value ); + } + break; + + default: + rc = cwLogError(kOpFailRC,"The variable type 0x%x cannot yet be set via a cfg.", var->varDesc->type ); + goto errLabel; + } + +errLabel: + if( rc != kOkRC ) + rc = cwLogError(kSyntaxErrorRC,"The %s:%i.%s:%i could not extract a type:%s from a configuration value.",var->inst->label,var->inst->label_sfx_id,var->label,var->label_sfx_id,_typeFlagToLabel(var->varDesc->type & kTypeMask)); + + return rc; + +} + cw::rc_t cw::flow::var_set( variable_t* var, const value_t* val ) { rc_t rc = kOkRC; @@ -2144,7 +2170,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, cons rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, val->tflag, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = var_set(var,val); return rc; @@ -2155,7 +2181,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kBoolTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kBoolTFl, val ); return rc; @@ -2166,7 +2192,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kUIntTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kUIntTFl, val ); return rc; @@ -2177,7 +2203,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_ rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kIntTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kIntTFl, val ); return rc; @@ -2188,7 +2214,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, floa rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kFloatTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kFloatTFl, val ); return rc; @@ -2199,7 +2225,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, doub rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kDoubleTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kDoubleTFl, val ); return rc; @@ -2210,7 +2236,7 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, cons rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kStringTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kStringTFl, val ); return rc; @@ -2221,20 +2247,11 @@ cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, cons rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_find_to_set(inst, vid, chIdx, kCfgTFl, var )) == kOkRC ) + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) rc = _var_set_driver( var, kCfgTFl, val ); return rc; } -const cw::flow::preset_t* cw::flow::class_preset_find( class_desc_t* cd, const char* preset_label ) -{ - const preset_t* pr; - for(pr=cd->presetL; pr!=nullptr; pr=pr->link) - if( textCompare(pr->label,preset_label) == 0 ) - return pr; - - return nullptr; -} diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 3116516..b0c4cf9 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -18,7 +18,9 @@ namespace cw kBaseSfxId = 0, kFbufVectN = 3, // count of signal vectors in fbuf (mag,phs,hz) kAnyChIdx = kInvalidIdx, - kLocalValueN = 2 + kLocalValueN = 2, + kDefaultFramesPerCycle=64, + kDefaultSampleRate=48000 }; typedef struct abuf_str @@ -78,8 +80,9 @@ namespace cw kTypeMask = 0x0000ffff, - kRuntimeTFl = 0x80000000 + kRuntimeTFl = 0x80000000, + kNumericFlags = kBoolMtxTFl | kUIntMtxTFl | kIntMtxTFl | kFloatMtxTFl | kDoubleMtxTFl }; typedef struct mtx_str @@ -111,7 +114,7 @@ namespace cw char* s; const object_t* cfg; - void* p; + void* p; } u; @@ -119,10 +122,6 @@ namespace cw } value_t; - - inline void set_null( value_t& v, unsigned tflag ) { v.tflag=tflag; v.u.p=nullptr; } - inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->tflag,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); } - inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->tflag,kBoolMtxTFl|kUIntMtxTFl|kIntMtxTFl|kFloatMtxTFl|kDoubleMtxTFl); } struct instance_str; struct variable_str; @@ -187,7 +186,8 @@ 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 label_sfx_id; // the label suffix id of this variable or kBaseSfxId if this has no suffix + unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'inst' unsigned chIdx; // channel index unsigned flags; // kLogVarFl @@ -262,6 +262,7 @@ namespace cw unsigned framesPerCycle; // sample frames per cycle (64) + srate_t sample_rate; // default sample rate (48000.0) bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application bool multiSecPresetProbFl; // bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application @@ -282,6 +283,14 @@ namespace cw // // Value Only // + + inline void set_null( value_t& v, unsigned tflag ) { v.tflag=tflag; v.u.p=nullptr; } + inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->tflag,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); } + inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->tflag,kNumericFlags); } + + // if all of the src flags are set in the dst flags then the two types are convertable. + inline bool can_convert( unsigned src_tflag, unsigned dst_tflag ) { return (src_tflag&dst_tflag)==src_tflag; } + abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN ); void abuf_destroy( abuf_t*& buf ); @@ -309,11 +318,13 @@ namespace cw // // Class and Variable Description // + + class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label ); var_desc_t* var_desc_find( class_desc_t* cd, const char* var_label ); rc_t var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef ); - class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label ); + const preset_t* class_preset_find( class_desc_t* cd, const char* preset_label ); void class_dict_print( flow_t* p ); @@ -341,7 +352,6 @@ namespace cw // Count of all var instances on this proc. This is a count of the length of inst->varL. unsigned instance_var_count( instance_t* inst ); - //------------------------------------------------------------------------------------------------------------------------ // @@ -358,9 +368,6 @@ namespace cw // automatically generated variable whose channel index is set to 'all'. 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 ); - // Set the var. type at runtime. - //rc_t var_set_type( instance_t* inst, unsigned chIdx, const char* var_label, unsigned sfx_id, unsigned type_flags ); - // Wrapper around call to var->inst->members->value() rc_t var_call_custom_value_func( variable_t* var ); @@ -377,7 +384,11 @@ namespace cw // Return true if this var is acting as a source for another var. bool is_a_source_var( const variable_t* var ); - + + // Connect in_var to src_var. + void var_connect( variable_t* src_var, variable_t* in_var ); + + // Get all the label-sfx-id's associated with a give var label rc_t var_mult_sfx_id_array( instance_t* inst, const char* var_label, unsigned* idA, unsigned idAllocN, unsigned& idN_ref ); //----------------- @@ -502,6 +513,10 @@ namespace cw 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 ); + + // + // var_get() coerces the value of the variable to the type of the returned value. + // rc_t var_get( const variable_t* var, bool& valRef ); rc_t var_get( const variable_t* var, uint_t& valRef ); @@ -537,6 +552,12 @@ namespace cw return value; } + // + // var_set() coerces the incoming value to the type of the variable (var->type) + // + + rc_t var_set_from_preset( variable_t* var, const object_t* val ); + rc_t var_set( variable_t* var, const value_t* val ); rc_t var_set( variable_t* var, bool val ); rc_t var_set( variable_t* var, uint_t val ); @@ -560,7 +581,6 @@ namespace cw rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t* val ); rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, const object_t* val ); - const preset_t* class_preset_find( class_desc_t* cd, const char* preset_label ); } }