Many updates and changes to cwFlow* and added Compressor processor.

This commit is contained in:
kevin 2021-08-22 22:41:33 -04:00
parent b5bf573748
commit b8dea27343
11 changed files with 1952 additions and 793 deletions

View File

@ -25,8 +25,8 @@ libcwSRC += src/libcw/cwSpScBuf.cpp src/libcw/cwSpScQu
libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwMidiFile.h libcwHDR += src/libcw/cwAudioFile.h src/libcw/cwMidiFile.h
libcwSRC += src/libcw/cwAudioFile.cpp src/libcw/cwMidiFile.cpp 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 libcwHDR += src/libcw/cwAudioFileOps.h src/libcw/cwAudioTransforms.h src/libcw/cwDspTransforms.h src/libcw/cwAudioFileProc.h src/libcw/cwPvAudioFileProc.h
libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp libcwSRC += src/libcw/cwAudioFileOps.cpp src/libcw/cwAudioTransforms.cpp src/libcw/cwDspTransforms.cpp src/libcw/cwAudioFileProc.cpp src/libcw/cwPvAudioFileProc.cpp
libcwHDR += src/libcw/cwFlow.h src/libcw/cwFlowTypes.h src/libcw/cwFlowProc.h 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 libcwSRC += src/libcw/cwFlow.cpp src/libcw/cwFlowTypes.cpp src/libcw/cwFlowProc.cpp

163
cwDspTransforms.cpp Normal file
View File

@ -0,0 +1,163 @@
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
#include "cwFile.h"
#include "cwText.h"
#include "cwObject.h"
#include "cwAudioFile.h"
#include "cwUtility.h"
#include "cwFileSys.h"
#include "cwAudioFileOps.h"
#include "cwVectOps.h"
#include "cwMath.h"
#include "cwDspTypes.h"
#include "cwDsp.h"
#include "cwDspTransforms.h"
namespace cw
{
namespace dsp
{
namespace compressor
{
void _ms_to_samples( obj_t*p, real_t ms, unsigned& outRef )
{
outRef = std::max((real_t)1,(real_t)floor(ms * p->srate / 1000.0));
}
}
}
}
cw::rc_t cw::dsp::compressor::create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio_num, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl )
{
p = mem::allocZ<obj_t>();
p->srate = srate;
p->procSmpCnt = procSmpCnt;
p->threshDb = threshDb;
p->ratio_num = ratio_num;
set_attack_ms(p,atkMs);
set_release_ms(p,rlsMs);
p->inGain = inGain;
p->outGain = outGain;
p->bypassFl = bypassFl;
p->rmsWndAllocCnt = (unsigned)std::max(1.0,floor(rmsWndMaxMs * srate / (1000.0 * procSmpCnt)));
p->rmsWnd = mem::allocZ<sample_t>(p->rmsWndAllocCnt);
set_rms_wnd_ms(p, rmsWndMs );
p->rmsWndIdx = 0;
p->state = kRlsCompId;
p->timeConstDb = 10.0;
p->accumDb = p->threshDb;
return kOkRC;
}
cw::rc_t cw::dsp::compressor::destroy( obj_t*& p )
{
mem::release(p->rmsWnd);
mem::release(p);
return kOkRC;
}
/*
The ratio determines to what degree a signal above the threshold is reduced.
Given a 2:1 ratio, a signal 2dB above the threshold will be reduced to 1db above the threshold.
Given a 4:1 ratio, a signal 2dB above the threshold will be reduced to 0.25db above the threshold.
Gain_reduction_db = (thresh - signal) / ratio_numerator (difference between the threshold and signal level after reduction)
Gain Coeff = 10^(gain_reduction_db / 20);
Total_reduction_db = signal - threshold + Gain_reduc_db
(total change in signal level)
The attack can be viewed as beginning at the threshold and moving to the peak
over some period of time. In linear terms this will go from 1.0 to the max gain
reductions. In this case we step from thresh to peak at a fixed rate in dB
based on the attack time.
Db: thresh - [thesh:peak] / ratio_num
Linear: pow(10, (thresh - [thesh:peak] / ratio_num)/20 );
During attacks p->accumDb increments toward the p->pkDb.
During release p->accumDb decrements toward the threshold.
(thresh - accumDb) / ratio_num gives the signal level which will be achieved
if this value is converted to linear form and applied as a gain coeff.
See compressor.m
*/
cw::rc_t cw::dsp::compressor::exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n )
{
sample_t xx[n];
vop::mul(xx,x,p->inGain,n); // apply input gain
p->rmsWnd[ p->rmsWndIdx ] = vop::rms(xx, n); // calc and store signal RMS
p->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer
real_t rmsLin = vop::mean(p->rmsWnd,p->rmsWndCnt); // calc avg RMS
real_t rmsDb = std::max(-100.0,20 * log10(std::max((real_t)0.00001,rmsLin))); // convert avg RMS to dB
rmsDb += 100.0;
// if the compressor is bypassed
if( p->bypassFl )
{
vop::copy(y,x,n); // copy through - with no input gain
return kOkRC;
}
// if the signal is above the threshold
if( rmsDb <= p->threshDb )
p->state = kRlsCompId;
else
{
if( rmsDb > p->pkDb )
p->pkDb = rmsDb;
p->state = kAtkCompId;
}
switch( p->state )
{
case kAtkCompId:
p->accumDb = std::min(p->pkDb, p->accumDb + p->timeConstDb * n / p->atkSmp );
break;
case kRlsCompId:
p->accumDb = std::max(p->threshDb, p->accumDb - p->timeConstDb * n / p->rlsSmp );
break;
}
p->gain = pow(10.0,(p->threshDb - p->accumDb) / (p->ratio_num * 20.0));
vop::mul(y,xx,p->gain * p->outGain,n);
return kOkRC;
}
void cw::dsp::compressor::set_attack_ms( obj_t* p, real_t ms )
{
_ms_to_samples(p,ms,p->atkSmp);
}
void cw::dsp::compressor::set_release_ms( obj_t* p, real_t ms )
{
_ms_to_samples(p,ms,p->rlsSmp);
}
void cw::dsp::compressor::set_rms_wnd_ms( obj_t* p, real_t ms )
{
p->rmsWndCnt = std::max((unsigned)1,(unsigned)floor(ms * p->srate / (1000.0 * p->procSmpCnt)));
// do not allow rmsWndCnt to exceed rmsWndAllocCnt
if( p->rmsWndCnt > p->rmsWndAllocCnt )
p->rmsWndCnt = p->rmsWndAllocCnt;
}

53
cwDspTransforms.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef cwDspTransforms_h
#define cwDspTransforms_h
namespace cw
{
namespace dsp
{
//---------------------------------------------------------------------------------------------------------------------------------
// compressor
//
namespace compressor
{
enum { kAtkCompId, kRlsCompId };
typedef struct
{
real_t srate; // system sample rate
unsigned procSmpCnt; // samples per exec cycle
real_t inGain; // input gain
real_t threshDb; // threshold in dB (max:100 min:0)
real_t ratio_num; // numerator of the ratio
unsigned atkSmp; // time to reduce the signal by 10.0 db
unsigned rlsSmp; // time to increase the signal by 10.0 db
real_t outGain; // makeup gain
bool bypassFl; // bypass enable
sample_t* rmsWnd; // rmsWnd[rmsWndAllocCnt]
unsigned rmsWndAllocCnt; //
unsigned rmsWndCnt; // current RMS window size (rmsWndCnt must be <= rmsWndAllocCnt)
unsigned rmsWndIdx; // next RMS window input index
unsigned state; // env. state
real_t rmsDb; // current incoming signal RMS (max:100 min:0)
real_t gain; // current compressor gain
real_t timeConstDb; // the atk/rls will incr/decr by 'timeConstDb' per atkMs/rlsMs.
real_t pkDb; //
real_t accumDb; //
} obj_t;
rc_t create( obj_t*& p, real_t srate, unsigned procSmpCnt, real_t inGain, real_t rmsWndMaxMs, real_t rmsWndMs, real_t threshDb, real_t ratio, real_t atkMs, real_t rlsMs, real_t outGain, bool bypassFl );
rc_t destroy( obj_t*& pp );
rc_t exec( obj_t* p, const sample_t* x, sample_t* y, unsigned n );
void set_attack_ms( obj_t* p, real_t ms );
void set_release_ms( obj_t* p, real_t ms );
void set_thresh_db( obj_t* p, real_t thresh );
void set_rms_wnd_ms( obj_t* p, real_t ms );
}
}
}
#endif

13
cwDspTypes.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef cwDspTypes_h
#define cwDspTypes_h
namespace cw
{
namespace dsp
{
typedef float real_t;
typedef real_t sample_t;
typedef real_t srate_t;
}
}
#endif

View File

