diff --git a/Makefile.am b/Makefile.am index b1816fe..6a8ed1b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,8 +22,14 @@ libcwSRC += src/libcw/cwThread.cpp src/libcw/cwMutex.cpp src/libcw/cwThreadMach libcwHDR += src/libcw/cwMpScNbQueue.h src/libcw/cwSpScBuf.h src/libcw/cwSpScQueueTmpl.h libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQueueTmpl.cpp -libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwAudioFileOps.h src/libcw/cwMidiFile.h -libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwAudioFileOps.cpp src/libcw/cwMidiFile.cpp +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/cwFlow.h src/libcw/cwFlowTypes.h src/libcw/cwFlowProc.h +libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp if cwWEBSOCK libcwHDR += src/libcw/cwWebSock.h src/libcw/cwWebSockSvr.h diff --git a/cwFlow.cpp b/cwFlow.cpp new file mode 100644 index 0000000..4799b45 --- /dev/null +++ b/cwFlow.cpp @@ -0,0 +1,689 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwAudioFile.h" +#include "cwVectOps.h" +#include "cwMtx.h" +#include "cwFlow.h" +#include "cwFlowTypes.h" +#include "cwFlowProc.h" + +namespace cw +{ + namespace flow + { + typedef struct library_str + { + const char* label; + class_members_t* members; + } library_t; + + library_t library[] = { + { "audioFileIn", &audioFileIn::members }, + { "audioFileOut", &audioFileOut::members }, + { "pv_analysis", &pv_analysis::members }, + { "pv_synthesis", &pv_synthesis::members }, + { "spec_dist", &spec_dist::members }, + { nullptr, nullptr } + }; + + class_members_t* _find_library_record( const char* label ) + { + for(library_t* l = library; l->label != nullptr; ++l) + if( textCompare(l->label,label) == 0) + return l->members; + + return nullptr; + } + + flow_t* _handleToPtr(handle_t h) + { return handleToPtr(h); } + + + rc_t _parse_class_cfg(flow_t* p, const library_t* library, const object_t* classCfg) + { + rc_t rc = kOkRC; + + if( !classCfg->is_dict() ) + return cwLogError(kSyntaxErrorRC,"The class description dictionary does not have dictionary syntax."); + + p->classDescN = classCfg->child_count(); + p->classDescA = mem::allocZ( p->classDescN ); + + // for each class description + for(unsigned i=0; iclassDescN; ++i) + { + const object_t* class_obj = classCfg->child_ele(i); + const object_t* varD = nullptr; + const object_t* presetD = nullptr; + class_desc_t* cd = p->classDescA + i; + + cd->cfg = class_obj->pair_value(); + cd->label = class_obj->pair_label(); + + // get the variable description + if((rc = cd->cfg->getv_opt("vars", varD, + "presets", presetD )) != kOkRC ) + { + rc = cwLogError(rc,"Parsing failed while parsing class desc:'%s'", cwStringNullGuard(cd->label) ); + goto errLabel; + } + + // parse the preset dictionary + if( presetD != nullptr ) + { + + if( !presetD->is_dict() ) + { + rc = cwLogError(rc,"The preset dictionary is not a dictionary on class desc:'%s'", cwStringNullGuard(cd->label) ); + goto errLabel; + } + + // for each preset in the class desc. + for(unsigned j=0; jchild_count(); ++j) + { + const object_t* pair = presetD->child_ele(j); + + if( !pair->pair_value()->is_dict() ) + { + rc = cwLogError(kSyntaxErrorRC,"The preset '%s' in class desc '%s' is not a dictionary.", cwStringNullGuard(pair->pair_label()), cwStringNullGuard(cd->label)); + goto errLabel; + } + + preset_t* preset = mem::allocZ< preset_t >(); + + preset->label = pair->pair_label(); + preset->cfg = pair->pair_value(); + preset->link = cd->presetL; + cd->presetL = preset; + } + } + + // parse the value dictionary + if( varD != nullptr ) + { + if( !varD->is_dict() ) + { + rc = cwLogError(rc,"The value dictionary is not a dictionary on class desc:'%s'", cwStringNullGuard(cd->label) ); + goto errLabel; + } + + // get the class member functions + if((cd->members = _find_library_record(cd->label)) == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The '%s' class member function record could not be found..", cd->label ); + goto errLabel; + } + + // for each class value description + for(unsigned j=0; jchild_count(); ++j) + { + const object_t* var_obj = varD->child_ele(j); + const char* type_str = nullptr; + unsigned type_flag = 0; + bool srcVarFl = false; + var_desc_t* vd = mem::allocZ(); + + vd->label = var_obj->pair_label(); + vd->cfg = var_obj->pair_value(); + + // get the variable description + if((rc = var_obj->getv("type", type_str, + "doc", vd->docText)) != kOkRC ) + { + rc = cwLogError(rc,"Parsing failed on class:%s variable: '%s'.", cd->label, vd->label ); + goto errLabel; + } + + // convert the type string to a numeric type flag + if( (type_flag = value_type_label_to_flag( type_str )) == kInvalidTId ) + { + rc = cwLogError(rc,"Invalid type flag: '%s' class:'%s' value:'%s'.", type_str, cd->label, vd->label ); + goto errLabel; + } + + // get the variable description + if((rc = var_obj->getv_opt("srcFl", srcVarFl)) != kOkRC ) + { + rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label ); + goto errLabel; + } + + + vd->type |= type_flag; + + if( srcVarFl ) + { + vd->flags |= kSrcVarFl; + } + + vd->link = cd->varDescL; + cd->varDescL = vd; + } + } + + } + + errLabel: + return rc; + } + + + + rc_t _setup_input( flow_t* p, instance_t* in_inst, const char* in_var_label, const char* src_label_arg ) + { + rc_t rc = kOkRC; + unsigned src_charN = textLength(src_label_arg); + variable_t* src_var = nullptr; + instance_t* src_inst = nullptr; + variable_t* in_var = nullptr; + + char sbuf[ src_charN+1 ]; + + // copy the id into the buf + strncpy(sbuf,src_label_arg,src_charN+1); + + // advance suffix to the '.' + char* suffix = sbuf; + while( *suffix && *suffix != '.') + ++suffix; + + // if a '.' suffix was found + if( *suffix ) + { + *suffix = 0; + ++suffix; + } + + // locate source instance + if((rc = instance_find(p, sbuf, src_inst )) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The source instance '%s' was not found.", cwStringNullGuard(sbuf) ); + goto errLabel; + } + + // locate source value + if((rc = var_get( 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 ) + { + rc = cwLogError(rc,"The input value '%s' was not found on the instance '%s'.", cwStringNullGuard(in_var_label), cwStringNullGuard(in_inst->label)); + goto errLabel; + } + + // verify that the src_value type is included in the in_value type flags + if( cwIsNotFlag(in_var->varDesc->type, src_var->varDesc->type) ) + { + rc = cwLogError(kSyntaxErrorRC,"The type flags don't match on input:%s %s source:%s %s .", in_inst->label, in_var_label, src_inst->label, suffix); + goto errLabel; + } + + + // connect in_var into src_var's outgoing var chain + in_var->connect_link = src_var->connect_link; + src_var->connect_link = in_var; + + + in_var->value = src_var->value; + + + //cwLogInfo("'%s:%s' connected to source '%s:%s'.", in_inst->label, in_var_label, src_inst->label, suffix ); + + errLabel: + return rc; + } + + + void _destroy_inst( instance_t* inst ) + { + if( inst->class_desc->members->destroy != nullptr && inst->userPtr != nullptr ) + inst->class_desc->members->destroy( inst ); + + // destroy the instance variables + variable_t* var0 = inst->varL; + variable_t* var1 = nullptr; + while( var0 != nullptr ) + { + var1 = var0->link; + _var_destroy(var0); + var0 = var1; + } + + + mem::release(inst->varMapA); + mem::release(inst); + } + + rc_t _create_instance_var_map( instance_t* inst ) + { + rc_t rc = kOkRC; + unsigned max_vid = kInvalidId; + unsigned max_chIdx = 0; + + // determine the max variable vid and max channel index value among all variables + for(variable_t* var=inst->varL; var!=nullptr; var=var->link) + { + + 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( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx ) + max_chIdx = var->chIdx; + } + + // If there are any variables + if( max_vid != kInvalidId ) + { + // create the variable map array + inst->varMapChN = max_chIdx + 1; + inst->varMapIdN = max_vid + 1; + inst->varMapN = inst->varMapIdN * inst->varMapChN; + inst->varMapA = mem::allocZ( inst->varMapN ); + + // assign each variable to a location in the map + for(variable_t* var=inst->varL; var!=nullptr; var=var->link) + { + unsigned idx = kInvalidIdx; + + if((rc = var_map_id_to_index( inst, var->vid, var->chIdx, idx )) != kOkRC ) + goto errLabel; + + + // verify that there are not multiple variables per map position + if( inst->varMapA[ idx ] != nullptr ) + { + variable_t* v0 = inst->varMapA[idx]; + rc = cwLogError(kInvalidStateRC,"The variable '%s' id:%i ch:%i and '%s' id:%i ch:%i share the same variable map position on instance: %s. This is usually cased by duplicate variable id's.", + v0->label,v0->vid,v0->chIdx, var->label,var->vid,var->chIdx,inst->label); + goto errLabel; + } + + // assign this variable to a map position + inst->varMapA[ idx ] = var; + } + + } + + errLabel: + return rc; + + } + + rc_t _create_instance( flow_t* p, const object_t* inst_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; + + // 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."); + goto errLabel; + } + + inst_label = inst_cfg->pair_label(); + + // verify that the instance label is unique + if( instance_find(p,inst_label) != nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The instance label '%s' has already been used.",inst_label); + goto errLabel; + } + + // get the instance class label + if((rc = inst_cfg->getv("class",inst_clas_label)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",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 ) + { + rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",inst_label); + goto errLabel; + } + + // if an argument dict was given + if( arg_dict != nullptr ) + { + bool rptErrFl = true; + + // if no label was given then try 'default' + if( arg_label == nullptr) + { + arg_label = "default"; + rptErrFl = false; + } + + if((arg_cfg = arg_dict->find_child(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); + goto errLabel; + } + + // no explicit arg. label was given - make arg_dict the instance arg cff. + arg_cfg = arg_dict; + arg_label = nullptr; + } + } + + // locate the class desc + if(( class_desc = class_desc_find(p,inst_clas_label)) == nullptr ) + { + rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(inst_clas_label)); + goto errLabel; + } + + // instantiate the instance + inst = mem::allocZ(); + + inst->ctx = p; + inst->label = inst_label; + inst->inst_cfg = inst_cfg; + inst->arg_label = arg_label; + inst->arg_cfg = 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 + 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; + } + } + + // connect the variable lists in the instance 'in' dictionary + if( in_dict != nullptr && in_dict->is_dict() ) + { + // for each input + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* in_pair = 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 + 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. + assert( cwIsFlag(vd->flags,kSrcVarFl) ); + + // if this value is a 'src' value then it must be setup prior to the instance being instantiated + if( cwIsFlag(vd->flags,kSrcVarFl) ) + { + in_pair->pair_value()->value(src_label); + + // locate the pointer to the referenced output abuf and store it in inst->srcABuf[i] + if((rc = _setup_input( p, inst, in_var_label, src_label )) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"The 'in' buffer at index %i is not valid on instance '%s'.", i, inst_label ); + goto errLabel; + } + } + } + } + + // complete the instantiation + if((rc = class_desc->members->create( inst )) != kOkRC ) + { + 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 ) + { + p->network_head = inst; + p->network_tail = inst; + } + else + { + p->network_tail->link = inst; + p->network_tail = inst; + } + + + errLabel: + if( rc != kOkRC ) + _destroy_inst(inst); + + return rc; + } + + + rc_t _destroy( flow_t* p) + { + rc_t rc = kOkRC; + + instance_t* i0=p->network_head; + instance_t* i1=nullptr; + + // destroy the instances + while(i0!=nullptr) + { + i1 = i0->link; + _destroy_inst(i0); + i0 = i1; + } + + // release the class records + for(unsigned i=0; iclassDescN; ++i) + { + class_desc_t* cd = p->classDescA + i; + + // release the var desc list + var_desc_t* vd0 = cd->varDescL; + var_desc_t* vd1 = nullptr; + while( vd0 != nullptr ) + { + vd1 = vd0->link; + mem::release(vd0); + vd0 = vd1; + } + + // release the preset list + preset_t* pr0 = cd->presetL; + preset_t* pr1 = nullptr; + while( pr0 != nullptr ) + { + pr1 = pr0->link; + mem::release(pr0); + pr0 = pr1; + } + } + + mem::release(p->classDescA); + mem::release(p); + + return rc; + } + + } +} + +cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ) +{ + rc_t rc = kOkRC; + const object_t* network; + + if(( rc = destroy(hRef)) != kOkRC ) + return rc; + + flow_t* p = mem::allocZ(); + p->cfg = &cfg; // TODO: duplicate cfg? + + // parse the class description array + if((rc = _parse_class_cfg(p,library,&classCfg)) != kOkRC ) + { + rc = cwLogError(kSyntaxErrorRC,"Error parsing the class description list."); + goto errLabel; + } + + // parse the main audio file processor cfg record + if((rc = cfg.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 ) + { + rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters."); + goto errLabel; + } + + // for each instance in the network + for(unsigned i=0; ichild_count(); ++i) + { + const object_t* inst_cfg = network->child_ele(i); + + // create the instance + if( (rc= _create_instance( p, inst_cfg ) ) != kOkRC ) + { + rc = cwLogError(rc,"The instantiation at 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; + + hRef.set(p); + + errLabel: + if( rc != kOkRC ) + _destroy(p); + + return rc; +} + +cw::rc_t cw::flow::exec( handle_t& hRef ) +{ + rc_t rc = kOkRC; + flow_t* p = _handleToPtr(hRef); + + while( true ) + { + for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) + if((rc = inst->class_desc->members->exec(inst)) != kOkRC ) + break; + + p->cycleIndex += 1; + if( p->maxCycleCount > 0 && p->cycleIndex >= p->maxCycleCount ) + break; + } + + return rc; +} + +cw::rc_t cw::flow::destroy( handle_t& hRef ) +{ + rc_t rc = kOkRC; + flow_t* p = nullptr;; + + if( !hRef.isValid() ) + return rc; + + p = _handleToPtr(hRef); + + _destroy(p); + + hRef.clear(); + + return rc; +} + +void cw::flow::print_class_list( handle_t& hRef ) +{ + class_desc_print(_handleToPtr(hRef)); +} + +void cw::flow::print_network( handle_t& hRef ) +{ + network_print(_handleToPtr(hRef)); +} + + +cw::rc_t cw::flow::test( const object_t* class_cfg, const object_t* cfg ) +{ + rc_t rc = kOkRC; + handle_t flowH; + + // create the flow object + if((rc = create( flowH, *class_cfg, *cfg)) != kOkRC ) + { + rc = cwLogError(rc,"Flow object create failed."); + goto errLabel; + } + + print_network(flowH); + + // run the network + if((rc = exec( flowH )) != kOkRC ) + rc = cwLogError(rc,"Execution failed."); + + + // destroy the flow object + if((rc = destroy(flowH)) != kOkRC ) + { + rc = cwLogError(rc,"Close the flow object."); + goto errLabel; + } + + errLabel: + return rc; +} + + + diff --git a/cwFlow.h b/cwFlow.h new file mode 100644 index 0000000..1f51a6e --- /dev/null +++ b/cwFlow.h @@ -0,0 +1,29 @@ +#ifndef cwFlowSys_h +#define cwFlowSys_h + +namespace cw +{ + namespace flow + { + + + + + typedef handle handle_t; + + rc_t create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ); + rc_t exec( handle_t& hRef ); + rc_t destroy( handle_t& hRef ); + + void print_class_list( handle_t& hRef ); + void print_network( handle_t& hRef ); + + rc_t test( const object_t* class_cfg, const object_t* cfg ); + + + + } +} + + +#endif diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp new file mode 100644 index 0000000..94d7474 --- /dev/null +++ b/cwFlowProc.cpp @@ -0,0 +1,708 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwObject.h" +#include "cwAudioFile.h" +#include "cwVectOps.h" +#include "cwMtx.h" +#include "cwFlow.h" +#include "cwFlowTypes.h" +#include "cwFlowProc.h" + +#include "cwFile.h" +#include "cwMath.h" +#include "cwDsp.h" +#include "cwAudioTransforms.h" + +namespace cw +{ + + namespace flow + { + //------------------------------------------------------------------------------------------------------------------ + // + // Template + // + namespace template_proc + { + typedef struct + { + + } inst_t; + + + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = mem::allocZ(); + ctx->userPtr = inst; + + // Custom create code goes here + + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + + // Custom clean-up code goes here + + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + //inst_t* inst = (inst_t*)ctx->userPtr; + + return rc; + } + } + + + //------------------------------------------------------------------------------------------------------------------ + // + // AudioFileIn + // + + namespace audioFileIn + { + enum + { + kOutPId + }; + + typedef struct + { + audiofile::handle_t afH; + bool eofFl; + const char* filename; + } inst_t; + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + audiofile::info_t info; + + inst_t* inst = mem::allocZ(); + ctx->userPtr = inst; + + // get the audio filename + if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != 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 ) + { + rc = cwLogError(kInvalidArgRC,"The audio file '%s' could not be opened.",inst->filename); + goto errLabel; + } + + 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 ); + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + + if((rc = audiofile::close(inst->afH)) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The close failed on the audio file '%s'.", cwStringNullGuard(inst->filename) ); + } + + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + unsigned actualFrameN = 0; + inst_t* inst = (inst_t*)ctx->userPtr; + abuf_t* abuf = nullptr; + + + // verify that a source buffer exists + if((rc = var_abuf_get(ctx,"out",kAnyChIdx,abuf)) != kOkRC ) + { + rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid audio output buffer.",ctx->label); + } + else + { + sample_t* chBuf[ abuf->chN ]; + + for(unsigned i=0; ichN; ++i) + chBuf[i] = abuf->buf + (i*abuf->frameN); + + rc = readFloat(inst->afH, abuf->frameN, 0, abuf->chN, chBuf, &actualFrameN ); + + if( inst->eofFl && actualFrameN == 0) + rc = kEofRC; + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec + }; + + } + + + //------------------------------------------------------------------------------------------------------------------ + // + // AudioFileOut + // + + namespace audioFileOut + { + enum + { + kInPId + }; + + typedef struct + { + audiofile::handle_t afH; + const char* filename; + } inst_t; + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; // + unsigned audioFileBits = 0; // set audio file sample format to 'float32'. + inst_t* inst = mem::allocZ(); // + abuf_t* src_abuf = nullptr; + ctx->userPtr = inst; + + // get the audio filename + if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != 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; + } + + // create the audio file + if((rc = audiofile::create( inst->afH, inst->filename, src_abuf->srate, audioFileBits, src_abuf->chN)) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The audio file create failed on '%s'.",cwStringNullGuard(inst->filename)); + goto errLabel; + } + + rc = var_init( ctx, kAnyChIdx, kInPId, "in", src_abuf); + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + + // close the audio file + if((rc = audiofile::close( inst->afH )) != kOkRC ) + { + rc = cwLogError(rc,"Close failed on the audio output file '%s'.",inst->filename); + goto errLabel; + } + + mem::release(inst); + + errLabel: + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const abuf_t* src_abuf = nullptr; + + 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); + else + { + sample_t* chBuf[ src_abuf->chN ]; + + for(unsigned i=0; ichN; ++i) + chBuf[i] = src_abuf->buf + (i*src_abuf->frameN); + + 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 ); + } + + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec + }; + + } + + //------------------------------------------------------------------------------------------------------------------ + // + // Phase Vocoder (Analysis) + // + namespace pv_analysis + { + typedef struct dsp::pv_anl::obj_str pv_t; + + enum { + kInPId, + kOutPId + }; + + typedef struct + { + pv_t** pvA; // pvA[ srcBuf.chN ] + unsigned wndSmpN; + unsigned hopSmpN; + bool hzFl; + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const abuf_t* srcBuf = nullptr; // + unsigned flags = 0; + 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 ) + { + 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 + const sample_t* magV[ srcBuf->chN ]; + const sample_t* phsV[ srcBuf->chN ]; + const sample_t* hzV[ srcBuf->chN ]; + + // create a pv anlaysis object for each input channel + for(unsigned i=0; ichN; ++i) + { + if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, inst->wndSmpN, inst->hopSmpN, flags )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The PV analysis object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + + magV[i] = inst->pvA[i]->magV; + phsV[i] = inst->pvA[i]->phsV; + hzV[i] = inst->pvA[i]->hzV; + } + + if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != 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 ); + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const abuf_t* srcBuf = nullptr; + fbuf_t* dstBuf = nullptr; + + // 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; + } + + // verify that the dst buffer exits + if((rc = var_fbuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) + { + rc = cwLogError(rc,"The instance '%s' does not have a valid output.",ctx->label); + goto errLabel; + } + + // for each input channel + for(unsigned i=0; ichN; ++i) + { + // call the PV analysis processor + 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); + } + + errLabel: + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec + }; + } + + //------------------------------------------------------------------------------------------------------------------ + // + // Phase Vocoder (Synthesis) + // + namespace pv_synthesis + { + typedef struct dsp::pv_syn::obj_str pv_t; + + enum { + kInPId, + kOutPId + }; + + + typedef struct + { + pv_t** pvA; // pvA[ srcBuf.chN ] + unsigned wndSmpN; // + unsigned hopSmpN; // + bool hzFl; // + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const fbuf_t* srcBuf = nullptr; // + inst_t* inst = mem::allocZ(); + ctx->userPtr = inst; + + + // verify that a source buffer exists + if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, 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 ); + + // create a pv anlaysis object for each input channel + for(unsigned i=0; ichN; ++i) + { + unsigned wndSmpN = (srcBuf->binN-1)*2; + + if((rc = create( inst->pvA[i], ctx->ctx->framesPerCycle, srcBuf->srate, wndSmpN, srcBuf->hopSmpN )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The PV synthesis object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + } + + if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != kOkRC ) + goto errLabel; + + // create the abuf 'out' + rc = var_abuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const fbuf_t* srcBuf = nullptr; + abuf_t* dstBuf = nullptr; + + // get the src buffer + if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + goto errLabel; + + // get the dst buffer + if((rc = var_abuf_get(ctx,"out", 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 ); + } + + + errLabel: + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec + }; + } + + //------------------------------------------------------------------------------------------------------------------ + // + // Spec Dist + // + namespace spec_dist + { + typedef struct dsp::spec_dist::obj_str spec_dist_t; + + enum + { + kInPId, + kCeilingPId, + kExpoPId, + kThreshPId, + kUprSlopePId, + kLwrSlopePId, + kMixPId, + kOutPId, + }; + + + typedef struct + { + spec_dist_t** sdA; + } inst_t; + + + rc_t create( instance_t* ctx ) + { + rc_t rc = kOkRC; + const fbuf_t* srcBuf = nullptr; // + inst_t* inst = mem::allocZ(); + + ctx->userPtr = inst; + + // verify that a source buffer exists + if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, 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->sdA = mem::allocZ( srcBuf->chN ); + + const sample_t* magV[ srcBuf->chN ]; + const sample_t* phsV[ srcBuf->chN ]; + const sample_t* hzV[ srcBuf->chN ]; + + + // create a spec_dist object for each input channel + for(unsigned i=0; ichN; ++i) + { + if((rc = create( inst->sdA[i], srcBuf->binN )) != kOkRC ) + { + rc = cwLogError(kOpFailRC,"The 'spec dist' object create failed on the instance '%s'.",ctx->label); + goto errLabel; + } + + // setup the output buffer pointers + magV[i] = inst->sdA[i]->outMagV; + 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 ) + { + goto errLabel; + } + + } + + // 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 ) + goto errLabel; + } + + errLabel: + return rc; + } + + rc_t destroy( instance_t* ctx ) + { + rc_t rc = kOkRC; + + inst_t* inst = (inst_t*)ctx->userPtr; + mem::release(inst); + + return rc; + } + + rc_t value( instance_t* ctx, variable_t* var ) + { + rc_t rc = kOkRC; + return rc; + } + + rc_t exec( instance_t* ctx ) + { + rc_t rc = kOkRC; + inst_t* inst = (inst_t*)ctx->userPtr; + const fbuf_t* srcBuf = nullptr; + fbuf_t* dstBuf = nullptr; + + // get the src buffer + if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) + goto errLabel; + + // get the dst buffer + if((rc = var_fbuf_get(ctx,"out", 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) ); + } + + + errLabel: + return rc; + } + + class_members_t members = { + .create = create, + .destroy = destroy, + .value = value, + .exec = exec + }; + } + + + } +} + + diff --git a/cwFlowProc.h b/cwFlowProc.h new file mode 100644 index 0000000..6ab0329 --- /dev/null +++ b/cwFlowProc.h @@ -0,0 +1,11 @@ +namespace cw +{ + namespace flow + { + 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; } + } +} diff --git a/cwFlowTypes.cpp b/cwFlowTypes.cpp new file mode 100644 index 0000000..4f5919d --- /dev/null +++ b/cwFlowTypes.cpp @@ -0,0 +1,1019 @@ +#include "cwCommon.h" +#include "cwLog.h" +#include "cwCommonImpl.h" +#include "cwMem.h" +#include "cwText.h" +#include "cwObject.h" +#include "cwVectOps.h" +#include "cwMtx.h" +#include "cwFlowTypes.h" + + +namespace cw +{ + namespace flow + { + idLabelPair_t typeLabelFlagsA[] = { + + { kBoolTFl, "bool" }, + { kUIntTFl, "uint" }, + { kIntTFl, "int", }, + { kRealTFl, "real" }, + { kF32TFl, "float"}, + { kF64TFl, "double"}, + + { kBoolMtxTFl, "bool_mtx" }, + { kUIntMtxTFl, "uint_mtx" }, + { kIntMtxTFl, "int_mtx" }, + { kRealMtxTFl, "real_mtx" }, + { kF32MtxTFl, "float_mtx" }, + { kF64MtxTFl, "double_mtx" }, + + { kABufTFl, "audio" }, + { kFBufTFl, "spectrum" }, + { kStringTFl, "string" }, + { kFNameTFl, "fname" }, + { kTimeTFl, "time" }, + { kInvalidTFl, nullptr } + }; + + const char* _typeFlagToLabel( unsigned flag ) + { + for(unsigned i=0; typeLabelFlagsA[i].id != kInvalidTFl; ++i) + if( typeLabelFlagsA[i].id == flag ) + return typeLabelFlagsA[i].label; + + return ""; + } + + + void _value_release( value_t* v ) + { + if( v == nullptr ) + return; + + switch( v->flags & kTypeMask ) + { + case kInvalidTFl: + break; + + case kBoolTFl: + case kUIntTFl: + case kIntTFl: + case kRealTFl: + case kF32TFl: + case kF64TFl: + break; + + case kABufTFl: + abuf_destroy( v->u.abuf ); + break; + + case kFBufTFl: + fbuf_destroy( v->u.fbuf ); + break; + + + case kBoolMtxTFl: + case kUIntMtxTFl: + case kIntMtxTFl: + case kRealMtxTFl: + case kF32MtxTFl: + case kF64MtxTFl: + 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; + + default: + assert(0); + break; + } + + v->flags = kInvalidTFl; + } + + void _value_print( const value_t* v ) + { + if( v == nullptr ) + return; + + switch( v->flags & kTypeMask ) + { + case kInvalidTFl: + break; + + case kBoolTFl: printf("%s ", v->u.b ? "True" : "False" ); break; + case kUIntTFl: printf("%i ", v->u.u ); break; + case kIntTFl: printf("%i ", v->u.i ); break; + case 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 kBoolMtxTFl: + case kUIntMtxTFl: + case kIntMtxTFl: + case kRealMtxTFl: + case kF32MtxTFl: + case kF64MtxTFl: + assert(0); // not implemeneted + break; + + case kStringTFl: printf("%s ", v->u.s); break; + case kFNameTFl: printf("%s ", v->u.fname); break; + + case kTimeTFl: + assert(0); + break; + + default: + assert(0); + break; + } + + } + + rc_t _var_get( instance_t* inst, unsigned vid, unsigned chIdx, unsigned typeFl, const char* typeLabel, variable_t*& varRef ) + { + rc_t rc = kOkRC; + unsigned idx = kInvalidIdx; + + varRef = nullptr; + + if((rc = var_map_id_to_index(inst, vid, chIdx, idx )) == kOkRC || idx == kInvalidIdx ) + { + 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; + } + + errLabel: + return rc; + } + + + variable_t* _var_find( instance_t* inst, const char* label, unsigned chIdx ) + { + 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; + + } + + rc_t _validate_var_assignment( variable_t* var, unsigned typeFl ) + { + if( cwIsFlag(var->varDesc->flags, kSrcVarFl ) ) + return cwLogError(kInvalidStateRC, "The variable '%s' on instance '%s' cannot be set because it is a 'src' variable.", var->label, var->inst->label); + + if( !cwIsFlag(var->varDesc->type, typeFl ) ) + return cwLogError(kTypeMismatchRC, "The variable '%s' on instance '%s' is not a '%s'.", var->label, var->inst->label, _typeFlagToLabel( typeFl )); + + return kOkRC; + } + + rc_t _var_broadcast_new_value( variable_t* var ) + { + rc_t rc = kOkRC; + + // notify each connected var that the value has changed + for(variable_t* con_var = var->connect_link; con_var!=nullptr; con_var=con_var->connect_link) + if((rc = con_var->inst->class_desc->members->value( con_var->inst, con_var )) != kOkRC ) + break; + + return rc; + } + + rc_t _var_set( variable_t* var, unsigned val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kUIntTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.u = val; + var->local_value.flags = kUIntTFl; + var->value = &var->local_value; + + return _var_broadcast_new_value( var ); + + } + + rc_t _var_set( variable_t* var, int val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kIntTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.i = val; + var->local_value.flags = kIntTFl; + var->value = &var->local_value; + + return _var_broadcast_new_value( var ); + } + + rc_t _var_set( variable_t* var, real_t val ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kRealTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.r = val; + var->local_value.flags = kRealTFl; + var->value = &var->local_value; + + return _var_broadcast_new_value( var ); + } + + rc_t _var_set( variable_t* var, abuf_t* abuf ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kABufTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.abuf = abuf; + var->local_value.flags = kABufTFl; + var->value = &var->local_value; + + return _var_broadcast_new_value( var ); + + } + + rc_t _var_set( variable_t* var, fbuf_t* fbuf ) + { + rc_t rc; + if((rc = _validate_var_assignment( var, kFBufTFl )) != kOkRC ) + return rc; + + _value_release(&var->local_value); + var->local_value.u.fbuf = fbuf; + var->local_value.flags = kFBufTFl; + var->value = &var->local_value; + + return _var_broadcast_new_value( var ); + } + + const preset_t* _preset_find( class_desc_t* cd, const char* preset_label ) + { + const preset_t* pr; + for(pr=cd->presetL; pr!=nullptr; pr=pr->link) + if( textCompare(pr->label,preset_label) == 0 ) + return pr; + + return nullptr; + } + + 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_get( inst, var_label, chIdx, var )) != kOkRC ) + goto errLabel; + + switch( var->varDesc->type & kTypeMask ) + { + case kUIntTFl: + { + unsigned v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set( var, v ); + } + break; + + case kIntTFl: + { + int v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set( var, v ); + } + break; + + case kRealTFl: + { + real_t v; + if((rc = value->value(v)) == kOkRC ) + rc = _var_set( 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(rc,"The value of instance:%s variable:%s could not be set via a preset.", inst->label, var_label ); + + return rc; + } + + } +} + + +cw::flow::abuf_t* cw::flow::abuf_create( srate_t srate, unsigned chN, unsigned frameN ) +{ + abuf_t* a = mem::allocZ(); + a->srate = srate; + a->chN = chN; + a->frameN = frameN; + a->buf = mem::allocZ( chN*frameN ); + + return a; +} + +void cw::flow::abuf_destroy( abuf_t* abuf ) +{ + if( abuf == nullptr ) + return; + + mem::release(abuf->buf); + mem::release(abuf); +} + +cw::rc_t cw::flow::abuf_set_channel( abuf_t* abuf, unsigned chIdx, const sample_t* v, unsigned vN ) +{ + rc_t rc = kOkRC; + + if( vN > abuf->frameN ) + rc = cwLogError(kInvalidArgRC,"Cannot copy source vector of length %i into an abuf of length %i.", vN, abuf->frameN); + else + if( chIdx > abuf->chN ) + rc = cwLogError(kInvalidArgRC,"The abuf destination channel %i is out of range.", chIdx); + else + vop::copy( abuf->buf + (chIdx*abuf->frameN), v, vN); + + return rc; +} + +const cw::flow::sample_t* cw::flow::abuf_get_channel( abuf_t* abuf, unsigned chIdx ) +{ + assert( abuf->buf != nullptr ); + return abuf->buf + (chIdx*abuf->frameN); +} + + + +cw::flow::fbuf_t* cw::flow::fbuf_create( srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV, const sample_t** phsV, const sample_t** hzV ) +{ + fbuf_t* f = mem::allocZ(); + + f->srate = srate; + f->chN = chN; + f->binN = binN; + f->hopSmpN = hopSmpN; + f->magV = mem::allocZ(chN); + f->phsV = mem::allocZ(chN); + f->hzV = mem::allocZ(chN); + + if( magV != nullptr || phsV != nullptr || hzV != nullptr ) + { + for(unsigned chIdx=0; chIdxmagV[ chIdx ] = (sample_t*)magV[chIdx]; + f->phsV[ chIdx ] = (sample_t*)phsV[chIdx]; + f->hzV[ chIdx ] = (sample_t*)hzV[chIdx]; + } + } + else + { + sample_t* buf = mem::allocZ( chN * kFbufVectN * binN ); + + for(unsigned chIdx=0,j=0; chIdxmagV[chIdx] = buf + j + 0 * binN; + f->phsV[chIdx] = buf + j + 1 * binN; + f->hzV[ chIdx] = buf + j + 2 * binN; + } + + f->buf = buf; + + } + + return f; +} + +void cw::flow::fbuf_destroy( fbuf_t* fbuf ) +{ + if( fbuf == nullptr ) + return; + + mem::release( fbuf->magV); + mem::release( fbuf->phsV); + mem::release( fbuf->hzV); + mem::release( fbuf->buf); + mem::release( fbuf); +} + +unsigned cw::flow::value_type_label_to_flag( const char* s ) +{ + unsigned flags = labelToId(typeLabelFlagsA,s,kInvalidTFl); + if( flags == kInvalidTFl ) + cwLogError(kInvalidArgRC,"Invalid type flag: '%s'",cwStringNullGuard(s)); + + return flags; +} + + +cw::flow::class_desc_t* cw::flow::class_desc_find( flow_t* p, const char* label ) +{ + for(unsigned i=0; iclassDescN; ++i) + if( textCompare(p->classDescA[i].label,label) == 0 ) + return p->classDescA + i; + return nullptr; +} + +cw::flow::var_desc_t* cw::flow::var_desc_find( class_desc_t* cd, const char* label ) +{ + var_desc_t* vd = cd->varDescL; + + for(; vd != nullptr; vd=vd->link ) + if( textCompare(vd->label,label) == 0 ) + return vd; + return nullptr; +} + +cw::rc_t cw::flow::var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef ) +{ + if((vdRef = var_desc_find(cd,label)) == nullptr ) + return cwLogError(kInvalidArgRC,"The variable desc. named '%s' could not be found on the class '%s'.",label,cd->label); + return kOkRC; +} + + +void cw::flow::class_desc_print( flow_t* p ) +{ + for(unsigned i=0; iclassDescN; ++i) + { + class_desc_t* cd = p->classDescA + i; + var_desc_t* vd = cd->varDescL; + printf("%s\n",cwStringNullGuard(cd->label)); + + for(; vd!=nullptr; vd=vd->link) + { + const char* srcFlStr = vd->flags&kSrcVarFl ? "src" : " "; + + printf(" %10s 0x%08x %s %s\n", cwStringNullGuard(vd->label), vd->type, srcFlStr, cwStringNullGuard(vd->docText) ); + } + } +} + +void cw::flow::network_print( flow_t* p ) +{ + for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link) + instance_print(inst); +} + +cw::flow::instance_t* cw::flow::instance_find( flow_t* p, const char* inst_label ) +{ + for(instance_t* inst = p->network_head; inst!=nullptr; inst=inst->link ) + if( textCompare(inst_label,inst->label) == 0 ) + return inst; + + return nullptr; +} + +cw::rc_t cw::flow::instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef ) +{ + rc_t rc = kOkRC; + + if((instPtrRef = instance_find(p,inst_label)) != nullptr ) + return rc; + + return cwLogError(kInvalidArgRC,"The instance '%s' was not found.", inst_label ); +} + +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"); + } +} + + +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); +} + +bool cw::flow::var_exists( instance_t* inst, const char* label, unsigned chIdx ) +{ return _var_find(inst,label,chIdx) != nullptr; } + +cw::rc_t cw::flow::var_get( instance_t* inst, const char* label, unsigned chIdx, variable_t*& vRef ) +{ + variable_t* var; + + if((var = _var_find(inst,label,chIdx)) != nullptr ) + { + vRef = var; + return kOkRC; + } + + return cwLogError(kInvalidIdRC,"The instance '%s' does not have a variable named '%s'.", inst->label, label ); +} + +cw::rc_t cw::flow::var_get( 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); + 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 ) +{ + 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) + { + var->vid = vid; + return kOkRC; // NOTE: when returning here 'varRef' should be NULL + } + + 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 ) +{ + 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, 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 ) +{ + 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; + + return kOkRC; +} + +cw::rc_t cw::flow::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_get(inst, var_label, chIdx, var )) == kOkRC) + rc = var_map_id_to_index( inst, var->vid, chIdx, idxRef ); + + 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 ); + + return rc; +} + +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, int_t val ) +{ + rc_t rc = kOkRC; + variable_t* var = nullptr; + + if((rc = _var_get(inst, vid, chIdx, kIntTFl, "int_t", var )) == kOkRC ) + _var_set( var, val ); + + return rc; +} + +cw::rc_t cw::flow::var_set( instance_t* inst, unsigned vid, unsigned chIdx, real_t 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 ); + + return rc; +} + + +cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, uint_t 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; +} + +cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, int_t 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; +} + +cw::rc_t cw::flow::var_set( instance_t* inst, const char* var_label, unsigned chIdx, real_t 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; +} + + +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: + + return rc; +} diff --git a/cwFlowTypes.h b/cwFlowTypes.h new file mode 100644 index 0000000..e9dbb1b --- /dev/null +++ b/cwFlowTypes.h @@ -0,0 +1,323 @@ +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; + + typedef unsigned vid_t; + + typedef struct abuf_str + { + struct value_str* base; + srate_t srate; // signal sample rate + unsigned chN; // count of channels + unsigned frameN; // count of sample frames per channel + sample_t* buf; // buf[ chN ][ frameN ] + } abuf_t; + + + enum { + kFbufVectN = 3, + kAnyChIdx = kInvalidIdx + }; + + typedef struct fbuf_str + { + struct value_str* base; + srate_t srate; // signal sample rate + unsigned flags; // See kXXXFbufFl + unsigned chN; // count of channels + unsigned binN; // count of sample frames per channel + unsigned hopSmpN; // hop sample count + sample_t** magV; // magV[ chN ][ binN ] + sample_t** phsV; // phsV[ chN ][ binN ] + sample_t** hzV; // hzV[ chN ][ binN ] + sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer) + } fbuf_t; + + enum + { + kInvalidTFl = 0x00000000, + kBoolTFl = 0x00000001, + kUIntTFl = 0x00000002, + kIntTFl = 0x00000004, + kRealTFl = 0x00000008, + kF32TFl = 0x00000010, + kF64TFl = 0x00000020, + + kBoolMtxTFl = 0x00000040, + kUIntMtxTFl = 0x00000080, + kIntMtxTFl = 0x00000100, + kRealMtxTFl = 0x00000200, + kF32MtxTFl = 0x00000400, + kF64MtxTFl = 0x00000800, + + kABufTFl = 0x00001000, + kFBufTFl = 0x00002000, + kStringTFl = 0x00004000, + kFNameTFl = 0x00008000, + kTimeTFl = 0x00010000, + + kTypeMask = 0x0001ffff, + + }; + + typedef struct mtx_str + { + union { + struct mtx::mtx_str< unsigned >* u; + struct mtx::mtx_str< int >* i; + struct mtx::mtx_str< real_t >* r; + struct mtx::mtx_str< float >* f; + struct mtx::mtx_str< double >* d; + } u; + } mtx_t; + + typedef struct value_str + { + unsigned flags; + union { + bool b; + uint_t u; + int_t i; + real_t r; + float f; + double d; + + mtx_t* mtx; + + abuf_t* abuf; + fbuf_t* fbuf; + + char* s; + char* fname; + + struct value_str* proxy; + } u; + + struct value_str* link; + + } value_t; + + 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 + { + kSrcVarFl = 0x01 + }; + + typedef struct class_members_str + { + member_func_t create; + member_func_t destroy; + member_value_func_t value; + member_func_t exec; + } 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; // + } var_desc_t; + + typedef struct preset_str + { + const char* label; + const object_t* cfg; + struct preset_str* link; + } preset_t; + + typedef struct class_desc_str + { + const object_t* cfg; // + const char* label; // class label; + var_desc_t* varDescL; // varDescA[varDescN] value description list + preset_t* presetL; // presetA[ presetN ] + class_members_t* members; // member functions for this class + } class_desc_t; + + + typedef struct variable_str + { + struct instance_str* inst; // pointer to this variables instance + char* label; // this variables label + unsigned vid; // this variables numeric id ( cat(vid,chIdx) forms a unique variable identifier on this 'inst' + var_desc_t* varDesc; // the variable description for this variable + value_t local_value; // 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* connect_link; // list of outgoing connections + } variable_t; + + + typedef struct instance_str + { + struct flow_str* ctx; // global system context + + class_desc_t* class_desc; // + + const char* label; // instance label + const object_t* inst_cfg; // instance configuration + + 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 + + variable_t* varL; // list of instance value + + unsigned varMapChN; // max count of channels among all variables + unsigned varMapIdN; + unsigned varMapN; // varMapN + variable_t** varMapA; // varMapA[ varMapN ] + + struct instance_str* link; + } instance_t; + + typedef struct flow_str + { + const object_t* cfg; + + unsigned framesPerCycle; // sample frames per cycle (64) + unsigned cycleIndex; // Incremented with each processing cycle + unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit. + + class_desc_t* classDescA; // + unsigned classDescN; // + + struct instance_str* network_head; // first instance + struct instance_str* network_tail; // last insance + } flow_t; + + //------------------------------------------------------------------------------------------------------------------------ + // + // Value Only + // + + abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN ); + void abuf_destroy( abuf_t* buf ); + 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 ); + + 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; } + + unsigned value_type_label_to_flag( const char* type_desc ); + + //------------------------------------------------------------------------------------------------------------------------ + // + // Class and Variable Description + // + + 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 ); + void network_print( flow_t* p ); + + //------------------------------------------------------------------------------------------------------------------------ + // + // Instance + // + + instance_t* instance_find( flow_t* p, const char* inst_label ); + rc_t instance_find( flow_t* p, const char* inst_label, instance_t*& instPtrRef ); + void instance_print( instance_t* inst ); + + //------------------------------------------------------------------------------------------------------------------------ + // + // Variable + // + + // 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 ); + + // 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 ); + + inline rc_t _var_init(cw::flow::instance_t* inst, unsigned int ) { return kOkRC; } + + 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 ) + { + rc_t rc; + + if((rc = var_init( inst, var_label, vid, chIdx, val )) == kOkRC ) + rc = _var_init( inst, chIdx, std::forward(args)...); + return rc; + } + + // Call var_init() 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)...); } + + 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 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_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 ); + + 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, 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 ); + + } +}