From b8dea27343014cae36b4073b238d291177e508d5 Mon Sep 17 00:00:00 2001 From: kevin Date: Sun, 22 Aug 2021 22:41:33 -0400 Subject: [PATCH] Many updates and changes to cwFlow* and added Compressor processor. --- Makefile.am | 4 +- cwDspTransforms.cpp | 163 ++++++ cwDspTransforms.h | 53 ++ cwDspTypes.h | 13 + cwFlow.cpp | 428 ++++++++++---- cwFlow.h | 2 +- cwFlowProc.cpp | 429 +++++++++++--- cwFlowProc.h | 3 +- cwFlowTypes.cpp | 1359 +++++++++++++++++++++++++++---------------- cwFlowTypes.h | 269 ++++++--- cwLog.h | 22 + 11 files changed, 1952 insertions(+), 793 deletions(-) create mode 100644 cwDspTransforms.cpp create mode 100644 cwDspTransforms.h create mode 100644 cwDspTypes.h diff --git a/Makefile.am b/Makefile.am index 6a8ed1b..8cffeff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,8 +25,8 @@ libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQu libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwMidiFile.h libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp -libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h -libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.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/cwFlowTypes.h src/libcw/cwFlowProc.h libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp diff --git a/cwDspTransforms.cpp b/cwDspTransforms.cpp new file mode 100644 index 0000000..f444658 --- /dev/null +++ b/cwDspTransforms.cpp @@ -0,0 +1,163 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwFile.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwAudioFile.h" +#include "cwUtility.h" +#include "cwFileSys.h" +#include "cwAudioFileOps.h" +#include "cwVectOps.h" +#include "cwMath.h" +#include "cwDspTypes.h" +#include "cwDsp.h" +#include "cwDspTransforms.h" + +namespace cw +{ + namespace dsp + { + namespace compressor + { + void _ms_to_samples( obj_t*p, real_t ms, unsigned& outRef ) + { + outRef = std::max((real_t)1,(real_t)floor(ms * p->srate / 1000.0)); + } + } + } +} + +cw::rc_t cw::dsp::compressor::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio_num, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl ) +{ + p = mem::allocZ(); + + p->srate = srate; + p->procSmpCnt = procSmpCnt; + p->threshDb = threshDb; + p->ratio_num = ratio_num; + + set_attack_ms(p,atkMs); + set_release_ms(p,rlsMs); + + p->inGain = inGain; + p->outGain = outGain; + p->bypassFl = bypassFl; + + p->rmsWndAllocCnt = (unsigned)std::max(1.0,floor(rmsWndMaxMs * srate / (1000.0 * procSmpCnt))); + p->rmsWnd = mem::allocZ(p->rmsWndAllocCnt); + set_rms_wnd_ms(p, rmsWndMs ); + p->rmsWndIdx = 0; + + p->state = kRlsCompId; + p->timeConstDb = 10.0; + p->accumDb = p->threshDb; + + return kOkRC; +} + +cw::rc_t cw::dsp::compressor::destroy( obj_t*& p ) +{ + mem::release(p->rmsWnd); + mem::release(p); + return kOkRC; +} + +/* + The ratio determines to what degree a signal above the threshold is reduced. + Given a 2:1 ratio, a signal 2dB above the threshold will be reduced to 1db above the threshold. + Given a 4:1 ratio, a signal 2dB above the threshold will be reduced to 0.25db above the threshold. + Gain_reduction_db = (thresh - signal) / ratio_numerator (difference between the threshold and signal level after reduction) + Gain Coeff = 10^(gain_reduction_db / 20); + + Total_reduction_db = signal - threshold + Gain_reduc_db + (total change in signal level) + + The attack can be viewed as beginning at the threshold and moving to the peak + over some period of time. In linear terms this will go from 1.0 to the max gain + reductions. In this case we step from thresh to peak at a fixed rate in dB + based on the attack time. + + Db: thresh - [thesh:peak] / ratio_num + Linear: pow(10, (thresh - [thesh:peak] / ratio_num)/20 ); + + During attacks p->accumDb increments toward the p->pkDb. + During release p->accumDb decrements toward the threshold. + + (thresh - accumDb) / ratio_num gives the signal level which will be achieved + if this value is converted to linear form and applied as a gain coeff. + + See compressor.m +*/ + +cw::rc_t cw::dsp::compressor::exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ) +{ + + sample_t xx[n]; + + vop::mul(xx,x,p->inGain,n); // apply input gain + + p->rmsWnd[ p->rmsWndIdx ] = vop::rms(xx, n); // calc and store signal RMS + p->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer + + real_t rmsLin = vop::mean(p->rmsWnd,p->rmsWndCnt); // calc avg RMS + real_t rmsDb = std::max(-100.0,20 * log10(std::max((real_t)0.00001,rmsLin))); // convert avg RMS to dB + rmsDb += 100.0; + + // if the compressor is bypassed + if( p->bypassFl ) + { + vop::copy(y,x,n); // copy through - with no input gain + return kOkRC; + } + + // if the signal is above the threshold + if( rmsDb <= p->threshDb ) + p->state = kRlsCompId; + else + { + if( rmsDb > p->pkDb ) + p->pkDb = rmsDb; + + p->state = kAtkCompId; + } + + switch( p->state ) + { + case kAtkCompId: + p->accumDb = std::min(p->pkDb, p->accumDb + p->timeConstDb * n / p->atkSmp ); + break; + + case kRlsCompId: + p->accumDb = std::max(p->threshDb, p->accumDb - p->timeConstDb * n / p->rlsSmp ); + break; + } + + p->gain = pow(10.0,(p->threshDb - p->accumDb) / (p->ratio_num * 20.0)); + + vop::mul(y,xx,p->gain * p->outGain,n); + + return kOkRC; + +} + + +void cw::dsp::compressor::set_attack_ms( obj_t* p, real_t ms ) +{ + _ms_to_samples(p,ms,p->atkSmp); +} + +void cw::dsp::compressor::set_release_ms( obj_t* p, real_t ms ) +{ + _ms_to_samples(p,ms,p->rlsSmp); +} + +void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms ) +{ + p->rmsWndCnt = std::max((unsigned)1,(unsigned)floor(ms * p->srate / (1000.0 * p->procSmpCnt))); + + // do not allow rmsWndCnt to exceed rmsWndAllocCnt + if( p->rmsWndCnt > p->rmsWndAllocCnt ) + p->rmsWndCnt = p->rmsWndAllocCnt; +} diff --git a/cwDspTransforms.h b/cwDspTransforms.h new file mode 100644 index 0000000..7ef92c9 --- /dev/null +++ b/cwDspTransforms.h @@ -0,0 +1,53 @@ +#ifndef cwDspTransforms_h +#define cwDspTransforms_h + +namespace cw +{ + namespace dsp + { + //--------------------------------------------------------------------------------------------------------------------------------- + // compressor + // + namespace compressor + { + enum { kAtkCompId, kRlsCompId }; + + typedef struct + { + real_t srate; // system sample rate + unsigned procSmpCnt; // samples per exec cycle + real_t inGain; // input gain + real_t threshDb; // threshold in dB (max:100 min:0) + real_t ratio_num; // numerator of the ratio + unsigned atkSmp; // time to reduce the signal by 10.0 db + unsigned rlsSmp; // time to increase the signal by 10.0 db + real_t outGain; // makeup gain + bool bypassFl; // bypass enable + sample_t* rmsWnd; // rmsWnd[rmsWndAllocCnt] + unsigned rmsWndAllocCnt; // + unsigned rmsWndCnt; // current RMS window size (rmsWndCnt must be <= rmsWndAllocCnt) + unsigned rmsWndIdx; // next RMS window input index + unsigned state; // env. state + real_t rmsDb; // current incoming signal RMS (max:100 min:0) + real_t gain; // current compressor gain + real_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs. + real_t pkDb; // + real_t accumDb; // + + } obj_t; + + rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl ); + rc_t destroy( obj_t*& pp ); + rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n ); + + void set_attack_ms( obj_t* p, real_t ms ); + void set_release_ms( obj_t* p, real_t ms ); + void set_thresh_db( obj_t* p, real_t thresh ); + void set_rms_wnd_ms( obj_t* p, real_t ms ); + } + + } + +} + +#endif diff --git a/cwDspTypes.h b/cwDspTypes.h new file mode 100644 index 0000000..adcc433 --- /dev/null +++ b/cwDspTypes.h @@ -0,0 +1,13 @@ +#ifndef cwDspTypes_h +#define cwDspTypes_h + +namespace cw +{ + namespace dsp + { + typedef float real_t; + typedef real_t sample_t; + typedef real_t srate_t; + } +} +#endif diff --git a/cwFlow.cpp b/cwFlow.cpp index 4799b45..fceedac 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -7,6 +7,7 @@ #include "cwAudioFile.h" #include "cwVectOps.h" #include "cwMtx.h" +#include "cwDspTypes.h" // real_t, sample_t #include "cwFlow.h" #include "cwFlowTypes.h" #include "cwFlowProc.h" @@ -27,6 +28,7 @@ namespace cw { "pv_analysis", &pv_analysis::members }, { "pv_synthesis", &pv_synthesis::members }, { "spec_dist", &spec_dist::members }, + { "compressor", &compressor::members }, { nullptr, nullptr } }; @@ -102,7 +104,7 @@ namespace cw } } - // parse the value dictionary + // parse the variable dictionary if( varD != nullptr ) { if( !varD->is_dict() ) @@ -124,7 +126,7 @@ namespace cw const object_t* var_obj = varD->child_ele(j); const char* type_str = nullptr; unsigned type_flag = 0; - bool srcVarFl = false; + bool srcVarFl = false; var_desc_t* vd = mem::allocZ(); vd->label = var_obj->pair_label(); @@ -146,7 +148,7 @@ namespace cw } // get the variable description - if((rc = var_obj->getv_opt("srcFl", srcVarFl)) != kOkRC ) + if((rc = var_obj->getv_opt("srcFl", srcVarFl,"value",vd->val_cfg)) != kOkRC ) { rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label ); goto errLabel; @@ -206,14 +208,14 @@ namespace cw } // locate source value - if((rc = var_get( src_inst, suffix, kAnyChIdx, src_var)) != kOkRC ) + if((rc = var_find( src_inst, suffix, 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_get( in_inst, in_var_label, kAnyChIdx, in_var )) != kOkRC ) + if((rc = var_find( in_inst, in_var_label, 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; @@ -244,6 +246,9 @@ namespace cw 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 ); @@ -252,7 +257,7 @@ namespace cw variable_t* var1 = nullptr; while( var0 != nullptr ) { - var1 = var0->link; + var1 = var0->var_link; _var_destroy(var0); var0 = var1; } @@ -262,27 +267,28 @@ namespace cw 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; - + 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(variable_t* var=inst->varL; var!=nullptr; var=var->link) + for(; var!=nullptr; var = var->var_link ) { - - if( var->vid == kInvalidId ) + if( var->vid != kInvalidId ) { - rc = cwLogError(kInvalidStateRC,"The variable '%s' on instance '%s' was not assigned an id.",var->label,inst->label); - goto errLabel; - } - - if( max_vid == kInvalidId || var->vid > max_vid ) - max_vid = var->vid; + if( max_vid == kInvalidId || var->vid > max_vid ) + max_vid = var->vid; - if( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx ) - max_chIdx = var->chIdx; + if( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx ) + max_chIdx = var->chIdx; + + } } // If there are any variables @@ -295,26 +301,27 @@ namespace cw 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->link) - { - unsigned idx = kInvalidIdx; + 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; + 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; - } + // 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; - } + // assign this variable to a map position + inst->varMapA[ idx ] = var; + } } @@ -322,85 +329,238 @@ namespace cw return rc; } - - rc_t _create_instance( flow_t* p, const object_t* inst_cfg ) + + 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; - const char* inst_label = nullptr; - const char* inst_clas_label = nullptr; - const object_t* in_dict = nullptr; - const char* arg_label = nullptr; - const char* preset_label = nullptr; - const object_t* arg_dict = nullptr; - const object_t* arg_cfg = nullptr; - instance_t* inst = nullptr; - class_desc_t* class_desc = nullptr; + 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(); + 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), dummy )) != kOkRC ) + goto errLabel; + } + else // otherwise a single value was given + { + if((rc = var_channelize( inst, value_label, kAnyChIdx, value, dummy )) != 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; + } + + + + 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 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 + { + // 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."); + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. is not a valid pair. No instance label could be parsed."); goto errLabel; } - inst_label = inst_cfg->pair_label(); + pvars.inst_label = inst_cfg->pair_label(); // verify that the instance label is unique - if( instance_find(p,inst_label) != nullptr ) + if( instance_find(p,pvars.inst_label) != nullptr ) { - rc = cwLogError(kSyntaxErrorRC,"The instance label '%s' has already been used.",inst_label); + 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->getv("class",inst_clas_label)) != kOkRC ) + if((rc = inst_cfg->getv("class",pvars.inst_clas_label)) != kOkRC ) { - rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",inst_label); + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",pvars.inst_label); goto errLabel; } // parse the optional args if((rc = inst_cfg->getv_opt("args", arg_dict, - "in", in_dict, - "argLabel", arg_label, - "preset", preset_label)) != kOkRC ) + "in", pvars.in_dict, + "argLabel", pvars.arg_label, + "preset", pvars.preset_labels)) != kOkRC ) { - rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",inst_label); + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",pvars.inst_label); goto errLabel; } - // if an argument dict was given + // if an argument dict was given in the instanec cfg if( arg_dict != nullptr ) { bool rptErrFl = true; - - // if no label was given then try 'default' - if( arg_label == nullptr) + + // verify the arg. dict is actually a dict. + if( !arg_dict->is_dict() ) { - arg_label = "default"; - rptErrFl = false; + cwLogError(kSyntaxErrorRC,"The instance argument dictionary on instance '%s' is not a dictionary.",pvars.inst_label); + goto errLabel; } - if((arg_cfg = arg_dict->find_child(arg_label)) == nullptr ) + // 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'.",arg_label,inst_label); + 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 cff. - arg_cfg = arg_dict; - arg_label = nullptr; + // 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 = {0}; + 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,inst_clas_label)) == nullptr ) + if(( class_desc = class_desc_find(p,pvars.inst_clas_label)) == nullptr ) { - rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(inst_clas_label)); + rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(pvars.inst_clas_label)); goto errLabel; } @@ -408,47 +568,67 @@ namespace cw inst = mem::allocZ(); inst->ctx = p; - inst->label = inst_label; + inst->label = pvars.inst_label; inst->inst_cfg = inst_cfg; - inst->arg_label = arg_label; - inst->arg_cfg = arg_cfg; + inst->arg_label = pvars.arg_label; + inst->arg_cfg = pvars.arg_cfg; inst->class_desc = class_desc; - inst->preset_label = preset_label; - // Instantiate the variables which have the 'src' attribute. We need these variables - // to exist so that they can be connected to their source prior to the instance - // custom constructorbeing exected + // 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( cwIsFlag(vd->flags,kSrcVarFl) ) - { - if((rc = var_create( inst, vd->label, kInvalidId, kAnyChIdx, var )) != kOkRC ) - goto errLabel; - } - } + 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( in_dict != nullptr && in_dict->is_dict() ) + if( pvars.in_dict != nullptr ) { - // for each input - for(unsigned i=0; ichild_count(); ++i) + if( !pvars.in_dict->is_dict() ) { - const object_t* in_pair = in_dict->child_ele(i); + 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; - // note + // 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 because they are the only ones that have been created so far. + // 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 @@ -459,24 +639,24 @@ namespace cw // 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' buffer at index %i is not valid on instance '%s'.", i, inst_label ); + rc = cwLogError(kSyntaxErrorRC,"The 'in' buffer at index %i is not valid on instance '%s'.", i, inst->label ); goto errLabel; } } } } - // complete the instantiation + // complete the instantiation + if((rc = class_desc->members->create( inst )) != kOkRC ) { - rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s'.", inst_label ); + rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s'.", inst->label ); goto errLabel; } - + if((rc =_create_instance_var_map( inst )) != kOkRC ) goto errLabel; - // insert an instance in the network if( p->network_tail == nullptr ) { @@ -502,6 +682,9 @@ namespace cw { rc_t rc = kOkRC; + if( p == nullptr ) + return rc; + instance_t* i0=p->network_head; instance_t* i1=nullptr; @@ -548,16 +731,18 @@ namespace cw } } -cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ) +cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const object_t& networkCfg ) { rc_t rc = kOkRC; const object_t* network; + bool printClassDictFl = false; + bool printNetworkFl = false; if(( rc = destroy(hRef)) != kOkRC ) return rc; flow_t* p = mem::allocZ(); - p->cfg = &cfg; // TODO: duplicate cfg? + p->cfg = &networkCfg; // TODO: duplicate cfg? // parse the class description array if((rc = _parse_class_cfg(p,library,&classCfg)) != kOkRC ) @@ -567,20 +752,27 @@ cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const objec } // parse the main audio file processor cfg record - if((rc = cfg.getv("framesPerCycle", p->framesPerCycle, - "network", network)) != kOkRC ) + if((rc = networkCfg.getv("framesPerCycle", p->framesPerCycle, + "network", network)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the required flow configuration parameters."); goto errLabel; } - if((rc = cfg.getv_opt("maxCycleCount", p->maxCycleCount)) != kOkRC ) + // parse the optional args + if((rc = networkCfg.getv_opt("maxCycleCount", p->maxCycleCount, + "printClassDictFl", printClassDictFl, + "printNetworkFl", printNetworkFl)) != kOkRC ) { rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters."); goto errLabel; } - // for each instance in the network + // print the class dict + if( printClassDictFl ) + class_dict_print( p ); + + // build the network for(unsigned i=0; ichild_count(); ++i) { const object_t* inst_cfg = network->child_ele(i); @@ -590,18 +782,18 @@ cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const objec { rc = cwLogError(rc,"The instantiation at network index %i is invalid.",i); goto errLabel; + } } - // apply preset - for(instance_t* inst=p->network_head; inst!=nullptr; inst=inst->link) - if( inst->preset_label != nullptr ) - if((rc = apply_preset( inst, inst->preset_label )) != kOkRC ) - goto errLabel; - + if( printNetworkFl ) + network_print(p); + hRef.set(p); errLabel: + + if( rc != kOkRC ) _destroy(p); @@ -615,10 +807,16 @@ cw::rc_t cw::flow::exec( handle_t& hRef ) while( true ) { - for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) + for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) if((rc = inst->class_desc->members->exec(inst)) != kOkRC ) break; - + + if( rc == kEofRC ) + { + rc = kOkRC; + break; + } + p->cycleIndex += 1; if( p->maxCycleCount > 0 && p->cycleIndex >= p->maxCycleCount ) break; @@ -646,7 +844,7 @@ cw::rc_t cw::flow::destroy( handle_t& hRef ) void cw::flow::print_class_list( handle_t& hRef ) { - class_desc_print(_handleToPtr(hRef)); + class_dict_print(_handleToPtr(hRef)); } void cw::flow::print_network( handle_t& hRef ) @@ -666,8 +864,6 @@ cw::rc_t cw::flow::test( const object_t* class_cfg, const object_t* cfg ) rc = cwLogError(rc,"Flow object create failed."); goto errLabel; } - - print_network(flowH); // run the network if((rc = exec( flowH )) != kOkRC ) diff --git a/cwFlow.h b/cwFlow.h index 1f51a6e..362b692 100644 --- a/cwFlow.h +++ b/cwFlow.h @@ -11,7 +11,7 @@ namespace cw typedef handle handle_t; - rc_t create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ); + rc_t create( handle_t& hRef, const object_t& classCfg, const object_t& networkCfg ); rc_t exec( handle_t& hRef ); rc_t destroy( handle_t& hRef ); diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index 94d7474..ec12ee9 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -6,6 +6,8 @@ #include "cwAudioFile.h" #include "cwVectOps.h" #include "cwMtx.h" + +#include "cwDspTypes.h" // real_t, sample_t #include "cwFlow.h" #include "cwFlowTypes.h" #include "cwFlowProc.h" @@ -14,6 +16,7 @@ #include "cwMath.h" #include "cwDsp.h" #include "cwAudioTransforms.h" +#include "cwDspTransforms.h" namespace cw { @@ -31,8 +34,6 @@ namespace cw } inst_t; - - rc_t create( instance_t* ctx ) { @@ -83,6 +84,8 @@ namespace cw { enum { + kFnamePId, + kEofFlPId, kOutPId }; @@ -101,20 +104,14 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - // get the audio filename - if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != kOkRC ) + // Register variable and get their current value + if((rc = var_register_and_get( ctx, kAnyChIdx, + kFnamePId, "fname", inst->filename, + kEofFlPId, "eofFl", inst->eofFl )) != kOkRC ) { - rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument."); goto errLabel; } - // get the 'eof' flag - if((rc = ctx->arg_cfg->getv_opt("eof",inst->eofFl)) != kOkRC ) - { - rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument."); - goto errLabel; - } - // open the audio file if((rc = audiofile::open(inst->afH,inst->filename,&info)) != kOkRC ) { @@ -125,7 +122,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 - rc = var_abuf_create( ctx, "out", kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle ); errLabel: return rc; @@ -162,7 +159,7 @@ namespace cw // verify that a source buffer exists - if((rc = var_abuf_get(ctx,"out",kAnyChIdx,abuf)) != kOkRC ) + if((rc = var_get(ctx,kOutPId,kAnyChIdx,abuf)) != kOkRC ) { rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid audio output buffer.",ctx->label); } @@ -175,7 +172,7 @@ namespace cw rc = readFloat(inst->afH, abuf->frameN, 0, abuf->chN, chBuf, &actualFrameN ); - if( inst->eofFl && actualFrameN == 0) + if( inst->eofFl && actualFrameN == 0) rc = kEofRC; } @@ -186,7 +183,8 @@ namespace cw .create = create, .destroy = destroy, .value = value, - .exec = exec + .exec = exec, + .report = nullptr }; } @@ -201,13 +199,15 @@ namespace cw { enum { - kInPId + kInPId, + kFnamePId }; typedef struct { audiofile::handle_t afH; - const char* filename; + const char* filename; + unsigned durSmpN; } inst_t; rc_t create( instance_t* ctx ) @@ -215,20 +215,14 @@ namespace cw rc_t rc = kOkRC; // unsigned audioFileBits = 0; // set audio file sample format to 'float32'. inst_t* inst = mem::allocZ(); // - abuf_t* src_abuf = nullptr; + const abuf_t* src_abuf = nullptr; ctx->userPtr = inst; - // get the audio filename - if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != kOkRC ) + // Register variables and get their current value + if((rc = var_register_and_get( ctx, kAnyChIdx, + kFnamePId, "fname", inst->filename, + kInPId, "in", src_abuf)) != kOkRC ) { - rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument."); - goto errLabel; - } - - // verify that a source buffer exists - if((rc = var_abuf_get(ctx,"in",kAnyChIdx,src_abuf)) != kOkRC ) - { - rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; } @@ -239,8 +233,6 @@ namespace cw goto errLabel; } - rc = var_init( ctx, kAnyChIdx, kInPId, "in", src_abuf); - errLabel: return rc; } @@ -275,7 +267,7 @@ namespace cw inst_t* inst = (inst_t*)ctx->userPtr; const abuf_t* src_abuf = nullptr; - if((rc = var_abuf_get(ctx,"in",kAnyChIdx,src_abuf)) != kOkRC ) + if((rc = var_get(ctx,kInPId,kAnyChIdx,src_abuf)) != kOkRC ) rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid input connection.",ctx->label); else { @@ -286,6 +278,12 @@ namespace cw if((rc = audiofile::writeFloat(inst->afH, src_abuf->frameN, src_abuf->chN, chBuf )) != kOkRC ) rc = cwLogError(rc,"Audio file write failed on instance: '%s'.", ctx->label ); + + // print a minutes counter + inst->durSmpN += src_abuf->frameN; + if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 ) + printf("%5.1f %s\n", inst->durSmpN/(src_abuf->srate*60)); + } return rc; @@ -295,7 +293,8 @@ namespace cw .create = create, .destroy = destroy, .value = value, - .exec = exec + .exec = exec, + .report = nullptr }; } @@ -310,12 +309,16 @@ namespace cw enum { kInPId, + kHopSmpNPId, + kWndSmpNPId, + kHzFlPId, kOutPId }; typedef struct { pv_t** pvA; // pvA[ srcBuf.chN ] + unsigned pvN; unsigned wndSmpN; unsigned hopSmpN; bool hzFl; @@ -330,32 +333,19 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - // get the wnd/hop sample count - if((rc = ctx->arg_cfg->getv("wndSmpCnt",inst->wndSmpN, - "hopSmpCnt",inst->hopSmpN )) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx, + kInPId, "in", srcBuf, + kHopSmpNPId, "hopSmpN", inst->hopSmpN, + kWndSmpNPId, "wndSmpN", inst->wndSmpN, + kHzFlPId, "hzFl", inst->hzFl )) != kOkRC ) { - rc = cwLogError(kSyntaxErrorRC,"PV Analysis required parameters parse failed on instance '%s'.",ctx->label); - goto errLabel; - } - - // get the optional arg's. - if((rc = ctx->arg_cfg->getv_opt("hzFl",inst->hzFl)) != kOkRC ) - { - rc = cwLogError(kSyntaxErrorRC,"PV Analysis optional parameters parse failed on instance '%s'.",ctx->label); - goto errLabel; - } - - // verify that a source buffer exists - if((rc = var_abuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) - { - rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; } else { - flags = inst->hzFl ? dsp::pv_anl::kCalcHzPvaFl : dsp::pv_anl::kNoCalcHzPvaFl; - inst->pvA = mem::allocZ( srcBuf->chN ); // allocate pv channel array + inst->pvN = srcBuf->chN; + inst->pvA = mem::allocZ( inst->pvN ); // allocate pv channel array const sample_t* magV[ srcBuf->chN ]; const sample_t* phsV[ srcBuf->chN ]; const sample_t* hzV[ srcBuf->chN ]; @@ -374,11 +364,12 @@ namespace cw hzV[i] = inst->pvA[i]->hzV; } - if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != kOkRC ) + if((rc = var_register( ctx, kAnyChIdx, kInPId, "in" )) != kOkRC ) goto errLabel; // create the fbuf 'out' - rc = var_fbuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV ); + rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV ); + } errLabel: @@ -390,6 +381,11 @@ namespace cw rc_t rc = kOkRC; inst_t* inst = (inst_t*)ctx->userPtr; + + for(unsigned i=0; ipvN; ++i) + destroy(inst->pvA[i]); + + mem::release(inst->pvA); mem::release(inst); return rc; @@ -409,14 +405,14 @@ namespace cw fbuf_t* dstBuf = nullptr; // verify that a source buffer exists - if((rc = var_abuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; } // verify that the dst buffer exits - if((rc = var_fbuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid output.",ctx->label); goto errLabel; @@ -425,11 +421,17 @@ namespace cw // for each input channel for(unsigned i=0; ichN; ++i) { + dstBuf->readyFlV[i] = false; + // call the PV analysis processor - dsp::pv_anl::exec( inst->pvA[i], srcBuf->buf + i*srcBuf->frameN, srcBuf->frameN ); + if( dsp::pv_anl::exec( inst->pvA[i], srcBuf->buf + i*srcBuf->frameN, srcBuf->frameN ) ) + { + // rescale the frequency domain magnitude + vop::mul(dstBuf->magV[i], dstBuf->binN/2, dstBuf->binN); + + dstBuf->readyFlV[i] = true; - // rescale the frequency domain magnitude - vop::mul(dstBuf->magV[i], dstBuf->binN/2, dstBuf->binN); + } } errLabel: @@ -440,7 +442,8 @@ namespace cw .create = create, .destroy = destroy, .value = value, - .exec = exec + .exec = exec, + .report = nullptr }; } @@ -461,6 +464,7 @@ namespace cw typedef struct { pv_t** pvA; // pvA[ srcBuf.chN ] + unsigned pvN; unsigned wndSmpN; // unsigned hopSmpN; // bool hzFl; // @@ -474,18 +478,16 @@ namespace cw inst_t* inst = mem::allocZ(); ctx->userPtr = inst; - - // verify that a source buffer exists - if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", srcBuf)) != kOkRC ) { - rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; } else { // allocate pv channel array - inst->pvA = mem::allocZ( srcBuf->chN ); + inst->pvN = srcBuf->chN; + inst->pvA = mem::allocZ( inst->pvN ); // create a pv anlaysis object for each input channel for(unsigned i=0; ichN; ++i) @@ -499,11 +501,11 @@ namespace cw } } - if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != kOkRC ) + if((rc = var_register( ctx, kAnyChIdx, kInPId, "in" )) != kOkRC ) goto errLabel; // create the abuf 'out' - rc = var_abuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); + rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); } errLabel: @@ -515,6 +517,10 @@ namespace cw rc_t rc = kOkRC; inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; ipvN; ++i) + destroy(inst->pvA[i]); + + mem::release(inst->pvA); mem::release(inst); return rc; @@ -534,18 +540,23 @@ namespace cw abuf_t* dstBuf = nullptr; // get the src buffer - if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) goto errLabel; // get the dst buffer - if((rc = var_abuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) goto errLabel; for(unsigned i=0; ichN; ++i) { - dsp::pv_syn::exec( inst->pvA[i], srcBuf->magV[i], srcBuf->phsV[i] ); - - abuf_set_channel( dstBuf, i, inst->pvA[i]->ola->outV, inst->pvA[i]->ola->hopSmpCnt ); + if( srcBuf->readyFlV[i] ) + dsp::pv_syn::exec( inst->pvA[i], srcBuf->magV[i], srcBuf->phsV[i] ); + + const sample_t* ola_out = dsp::ola::execOut(inst->pvA[i]->ola); + if( ola_out != nullptr ) + abuf_set_channel( dstBuf, i, ola_out, inst->pvA[i]->ola->procSmpCnt ); + + //abuf_set_channel( dstBuf, i, inst->pvA[i]->ola->outV, dstBuf->frameN ); } @@ -557,7 +568,8 @@ namespace cw .create = create, .destroy = destroy, .value = value, - .exec = exec + .exec = exec, + .report = nullptr }; } @@ -585,6 +597,7 @@ namespace cw typedef struct { spec_dist_t** sdA; + unsigned sdN; } inst_t; @@ -597,7 +610,7 @@ namespace cw ctx->userPtr = inst; // verify that a source buffer exists - if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) { rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); goto errLabel; @@ -605,12 +618,15 @@ namespace cw else { // allocate pv channel array - inst->sdA = mem::allocZ( srcBuf->chN ); + inst->sdN = srcBuf->chN; + inst->sdA = mem::allocZ( inst->sdN ); const sample_t* magV[ srcBuf->chN ]; const sample_t* phsV[ srcBuf->chN ]; const sample_t* hzV[ srcBuf->chN ]; - + + //if((rc = var_register(ctx, kAnyChIdx, kInPId, "in")) != kOkRC ) + // goto errLabel; // create a spec_dist object for each input channel for(unsigned i=0; ichN; ++i) @@ -626,14 +642,15 @@ namespace cw phsV[i] = inst->sdA[i]->outPhsV; hzV[i] = nullptr; - if((rc = var_init( ctx, i, - kInPId, "in", srcBuf, - kCeilingPId, "ceiling", 30.0f, - kExpoPId, "expo", 3.0f, - kThreshPId, "thresh", 54.0f, - kUprSlopePId,"uprSlope", -0.7f, - kLwrSlopePId,"lwrSlope", 2.0f, - kMixPId, "mix", 0.0f )) != kOkRC ) + spec_dist_t* sd = inst->sdA[i]; + + if((rc = var_register_and_get( ctx, i, + 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 ) { goto errLabel; } @@ -641,7 +658,7 @@ namespace cw } // create the output buffer - if((rc = var_fbuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->binN, srcBuf->hopSmpN, magV, phsV, hzV )) != kOkRC ) + if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->binN, srcBuf->hopSmpN, magV, phsV, hzV )) != kOkRC ) goto errLabel; } @@ -654,6 +671,10 @@ namespace cw rc_t rc = kOkRC; inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; isdN; ++i) + destroy(inst->sdA[i]); + + mem::release(inst->sdA); mem::release(inst); return rc; @@ -661,7 +682,24 @@ namespace cw rc_t value( instance_t* ctx, variable_t* var ) { - rc_t rc = kOkRC; + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + + if( var->chIdx != kAnyChIdx && var->chIdx < inst->sdN ) + { + switch( var->vid ) + { + case kCeilingPId: var_get( var, inst->sdA[ var->chIdx ]->ceiling ); break; + case kExpoPId: var_get( var, inst->sdA[ var->chIdx ]->expo ); break; + case kThreshPId: var_get( var, inst->sdA[ var->chIdx ]->thresh ); break; + case kUprSlopePId: var_get( var, inst->sdA[ var->chIdx ]->uprSlope ); break; + case kLwrSlopePId: var_get( var, inst->sdA[ var->chIdx ]->lwrSlope ); break; + case kMixPId: var_get( var, inst->sdA[ var->chIdx ]->mix ); break; + default: + cwLogWarning("Unhandled variable id '%i' on instance: %s.", var->vid, ctx->label ); + } + } + return rc; } @@ -671,23 +709,30 @@ namespace cw inst_t* inst = (inst_t*)ctx->userPtr; const fbuf_t* srcBuf = nullptr; fbuf_t* dstBuf = nullptr; + unsigned chN = 0; // get the src buffer - if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) goto errLabel; // get the dst buffer - if((rc = var_fbuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) goto errLabel; - - for(unsigned i=0; ichN; ++i) - { - dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN ); - //if( i == 0 ) - // printf("%f %f\n", vop::sum(srcBuf->magV[i],srcBuf->binN), vop::sum(dstBuf->magV[i], dstBuf->binN) ); + chN = std::min(srcBuf->chN,inst->sdN); + + for(unsigned i=0; ireadyFlV[i] = false; + if( srcBuf->readyFlV[i] ) + { + dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN ); + + dstBuf->readyFlV[i] = true; + //If == 0 ) + // printf("%f %f\n", vop::sum(srcBuf->magV[i],srcBuf->binN), vop::sum(dstBuf->magV[i], dstBuf->binN) ); + } } - errLabel: return rc; @@ -697,10 +742,200 @@ namespace cw .create = create, .destroy = destroy, .value = value, - .exec = exec + .exec = exec, + .report = nullptr }; } + //------------------------------------------------------------------------------------------------------------------ + // + // Compressor + // + namespace compressor + { + + enum + { + kInPId, + kBypassPId, + kInGainPId, + kThreshPId, + kRatioPId, + kAtkMsPId, + kRlsMsPId, + kWndMsPId, + kMaxWndMsPId, + kOutGainPId, + kOutPId, + kEnvPId + }; + + + typedef dsp::compressor::obj_t compressor_t; + + typedef struct + { + compressor_t** cmpA; + unsigned cmpN; + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const abuf_t* srcBuf = nullptr; // + inst_t* inst = mem::allocZ(); + + ctx->userPtr = inst; + + // verify that a source buffer exists + if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC ) + { + rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); + goto errLabel; + } + else + { + // allocate pv channel array + inst->cmpN = srcBuf->chN; + inst->cmpA = mem::allocZ( inst->cmpN ); + + // create a compressor object for each input channel + for(unsigned i=0; ichN; ++i) + { + real_t igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain, bypassFl; + + + // 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 ) + { + goto errLabel; + } + + // create the compressor instance + if((rc = dsp::compressor::create( inst->cmpA[i], srcBuf->srate, srcBuf->frameN, igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain, bypassFl)) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The 'compressor' object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + + } + + // create the output audio buffer + if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC ) + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; icmpN; ++i) + destroy(inst->cmpA[i]); + + mem::release(inst->cmpA); + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + real_t tmp; + + if( var->chIdx != kAnyChIdx && var->chIdx < inst->cmpN ) + { + + switch( var->vid ) + { + case kBypassPId: var_get( var, inst->cmpA[ var->chIdx ]->bypassFl ); break; + case kInGainPId: var_get( var, inst->cmpA[ var->chIdx ]->inGain ); break; + case kOutGainPId: var_get( var, inst->cmpA[ var->chIdx ]->outGain ); break; + case kRatioPId: var_get( var, inst->cmpA[ var->chIdx ]->ratio_num ); break; + case kThreshPId: var_get( var, inst->cmpA[ var->chIdx ]->threshDb ); break; + case kAtkMsPId: var_get( var, tmp ); set_attack_ms(inst->cmpA[ var->chIdx ], tmp ); break; + case kRlsMsPId: var_get( var, tmp ); set_release_ms(inst->cmpA[ var->chIdx ], tmp ); break; + case kWndMsPId: var_get( var, tmp ); set_rms_wnd_ms(inst->cmpA[ var->chIdx ], tmp ); break; + default: + cwLogWarning("Unhandled variable id '%i' on instance: %s.", var->vid, ctx->label ); + } + } + + + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const abuf_t* srcBuf = nullptr; + abuf_t* dstBuf = nullptr; + unsigned chN = 0; + + // get the src buffer + if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC ) + goto errLabel; + + // get the dst buffer + if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC ) + goto errLabel; + + chN = std::min(srcBuf->chN,inst->cmpN); + + for(unsigned i=0; icmpA[i], srcBuf->buf + i*srcBuf->frameN, dstBuf->buf + i*srcBuf->frameN, srcBuf->frameN ); + } + + + + + errLabel: + return rc; + } + + rc_t report( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + for(unsigned i=0; icmpN; ++i) + { + compressor_t* c = inst->cmpA[i]; + cwLogInfo("%s ch:%i : sr:%f bypass:%i procSmpN:%i igain:%f threshdb:%f ratio:%f atkSmp:%i rlsSmp:%i ogain:%f rmsWndN:%i maxRmsWndN%i", + ctx->label,i,c->srate,c->bypassFl,c->procSmpCnt,c->inGain,c->threshDb,c->ratio_num,c->atkSmp,c->rlsSmp,c->outGain,c->rmsWndCnt,c->rmsWndAllocCnt + ); + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec, + .report = report + }; + } + + } } diff --git a/cwFlowProc.h b/cwFlowProc.h index 6ab0329..d0292a9 100644 --- a/cwFlowProc.h +++ b/cwFlowProc.h @@ -2,10 +2,11 @@ namespace cw { namespace flow { - namespace audioFileIn { extern class_members_t members; } + namespace audioFileIn { extern class_members_t members; } namespace audioFileOut { extern class_members_t members; } namespace pv_analysis { extern class_members_t members; } namespace pv_synthesis { extern class_members_t members; } namespace spec_dist { extern class_members_t members; } + namespace compressor { extern class_members_t members; } } } diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp index 4f5919d..702ef47 100644 --- a/cwFlowTypes.cpp +++ b/cwFlowTypes.cpp @@ -6,6 +6,7 @@ #include "cwObject.h" #include "cwVectOps.h" #include "cwMtx.h" +#include "cwDspTypes.h" // real_t, sample_t #include "cwFlowTypes.h" @@ -18,21 +19,19 @@ namespace cw { kBoolTFl, "bool" }, { kUIntTFl, "uint" }, { kIntTFl, "int", }, - { kRealTFl, "real" }, - { kF32TFl, "float"}, - { kF64TFl, "double"}, + { kFloatTFl, "float"}, + { kRealTFl, "real"}, + { kDoubleTFl, "double"}, { kBoolMtxTFl, "bool_mtx" }, { kUIntMtxTFl, "uint_mtx" }, { kIntMtxTFl, "int_mtx" }, - { kRealMtxTFl, "real_mtx" }, - { kF32MtxTFl, "float_mtx" }, - { kF64MtxTFl, "double_mtx" }, + { kFloatMtxTFl, "float_mtx" }, + { kDoubleMtxTFl, "double_mtx" }, { kABufTFl, "audio" }, { kFBufTFl, "spectrum" }, { kStringTFl, "string" }, - { kFNameTFl, "fname" }, { kTimeTFl, "time" }, { kInvalidTFl, nullptr } }; @@ -60,9 +59,8 @@ namespace cw case kBoolTFl: case kUIntTFl: case kIntTFl: - case kRealTFl: - case kF32TFl: - case kF64TFl: + case kFloatTFl: + case kDoubleTFl: break; case kABufTFl: @@ -77,20 +75,15 @@ namespace cw case kBoolMtxTFl: case kUIntMtxTFl: case kIntMtxTFl: - case kRealMtxTFl: - case kF32MtxTFl: - case kF64MtxTFl: + case kFloatMtxTFl: + case kDoubleMtxTFl: assert(0); // not implemeneted break; case kStringTFl: mem::release( v->u.s ); break; - - case kFNameTFl: - mem::release( v->u.fname ); - break; - + case kTimeTFl: assert(0); break; @@ -103,6 +96,58 @@ namespace cw v->flags = kInvalidTFl; } + void _value_duplicate( value_t& dst, const value_t& src ) + { + + switch( src.flags & kTypeMask ) + { + case kInvalidTFl: + break; + + case kBoolTFl: + case kUIntTFl: + case kIntTFl: + case kFloatTFl: + case kDoubleTFl: + dst = src; + break; + + case kABufTFl: + + dst.u.abuf = src.u.abuf == nullptr ? nullptr : abuf_duplicate(src.u.abuf); + dst.flags = src.flags; + break; + + case kFBufTFl: + dst.u.fbuf = src.u.fbuf == nullptr ? nullptr : fbuf_duplicate(src.u.fbuf); + dst.flags = src.flags; + break; + + + case kBoolMtxTFl: + case kUIntMtxTFl: + case kIntMtxTFl: + case kFloatMtxTFl: + case kDoubleMtxTFl: + assert(0); // not implemeneted + break; + + case kStringTFl: + dst.u.s = mem::duplStr( dst.u.s ); + dst.flags = src.flags; + break; + + case kTimeTFl: + assert(0); + break; + + default: + assert(0); + break; + } + + } + void _value_print( const value_t* v ) { if( v == nullptr ) @@ -116,24 +161,33 @@ namespace cw case kBoolTFl: printf("%s ", v->u.b ? "True" : "False" ); break; case kUIntTFl: printf("%i ", v->u.u ); break; case kIntTFl: printf("%i ", v->u.i ); break; - case kRealTFl: printf("%f ", v->u.r ); break; - case kF32TFl: printf("%f ", v->u.f ); break; - case kF64TFl: printf("%f ", v->u.d ); break; - case kABufTFl: printf("abuf: chN:%i frameN:%i srate:%8.1f ", v->u.abuf->chN, v->u.abuf->frameN, v->u.abuf->srate ); break; - case kFBufTFl: printf("fbuf: chN:%i binN:%i hopSmpN:%i srate:%8.1f", v->u.fbuf->chN, v->u.fbuf->binN, v->u.fbuf->hopSmpN, v->u.fbuf->srate ); break; - + case kFloatTFl: printf("%f ", v->u.f ); break; + case kDoubleTFl:printf("%f ", v->u.d ); break; + case kABufTFl: + if( v->u.abuf == nullptr ) + printf("abuf: "); + else + printf("abuf: chN:%i frameN:%i srate:%8.1f ", v->u.abuf->chN, v->u.abuf->frameN, v->u.abuf->srate ); + break; + + case kFBufTFl: + if( v->u.fbuf == nullptr ) + printf("fbuf: "); + else + printf("fbuf: chN:%i binN:%i hopSmpN:%i srate:%8.1f", v->u.fbuf->chN, v->u.fbuf->binN, v->u.fbuf->hopSmpN, v->u.fbuf->srate ); + break; case kBoolMtxTFl: case kUIntMtxTFl: case kIntMtxTFl: - case kRealMtxTFl: - case kF32MtxTFl: - case kF64MtxTFl: + case kFloatMtxTFl: + case kDoubleMtxTFl: assert(0); // not implemeneted break; - case kStringTFl: printf("%s ", v->u.s); break; - case kFNameTFl: printf("%s ", v->u.fname); break; + case kStringTFl: + printf("%s ", v->u.s); + break; case kTimeTFl: assert(0); @@ -145,41 +199,227 @@ namespace cw } } + - rc_t _var_get( instance_t* inst, unsigned vid, unsigned chIdx, unsigned typeFl, const char* typeLabel, variable_t*& varRef ) + rc_t _val_get( const value_t* val, bool& valRef ) { - rc_t rc = kOkRC; - unsigned idx = kInvalidIdx; - - varRef = nullptr; - - if((rc = var_map_id_to_index(inst, vid, chIdx, idx )) == kOkRC || idx == kInvalidIdx ) + rc_t rc = kOkRC; + switch( val->flags & kTypeMask ) { - variable_t* var = inst->varMapA[idx]; - - if( !cwIsFlag(var->varDesc->type,typeFl ) ) - { - rc = cwLogError(kTypeMismatchRC,"Instance:%s variable:%s is not a %s.",inst->label,var->label,typeLabel); - goto errLabel; - } - - varRef = var; + case kBoolTFl: valRef = val->u.b; break; + case kUIntTFl: valRef = val->u.u!=0; break; + case kIntTFl: valRef = val->u.i!=0; break; + case kFloatTFl: valRef = val->u.f!=0; break; + case kDoubleTFl: valRef = val->u.d!=0; break; + default: + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a bool."); } + return rc; + } + + rc_t _val_get( const value_t* val, uint_t& valRef ) + { + rc_t rc = kOkRC; + switch( val->flags & kTypeMask ) + { + case kBoolTFl: valRef = val->u.b ? 1 : 0; break; + case kUIntTFl: valRef = val->u.u; break; + case kIntTFl: valRef = val->u.i; break; + case kFloatTFl: valRef = (uint_t)val->u.f; break; + case kDoubleTFl: valRef = (uint_t)val->u.d; break; + default: + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a uint_t."); + } + return rc; + } - errLabel: + rc_t _val_get( const value_t* val, int_t& valRef ) + { + rc_t rc = kOkRC; + switch( val->flags & kTypeMask ) + { + case kBoolTFl: valRef = val->u.b ? 1 : 0; break; + case kUIntTFl: valRef = (int_t)val->u.u; break; + case kIntTFl: valRef = val->u.i; break; + case kFloatTFl: valRef = (int_t)val->u.f; break; + case kDoubleTFl: valRef = (int_t)val->u.d; break; + default: + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a int_t."); + } return rc; } - - variable_t* _var_find( instance_t* inst, const char* label, unsigned chIdx ) + rc_t _val_get( const value_t* val, float& valRef ) { + rc_t rc = kOkRC; + switch( val->flags & kTypeMask ) + { + case kBoolTFl: valRef = val->u.b ? 1 : 0; break; + case kUIntTFl: valRef = (float)val->u.u; break; + case kIntTFl: valRef = (float)val->u.i; break; + case kFloatTFl: valRef = (float)val->u.f; break; + case kDoubleTFl: valRef = (float)val->u.d; break; + default: + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a float."); + } + return rc; + } + + rc_t _val_get( const value_t* val, double& valRef ) + { + rc_t rc = kOkRC; + switch( val->flags & kTypeMask ) + { + case kBoolTFl: valRef = val->u.b ? 1 : 0; break; + case kUIntTFl: valRef = (double)val->u.u; break; + case kIntTFl: valRef = (double)val->u.i; break; + case kFloatTFl: valRef = (double)val->u.f; break; + case kDoubleTFl: valRef = val->u.d; break; + default: + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a double."); + } + return rc; + } + + rc_t _val_get( const value_t* val, const char*& valRef ) + { + rc_t rc = kOkRC; + if( cwIsFlag(val->flags & kTypeMask, kStringTFl) ) + valRef = val->u.s; + else + { + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to a string."); + valRef = nullptr; + } + + return rc; + } + + rc_t _val_get( value_t* val, abuf_t*& valRef ) + { + rc_t rc = kOkRC; + if( cwIsFlag(val->flags & kTypeMask, kABufTFl) ) + valRef = val->u.abuf; + else + { + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to an abuf_t."); + valRef = nullptr; + } + return rc; + } + + rc_t _val_get( value_t* val, const abuf_t*& valRef ) + { + abuf_t* non_const_val; + rc_t rc = kOkRC; + if((rc = _val_get(val,non_const_val)) == kOkRC ) + valRef = non_const_val; + return rc; + } + + rc_t _val_get( value_t* val, fbuf_t*& valRef ) + { + rc_t rc = kOkRC; + if( cwIsFlag(val->flags & kTypeMask, kFBufTFl) ) + valRef = val->u.fbuf; + else + { + valRef = nullptr; + rc = cwLogError(kTypeMismatchRC,"The type 0x%x could not be converted to an fbuf_t."); + } + return rc; + } + + rc_t _val_get( value_t* val, const fbuf_t*& valRef ) + { + fbuf_t* non_const_val; + rc_t rc = kOkRC; + if((rc = _val_get(val,non_const_val)) == kOkRC ) + valRef = non_const_val; + return rc; + } + + + rc_t _var_find_to_set( instance_t* inst, unsigned vid, unsigned chIdx, unsigned typeFl, variable_t*& varRef ) + { + rc_t rc = kOkRC; + varRef = nullptr; + + // + if((rc = var_find(inst,vid,chIdx,varRef)) == kOkRC ) + { + // validate the type of the variable against the description + if( !cwIsFlag(varRef->varDesc->type,typeFl ) ) + rc = cwLogError(kTypeMismatchRC,"Type mismatch. Instance:%s variable:%s with type 0x%x does not match requested type:0x%x.",varRef->inst->label,varRef->label,varRef->varDesc->type,typeFl); + + } + + return rc; + } + + + // Variable lookup: Exact match on vid and chIdx + rc_t _var_find_on_vid_and_ch( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ) + { + varRef = nullptr; + + for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link) + { + // the variable vid and chIdx should form a unique pair + if( var->vid==vid && var->chIdx == chIdx ) + { + varRef = var; + return kOkRC; + } + } + return cwLogError(kInvalidIdRC,"The variable matching id:%i ch:%i on instance '%s' could not be found.", vid, chIdx, inst->label); + } + + // Variable lookup: Exact match on label and chIdx + variable_t* _var_find_on_label_and_ch( instance_t* inst, const char* var_label, unsigned chIdx ) + { + for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link) + { + // the variable vid and chIdx should form a unique pair + if( textCompare(var->label,var_label)==0 && var->chIdx == chIdx ) + return var; + } + + return nullptr; + } + + + // Find a variable: If an exact match on label,chIdx is found this is returned. + // Otherwise if the arg 'chIdx' is a numeric channel idx the 'any' var is returned. + // if the arg 'chIdx' is 'any' then the 'any' or the lowest numeric channel is returned + variable_t* _var_find_best( instance_t* inst, const char* label, unsigned chIdx ) + { + /* + variable_t* v0 = nullptr; variable_t* var = inst->varL; - for(; var!=nullptr; var=var->link) - if( textCompare(var->label,label) == 0 && (var->chIdx==chIdx || var->chIdx==kAnyChIdx || (chIdx==kAnyChIdx && var->chIdx==0))) - return var; - return nullptr; - + for(; var!=nullptr; var=var->var_link) + if( textCompare(var->label,label) == 0 ) + { + // if the channel matches exactly - return this var + if( var->chIdx == chIdx ) + return var; + + // if we encounter a var with 'any' channel - store this we will keep looking because we may still find an exact match + if( var->chIdx == kAnyChIdx ) + v0 = var; + else + // if 'any' was requested then try to get ch==0 but a non-zero channel will suffice otherwise + if( chIdx == kAnyChIdx ) + if( v0 == nullptr || var->chIdx < v0->chIdx ) + v0 = var; + } + + return v0; + */ + + return _var_find_on_label_and_ch(inst,label,chIdx); + } rc_t _validate_var_assignment( variable_t* var, unsigned typeFl ) @@ -189,7 +429,7 @@ namespace cw if( !cwIsFlag(var->varDesc->type, typeFl ) ) return cwLogError(kTypeMismatchRC, "The variable '%s' on instance '%s' is not a '%s'.", var->label, var->inst->label, _typeFlagToLabel( typeFl )); - + return kOkRC; } @@ -204,6 +444,22 @@ namespace cw return rc; } + + rc_t _var_set( variable_t* var, bool val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kBoolTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.b = val; + var->local_value.flags = kBoolTFl; + var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %i (bool).",var->inst->label,var->label,var->chIdx,val); + + return _var_broadcast_new_value( var ); + } rc_t _var_set( variable_t* var, unsigned val ) { @@ -212,10 +468,12 @@ namespace cw return rc; _value_release(&var->local_value); - var->local_value.u.u = val; - var->local_value.flags = kUIntTFl; - var->value = &var->local_value; + var->local_value.u.u = val; + var->local_value.flags = kUIntTFl; + var->value = &var->local_value; + cwLogMod("%s.%s ch:%i %i (uint_t).",var->inst->label,var->label,var->chIdx,val); + return _var_broadcast_new_value( var ); } @@ -231,20 +489,56 @@ namespace cw var->local_value.flags = kIntTFl; var->value = &var->local_value; + cwLogMod("%s.%s ch:%i %i (int_t).",var->inst->label,var->label,var->chIdx,val); + return _var_broadcast_new_value( var ); } - rc_t _var_set( variable_t* var, real_t val ) + rc_t _var_set( variable_t* var, float val ) { rc_t rc; - if((rc = _validate_var_assignment( var, kRealTFl )) != kOkRC ) + if((rc = _validate_var_assignment( var, kFloatTFl )) != kOkRC ) return rc; _value_release(&var->local_value); - var->local_value.u.r = val; - var->local_value.flags = kRealTFl; + var->local_value.u.f = val; + var->local_value.flags = kFloatTFl; var->value = &var->local_value; + cwLogMod("%s.%s ch:%i %f (float).",var->inst->label,var->label,var->chIdx,val); + + return _var_broadcast_new_value( var ); + } + + rc_t _var_set( variable_t* var, double val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kDoubleTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.d = val; + var->local_value.flags = kDoubleTFl; + var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %f (double).",var->inst->label,var->label,var->chIdx,val); + + return _var_broadcast_new_value( var ); + } + + rc_t _var_set( variable_t* var, const char* val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kStringTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.s = mem::duplStr(val); + var->local_value.flags = kStringTFl; + var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %s (string).",var->inst->label,var->label,var->chIdx,cwStringNullGuard(val)); + return _var_broadcast_new_value( var ); } @@ -259,6 +553,8 @@ namespace cw var->local_value.flags = kABufTFl; var->value = &var->local_value; + cwLogMod("%s.%s ch:%i %s (abuf).",var->inst->label,var->label,var->chIdx,abuf==nullptr ? "null" : "valid"); + return _var_broadcast_new_value( var ); } @@ -273,36 +569,79 @@ namespace cw var->local_value.u.fbuf = fbuf; var->local_value.flags = kFBufTFl; var->value = &var->local_value; + + cwLogMod("%s.%s ch:%i %s (fbuf).",var->inst->label,var->label,var->chIdx,fbuf==nullptr ? "null" : "valid"); return _var_broadcast_new_value( var ); } - const preset_t* _preset_find( class_desc_t* cd, const char* preset_label ) + template< typename T > + rc_t _var_set_driver( variable_t* var, T value ) { - const preset_t* pr; - for(pr=cd->presetL; pr!=nullptr; pr=pr->link) - if( textCompare(pr->label,preset_label) == 0 ) - return pr; + rc_t rc; - return nullptr; + // if this assignment targets a specific channel ... + if( var->chIdx != kAnyChIdx ) + { + rc = _var_set(var,value); // ... then set it alone + } + else // ... otherwise set all channels. + { + for(; var!=nullptr; var=var->ch_link) + if((rc = _var_set(var,value)) != kOkRC ) + break; + } + + return rc; } + + - rc_t _preset_set_var_value( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value ) + rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, abuf_t* abuf ) + { + rc_t rc; + variable_t* var = nullptr; + if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) != kOkRC ) + return rc; + + if( var != nullptr ) + _var_set_driver( var, abuf ); + + return rc; + } + + rc_t _var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, fbuf_t* fbuf ) + { + rc_t rc; + variable_t* var = nullptr; + if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) != kOkRC ) + return rc; + + if( var != nullptr ) + _var_set_driver( var, fbuf ); + + return rc; + } + + rc_t _set_var_value_from_cfg( variable_t* var, const object_t* value ) { rc_t rc = kOkRC; - variable_t* var = nullptr; - // get the variable - if((rc = var_get( inst, var_label, chIdx, var )) != kOkRC ) - goto errLabel; - switch( var->varDesc->type & kTypeMask ) { + case kBoolTFl: + { + bool v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, v ); + } + break; + case kUIntTFl: { unsigned v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set( var, v ); + rc = _var_set_driver( var, v ); } break; @@ -310,29 +649,208 @@ namespace cw { int v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set( var, v ); + rc = _var_set_driver( var, v ); } break; - case kRealTFl: + case kFloatTFl: { - real_t v; + float v; if((rc = value->value(v)) == kOkRC ) - rc = _var_set( var, v ); + rc = _var_set_driver( var, v ); + } + break; + + case kDoubleTFl: + { + double v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, v ); } break; + case kStringTFl: + { + const char* v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set_driver( var, v ); + } + break; + default: rc = cwLogError(kOpFailRC,"The variable type 0x%x cannot yet be set via a preset.", var->varDesc->type ); goto errLabel; } + errLabel: + if( rc != kOkRC ) + rc = cwLogError(kSyntaxErrorRC,"The %s.%s could not extract a type:%s from a configuration value.",var->inst->label,var->label,_typeFlagToLabel(var->varDesc->type & kTypeMask)); + return rc; + + } + + rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ) + { + unsigned idx = vid * inst->varMapChN + (chIdx == kAnyChIdx ? 0 : chIdx); + + // verify that the map idx is valid + if( idx >= inst->varMapN ) + return cwLogError(kAssertFailRC,"The variable map positioning location %i is out of the range % on instance '%s' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx); + + idxRef = idx; + + return kOkRC; + } + + rc_t _var_map_label_to_index( instance_t* inst, const char* var_label, unsigned chIdx, unsigned& idxRef ) + { + rc_t rc = kOkRC; + variable_t* var = nullptr; + + idxRef = kInvalidIdx; + if((rc = var_find(inst, var_label, chIdx, var )) == kOkRC) + rc = _var_map_id_to_index( inst, var->vid, chIdx, idxRef ); + + return rc; + } + + rc_t _var_add_to_ch_list( instance_t* inst, variable_t* new_var ) + { + rc_t rc = kOkRC; + + variable_t* base_var = nullptr; + variable_t* v0 = nullptr; + variable_t* v1 = nullptr; + + if( new_var->chIdx == kAnyChIdx ) + return kOkRC; + + if((base_var = _var_find_on_label_and_ch( inst, new_var->label, kAnyChIdx )) == nullptr ) + { + rc = cwLogError(kInvalidStateRC,"The base channel variable does not exist for '%s.%s'. This is an illegal state.", inst->label, new_var->label ); + goto errLabel; + } + + // insert v0 in order by channel number + for(v0=base_var,v1=base_var->ch_link; v1!=nullptr; v1=v1->ch_link) + { + if( v1->chIdx > new_var->chIdx ) + break; + v0 = v1; + } + + // the new var channel index should never match the previous or next channel index + assert( v0->chIdx != new_var->chIdx && (v1==nullptr || v1->chIdx != new_var->chIdx ) ); + + new_var->ch_link = v1; + v0->ch_link = new_var; + + + errLabel: + return rc; + + } + + // Create a variable and set it's value from 'value_cfg'. + // If 'value_cfg' is null then use the value from var->varDesc->val_cfg. + rc_t _var_create( instance_t* inst, const char* var_label, unsigned id, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ) + { + rc_t rc = kOkRC; + variable_t* var = nullptr; + var_desc_t* vd = nullptr; + + varRef = nullptr; + + // if this var already exists - it can't be created again + if((var = _var_find_on_label_and_ch(inst,var_label,chIdx)) != nullptr ) + { + rc = cwLogError(kInvalidStateRC,"The variable '%s' ch:%i has already been created on the instance: '%s'.",var_label,chIdx,inst->label); + goto errLabel; + } + + // locate the var desc + if((vd = var_desc_find( inst->class_desc, var_label)) == nullptr ) + { + rc = cwLogError(kInvalidIdRC,"Unable to locate the variable '%s' in class '%s'.", var_label, inst->class_desc->label ); + goto errLabel; + } + + // create the var + var = mem::allocZ(); + + var->varDesc = vd; + var->inst = inst; + var->label = mem::duplStr(var_label); + var->vid = id; + var->chIdx = chIdx; + var->value = nullptr; + + // if no value was given then set the value to the value given in the class + if( value_cfg == nullptr ) + value_cfg = var->varDesc->val_cfg; + + // if value_cfg is valid set the variable value + if( value_cfg != nullptr ) + if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC ) + goto errLabel; + + var->var_link = inst->varL; + inst->varL = var; + + // link the new var into the ch_link list + if((rc = _var_add_to_ch_list(inst, var )) != kOkRC ) + goto errLabel; + + + errLabel: + if( rc != kOkRC ) + { + _var_destroy(var); + cwLogError(kOpFailRC,"Variable creation failed on '%s.%s' ch:%i.", inst->label, var_label, chIdx ); + } + else + { + varRef = var; + cwLogMod("Created var: %s.%s ch:%i.", inst->label, var_label, chIdx ); + } + + return rc; + } + + void _var_print( const variable_t* var ) + { + const char* local_label = var->value==nullptr || var->value == &var->local_value ? "local" : " "; + + printf(" %20s id:%4i ch:%3i : %s : ", var->label, var->vid, var->chIdx, local_label ); + + if( var->value == nullptr ) + _value_print( &var->local_value ); + else + _value_print( var->value ); + + printf("\n"); + } + + + rc_t _preset_set_var_value( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value ) + { + rc_t rc = kOkRC; + variable_t* var = nullptr; + + // get the variable + if((rc = var_find( inst, var_label, chIdx, var )) != kOkRC ) + goto errLabel; + + rc = _set_var_value_from_cfg( var, value ); + errLabel: if( rc != kOkRC ) rc = cwLogError(rc,"The value of instance:%s variable:%s could not be set via a preset.", inst->label, var_label ); return rc; } + + } } @@ -358,6 +876,12 @@ void cw::flow::abuf_destroy( abuf_t* abuf ) mem::release(abuf); } +cw::flow::abuf_t* cw::flow::abuf_duplicate( const abuf_t* src ) +{ + return abuf_create( src->srate, src->chN, src->frameN ); +} + + cw::rc_t cw::flow::abuf_set_channel( abuf_t* abuf, unsigned chIdx, const sample_t* v, unsigned vN ) { rc_t rc = kOkRC; @@ -392,6 +916,7 @@ cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, unsigned f->magV = mem::allocZ(chN); f->phsV = mem::allocZ(chN); f->hzV = mem::allocZ(chN); + f->readyFlV= mem::allocZ(chN); if( magV != nullptr || phsV != nullptr || hzV != nullptr ) { @@ -429,9 +954,23 @@ void cw::flow::fbuf_destroy( fbuf_t* fbuf ) mem::release( fbuf->phsV); mem::release( fbuf->hzV); mem::release( fbuf->buf); + mem::release( fbuf->readyFlV); mem::release( fbuf); } +cw::flow::fbuf_t* cw::flow::fbuf_duplicate( const fbuf_t* src ) +{ + fbuf_t* fbuf = fbuf_create( src->srate, src->chN, src->binN, src->hopSmpN ); + for(unsigned i=0; ichN; ++i) + { + vop::copy( fbuf->magV[i], src->magV[i], fbuf->binN ); + vop::copy( fbuf->phsV[i], src->phsV[i], fbuf->binN ); + vop::copy( fbuf->hzV[i], src->hzV[i], fbuf->binN ); + } + return fbuf; +} + + unsigned cw::flow::value_type_label_to_flag( const char* s ) { unsigned flags = labelToId(typeLabelFlagsA,s,kInvalidTFl); @@ -468,7 +1007,7 @@ cw::rc_t cw::flow::var_desc_find( class_desc_t* cd, const char* label, var_desc_ } -void cw::flow::class_desc_print( flow_t* p ) +void cw::flow::class_dict_print( flow_t* p ) { for(unsigned i=0; iclassDescN; ++i) { @@ -510,75 +1049,156 @@ cw::rc_t cw::flow::instance_find( flow_t* p, const char* inst_label, instance_t* return cwLogError(kInvalidArgRC,"The instance '%s' was not found.", inst_label ); } + void cw::flow::instance_print( instance_t* inst ) { printf("%s\n", inst->label); - for(variable_t* var = inst->varL; var!=nullptr; var=var->link) - { - printf(" %20s id:%4i ch:%3i : ", var->label, var->vid, var->chIdx ); - _value_print( var->value ); - printf("\n"); - } -} + for(variable_t* var = inst->varL; var!=nullptr; var=var->var_link) + if( var->chIdx == kAnyChIdx ) + for(variable_t* v0 = var; v0!=nullptr; v0=v0->ch_link) + _var_print(v0); + + if( inst->class_desc->members->report ) + inst->class_desc->members->report( inst ); + - -cw::rc_t cw::flow::var_create( instance_t* inst, const char* var_label, unsigned id, unsigned chIdx, variable_t*& varRef ) -{ - rc_t rc = kOkRC; - - varRef = nullptr; - - variable_t* var = nullptr; - - // if this var already exists then just update its id - if( var_exists(inst,var_label,chIdx) ) - { - rc = cwLogError(kInvalidStateRC,"The variable '%s' has already been created on the instance: '%s'.",var_label,inst->label); - goto errLabel; - } - - var = mem::allocZ(); - - if((var->varDesc = var_desc_find( inst->class_desc, var_label)) == nullptr ) - { - rc = cwLogError(kInvalidIdRC,"Unable to locate the variable '%s' in class '%s'.", var_label, inst->class_desc->label ); - goto errLabel; - } - - var->inst = inst; - var->label = mem::duplStr(var_label); - var->vid = id; - var->chIdx = chIdx; - var->value = nullptr; - var->link = inst->varL; - inst->varL = var; - - - errLabel: - - if(rc != kOkRC ) - rc = cwLogError(kOpFailRC,"Creation failed for variable '%s' on instance '%s'.", var_label, inst->label ); - else - varRef = var; - - return kOkRC; } void cw::flow::_var_destroy( variable_t* var ) { - _value_release(&var->local_value); - mem::release(var->label); - mem::release(var); + if( var != nullptr ) + { + _value_release(&var->local_value); + mem::release(var->label); + mem::release(var); + } +} + + +cw::rc_t cw::flow::var_create( instance_t* inst, const char* var_label, unsigned id, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ) +{ + rc_t rc = kOkRC; + + rc = _var_create( inst, var_label, id, chIdx, value_cfg, varRef ); + + return rc; +} + +cw::rc_t cw::flow::var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ) +{ + rc_t rc = kOkRC; + variable_t* var = nullptr; + variable_t* base_var = nullptr; + varRef = nullptr; + + if((base_var = _var_find_on_label_and_ch( inst, var_label, kAnyChIdx)) == nullptr) + { + rc = cwLogError(kInvalidStateRC,"The base ('any') channel variable could not be located on '%s.%s'.",inst->label,var_label); + goto errLabel; + } + + + // locate the variable with the stated chIdx + var = _var_find_on_label_and_ch( inst, var_label, chIdx ); + + + // 'src' variables cannot be channelized + if( cwIsFlag(base_var->varDesc->flags,kSrcVarFl) ) + { + rc = cwLogError(rc,"'src' variables cannot be channelized."); + goto errLabel; + } + + // if the requested var was not found then create a new variable with the requested channel index + if( var == nullptr && chIdx != kAnyChIdx ) + { + // create the channelized var + if((rc = _var_create( inst, var_label, kInvalidId, chIdx, value_cfg, var )) != kOkRC ) + goto errLabel; + + // if no value was set then set the value from the 'any' channel + if( value_cfg == nullptr ) + { + // Set the value of the new variable to the value of the 'any' channel + _value_duplicate( var->local_value, base_var->local_value ); + + // If the 'any' channel value was set to point to it's local value then do same with this value + if( &base_var->local_value == base_var->value ) + var->value = &var->local_value; + } + + } + else + { + + // a correctly channelized var was found - but we still may need to set the value + if( value_cfg != nullptr ) + { + rc = _set_var_value_from_cfg( var, value_cfg ); + } + else + { + cwLogWarning("An existing var (%s.%s ch:%i) was specified for channelizing but no value was provided.", inst->label, var_label, chIdx ); + } + } + + assert( var != nullptr ); + varRef = var; + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(rc,"Channelize failed for variable '%s' on instance '%s' ch:%i.", var_label, inst->label, chIdx ); + + return rc; } bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx ) -{ return _var_find(inst,label,chIdx) != nullptr; } +{ return _var_find_on_label_and_ch(inst,label,chIdx) != nullptr; } -cw::rc_t cw::flow::var_get( instance_t* inst, const char* label, unsigned chIdx, variable_t*& vRef ) + +cw::rc_t cw::flow::var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef ) +{ + rc_t rc = kOkRC; + unsigned idx = kInvalidIdx; + variable_t* var = nullptr; + + varRef = nullptr; + + // if the varMapA[] has not yet been formed (we are inside the instance constructor) then do a slow lookup of the variable + if( inst->varMapA == nullptr ) + { + if((rc = _var_find_on_vid_and_ch(inst,vid,chIdx,var)) != kOkRC ) + goto errLabel; + } + else + { + // otherwise do a fast lookup using inst->varMapA[] + if((rc = _var_map_id_to_index(inst, vid, chIdx, idx )) == kOkRC && (idx != kInvalidIdx )) + var = inst->varMapA[idx]; + else + { + rc = cwLogError(kInvalidIdRC,"The index of variable vid:%i chIdx:%i on instance '%s' could not be calculated and the variable value could not be retrieved.", vid, chIdx, inst->label); + goto errLabel; + } + } + + // if we get here var must be non-null + assert( var != nullptr && rc == kOkRC ); + varRef = var; + + errLabel: + + return rc; +} + + + +cw::rc_t cw::flow::var_find( instance_t* inst, const char* label, unsigned chIdx, variable_t*& vRef ) { variable_t* var; - - if((var = _var_find(inst,label,chIdx)) != nullptr ) + vRef = nullptr; + + if((var = _var_find_best(inst,label,chIdx)) != nullptr ) { vRef = var; return kOkRC; @@ -587,298 +1207,131 @@ cw::rc_t cw::flow::var_get( instance_t* inst, const char* label, unsigned chIdx, return cwLogError(kInvalidIdRC,"The instance '%s' does not have a variable named '%s'.", inst->label, label ); } -cw::rc_t cw::flow::var_get( 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 chIdx, const variable_t*& vRef ) { variable_t* v = nullptr; - rc_t rc = var_get(inst,label,chIdx,v); + rc_t rc = var_find(inst,label,chIdx,v); vRef = v; return rc; } -cw::rc_t cw::flow::value_get( instance_t* inst, const char* label, unsigned chIdx, value_t*& vRef ) -{ - variable_t* var = nullptr; - rc_t rc = kOkRC; - if((rc = var_get( inst, label, chIdx, var )) != kOkRC ) - return rc; - - vRef = var->value; - return rc; -} - -cw::rc_t cw::flow::value_get( instance_t* inst, const char* label, unsigned chIdx, const value_t*& vRef ) -{ - value_t* v = nullptr; - rc_t rc = value_get( inst, label, chIdx, v ); - vRef = v; - return rc; -} - -cw::rc_t cw::flow::var_abuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ) -{ - rc_t rc; - abuf_t* abuf = nullptr; - variable_t* var = nullptr; - - if((rc = var_create( inst, var_label, vid, chIdx, var)) != kOkRC ) - return rc; - - if((abuf = abuf_create( srate, chN, frameN )) == nullptr ) - return cwLogError(kOpFailRC,"abuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label); - - rc = _var_set( var, abuf ); - - return rc; -} - -cw::rc_t cw::flow::var_fbuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) -{ - rc_t rc; - fbuf_t* fbuf = nullptr; - variable_t* var = nullptr; - - if((rc = var_create( inst, var_label, vid, chIdx, var)) != kOkRC ) - return rc; - - if((fbuf = fbuf_create( srate, chN, binN, hopSmpN, magV, phsV, hzV )) == nullptr ) - return cwLogError(kOpFailRC,"fbuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label); - - rc = _var_set( var, fbuf ); - - return rc; -} - -cw::rc_t cw::flow::var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, abuf_t*& abufRef ) -{ - rc_t rc = kOkRC; - value_t* val; - if((rc = value_get(inst,var_label,chIdx,val)) != kOkRC ) - goto errLabel; - - if( !value_is_abuf(val)) - { - rc = cwLogError(kTypeMismatchRC,"The variable '%' on instance '%s' is not an abuf."); - goto errLabel; - } - - errLabel: - if( rc == kOkRC ) - abufRef = val->u.abuf; - else - rc = cwLogError(rc,"No abuf was retrieved from variable: '%s' instance: '%s'", var_label, inst->label ); - - return rc; -} - -cw::rc_t cw::flow::var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const abuf_t*& abufRef ) -{ - rc_t rc; - abuf_t* abuf; - abufRef = (rc = var_abuf_get( inst, var_label, chIdx, abuf)) == kOkRC ? abuf : nullptr; - return rc; -} - -cw::rc_t cw::flow::var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, fbuf_t*& fbufRef ) -{ - rc_t rc = kOkRC; - value_t* val; - if((rc = value_get(inst,var_label,chIdx,val)) != kOkRC ) - goto errLabel; - - if( !value_is_fbuf(val)) - { - rc = cwLogError(kTypeMismatchRC,"The variable '%' on instance '%s' is not an fbuf."); - goto errLabel; - } - - errLabel: - if( rc == kOkRC ) - fbufRef = val->u.fbuf; - else - rc = cwLogError(rc,"No fbuf was retrieved from variable: '%s' instance: '%s'", var_label, inst->label ); - - return rc; -} - -cw::rc_t cw::flow::var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const fbuf_t*& fbufRef ) -{ - rc_t rc; - fbuf_t* fbuf; - fbufRef = (rc = var_fbuf_get( inst, var_label, chIdx, fbuf)) == kOkRC ? fbuf : nullptr; - return rc; -} - -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, variable_t*& varRef ) + +cw::rc_t cw::flow::var_register( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef ) { + rc_t rc = kOkRC; variable_t* var = nullptr; varRef = nullptr; - // if the variable already exists then update the vid, and set the returned variable to null. - if((var = _var_find(inst,var_label,chIdx)) != nullptr) + // TODO: check for duplicate 'vid'-'chIdx' pairs on this instance + // The concatenation of 'vid' and 'chIdx' should be unique + + // if an exact match to label/chIdx was found + if((var = _var_find_on_label_and_ch(inst,var_label,chIdx)) != nullptr ) { - var->vid = vid; - return kOkRC; // NOTE: when returning here 'varRef' should be NULL + // if a value was given - then update the value + if( value_cfg != nullptr ) + if((rc = _set_var_value_from_cfg( var, value_cfg )) != kOkRC ) + goto errLabel; } + else // an exact match was not found - channelize the variable + { + if((rc = var_channelize(inst,var_label,chIdx,value_cfg,var)) != kOkRC ) + goto errLabel; + } + + var->vid = vid; + varRef = var; + + errLabel: + if( rc != kOkRC ) + rc = cwLogError(rc,"Registration failed on variable '%s' instance '%s' ch: %i.", var_label, inst->label, chIdx); - return var_create( inst, var_label, vid, chIdx, varRef); -} - -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, unsigned value ) -{ - rc_t rc; - variable_t* var = nullptr; - if((rc = var_init( inst, var_label, vid, chIdx, var)) != kOkRC ) - return rc; - - if( var != nullptr ) - _var_set( var, value ); - return rc; } -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, int value ) + +cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, variable_t*& varRef ) { - rc_t rc; - variable_t* var = nullptr; - if((rc = var_init( inst, var_label, vid, chIdx, var)) != kOkRC ) - return rc; - - if( var != nullptr ) - _var_set( var, value ); - - return rc; + return var_register( inst, var_label, vid, chIdx, nullptr, varRef ); } -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, real_t value ) -{ - rc_t rc; - variable_t* var = nullptr; - if((rc = var_init( inst, var_label, vid, chIdx, var)) != kOkRC ) - return rc; - - if( var != nullptr ) - _var_set( var, value ); - - return rc; -} - -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const abuf_t* abuf ) +cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ) { rc_t rc = kOkRC; - variable_t* var; - - if((var = _var_find(inst,var_label,chIdx)) != nullptr ) - var->vid = vid; - else - rc = var_abuf_create(inst, var_label, vid, chIdx, abuf->srate, abuf->chN, abuf->frameN ); - - return rc; -} - -cw::rc_t cw::flow::var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const fbuf_t* fbuf ) -{ - rc_t rc = kOkRC; - variable_t* var; - if((var = _var_find(inst,var_label,chIdx)) != nullptr ) - var->vid = vid; - else - rc = var_fbuf_create(inst, var_label, vid, chIdx, fbuf->srate, fbuf->chN, fbuf->binN, fbuf->hopSmpN ); - - return rc; -} - -cw::rc_t cw::flow::var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ) -{ - unsigned idx = vid * inst->varMapChN + (chIdx == kAnyChIdx ? 0 : chIdx); - - // verify that the map idx is valid - if( idx >= inst->varMapN ) - return cwLogError(kAssertFailRC,"The variable map positioning location %i is out of the range % on instance '%s' vid:%i ch:%i.", idx, inst->varMapN, inst->label,vid,chIdx); - - idxRef = idx; + abuf_t* abuf; - return kOkRC; + if((abuf = abuf_create( srate, chN, frameN )) == nullptr ) + return cwLogError(kOpFailRC,"abuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label); + + if((rc = _var_register_and_set( inst, var_label, vid, chIdx, abuf )) != kOkRC ) + abuf_destroy(abuf); + + return rc; } -cw::rc_t cw::flow::var_map_label_to_index( instance_t* inst, const char* var_label, unsigned chIdx, unsigned& idxRef ) +cw::rc_t cw::flow::var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +{ + rc_t rc = kOkRC; + fbuf_t* fbuf; + if((fbuf = fbuf_create( srate, chN, binN, hopSmpN, magV, phsV, hzV )) == nullptr ) + return cwLogError(kOpFailRC,"fbuf create failed on instance:'%s' variable:'%s'.", inst->label, var_label); + + if((rc = _var_register_and_set( inst, var_label, vid, chIdx, fbuf )) != kOkRC ) + fbuf_destroy(fbuf); + + return rc; +} + + +cw::rc_t cw::flow::var_get( const variable_t* var, bool& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, uint_t& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, int_t& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, float& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, double& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, const char*& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, const abuf_t*& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( variable_t* var, abuf_t*& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( const variable_t* var, const fbuf_t*& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_get( variable_t* var, fbuf_t*& valRef ) +{ return _val_get(var->value,valRef); } + +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool val ) { rc_t rc = kOkRC; variable_t* var = nullptr; - idxRef = kInvalidIdx; - if((rc = var_get(inst, var_label, chIdx, var )) == kOkRC) - rc = var_map_id_to_index( inst, var->vid, chIdx, idxRef ); - - return rc; + if((rc = _var_find_to_set(inst, vid, chIdx, kBoolTFl, var )) == kOkRC ) + _var_set_driver( var, val ); + + return rc; } - -cw::rc_t cw::flow::var_get( instance_t* inst, unsigned vid, unsigned chIdx, uint_t& valRef ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_get(inst, vid, chIdx, kUIntTFl, "uint_t", var )) != kOkRC ) - return rc; - - valRef = var->value->u.u; - - return rc; -} - -cw::rc_t cw::flow::var_get( instance_t* inst, unsigned vid, unsigned chIdx, int_t& valRef ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_get(inst, vid, chIdx, kIntTFl, "int_t", var )) == kOkRC ) - valRef = var->value->u.i; - - return rc; -} - -cw::rc_t cw::flow::var_get( instance_t* inst, unsigned vid, unsigned chIdx, real_t& valRef ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_get(inst, vid, chIdx, kRealTFl, "real_t", var )) == kOkRC ) - valRef = var->value->u.r; - - return rc; -} - -cw::rc_t cw::flow::var_get( instance_t* inst, unsigned vid, unsigned chIdx, abuf_t*& valRef ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_get(inst, vid, chIdx, kABufTFl, "abuf_t", var )) == kOkRC ) - valRef = var->value->u.abuf; - - return rc; -} - -cw::rc_t cw::flow::var_get( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t*& valRef ) -{ - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = _var_get(inst, vid, chIdx, kFBufTFl, "fbuf_t", var )) == kOkRC ) - valRef = var->value->u.fbuf; - - return rc; -} - - cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint_t val ) { rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_get(inst, vid, chIdx, kUIntTFl, "uint_t", var )) == kOkRC ) - _var_set( var, val ); + if((rc = _var_find_to_set(inst, vid, chIdx, kUIntTFl, var )) == kOkRC ) + _var_set_driver( var, val ); return rc; } @@ -888,132 +1341,52 @@ 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_get(inst, vid, chIdx, kIntTFl, "int_t", var )) == kOkRC ) - _var_set( var, val ); + if((rc = _var_find_to_set(inst, vid, chIdx, kIntTFl, var )) == kOkRC ) + _var_set_driver( var, val ); return rc; } -cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, real_t val ) +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, float val ) { rc_t rc = kOkRC; variable_t* var = nullptr; - if((rc = _var_get(inst, vid, chIdx, kRealTFl, "real_t", var )) == kOkRC ) - _var_set( var, val ); + if((rc = _var_find_to_set(inst, vid, chIdx, kFloatTFl, var )) == kOkRC ) + _var_set_driver( var, val ); return rc; } - -cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, uint_t val ) +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, double val ) { rc_t rc = kOkRC; variable_t* var = nullptr; - - if((rc = var_get(inst, var_label, chIdx, var)) == kOkRC ) - rc = var_set( inst, var->vid, chIdx, val ); - return rc; + + if((rc = _var_find_to_set(inst, vid, chIdx, kDoubleTFl, var )) == kOkRC ) + _var_set_driver( var, val ); + + return rc; } -cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, int_t val ) +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, const char* val ) { rc_t rc = kOkRC; variable_t* var = nullptr; - - if((rc = var_get(inst, var_label, chIdx, var)) == kOkRC ) - rc = var_set( inst, var->vid, chIdx, val ); - return rc; + + if((rc = _var_find_to_set(inst, vid, chIdx, kStringTFl, var )) == kOkRC ) + _var_set_driver( var, val ); + + return rc; } -cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, real_t val ) +const cw::flow::preset_t* cw::flow::class_preset_find( class_desc_t* cd, const char* preset_label ) { - rc_t rc = kOkRC; - variable_t* var = nullptr; - - if((rc = var_get(inst, var_label, chIdx, var)) == kOkRC ) - rc = var_set( inst, var->vid, chIdx, val ); - return rc; -} - - -cw::rc_t cw::flow::apply_preset( instance_t* inst, const char* preset_label ) -{ - rc_t rc = kOkRC; const preset_t* pr; - - // locate the requestd preset record - if((pr = _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; - } - - // validate the syntax of the preset record - if( !pr->cfg->is_dict() ) - { - rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on class '%s' is not a dictionary.", preset_label, inst->class_desc->label ); - goto errLabel; - } - - // for each variable - for(unsigned i=0; icfg->child_count(); ++i) - { - const object_t* value_list = pr->cfg->child_ele(i)->pair_value(); - const char* value_label = pr->cfg->child_ele(i)->pair_label(); - - unsigned preset_valueN = value_list->child_count(); - unsigned inst_chN = inst->varMapChN; - - if( preset_valueN == 0 ) - continue; - - enum { kOneToOneAlgoId, kOneToManyAlgoId, kModuloAlgoId, kRepeatLastAlgoId }; - - unsigned algo_id = kModuloAlgoId; - - if( preset_valueN == inst_chN ) - algo_id = kOneToOneAlgoId; - else - if( preset_valueN == 1 && inst_chN >= 1 ) - algo_id = kOneToManyAlgoId; - else - algo_id = kModuloAlgoId; - - // for each value in this variables value list/ each var channel on the inst - for(unsigned chIdx=0; chIdxvarMapChN; ++chIdx) - { - if( var_exists( inst, value_label, chIdx ) ) - { - unsigned value_list_idx = 0; - - switch( algo_id ) - { - case kOneToOneAlgoId: - value_list_idx = chIdx; - break; - - case kOneToManyAlgoId: - value_list_idx = 0; - break; - - case kModuloAlgoId: - value_list_idx = chIdx % value_list->child_count(); - break; - - default: - assert(0); - } - - // set the value of the preset - if((rc = _preset_set_var_value( inst, value_label, chIdx, value_list->child_ele(value_list_idx) )) != kOkRC) - break; - - } // if exitst - } // for varMapN - } // for value_list - - errLabel: + for(pr=cd->presetL; pr!=nullptr; pr=pr->link) + if( textCompare(pr->label,preset_label) == 0 ) + return pr; - return rc; + return nullptr; } + diff --git a/cwFlowTypes.h b/cwFlowTypes.h index e9dbb1b..f649a86 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -3,12 +3,14 @@ namespace cw namespace flow { - typedef float real_t; - typedef real_t sample_t; - typedef real_t srate_t; - typedef unsigned uint_t; - typedef int int_t; - + #define kRealTFl kFloatTFl + typedef dsp::real_t real_t; + typedef dsp::sample_t sample_t; + typedef dsp::srate_t srate_t; + typedef unsigned uint_t; + typedef int int_t; + + typedef unsigned vid_t; typedef struct abuf_str @@ -37,6 +39,7 @@ namespace cw sample_t** magV; // magV[ chN ][ binN ] sample_t** phsV; // phsV[ chN ][ binN ] sample_t** hzV; // hzV[ chN ][ binN ] + bool* readyFlV;// readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate) sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer) } fbuf_t; @@ -46,24 +49,22 @@ namespace cw kBoolTFl = 0x00000001, kUIntTFl = 0x00000002, kIntTFl = 0x00000004, - kRealTFl = 0x00000008, - kF32TFl = 0x00000010, - kF64TFl = 0x00000020, + kFloatTFl = 0x00000008, + kDoubleTFl = 0x00000010, - kBoolMtxTFl = 0x00000040, - kUIntMtxTFl = 0x00000080, - kIntMtxTFl = 0x00000100, - kRealMtxTFl = 0x00000200, - kF32MtxTFl = 0x00000400, - kF64MtxTFl = 0x00000800, + kBoolMtxTFl = 0x00000020, + kUIntMtxTFl = 0x00000040, + kIntMtxTFl = 0x00000080, + kRealMtxTFl = 0x00000100, + kFloatMtxTFl = 0x00000200, + kDoubleMtxTFl= 0x00000400, - kABufTFl = 0x00001000, - kFBufTFl = 0x00002000, - kStringTFl = 0x00004000, - kFNameTFl = 0x00008000, - kTimeTFl = 0x00010000, + kABufTFl = 0x00000800, + kFBufTFl = 0x00001000, + kStringTFl = 0x00002000, + kTimeTFl = 0x00004000, - kTypeMask = 0x0001ffff, + kTypeMask = 0x00007fff, }; @@ -85,7 +86,6 @@ namespace cw bool b; uint_t u; int_t i; - real_t r; float f; double d; @@ -97,20 +97,19 @@ namespace cw char* s; char* fname; - struct value_str* proxy; } u; struct value_str* link; } value_t; + + inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->flags,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); } + inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->flags,kBoolMtxTFl|kUIntMtxTFl|kIntMtxTFl|kFloatMtxTFl|kDoubleMtxTFl); } + struct instance_str; struct variable_str; - - typedef struct ctx_str - { - } ctx_t; - + typedef rc_t (*member_func_t)( struct instance_str* ctx ); typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var ); enum @@ -124,16 +123,18 @@ namespace cw member_func_t destroy; member_value_func_t value; member_func_t exec; + member_func_t report; } class_members_t; typedef struct var_desc_str { - const object_t* cfg; // - const char* label; // - unsigned type; // value type id - unsigned flags; // - const char* docText; // - struct var_desc_str* link; // + const object_t* cfg; // The cfg object that describes this variable from 'flow_class'. + const object_t* val_cfg; // An object containing the default value for this variable. + const char* label; // Name of this var. + unsigned type; // Value type id (e.g. kBoolTFl, kIntTFl, ...) + unsigned flags; // Attributes for this var. (e.g. kSrcVarFl ) + const char* docText; // User help string for this var. + struct var_desc_str* link; // class_desc->varDescL list link } var_desc_t; typedef struct preset_str @@ -152,7 +153,9 @@ namespace cw class_members_t* members; // member functions for this class } class_desc_t; - + + // Note: The concatenation of 'vid' and 'chIdx' should form a unique identifier among all variables + // on a given 'instance'. typedef struct variable_str { struct instance_str* inst; // pointer to this variables instance @@ -162,8 +165,9 @@ namespace cw value_t local_value; // the local value instance (actual value if this is not a 'src' variable) value_t* value; // pointer to the value associated with this variable unsigned chIdx; // channel index - struct variable_str* link; // link to other var's on 'inst' + struct variable_str* var_link; // link to other var's on 'inst' struct variable_str* connect_link; // list of outgoing connections + struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number) } variable_t; @@ -178,7 +182,6 @@ namespace cw const char* arg_label; // optional args label const object_t* arg_cfg; // optional args configuration - const char* preset_label; // optional preset label void* userPtr; // instance state @@ -214,11 +217,13 @@ namespace cw abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN ); void abuf_destroy( abuf_t* buf ); + abuf_t* abuf_duplicate( const abuf_t* src ); rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN ); const sample_t* abuf_get_channel( abuf_t* buf, unsigned chIdx ); fbuf_t* fbuf_create( srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); void fbuf_destroy( fbuf_t* buf ); + fbuf_t* fbuf_duplicate( const fbuf_t* src ); inline bool value_is_abuf( const value_t* v ) { return v->flags & kABufTFl; } inline bool value_is_fbuf( const value_t* v ) { return v->flags & kFBufTFl; } @@ -233,8 +238,15 @@ namespace cw 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 ); - void class_desc_print( flow_t* p ); + class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label ); + + void class_dict_print( flow_t* p ); + + + //------------------------------------------------------------------------------------------------------------------------ + // + // Network + // void network_print( flow_t* p ); //------------------------------------------------------------------------------------------------------------------------ @@ -252,72 +264,163 @@ namespace cw // // Create a variable but do not assign it a value. Return a pointer to the new variable. - rc_t var_create( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef ); + // 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 ); - // var_init(). 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_init( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef ); - rc_t var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, unsigned value ); - rc_t var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, int value ); - rc_t var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, real_t value ); - rc_t var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const abuf_t* abuf ); - rc_t var_init( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const fbuf_t* fbuf ); + // 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, variable_t*& varRef ); - inline rc_t _var_init(cw::flow::instance_t* inst, unsigned int ) { return kOkRC; } + // `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 ); - template< typename T0, typename T1, typename T2, typename... ARGS > - rc_t _var_init( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2 val, ARGS&&... args ) + + //----------------- + // + // var_register + // + + 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 rc; - - if((rc = var_init( inst, var_label, vid, chIdx, val )) == kOkRC ) - rc = _var_init( inst, chIdx, std::forward(args)...); + variable_t* dummy = nullptr; + if((rc = var_register( inst, var_label, vid, chIdx, nullptr, dummy )) == kOkRC ) + if((rc = _var_reg( inst, chIdx, std::forward(args)...)) != kOkRC ) + return rc; return rc; } - // Call var_init() on a list of variables. + // Call var_register() on a list of variables. template< typename... ARGS > - rc_t var_init( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args ) - { return _var_init( inst, chIdx, vid, var_label, std::forward(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)...); } + + + + //--------------------- + // + // var_register_and_get + // + + 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 rc; + variable_t* var; + if((rc = var_register(inst,var_label,vid,chIdx,nullptr,var)) == kOkRC ) + rc = var_get(var,valRef); + return rc; + } + + 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 rc; + + if((rc = var_register_and_get( inst, var_label, vid, chIdx, valRef )) == kOkRC ) + if((rc = _var_reg_and_get( inst, chIdx, std::forward(args)...)) != kOkRC ) + return rc; + + return rc; + } + + // 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)...); } + + + + //--------------------- + // + // var_register_and_set + // + + // 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* 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, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_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 rc; + + variable_t* var = nullptr; + if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) == kOkRC ) + { + var_set( var, val ); + if((rc = _var_register_and_set( inst, chIdx, std::forward(args)...)) != kOkRC ) + return rc; + } + + return rc; + } + + // 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)...); } + + + void _var_destroy( variable_t* var ); bool var_exists( instance_t* inst, const char* label, unsigned chIdx ); - rc_t var_get( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& vRef ); - rc_t var_get( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& vRef ); + 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 value_get( instance_t* inst, const char* label, unsigned chIdx, value_t*& vRef ); - rc_t value_get( instance_t* inst, const char* label, unsigned chIdx, const value_t*& vRef ); - - rc_t var_abuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ); - rc_t var_fbuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); + rc_t var_get( const variable_t* var, bool& valRef ); + rc_t var_get( const variable_t* var, uint_t& valRef ); + rc_t var_get( const variable_t* var, int_t& valRef ); + rc_t var_get( const variable_t* var, float& valRef ); + rc_t var_get( const variable_t* var, double& valRef ); + rc_t var_get( const variable_t* var, const char*& valRef ); + rc_t var_get( const variable_t* var, const abuf_t*& valRef ); + rc_t var_get( variable_t* var, abuf_t*& valRef ); + rc_t var_get( const variable_t* var, const fbuf_t*& valRef ); + rc_t var_get( variable_t* var, fbuf_t*& valRef ); - rc_t var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, abuf_t*& abufRef ); - rc_t var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const abuf_t*& abufRef ); - rc_t var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, fbuf_t*& fbufRef ); - rc_t var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const fbuf_t*& fbufRef ); - - rc_t var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef ); - rc_t var_map_label_to_index( instance_t* inst, const char* var_label, unsigned chIdx, unsigned& idxRef ); - rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, uint_t& valRef ); - rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, int_t& valRef ); - rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, real_t& valRef ); - rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, abuf_t*& valRef ); - rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t*& valRef ); + template< typename T> + rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, T& valRef) + { + rc_t rc = kOkRC; + variable_t* var = nullptr; + + if((rc = var_find(inst, vid, chIdx, var )) == kOkRC ) + rc = var_get(var,valRef); + + return rc; + } + + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool val ); rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint_t val ); rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_t val ); - rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, real_t val ); + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, float val ); + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, double val ); + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, const char* val ); + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, abuf_t* val ); + rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t* val ); - rc_t var_set( instance_t* inst, const char* var_label, unsigned chIdx, uint_t val ); - rc_t var_set( instance_t* inst, const char* var_label, unsigned chIdx, int_t val ); - rc_t var_set( instance_t* inst, const char* var_label, unsigned chIdx, real_t val ); - - rc_t apply_preset( instance_t* inst, const char* preset_label ); + const preset_t* class_preset_find( class_desc_t* cd, const char* preset_label ); } } diff --git a/cwLog.h b/cwLog.h index e782296..ae3bdd5 100644 --- a/cwLog.h +++ b/cwLog.h @@ -109,4 +109,26 @@ namespace cw #define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ ) +// This log level is intended for debugging individual modules. +// By defining cwLOG_MODULE prior to cwLog.h in a given module these logging lines will be enabled. +#ifdef cwLOG_MODULE + +#define cwLogVModRC(rc,fmt, vl) cwLogVInfoH( cw::log::globalhandle(), (rc), (fmt), (vl) ) +#define cwLogModRC( rc,fmt,...) cwLogInfoH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ ) + +#define cwLogVMod(fmt, vl) cwLogVInfoH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) ) +#define cwLogMod( fmt,...) cwLogInfoH( cw::log::globalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ ) + +#else + +#define cwLogVModRC(rc,fmt, vl) +#define cwLogModRC( rc,fmt,...) + +#define cwLogVMod(fmt, vl) +#define cwLogMod( fmt,...) + +#endif + + + #endif