@ -7,6 +7,7 @@
#include "cwAudioFile.h" #include "cwAudioFile.h"
#include "cwVectOps.h" #include "cwVectOps.h"
#include "cwMtx.h" #include "cwMtx.h"
#include "cwDspTypes.h" // real_t, sample_t
#include "cwFlow.h" #include "cwFlow.h"
#include "cwFlowTypes.h" #include "cwFlowTypes.h"
#include "cwFlowProc.h" #include "cwFlowProc.h"
@ -27,6 +28,7 @@ namespace cw
{ "pv_analysis", &pv_analysis::members }, { "pv_analysis", &pv_analysis::members },
{ "pv_synthesis", &pv_synthesis::members }, { "pv_synthesis", &pv_synthesis::members },
{ "spec_dist", &spec_dist::members }, { "spec_dist", &spec_dist::members },
{ "compressor", &compressor::members },
{ nullptr, nullptr } { nullptr, nullptr }
}; };
@ -102,7 +104,7 @@ namespace cw
} }
} }
// parse the value dictionary // parse the variable dictionary
if( varD != nullptr ) if( varD != nullptr )
{ {
if( !varD->is_dict() ) if( !varD->is_dict() )
@ -146,7 +148,7 @@ namespace cw
} }
// get the variable description // get the variable description
if((rc = var_obj->getv_opt("srcFl", srcVarFl)) != kOkRC ) if((rc = var_obj->getv_opt("srcFl", srcVarFl,"value",vd->val_cfg)) != kOkRC )
{ {
rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label ); rc = cwLogError(rc,"Parsing optional fields failed on class:%s variable: '%s'.", cd->label, vd->label );
goto errLabel; goto errLabel;
@ -206,14 +208,14 @@ namespace cw
} }
// locate source value // locate source value
if((rc = var_get( src_inst, suffix, kAnyChIdx, src_var)) != kOkRC ) if((rc = var_find( src_inst, suffix, kAnyChIdx, src_var)) != kOkRC )
{ {
rc = cwLogError(rc,"The source var '%s' was not found on the source instance '%s'.", cwStringNullGuard(suffix), cwStringNullGuard(sbuf)); rc = cwLogError(rc,"The source var '%s' was not found on the source instance '%s'.", cwStringNullGuard(suffix), cwStringNullGuard(sbuf));
goto errLabel; goto errLabel;
} }
// locate input value // locate input value
if((rc = var_get( in_inst, in_var_label, kAnyChIdx, in_var )) != kOkRC ) if((rc = var_find( in_inst, in_var_label, kAnyChIdx, in_var )) != kOkRC )
{ {
rc = cwLogError(rc,"The input value '%s' was not found on the instance '%s'.", cwStringNullGuard(in_var_label), cwStringNullGuard(in_inst->label)); rc = cwLogError(rc,"The input value '%s' was not found on the instance '%s'.", cwStringNullGuard(in_var_label), cwStringNullGuard(in_inst->label));
goto errLabel; goto errLabel;
@ -244,6 +246,9 @@ namespace cw
void _destroy_inst( instance_t* inst ) void _destroy_inst( instance_t* inst )
{ {
if( inst == nullptr )
return;
if( inst->class_desc->members->destroy != nullptr && inst->userPtr != nullptr ) if( inst->class_desc->members->destroy != nullptr && inst->userPtr != nullptr )
inst->class_desc->members->destroy( inst ); inst->class_desc->members->destroy( inst );
@ -252,7 +257,7 @@ namespace cw
variable_t* var1 = nullptr; variable_t* var1 = nullptr;
while( var0 != nullptr ) while( var0 != nullptr )
{ {
var1 = var0->link; var1 = var0->var_link;
_var_destroy(var0); _var_destroy(var0);
var0 = var1; var0 = var1;
} }
@ -262,27 +267,28 @@ namespace cw
mem::release(inst); mem::release(inst);
} }
rc_t _var_map_id_to_index( instance_t* inst, unsigned vid, unsigned chIdx, unsigned& idxRef );
rc_t _create_instance_var_map( instance_t* inst ) rc_t _create_instance_var_map( instance_t* inst )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
unsigned max_vid = kInvalidId; unsigned max_vid = kInvalidId;
unsigned max_chIdx = 0; unsigned max_chIdx = 0;
variable_t* var = inst->varL;
//variable_t* v0 = nullptr;
// determine the max variable vid and max channel index value among all variables // determine the max variable vid and max channel index value among all variables
for(variable_t* var=inst->varL; var!=nullptr; var=var->link) for(; var!=nullptr; var = var->var_link )
{ {
if( var->vid != kInvalidId )
if( var->vid == kInvalidId )
{ {
rc = cwLogError(kInvalidStateRC,"The variable '%s' on instance '%s' was not assigned an id.",var->label,inst->label);
goto errLabel;
}
if( max_vid == kInvalidId || var->vid > max_vid ) if( max_vid == kInvalidId || var->vid > max_vid )
max_vid = var->vid; max_vid = var->vid;
if( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx ) if( var->chIdx != kAnyChIdx && var->chIdx > max_chIdx )
max_chIdx = var->chIdx; max_chIdx = var->chIdx;
}
} }
// If there are any variables // If there are any variables
@ -295,11 +301,12 @@ namespace cw
inst->varMapA = mem::allocZ<variable_t*>( inst->varMapN ); inst->varMapA = mem::allocZ<variable_t*>( inst->varMapN );
// assign each variable to a location in the map // assign each variable to a location in the map
for(variable_t* var=inst->varL; var!=nullptr; var=var->link) for(variable_t* var=inst->varL; var!=nullptr; var=var->var_link)
if( var->vid != kInvalidId )
{ {
unsigned idx = kInvalidIdx; unsigned idx = kInvalidIdx;
if((rc = var_map_id_to_index( inst, var->vid, var->chIdx, idx )) != kOkRC ) if((rc = _var_map_id_to_index( inst, var->vid, var->chIdx, idx )) != kOkRC )
goto errLabel; goto errLabel;
@ -323,84 +330,237 @@ namespace cw
} }
rc_t _create_instance( flow_t* p, const object_t* inst_cfg ) rc_t _preset_channelize_vars( instance_t* inst, const char* type_src_label, const char* preset_label, const object_t* preset_cfg )
{
rc_t rc = kOkRC;
//cwLogInfo("Channelizing '%s' preset %i vars for '%s'.",type_src_label, preset_cfg==nullptr ? 0 : preset_cfg->child_count(), inst->label );
// validate the syntax of the preset record
if( !preset_cfg->is_dict() )
{
rc = cwLogError(kSyntaxErrorRC,"The preset record '%s' on %s '%s' is not a dictionary.", preset_label, type_src_label, inst->class_desc->label );
goto errLabel;
}
// for each preset variable
for(unsigned i=0; i<preset_cfg->child_count(); ++i)
{
const object_t* value = preset_cfg->child_ele(i)->pair_value();
const char* value_label = preset_cfg->child_ele(i)->pair_label();
variable_t* dummy = nullptr;
// verify that a valid value exists
if( value == nullptr )
{
rc = cwLogError(kSyntaxErrorRC,"Unexpected missig value on %s preset '%s' instance '%s' variable '%s'.", type_src_label, preset_label, inst->label, cwStringNullGuard(value_label) );
goto errLabel;
}
// if a list of values was given
if( value->is_list() )
{
for(unsigned chIdx=0; chIdx<value->child_count(); ++chIdx)
if((rc = var_channelize( inst, value_label, chIdx, value->child_ele(chIdx), dummy )) != kOkRC )
goto errLabel;
}
else // otherwise a single value was given
{
if((rc = var_channelize( inst, value_label, kAnyChIdx, value, dummy )) != kOkRC )
goto errLabel;
}
}
errLabel:
if( rc != kOkRC )
rc = cwLogError(rc,"Apply %s preset failed on instance:%s class:%s preset:%s.", type_src_label, inst->label, inst->class_desc->label, preset_label );
return rc;
}
rc_t _class_preset_channelize_vars( instance_t* inst, const char* preset_label )
{
rc_t rc = kOkRC;
const preset_t* pr;
if( preset_label == nullptr )
return kOkRC;
// locate the requestd preset record
if((pr = class_preset_find(inst->class_desc, preset_label)) == nullptr )
{
rc = cwLogError(kInvalidIdRC,"The preset '%s' could not be found for the instance '%s'.", preset_label, inst->label);
goto errLabel;
}
rc = _preset_channelize_vars( inst, "class", preset_label, pr->cfg);
errLabel:
return rc;
}
rc_t _class_apply_presets( instance_t* inst, const object_t* preset_labels )
{
rc_t rc = kOkRC;
const char* s = nullptr;
// if preset_labels is a string
if( preset_labels->is_string() && preset_labels->value(s)==kOkRC )
return _class_preset_channelize_vars(inst,s);
// if the preset_labels is a list
if( !preset_labels->is_list() )
rc = cwLogError(kSyntaxErrorRC,"The preset list on instance '%s' is neither a list nor a string.",inst->label);
else
{
// for each label listed in the preset label list
for(unsigned i=0; i<preset_labels->child_count(); ++i)
{
const object_t* label_obj = preset_labels->child_ele(i);
// verify that the label is a strng
if( !label_obj->is_string() || label_obj->value(s) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"The preset list does not contain string on instance '%s'.",inst->label);
goto errLabel;
}
// apply a preset label
if((rc = _class_preset_channelize_vars( inst, s)) != kOkRC )
goto errLabel;
}
}
errLabel:
return rc;
}
rc_t _inst_args_channelize_vars( instance_t* inst, const char* arg_label, const object_t* arg_cfg )
{
rc_t rc = kOkRC;
if( arg_cfg == nullptr )
return rc;
return _preset_channelize_vars( inst, "instance", arg_label, arg_cfg );
}
typedef struct inst_parse_vars_str
{
const char* inst_label;
const char* inst_clas_label;
const object_t* in_dict;
const char* arg_label;
const object_t* preset_labels;
const object_t* arg_cfg;
} inst_parse_vars_t;
rc_t _parse_instance_cfg( flow_t* p, const object_t* inst_cfg, inst_parse_vars_t& pvars )
{ {
rc_t rc = kOkRC; 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_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 // 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 ) if( inst_cfg == nullptr || !inst_cfg->is_pair() || inst_cfg->pair_label()==nullptr || inst_cfg->pair_value()==nullptr )
{ {
rc = cwLogError(kSyntaxErrorRC,"The instance cfg. is not a valid pair."); rc = cwLogError(kSyntaxErrorRC,"The instance cfg. is not a valid pair. No instance label could be parsed.");
goto errLabel; goto errLabel;
} }
inst_label = inst_cfg->pair_label(); pvars.inst_label = inst_cfg->pair_label();
// verify that the instance label is unique // verify that the instance label is unique
if( instance_find(p,inst_label) != nullptr ) if( instance_find(p,pvars.inst_label) != nullptr )
{ {
rc = cwLogError(kSyntaxErrorRC,"The instance label '%s' has already been used.",inst_label); rc = cwLogError(kSyntaxErrorRC,"The instance label '%s' has already been used.",pvars.inst_label);
goto errLabel; goto errLabel;
} }
// get the instance class label // get the instance class label
if((rc = inst_cfg->getv("class",inst_clas_label)) != kOkRC ) if((rc = inst_cfg->getv("class",pvars.inst_clas_label)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",inst_label); rc = cwLogError(kSyntaxErrorRC,"The instance cfg. %s is missing: 'type'.",pvars.inst_label);
goto errLabel; goto errLabel;
} }
// parse the optional args // parse the optional args
if((rc = inst_cfg->getv_opt("args", arg_dict, if((rc = inst_cfg->getv_opt("args", arg_dict,
"in", in_dict, "in", pvars.in_dict,
"argLabel", arg_label, "argLabel", pvars.arg_label,
"preset", preset_label)) != kOkRC ) "preset", pvars.preset_labels)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",inst_label); rc = cwLogError(kSyntaxErrorRC,"The instance cfg. '%s' missing: 'type'.",pvars.inst_label);
goto errLabel; goto errLabel;
} }
// if an argument dict was given // if an argument dict was given in the instanec cfg
if( arg_dict != nullptr ) if( arg_dict != nullptr )
{ {
bool rptErrFl = true; bool rptErrFl = true;
// if no label was given then try 'default' // verify the arg. dict is actually a dict.
if( arg_label == nullptr) if( !arg_dict->is_dict() )
{ {
arg_label = "default"; cwLogError(kSyntaxErrorRC,"The instance argument dictionary on instance '%s' is not a dictionary.",pvars.inst_label);
goto errLabel;
}
// if no label was given then try 'default'
if( pvars.arg_label == nullptr)
{
pvars.arg_label = "default";
rptErrFl = false; rptErrFl = false;
} }
if((arg_cfg = arg_dict->find_child(arg_label)) == nullptr ) // locate the specified argument record
if((pvars.arg_cfg = arg_dict->find_child(pvars.arg_label)) == nullptr )
{ {
// if an explicit arg. label was given but it was not found // if an explicit arg. label was given but it was not found
if( rptErrFl ) if( rptErrFl )
{ {
rc = cwLogError(kSyntaxErrorRC,"The argument cfg. '%s' was not found on instance cfg. '%s'.",arg_label,inst_label); rc = cwLogError(kSyntaxErrorRC,"The argument cfg. '%s' was not found on instance cfg. '%s'.",pvars.arg_label,pvars.inst_label);
goto errLabel; goto errLabel;
} }
// no explicit arg. label was given - make arg_dict the instance arg cff. // no explicit arg. label was given - make arg_dict the instance arg cfg.
arg_cfg = arg_dict; pvars.arg_cfg = arg_dict;
arg_label = nullptr; pvars.arg_label = nullptr;
} }
} }
// locate the class desc errLabel:
if(( class_desc = class_desc_find(p,inst_clas_label)) == nullptr ) if( rc != kOkRC )
rc = cwLogError(kSyntaxErrorRC,"Configuration parsing failed on instance: '%s'.", cwStringNullGuard(pvars.inst_label) );
return rc;
}
rc_t _create_instance( flow_t* p, const object_t* inst_cfg )
{ {
rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(inst_clas_label)); rc_t rc = kOkRC;
inst_parse_vars_t pvars = {0};
instance_t* inst = nullptr;
class_desc_t* class_desc = nullptr;
// parse the instance configuration
if((rc = _parse_instance_cfg( p, inst_cfg, pvars )) != kOkRC )
goto errLabel;
// locate the class desc
if(( class_desc = class_desc_find(p,pvars.inst_clas_label)) == nullptr )
{
rc = cwLogError(kSyntaxErrorRC,"The flow class '%s' was not found.",cwStringNullGuard(pvars.inst_clas_label));
goto errLabel; goto errLabel;
} }
@ -408,47 +568,67 @@ namespace cw
inst = mem::allocZ<instance_t>(); inst = mem::allocZ<instance_t>();
inst->ctx = p; inst->ctx = p;
inst->label = inst_label; inst->label = pvars.inst_label;
inst->inst_cfg = inst_cfg; inst->inst_cfg = inst_cfg;
inst->arg_label = arg_label; inst->arg_label = pvars.arg_label;
inst->arg_cfg = arg_cfg; inst->arg_cfg = pvars.arg_cfg;
inst->class_desc = class_desc; inst->class_desc = class_desc;
inst->preset_label = preset_label;
// Instantiate the variables which have the 'src' attribute. We need these variables // Instantiate all the variables in the class description
// 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) for(var_desc_t* vd=class_desc->varDescL; vd!=nullptr; vd=vd->link)
{ {
variable_t* var = nullptr; variable_t* var = nullptr;
if((rc = var_create( inst, vd->label, kInvalidId, kAnyChIdx, vd->val_cfg, var )) != kOkRC )
if( cwIsFlag(vd->flags,kSrcVarFl) )
{
if((rc = var_create( inst, vd->label, kInvalidId, kAnyChIdx, var )) != kOkRC )
goto errLabel; goto errLabel;
} }
}
// All the variables that can be used by this instance have now been created
// and the chIdx of each variable is set to 'any'.
// If a 'preset' field was included in the instance cfg then apply the specified class preset
if( pvars.preset_labels != nullptr )
if((rc = _class_apply_presets(inst, pvars.preset_labels )) != kOkRC )
goto errLabel;
// All the class presets values have now been set and those variables
// that were expressed with a list have numeric channel indexes assigned.
// Apply the instance preset values.
if( pvars.arg_cfg != nullptr )
if((rc = _inst_args_channelize_vars( inst, pvars.arg_label, pvars.arg_cfg )) != kOkRC )
goto errLabel;
// All the instance arg values have now been set and those variables
// that were expressed with a list have numeric channel indexes assigned.
// TODO: Should the 'all' variable be removed for variables that have numeric channel indexes.
// connect the variable lists in the instance 'in' dictionary // connect the variable lists in the instance 'in' dictionary
if( in_dict != nullptr && in_dict->is_dict() ) if( pvars.in_dict != nullptr )
{ {
// for each input if( !pvars.in_dict->is_dict() )
for(unsigned i=0; i<in_dict->child_count(); ++i)
{ {
const object_t* in_pair = in_dict->child_ele(i); cwLogError(kSyntaxErrorRC,"The 'in' dict in instance '%s' is not a valid dictionary.",inst->label);
goto errLabel;
}
// for each input variable in the 'in' set
for(unsigned i=0; i<pvars.in_dict->child_count(); ++i)
{
const object_t* in_pair = pvars.in_dict->child_ele(i);
const char* in_var_label = in_pair->pair_label(); const char* in_var_label = in_pair->pair_label();
const char* src_label = nullptr; const char* src_label = nullptr;
const var_desc_t* vd = nullptr; const var_desc_t* vd = nullptr;
// note // locate the var desc of the associated variable
if((vd = var_desc_find( class_desc, in_var_label)) == nullptr ) 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); 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; goto errLabel;
} }
// Note that all variable's found by the above call to var_desc_find() should be 'src' // Note that all variable's found by the above call to var_desc_find() should be 'src' variables.
// variables because they are the only ones that have been created so far.
assert( cwIsFlag(vd->flags,kSrcVarFl) ); assert( cwIsFlag(vd->flags,kSrcVarFl) );
// if this value is a 'src' value then it must be setup prior to the instance being instantiated // if this value is a 'src' value then it must be setup prior to the instance being instantiated
@ -459,7 +639,7 @@ namespace cw
// locate the pointer to the referenced output abuf and store it in inst->srcABuf[i] // 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 ) if((rc = _setup_input( p, inst, in_var_label, src_label )) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"The 'in' buffer at index %i is not valid on instance '%s'.", i, inst_label ); rc = cwLogError(kSyntaxErrorRC,"The 'in' buffer at index %i is not valid on instance '%s'.", i, inst->label );
goto errLabel; goto errLabel;
} }
} }
@ -467,16 +647,16 @@ namespace cw
} }
// complete the instantiation // complete the instantiation
if((rc = class_desc->members->create( inst )) != kOkRC ) if((rc = class_desc->members->create( inst )) != kOkRC )
{ {
rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s'.", inst_label ); rc = cwLogError(kInvalidArgRC,"Instantiation failed on instance '%s'.", inst->label );
goto errLabel; goto errLabel;
} }
if((rc =_create_instance_var_map( inst )) != kOkRC ) if((rc =_create_instance_var_map( inst )) != kOkRC )
goto errLabel; goto errLabel;
// insert an instance in the network // insert an instance in the network
if( p->network_tail == nullptr ) if( p->network_tail == nullptr )
{ {
@ -502,6 +682,9 @@ namespace cw
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
if( p == nullptr )
return rc;
instance_t* i0=p->network_head; instance_t* i0=p->network_head;
instance_t* i1=nullptr; instance_t* i1=nullptr;
@ -548,16 +731,18 @@ namespace cw
} }
} }
cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ) cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const object_t& networkCfg )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const object_t* network; const object_t* network;
bool printClassDictFl = false;
bool printNetworkFl = false;
if(( rc = destroy(hRef)) != kOkRC ) if(( rc = destroy(hRef)) != kOkRC )
return rc; return rc;
flow_t* p = mem::allocZ<flow_t>(); flow_t* p = mem::allocZ<flow_t>();
p->cfg = &cfg; // TODO: duplicate cfg? p->cfg = &networkCfg; // TODO: duplicate cfg?
// parse the class description array // parse the class description array
if((rc = _parse_class_cfg(p,library,&classCfg)) != kOkRC ) if((rc = _parse_class_cfg(p,library,&classCfg)) != kOkRC )
@ -567,20 +752,27 @@ cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const objec
} }
// parse the main audio file processor cfg record // parse the main audio file processor cfg record
if((rc = cfg.getv("framesPerCycle", p->framesPerCycle, if((rc = networkCfg.getv("framesPerCycle", p->framesPerCycle,
"network", network)) != kOkRC ) "network", network)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"Error parsing the required flow configuration parameters."); rc = cwLogError(kSyntaxErrorRC,"Error parsing the required flow configuration parameters.");
goto errLabel; goto errLabel;
} }
if((rc = cfg.getv_opt("maxCycleCount", p->maxCycleCount)) != kOkRC ) // parse the optional args
if((rc = networkCfg.getv_opt("maxCycleCount", p->maxCycleCount,
"printClassDictFl", printClassDictFl,
"printNetworkFl", printNetworkFl)) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters."); rc = cwLogError(kSyntaxErrorRC,"Error parsing the optional flow configuration parameters.");
goto errLabel; goto errLabel;
} }
// for each instance in the network // print the class dict
if( printClassDictFl )
class_dict_print( p );
// build the network
for(unsigned i=0; i<network->child_count(); ++i) for(unsigned i=0; i<network->child_count(); ++i)
{ {
const object_t* inst_cfg = network->child_ele(i); const object_t* inst_cfg = network->child_ele(i);
@ -590,18 +782,18 @@ cw::rc_t cw::flow::create( handle_t& hRef, const object_t& classCfg, const objec
{ {
rc = cwLogError(rc,"The instantiation at network index %i is invalid.",i); rc = cwLogError(rc,"The instantiation at network index %i is invalid.",i);
goto errLabel; goto errLabel;
} }
} }
// apply preset if( printNetworkFl )
for(instance_t* inst=p->network_head; inst!=nullptr; inst=inst->link) network_print(p);
if( inst->preset_label != nullptr )
if((rc = apply_preset( inst, inst->preset_label )) != kOkRC )
goto errLabel;
hRef.set(p); hRef.set(p);
errLabel: errLabel:
if( rc != kOkRC ) if( rc != kOkRC )
_destroy(p); _destroy(p);
@ -619,6 +811,12 @@ cw::rc_t cw::flow::exec( handle_t& hRef )
if((rc = inst->class_desc->members->exec(inst)) != kOkRC ) if((rc = inst->class_desc->members->exec(inst)) != kOkRC )
break; break;
if( rc == kEofRC )
{
rc = kOkRC;
break;
}
p->cycleIndex += 1; p->cycleIndex += 1;
if( p->maxCycleCount > 0 && p->cycleIndex >= p->maxCycleCount ) if( p->maxCycleCount > 0 && p->cycleIndex >= p->maxCycleCount )
break; break;
@ -646,7 +844,7 @@ cw::rc_t cw::flow::destroy( handle_t& hRef )
void cw::flow::print_class_list( handle_t& hRef ) void cw::flow::print_class_list( handle_t& hRef )
{ {
class_desc_print(_handleToPtr(hRef)); class_dict_print(_handleToPtr(hRef));
} }
void cw::flow::print_network( handle_t& hRef ) void cw::flow::print_network( handle_t& hRef )
@ -667,8 +865,6 @@ cw::rc_t cw::flow::test( const object_t* class_cfg, const object_t* cfg )
goto errLabel; goto errLabel;
} }
print_network(flowH);
// run the network // run the network
if((rc = exec( flowH )) != kOkRC ) if((rc = exec( flowH )) != kOkRC )
rc = cwLogError(rc,"Execution failed."); rc = cwLogError(rc,"Execution failed.");

