cwFlow.h/cpp,cwFlowProc.h/cpp,cwFlowTypes.h/cpp : Initial commit.
This commit is contained in:
parent
02cd79c61f
commit
4dac2f5d1b
10
Makefile.am
10
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
|
||||
|
689
cwFlow.cpp
Normal file
689
cwFlow.cpp
Normal file
@ -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<handle_t,flow_t>(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<class_desc_t>( p->classDescN );
|
||||
|
||||
// for each class description
|
||||
for(unsigned i=0; i<p->classDescN; ++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; j<presetD->child_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; j<varD->child_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<var_desc_t>();
|
||||
|
||||
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<variable_t*>( 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<instance_t>();
|
||||
|
||||
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; i<in_dict->child_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; i<p->classDescN; ++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<flow_t>();
|
||||
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; i<network->child_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;
|
||||
}
|
||||
|
||||
|
||||
|
29
cwFlow.h
Normal file
29
cwFlow.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef cwFlowSys_h
|
||||
#define cwFlowSys_h
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace flow
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
typedef handle<struct flow_str> 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
|
708
cwFlowProc.cpp
Normal file
708
cwFlowProc.cpp
Normal file
@ -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<inst_t>();
|
||||
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<inst_t>();
|
||||
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; i<abuf->chN; ++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<inst_t>(); //
|
||||
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; i<src_abuf->chN; ++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<sample_t> 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<inst_t>();
|
||||
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<pv_t*>( 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; i<srcBuf->chN; ++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; i<srcBuf->chN; ++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<sample_t> 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<inst_t>();
|
||||
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<pv_t*>( srcBuf->chN );
|
||||
|
||||
// create a pv anlaysis object for each input channel
|
||||
for(unsigned i=0; i<srcBuf->chN; ++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; i<srcBuf->chN; ++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<sample_t,sample_t> 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<inst_t>();
|
||||
|
||||
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<spec_dist_t*>( 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; i<srcBuf->chN; ++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; i<srcBuf->chN; ++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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
11
cwFlowProc.h
Normal file
11
cwFlowProc.h
Normal file
@ -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; }
|
||||
}
|
||||
}
|
1019
cwFlowTypes.cpp
Normal file
1019
cwFlowTypes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
323
cwFlowTypes.h
Normal file
323
cwFlowTypes.h
Normal file
@ -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>(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>(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 );
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user