View File

@ -11,7 +11,7 @@ namespace cw
typedef handle<struct flow_str> handle_t; typedef handle<struct flow_str> handle_t;
rc_t create( handle_t& hRef, const object_t& classCfg, const object_t& cfg ); rc_t create( handle_t& hRef, const object_t& classCfg, const object_t& networkCfg );
rc_t exec( handle_t& hRef ); rc_t exec( handle_t& hRef );
rc_t destroy( handle_t& hRef ); rc_t destroy( handle_t& hRef );

View File

@ -6,6 +6,8 @@
#include "cwAudioFile.h" #include "cwAudioFile.h"
#include "cwVectOps.h" #include "cwVectOps.h"
#include "cwMtx.h" #include "cwMtx.h"
#include "cwDspTypes.h" // real_t, sample_t
#include "cwFlow.h" #include "cwFlow.h"
#include "cwFlowTypes.h" #include "cwFlowTypes.h"
#include "cwFlowProc.h" #include "cwFlowProc.h"
@ -14,6 +16,7 @@
#include "cwMath.h" #include "cwMath.h"
#include "cwDsp.h" #include "cwDsp.h"
#include "cwAudioTransforms.h" #include "cwAudioTransforms.h"
#include "cwDspTransforms.h"
namespace cw namespace cw
{ {
@ -32,8 +35,6 @@ namespace cw
} inst_t; } inst_t;
rc_t create( instance_t* ctx ) rc_t create( instance_t* ctx )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
@ -83,6 +84,8 @@ namespace cw
{ {
enum enum
{ {
kFnamePId,
kEofFlPId,
kOutPId kOutPId
}; };
@ -101,17 +104,11 @@ namespace cw
inst_t* inst = mem::allocZ<inst_t>(); inst_t* inst = mem::allocZ<inst_t>();
ctx->userPtr = inst; ctx->userPtr = inst;
// get the audio filename // Register variable and get their current value
if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != kOkRC ) if((rc = var_register_and_get( ctx, kAnyChIdx,
kFnamePId, "fname", inst->filename,
kEofFlPId, "eofFl", inst->eofFl )) != kOkRC )
{ {
rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument.");
goto errLabel;
}
// get the 'eof' flag
if((rc = ctx->arg_cfg->getv_opt("eof",inst->eofFl)) != kOkRC )
{
rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument.");
goto errLabel; goto errLabel;
} }
@ -125,7 +122,7 @@ namespace cw
cwLogInfo("Audio '%s' srate:%f chs:%i frames:%i %f seconds.",inst->filename,info.srate,info.chCnt,info.frameCnt, info.frameCnt/info.srate ); 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 // create one output audio buffer
rc = var_abuf_create( ctx, "out", kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle ); rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, info.srate, info.chCnt, ctx->ctx->framesPerCycle );
errLabel: errLabel:
return rc; return rc;
@ -162,7 +159,7 @@ namespace cw
// verify that a source buffer exists // verify that a source buffer exists
if((rc = var_abuf_get(ctx,"out",kAnyChIdx,abuf)) != kOkRC ) if((rc = var_get(ctx,kOutPId,kAnyChIdx,abuf)) != kOkRC )
{ {
rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid audio output buffer.",ctx->label); rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid audio output buffer.",ctx->label);
} }
@ -186,7 +183,8 @@ namespace cw
.create = create, .create = create,
.destroy = destroy, .destroy = destroy,
.value = value, .value = value,
.exec = exec .exec = exec,
.report = nullptr
}; };
} }
@ -201,13 +199,15 @@ namespace cw
{ {
enum enum
{ {
kInPId kInPId,
kFnamePId
}; };
typedef struct typedef struct
{ {
audiofile::handle_t afH; audiofile::handle_t afH;
const char* filename; const char* filename;
unsigned durSmpN;
} inst_t; } inst_t;
rc_t create( instance_t* ctx ) rc_t create( instance_t* ctx )
@ -215,20 +215,14 @@ namespace cw
rc_t rc = kOkRC; // rc_t rc = kOkRC; //
unsigned audioFileBits = 0; // set audio file sample format to 'float32'. unsigned audioFileBits = 0; // set audio file sample format to 'float32'.
inst_t* inst = mem::allocZ<inst_t>(); // inst_t* inst = mem::allocZ<inst_t>(); //
abuf_t* src_abuf = nullptr; const abuf_t* src_abuf = nullptr;
ctx->userPtr = inst; ctx->userPtr = inst;
// get the audio filename // Register variables and get their current value
if((rc = ctx->arg_cfg->getv("fn",inst->filename)) != kOkRC ) if((rc = var_register_and_get( ctx, kAnyChIdx,
kFnamePId, "fname", inst->filename,
kInPId, "in", src_abuf)) != kOkRC )
{ {
rc = cwLogError(kInvalidArgRC,"The audio input file has no 'fn' argument.");
goto errLabel;
}
// verify that a source buffer exists
if((rc = var_abuf_get(ctx,"in",kAnyChIdx,src_abuf)) != kOkRC )
{
rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid input connection.",ctx->label);
goto errLabel; goto errLabel;
} }
@ -239,8 +233,6 @@ namespace cw
goto errLabel; goto errLabel;
} }
rc = var_init( ctx, kAnyChIdx, kInPId, "in", src_abuf);
errLabel: errLabel:
return rc; return rc;
} }
@ -275,7 +267,7 @@ namespace cw
inst_t* inst = (inst_t*)ctx->userPtr; inst_t* inst = (inst_t*)ctx->userPtr;
const abuf_t* src_abuf = nullptr; const abuf_t* src_abuf = nullptr;
if((rc = var_abuf_get(ctx,"in",kAnyChIdx,src_abuf)) != kOkRC ) if((rc = var_get(ctx,kInPId,kAnyChIdx,src_abuf)) != kOkRC )
rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid input connection.",ctx->label); rc = cwLogError(kInvalidStateRC,"The audio file instance '%s' does not have a valid input connection.",ctx->label);
else else
{ {
@ -286,6 +278,12 @@ namespace cw
if((rc = audiofile::writeFloat(inst->afH, src_abuf->frameN, src_abuf->chN, chBuf )) != kOkRC ) 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 ); rc = cwLogError(rc,"Audio file write failed on instance: '%s'.", ctx->label );
// print a minutes counter
inst->durSmpN += src_abuf->frameN;
if( inst->durSmpN % ((unsigned)src_abuf->srate*60) == 0 )
printf("%5.1f %s\n", inst->durSmpN/(src_abuf->srate*60));
} }
return rc; return rc;
@ -295,7 +293,8 @@ namespace cw
.create = create, .create = create,
.destroy = destroy, .destroy = destroy,
.value = value, .value = value,
.exec = exec .exec = exec,
.report = nullptr
}; };
} }
@ -310,12 +309,16 @@ namespace cw
enum { enum {
kInPId, kInPId,
kHopSmpNPId,
kWndSmpNPId,
kHzFlPId,
kOutPId kOutPId
}; };
typedef struct typedef struct
{ {
pv_t** pvA; // pvA[ srcBuf.chN ] pv_t** pvA; // pvA[ srcBuf.chN ]
unsigned pvN;
unsigned wndSmpN; unsigned wndSmpN;
unsigned hopSmpN; unsigned hopSmpN;
bool hzFl; bool hzFl;
@ -330,32 +333,19 @@ namespace cw
inst_t* inst = mem::allocZ<inst_t>(); inst_t* inst = mem::allocZ<inst_t>();
ctx->userPtr = inst; ctx->userPtr = inst;
// get the wnd/hop sample count if((rc = var_register_and_get( ctx, kAnyChIdx,
if((rc = ctx->arg_cfg->getv("wndSmpCnt",inst->wndSmpN, kInPId, "in", srcBuf,
"hopSmpCnt",inst->hopSmpN )) != kOkRC ) kHopSmpNPId, "hopSmpN", inst->hopSmpN,
kWndSmpNPId, "wndSmpN", inst->wndSmpN,
kHzFlPId, "hzFl", inst->hzFl )) != kOkRC )
{ {
rc = cwLogError(kSyntaxErrorRC,"PV Analysis required parameters parse failed on instance '%s'.",ctx->label);
goto errLabel;
}
// get the optional arg's.
if((rc = ctx->arg_cfg->getv_opt("hzFl",inst->hzFl)) != kOkRC )
{
rc = cwLogError(kSyntaxErrorRC,"PV Analysis optional parameters parse failed on instance '%s'.",ctx->label);
goto errLabel;
}
// verify that a source buffer exists
if((rc = var_abuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC )
{
rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label);
goto errLabel; goto errLabel;
} }
else else
{ {
flags = inst->hzFl ? dsp::pv_anl::kCalcHzPvaFl : dsp::pv_anl::kNoCalcHzPvaFl; flags = inst->hzFl ? dsp::pv_anl::kCalcHzPvaFl : dsp::pv_anl::kNoCalcHzPvaFl;
inst->pvA = mem::allocZ<pv_t*>( srcBuf->chN ); // allocate pv channel array inst->pvN = srcBuf->chN;
inst->pvA = mem::allocZ<pv_t*>( inst->pvN ); // allocate pv channel array
const sample_t* magV[ srcBuf->chN ]; const sample_t* magV[ srcBuf->chN ];
const sample_t* phsV[ srcBuf->chN ]; const sample_t* phsV[ srcBuf->chN ];
const sample_t* hzV[ srcBuf->chN ]; const sample_t* hzV[ srcBuf->chN ];
@ -374,11 +364,12 @@ namespace cw
hzV[i] = inst->pvA[i]->hzV; hzV[i] = inst->pvA[i]->hzV;
} }
if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != kOkRC ) if((rc = var_register( ctx, kAnyChIdx, kInPId, "in" )) != kOkRC )
goto errLabel; goto errLabel;
// create the fbuf 'out' // create the fbuf 'out'
rc = var_fbuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV ); rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, inst->pvA[0]->binCnt, inst->pvA[0]->hopSmpCnt, magV, phsV, hzV );
} }
errLabel: errLabel:
@ -390,6 +381,11 @@ namespace cw
rc_t rc = kOkRC; rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr; inst_t* inst = (inst_t*)ctx->userPtr;
for(unsigned i=0; i<inst->pvN; ++i)
destroy(inst->pvA[i]);
mem::release(inst->pvA);
mem::release(inst); mem::release(inst);
return rc; return rc;
@ -409,14 +405,14 @@ namespace cw
fbuf_t* dstBuf = nullptr; fbuf_t* dstBuf = nullptr;
// verify that a source buffer exists // verify that a source buffer exists
if((rc = var_abuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC )
{ {
rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label);
goto errLabel; goto errLabel;
} }
// verify that the dst buffer exits // verify that the dst buffer exits
if((rc = var_fbuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC )
{ {
rc = cwLogError(rc,"The instance '%s' does not have a valid output.",ctx->label); rc = cwLogError(rc,"The instance '%s' does not have a valid output.",ctx->label);
goto errLabel; goto errLabel;
@ -425,11 +421,17 @@ namespace cw
// for each input channel // for each input channel
for(unsigned i=0; i<srcBuf->chN; ++i) for(unsigned i=0; i<srcBuf->chN; ++i)
{ {
// call the PV analysis processor dstBuf->readyFlV[i] = false;
dsp::pv_anl::exec( inst->pvA[i], srcBuf->buf + i*srcBuf->frameN, srcBuf->frameN );
// call the PV analysis processor
if( dsp::pv_anl::exec( inst->pvA[i], srcBuf->buf + i*srcBuf->frameN, srcBuf->frameN ) )
{
// rescale the frequency domain magnitude // rescale the frequency domain magnitude
vop::mul(dstBuf->magV[i], dstBuf->binN/2, dstBuf->binN); vop::mul(dstBuf->magV[i], dstBuf->binN/2, dstBuf->binN);
dstBuf->readyFlV[i] = true;
}
} }
errLabel: errLabel:
@ -440,7 +442,8 @@ namespace cw
.create = create, .create = create,
.destroy = destroy, .destroy = destroy,
.value = value, .value = value,
.exec = exec .exec = exec,
.report = nullptr
}; };
} }
@ -461,6 +464,7 @@ namespace cw
typedef struct typedef struct
{ {
pv_t** pvA; // pvA[ srcBuf.chN ] pv_t** pvA; // pvA[ srcBuf.chN ]
unsigned pvN;
unsigned wndSmpN; // unsigned wndSmpN; //
unsigned hopSmpN; // unsigned hopSmpN; //
bool hzFl; // bool hzFl; //
@ -474,18 +478,16 @@ namespace cw
inst_t* inst = mem::allocZ<inst_t>(); inst_t* inst = mem::allocZ<inst_t>();
ctx->userPtr = inst; ctx->userPtr = inst;
if((rc = var_register_and_get( ctx, kAnyChIdx,kInPId, "in", srcBuf)) != kOkRC )
// 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; goto errLabel;
} }
else else
{ {
// allocate pv channel array // allocate pv channel array
inst->pvA = mem::allocZ<pv_t*>( srcBuf->chN ); inst->pvN = srcBuf->chN;
inst->pvA = mem::allocZ<pv_t*>( inst->pvN );
// create a pv anlaysis object for each input channel // create a pv anlaysis object for each input channel
for(unsigned i=0; i<srcBuf->chN; ++i) for(unsigned i=0; i<srcBuf->chN; ++i)
@ -499,11 +501,11 @@ namespace cw
} }
} }
if((rc = var_init( ctx, kAnyChIdx, kInPId, "in", srcBuf )) != kOkRC ) if((rc = var_register( ctx, kAnyChIdx, kInPId, "in" )) != kOkRC )
goto errLabel; goto errLabel;
// create the abuf 'out' // create the abuf 'out'
rc = var_abuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle ); rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, ctx->ctx->framesPerCycle );
} }
errLabel: errLabel:
@ -515,6 +517,10 @@ namespace cw
rc_t rc = kOkRC; rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr; inst_t* inst = (inst_t*)ctx->userPtr;
for(unsigned i=0; i<inst->pvN; ++i)
destroy(inst->pvA[i]);
mem::release(inst->pvA);
mem::release(inst); mem::release(inst);
return rc; return rc;
@ -534,18 +540,23 @@ namespace cw
abuf_t* dstBuf = nullptr; abuf_t* dstBuf = nullptr;
// get the src buffer // get the src buffer
if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC )
goto errLabel; goto errLabel;
// get the dst buffer // get the dst buffer
if((rc = var_abuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC )
goto errLabel; goto errLabel;
for(unsigned i=0; i<srcBuf->chN; ++i) for(unsigned i=0; i<srcBuf->chN; ++i)
{ {
if( srcBuf->readyFlV[i] )
dsp::pv_syn::exec( inst->pvA[i], srcBuf->magV[i], srcBuf->phsV[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 ); const sample_t* ola_out = dsp::ola::execOut(inst->pvA[i]->ola);
if( ola_out != nullptr )
abuf_set_channel( dstBuf, i, ola_out, inst->pvA[i]->ola->procSmpCnt );
//abuf_set_channel( dstBuf, i, inst->pvA[i]->ola->outV, dstBuf->frameN );
} }
@ -557,7 +568,8 @@ namespace cw
.create = create, .create = create,
.destroy = destroy, .destroy = destroy,
.value = value, .value = value,
.exec = exec .exec = exec,
.report = nullptr
}; };
} }
@ -585,6 +597,7 @@ namespace cw
typedef struct typedef struct
{ {
spec_dist_t** sdA; spec_dist_t** sdA;
unsigned sdN;
} inst_t; } inst_t;
@ -597,7 +610,7 @@ namespace cw
ctx->userPtr = inst; ctx->userPtr = inst;
// verify that a source buffer exists // verify that a source buffer exists
if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC )
{ {
rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label); rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label);
goto errLabel; goto errLabel;
@ -605,12 +618,15 @@ namespace cw
else else
{ {
// allocate pv channel array // allocate pv channel array
inst->sdA = mem::allocZ<spec_dist_t*>( srcBuf->chN ); inst->sdN = srcBuf->chN;
inst->sdA = mem::allocZ<spec_dist_t*>( inst->sdN );
const sample_t* magV[ srcBuf->chN ]; const sample_t* magV[ srcBuf->chN ];
const sample_t* phsV[ srcBuf->chN ]; const sample_t* phsV[ srcBuf->chN ];
const sample_t* hzV[ srcBuf->chN ]; const sample_t* hzV[ srcBuf->chN ];
//if((rc = var_register(ctx, kAnyChIdx, kInPId, "in")) != kOkRC )
// goto errLabel;
// create a spec_dist object for each input channel // create a spec_dist object for each input channel
for(unsigned i=0; i<srcBuf->chN; ++i) for(unsigned i=0; i<srcBuf->chN; ++i)
@ -626,14 +642,15 @@ namespace cw
phsV[i] = inst->sdA[i]->outPhsV; phsV[i] = inst->sdA[i]->outPhsV;
hzV[i] = nullptr; hzV[i] = nullptr;
if((rc = var_init( ctx, i, spec_dist_t* sd = inst->sdA[i];
kInPId, "in", srcBuf,
kCeilingPId, "ceiling", 30.0f, if((rc = var_register_and_get( ctx, i,
kExpoPId, "expo", 3.0f, kCeilingPId, "ceiling", sd->ceiling,
kThreshPId, "thresh", 54.0f, kExpoPId, "expo", sd->expo,
kUprSlopePId,"uprSlope", -0.7f, kThreshPId, "thresh", sd->thresh,
kLwrSlopePId,"lwrSlope", 2.0f, kUprSlopePId, "upr", sd->uprSlope,
kMixPId, "mix", 0.0f )) != kOkRC ) kLwrSlopePId, "lwr", sd->lwrSlope,
kMixPId, "mix", sd->mix )) != kOkRC )
{ {
goto errLabel; goto errLabel;
} }
@ -641,7 +658,7 @@ namespace cw
} }
// create the output buffer // create the output buffer
if((rc = var_fbuf_create( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->binN, srcBuf->hopSmpN, magV, phsV, hzV )) != kOkRC ) if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->binN, srcBuf->hopSmpN, magV, phsV, hzV )) != kOkRC )
goto errLabel; goto errLabel;
} }
@ -654,6 +671,10 @@ namespace cw
rc_t rc = kOkRC; rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr; inst_t* inst = (inst_t*)ctx->userPtr;
for(unsigned i=0; i<inst->sdN; ++i)
destroy(inst->sdA[i]);
mem::release(inst->sdA);
mem::release(inst); mem::release(inst);
return rc; return rc;
@ -662,6 +683,23 @@ namespace cw
rc_t value( instance_t* ctx, variable_t* var ) rc_t value( instance_t* ctx, variable_t* var )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr;
if( var->chIdx != kAnyChIdx && var->chIdx < inst->sdN )
{
switch( var->vid )
{
case kCeilingPId: var_get( var, inst->sdA[ var->chIdx ]->ceiling ); break;
case kExpoPId: var_get( var, inst->sdA[ var->chIdx ]->expo ); break;
case kThreshPId: var_get( var, inst->sdA[ var->chIdx ]->thresh ); break;
case kUprSlopePId: var_get( var, inst->sdA[ var->chIdx ]->uprSlope ); break;
case kLwrSlopePId: var_get( var, inst->sdA[ var->chIdx ]->lwrSlope ); break;
case kMixPId: var_get( var, inst->sdA[ var->chIdx ]->mix ); break;
default:
cwLogWarning("Unhandled variable id '%i' on instance: %s.", var->vid, ctx->label );
}
}
return rc; return rc;
} }
@ -671,23 +709,30 @@ namespace cw
inst_t* inst = (inst_t*)ctx->userPtr; inst_t* inst = (inst_t*)ctx->userPtr;
const fbuf_t* srcBuf = nullptr; const fbuf_t* srcBuf = nullptr;
fbuf_t* dstBuf = nullptr; fbuf_t* dstBuf = nullptr;
unsigned chN = 0;
// get the src buffer // get the src buffer
if((rc = var_fbuf_get(ctx,"in", kAnyChIdx, srcBuf )) != kOkRC ) if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC )
goto errLabel; goto errLabel;
// get the dst buffer // get the dst buffer
if((rc = var_fbuf_get(ctx,"out", kAnyChIdx, dstBuf)) != kOkRC ) if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC )
goto errLabel; goto errLabel;
for(unsigned i=0; i<srcBuf->chN; ++i) chN = std::min(srcBuf->chN,inst->sdN);
for(unsigned i=0; i<chN; ++i)
{
dstBuf->readyFlV[i] = false;
if( srcBuf->readyFlV[i] )
{ {
dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN ); dsp::spec_dist::exec( inst->sdA[i], srcBuf->magV[i], srcBuf->phsV[i], srcBuf->binN );
//if( i == 0 ) dstBuf->readyFlV[i] = true;
//If == 0 )
// printf("%f %f\n", vop::sum(srcBuf->magV[i],srcBuf->binN), vop::sum(dstBuf->magV[i], dstBuf->binN) ); // printf("%f %f\n", vop::sum(srcBuf->magV[i],srcBuf->binN), vop::sum(dstBuf->magV[i], dstBuf->binN) );
} }
}
errLabel: errLabel:
return rc; return rc;
@ -697,10 +742,200 @@ namespace cw
.create = create, .create = create,
.destroy = destroy, .destroy = destroy,
.value = value, .value = value,
.exec = exec .exec = exec,
.report = nullptr
}; };
} }
//------------------------------------------------------------------------------------------------------------------
//
// Compressor
//
namespace compressor
{
enum
{
kInPId,
kBypassPId,
kInGainPId,
kThreshPId,
kRatioPId,
kAtkMsPId,
kRlsMsPId,
kWndMsPId,
kMaxWndMsPId,
kOutGainPId,
kOutPId,
kEnvPId
};
typedef dsp::compressor::obj_t compressor_t;
typedef struct
{
compressor_t** cmpA;
unsigned cmpN;
} inst_t;
rc_t create( instance_t* ctx )
{
rc_t rc = kOkRC;
const abuf_t* srcBuf = nullptr; //
inst_t* inst = mem::allocZ<inst_t>();
ctx->userPtr = inst;
// verify that a source buffer exists
if((rc = var_register_and_get(ctx, kAnyChIdx,kInPId,"in",srcBuf )) != kOkRC )
{
rc = cwLogError(rc,"The instance '%s' does not have a valid input connection.",ctx->label);
goto errLabel;
}
else
{
// allocate pv channel array
inst->cmpN = srcBuf->chN;
inst->cmpA = mem::allocZ<compressor_t*>( inst->cmpN );
// create a compressor object for each input channel
for(unsigned i=0; i<srcBuf->chN; ++i)
{
real_t igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain, bypassFl;
// get the compressor variable values
if((rc = var_register_and_get( ctx, i,
kBypassPId, "bypass", bypassFl,
kInGainPId, "igain", igain,
kThreshPId, "thresh", thresh,
kRatioPId, "ratio", ratio,
kAtkMsPId, "atk_ms", atk_ms,
kRlsMsPId, "rls_ms", rls_ms,
kWndMsPId, "wnd_ms", wnd_ms,
kMaxWndMsPId, "maxWnd_ms", maxWnd_ms,
kOutGainPId, "ogain", ogain )) != kOkRC )
{
goto errLabel;
}
// create the compressor instance
if((rc = dsp::compressor::create( inst->cmpA[i], srcBuf->srate, srcBuf->frameN, igain, maxWnd_ms, wnd_ms, thresh, ratio, atk_ms, rls_ms, ogain, bypassFl)) != kOkRC )
{
rc = cwLogError(kOpFailRC,"The 'compressor' object create failed on the instance '%s'.",ctx->label);
goto errLabel;
}
}
// create the output audio buffer
if((rc = var_register_and_set( ctx, "out", kOutPId, kAnyChIdx, srcBuf->srate, srcBuf->chN, srcBuf->frameN )) != kOkRC )
goto errLabel;
}
errLabel:
return rc;
}
rc_t destroy( instance_t* ctx )
{
rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr;
for(unsigned i=0; i<inst->cmpN; ++i)
destroy(inst->cmpA[i]);
mem::release(inst->cmpA);
mem::release(inst);
return rc;
}
rc_t value( instance_t* ctx, variable_t* var )
{
rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr;
real_t tmp;
if( var->chIdx != kAnyChIdx && var->chIdx < inst->cmpN )
{
switch( var->vid )
{
case kBypassPId: var_get( var, inst->cmpA[ var->chIdx ]->bypassFl ); break;
case kInGainPId: var_get( var, inst->cmpA[ var->chIdx ]->inGain ); break;
case kOutGainPId: var_get( var, inst->cmpA[ var->chIdx ]->outGain ); break;
case kRatioPId: var_get( var, inst->cmpA[ var->chIdx ]->ratio_num ); break;
case kThreshPId: var_get( var, inst->cmpA[ var->chIdx ]->threshDb ); break;
case kAtkMsPId: var_get( var, tmp ); set_attack_ms(inst->cmpA[ var->chIdx ], tmp ); break;
case kRlsMsPId: var_get( var, tmp ); set_release_ms(inst->cmpA[ var->chIdx ], tmp ); break;
case kWndMsPId: var_get( var, tmp ); set_rms_wnd_ms(inst->cmpA[ var->chIdx ], tmp ); break;
default:
cwLogWarning("Unhandled variable id '%i' on instance: %s.", var->vid, ctx->label );
}
}
return rc;
}
rc_t exec( instance_t* ctx )
{
rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr;
const abuf_t* srcBuf = nullptr;
abuf_t* dstBuf = nullptr;
unsigned chN = 0;
// get the src buffer
if((rc = var_get(ctx,kInPId, kAnyChIdx, srcBuf )) != kOkRC )
goto errLabel;
// get the dst buffer
if((rc = var_get(ctx,kOutPId, kAnyChIdx, dstBuf)) != kOkRC )
goto errLabel;
chN = std::min(srcBuf->chN,inst->cmpN);
for(unsigned i=0; i<chN; ++i)
{
dsp::compressor::exec( inst->cmpA[i], srcBuf->buf + i*srcBuf->frameN, dstBuf->buf + i*srcBuf->frameN, srcBuf->frameN );
}
errLabel:
return rc;
}
rc_t report( instance_t* ctx )
{
rc_t rc = kOkRC;
inst_t* inst = (inst_t*)ctx->userPtr;
for(unsigned i=0; i<inst->cmpN; ++i)
{
compressor_t* c = inst->cmpA[i];
cwLogInfo("%s ch:%i : sr:%f bypass:%i procSmpN:%i igain:%f threshdb:%f ratio:%f atkSmp:%i rlsSmp:%i ogain:%f rmsWndN:%i maxRmsWndN%i",
ctx->label,i,c->srate,c->bypassFl,c->procSmpCnt,c->inGain,c->threshDb,c->ratio_num,c->atkSmp,c->rlsSmp,c->outGain,c->rmsWndCnt,c->rmsWndAllocCnt
);
}
return rc;
}
class_members_t members = {
.create = create,
.destroy = destroy,
.value = value,
.exec = exec,
.report = report
};
}
} }
} }

View File

@ -7,5 +7,6 @@ namespace cw
namespace pv_analysis { extern class_members_t members; } namespace pv_analysis { extern class_members_t members; }
namespace pv_synthesis { extern class_members_t members; } namespace pv_synthesis { extern class_members_t members; }
namespace spec_dist { extern class_members_t members; } namespace spec_dist { extern class_members_t members; }
namespace compressor { extern class_members_t members; }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,14 @@ namespace cw
namespace flow namespace flow
{ {
typedef float real_t; #define kRealTFl kFloatTFl
typedef real_t sample_t; typedef dsp::real_t real_t;
typedef real_t srate_t; typedef dsp::sample_t sample_t;
typedef dsp::srate_t srate_t;
typedef unsigned uint_t; typedef unsigned uint_t;
typedef int int_t; typedef int int_t;
typedef unsigned vid_t; typedef unsigned vid_t;
typedef struct abuf_str typedef struct abuf_str
@ -37,6 +39,7 @@ namespace cw
sample_t** magV; // magV[ chN ][ binN ] sample_t** magV; // magV[ chN ][ binN ]
sample_t** phsV; // phsV[ chN ][ binN ] sample_t** phsV; // phsV[ chN ][ binN ]
sample_t** hzV; // hzV[ chN ][ binN ] sample_t** hzV; // hzV[ chN ][ binN ]
bool* readyFlV;// readyFlV[chN] true if this channel is ready to be processed (used to sync. fbuf rate to abuf rate)
sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer) sample_t* buf; // memory used by this buffer (or NULL if magV,phsV,hzV point are proxied to another buffer)
} fbuf_t; } fbuf_t;
@ -46,24 +49,22 @@ namespace cw
kBoolTFl = 0x00000001, kBoolTFl = 0x00000001,
kUIntTFl = 0x00000002, kUIntTFl = 0x00000002,
kIntTFl = 0x00000004, kIntTFl = 0x00000004,
kRealTFl = 0x00000008, kFloatTFl = 0x00000008,
kF32TFl = 0x00000010, kDoubleTFl = 0x00000010,
kF64TFl = 0x00000020,
kBoolMtxTFl = 0x00000040, kBoolMtxTFl = 0x00000020,
kUIntMtxTFl = 0x00000080, kUIntMtxTFl = 0x00000040,
kIntMtxTFl = 0x00000100, kIntMtxTFl = 0x00000080,
kRealMtxTFl = 0x00000200, kRealMtxTFl = 0x00000100,
kF32MtxTFl = 0x00000400, kFloatMtxTFl = 0x00000200,
kF64MtxTFl = 0x00000800, kDoubleMtxTFl= 0x00000400,
kABufTFl = 0x00001000, kABufTFl = 0x00000800,
kFBufTFl = 0x00002000, kFBufTFl = 0x00001000,
kStringTFl = 0x00004000, kStringTFl = 0x00002000,
kFNameTFl = 0x00008000, kTimeTFl = 0x00004000,
kTimeTFl = 0x00010000,
kTypeMask = 0x0001ffff, kTypeMask = 0x00007fff,
}; };
@ -85,7 +86,6 @@ namespace cw
bool b; bool b;
uint_t u; uint_t u;
int_t i; int_t i;
real_t r;
float f; float f;
double d; double d;
@ -97,20 +97,19 @@ namespace cw
char* s; char* s;
char* fname; char* fname;
struct value_str* proxy;
} u; } u;
struct value_str* link; struct value_str* link;
} value_t; } value_t;
inline bool is_numeric( const value_t* v ) { return cwIsFlag(v->flags,kBoolTFl|kUIntTFl|kIntTFl|kFloatTFl|kDoubleTFl); }
inline bool is_matrix( const value_t* v ) { return cwIsFlag(v->flags,kBoolMtxTFl|kUIntMtxTFl|kIntMtxTFl|kFloatMtxTFl|kDoubleMtxTFl); }
struct instance_str; struct instance_str;
struct variable_str; struct variable_str;
typedef struct ctx_str
{
} ctx_t;
typedef rc_t (*member_func_t)( struct instance_str* ctx ); 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 ); typedef rc_t (*member_value_func_t)( struct instance_str* ctx, struct variable_str* var );
enum enum
@ -124,16 +123,18 @@ namespace cw
member_func_t destroy; member_func_t destroy;
member_value_func_t value; member_value_func_t value;
member_func_t exec; member_func_t exec;
member_func_t report;
} class_members_t; } class_members_t;
typedef struct var_desc_str typedef struct var_desc_str
{ {
const object_t* cfg; // const object_t* cfg; // The cfg object that describes this variable from 'flow_class'.
const char* label; // const object_t* val_cfg; // An object containing the default value for this variable.
unsigned type; // value type id const char* label; // Name of this var.
unsigned flags; // unsigned type; // Value type id (e.g. kBoolTFl, kIntTFl, ...)
const char* docText; // unsigned flags; // Attributes for this var. (e.g. kSrcVarFl )
struct var_desc_str* link; // const char* docText; // User help string for this var.
struct var_desc_str* link; // class_desc->varDescL list link
} var_desc_t; } var_desc_t;
typedef struct preset_str typedef struct preset_str
@ -153,6 +154,8 @@ namespace cw
} class_desc_t; } class_desc_t;
// Note: The concatenation of 'vid' and 'chIdx' should form a unique identifier among all variables
// on a given 'instance'.
typedef struct variable_str typedef struct variable_str
{ {
struct instance_str* inst; // pointer to this variables instance struct instance_str* inst; // pointer to this variables instance
@ -162,8 +165,9 @@ namespace cw
value_t local_value; // the local value instance (actual value if this is not a 'src' variable) value_t 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 value_t* value; // pointer to the value associated with this variable
unsigned chIdx; // channel index unsigned chIdx; // channel index
struct variable_str* link; // link to other var's on 'inst' struct variable_str* var_link; // link to other var's on 'inst'
struct variable_str* connect_link; // list of outgoing connections struct variable_str* connect_link; // list of outgoing connections
struct variable_str* ch_link; // list of channels that share this variable (rooted on 'any' channel - in order by channel number)
} variable_t; } variable_t;
@ -178,7 +182,6 @@ namespace cw
const char* arg_label; // optional args label const char* arg_label; // optional args label
const object_t* arg_cfg; // optional args configuration const object_t* arg_cfg; // optional args configuration
const char* preset_label; // optional preset label
void* userPtr; // instance state void* userPtr; // instance state
@ -214,11 +217,13 @@ namespace cw
abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN ); abuf_t* abuf_create( srate_t srate, unsigned chN, unsigned frameN );
void abuf_destroy( abuf_t* buf ); void abuf_destroy( abuf_t* buf );
abuf_t* abuf_duplicate( const abuf_t* src );
rc_t abuf_set_channel( abuf_t* buf, unsigned chIdx, const sample_t* v, unsigned vN ); 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 ); 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 ); 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 ); void fbuf_destroy( fbuf_t* buf );
fbuf_t* fbuf_duplicate( const fbuf_t* src );
inline bool value_is_abuf( const value_t* v ) { return v->flags & kABufTFl; } inline bool value_is_abuf( const value_t* v ) { return v->flags & kABufTFl; }
inline bool value_is_fbuf( const value_t* v ) { return v->flags & kFBufTFl; } inline bool value_is_fbuf( const value_t* v ) { return v->flags & kFBufTFl; }
@ -234,7 +239,14 @@ namespace cw
rc_t var_desc_find( class_desc_t* cd, const char* label, var_desc_t*& vdRef ); 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 ); class_desc_t* class_desc_find( flow_t* p, const char* class_desc_label );
void class_desc_print( flow_t* p );
void class_dict_print( flow_t* p );
//------------------------------------------------------------------------------------------------------------------------
//
// Network
//
void network_print( flow_t* p ); void network_print( flow_t* p );
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
@ -252,72 +264,163 @@ namespace cw
// //
// Create a variable but do not assign it a value. Return a pointer to the new variable. // Create a variable but do not assign it a value. Return a pointer to the new variable.
rc_t var_create( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef ); // Note: `value_cfg` is optional. Set it to NULL to ignore
rc_t var_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
// var_init(). If the variable has not yet been created then it is created and assigned a value. // Channelizing creates a new var record with an explicit channel index to replace the
// If the variable has already been created then 'vid' and the value are updated. // automatically generated variable whose channel index is set to 'all'.
// (Note that abuf and fbuf values are not changed by this function only the 'vid' is updated.) rc_t var_channelize( instance_t* inst, const char* var_label, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
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; } // `value_cfg` is optional. Set it to NULL to ignore
rc_t var_register( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, const object_t* value_cfg, variable_t*& varRef );
template< typename T0, typename T1, typename T2, typename... ARGS >
rc_t _var_init( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2 val, ARGS&&... args ) //-----------------
//
// var_register
//
inline rc_t _var_reg(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
template< typename T0, typename T1, typename... ARGS >
rc_t _var_reg( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, ARGS&&... args )
{ {
rc_t rc; rc_t rc;
variable_t* dummy = nullptr;
if((rc = var_init( inst, var_label, vid, chIdx, val )) == kOkRC ) if((rc = var_register( inst, var_label, vid, chIdx, nullptr, dummy )) == kOkRC )
rc = _var_init( inst, chIdx, std::forward<ARGS>(args)...); if((rc = _var_reg( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
return rc;
return rc; return rc;
} }
// Call var_init() on a list of variables. // Call var_register() on a list of variables.
template< typename... ARGS > template< typename... ARGS >
rc_t var_init( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args ) rc_t var_register( 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)...); } { return _var_reg( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
//---------------------
//
// var_register_and_get
//
inline rc_t _var_register_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
template< typename T>
rc_t var_register_and_get( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, T& valRef )
{
rc_t rc;
variable_t* var;
if((rc = var_register(inst,var_label,vid,chIdx,nullptr,var)) == kOkRC )
rc = var_get(var,valRef);
return rc;
}
inline rc_t _var_reg_and_get(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
template< typename T0, typename T1, typename T2, typename... ARGS >
rc_t _var_reg_and_get( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2& valRef, ARGS&&... args )
{
rc_t rc;
if((rc = var_register_and_get( inst, var_label, vid, chIdx, valRef )) == kOkRC )
if((rc = _var_reg_and_get( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
return rc;
return rc;
}
// Call var_register_and_get() on a list of variables.
template< typename... ARGS >
rc_t var_register_and_get( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
{ return _var_reg_and_get( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
//---------------------
//
// var_register_and_set
//
// var_register_and_set(). If the variable has not yet been created then it is created and assigned a value.
// If the variable has already been created then 'vid' and the value are updated.
// (Note that abuf and fbuf values are not changed by this function only the 'vid' is updated.)
rc_t var_register_and_set( instance_t* inst, const char* label, unsigned vid, unsigned chIdx, variable_t*& varRef );
rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN );
rc_t var_register_and_set( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr );
inline rc_t _var_register_and_set(cw::flow::instance_t*, unsigned int ) { return kOkRC; }
template< typename T0, typename T1, typename T2, typename... ARGS >
rc_t _var_register_and_set( instance_t* inst, unsigned chIdx, T0 vid, T1 var_label, T2 val, ARGS&&... args )
{
rc_t rc;
variable_t* var = nullptr;
if((rc = var_register_and_set( inst, var_label, vid, chIdx, var)) == kOkRC )
{
var_set( var, val );
if((rc = _var_register_and_set( inst, chIdx, std::forward<ARGS>(args)...)) != kOkRC )
return rc;
}
return rc;
}
// Call var_register_and_set() on a list of variables.
template< typename... ARGS >
rc_t var_register_and_set( instance_t* inst, unsigned chIdx, unsigned vid, const char* var_label, ARGS&&... args )
{ return _var_register_and_set( inst, chIdx, vid, var_label, std::forward<ARGS>(args)...); }
void _var_destroy( variable_t* var ); void _var_destroy( variable_t* var );
bool var_exists( instance_t* inst, const char* label, unsigned chIdx ); 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_find( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& varRef );
rc_t var_get( instance_t* inst, const char* var_label, unsigned chIdx, const variable_t*& vRef ); rc_t var_find( instance_t* inst, const char* var_label, unsigned chIdx, variable_t*& varRef );
rc_t var_find( instance_t* inst, unsigned vid, unsigned chIdx, variable_t*& varRef );
rc_t value_get( instance_t* inst, const char* label, unsigned chIdx, value_t*& vRef ); rc_t var_get( const variable_t* var, bool& valRef );
rc_t value_get( instance_t* inst, const char* label, unsigned chIdx, const value_t*& vRef ); rc_t var_get( const variable_t* var, uint_t& valRef );
rc_t var_get( const variable_t* var, int_t& valRef );
rc_t var_abuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned frameN ); rc_t var_get( const variable_t* var, float& valRef );
rc_t var_fbuf_create( instance_t* inst, const char* var_label, unsigned vid, unsigned chIdx, srate_t srate, unsigned chN, unsigned binN, unsigned hopSmpN, const sample_t** magV=nullptr, const sample_t** phsV=nullptr, const sample_t** hzV=nullptr ); rc_t var_get( const variable_t* var, double& valRef );
rc_t var_get( const variable_t* var, const char*& valRef );
rc_t var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, abuf_t*& abufRef ); rc_t var_get( const variable_t* var, const abuf_t*& valRef );
rc_t var_abuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const abuf_t*& abufRef ); rc_t var_get( variable_t* var, abuf_t*& valRef );
rc_t var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, fbuf_t*& fbufRef ); rc_t var_get( const variable_t* var, const fbuf_t*& valRef );
rc_t var_fbuf_get( instance_t* inst, const char* var_label, unsigned chIdx, const fbuf_t*& fbufRef ); rc_t var_get( variable_t* var, fbuf_t*& valRef );
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 ); template< typename T>
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, 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 rc = kOkRC;
rc_t var_get( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t*& valRef ); variable_t* var = nullptr;
if((rc = var_find(inst, vid, chIdx, var )) == kOkRC )
rc = var_get(var,valRef);
return rc;
}
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, bool val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, uint_t val ); rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, 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, int_t val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, real_t val ); rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, float val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, double val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, const char* val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, abuf_t* val );
rc_t var_set( instance_t* inst, unsigned vid, unsigned chIdx, fbuf_t* val );
rc_t var_set( instance_t* inst, const char* var_label, unsigned chIdx, uint_t val ); const preset_t* class_preset_find( class_desc_t* cd, const char* preset_label );
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 );
} }
} }

22
cwLog.h
View File

@ -109,4 +109,26 @@ namespace cw
#define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ ) #define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
// This log level is intended for debugging individual modules.
// By defining cwLOG_MODULE prior to cwLog.h in a given module these logging lines will be enabled.
#ifdef cwLOG_MODULE
#define cwLogVModRC(rc,fmt, vl) cwLogVInfoH( cw::log::globalhandle(), (rc), (fmt), (vl) )
#define cwLogModRC( rc,fmt,...) cwLogInfoH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
#define cwLogVMod(fmt, vl) cwLogVInfoH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) )
#define cwLogMod( fmt,...) cwLogInfoH( cw::log::globalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
#else
#define cwLogVModRC(rc,fmt, vl)
#define cwLogModRC( rc,fmt,...)
#define cwLogVMod(fmt, vl)
#define cwLogMod( fmt,...)
#endif
#endif #endif