From 072d0eecd60248be171831c0f42d510449e35164 Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 3 May 2024 09:22:16 -0400 Subject: [PATCH] cwFlowProc.cpp : Refactored xfade_ctl to implement preset updates. --- cwFlowProc.cpp | 321 ++++++++++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 137 deletions(-) diff --git a/cwFlowProc.cpp b/cwFlowProc.cpp index 7dbb49c..f00d2bc 100644 --- a/cwFlowProc.cpp +++ b/cwFlowProc.cpp @@ -3339,54 +3339,44 @@ namespace cw kPresetPId, kGainPId, }; + + typedef struct poly_ch_str + { + network_t net; + coeff_t target_gain; + coeff_t cur_gain; + } poly_ch_t; typedef struct { unsigned xfadeDurMs; // crossfade duration in milliseconds instance_t* net_proc; // source 'poly' network - network_t net; // internal proxy network - unsigned poly_ch_cnt; // set to 2 (one for 'cur' poly-ch., one for 'next' poly-ch.) + poly_ch_t* netA; // netA[ poly_ch_cnt ] internal proxy network + unsigned poly_ch_cnt; // count of poly channels in net_proc unsigned net_proc_cnt; // count of proc's in a single poly-channel (net_proc->proc_arrayN/poly_cnt) - unsigned cur_poly_ch_idx; // - unsigned next_poly_ch_idx; // - float* target_gainA; // target_gainA[net_proc->poly_cnt] - float* cur_gainA; // cur_gainA[net_proc->poly_cnt] - double srate; - bool preset_delta_fl; - bool trigFl; - bool trigVal; + unsigned cur_poly_ch_idx; // This is the active channel. + unsigned next_poly_ch_idx; // This is the next channel that will be active. + srate_t srate; // Sample rate used for time base + bool preset_delta_fl; // Preset change trigger flag. + bool trigFl; // Cross-fade trigger flag. } inst_t; void _trigger_xfade( inst_t* p ) { // begin fading out the cur channel - p->target_gainA[ p->cur_poly_ch_idx ] = 0; + p->netA[p->cur_poly_ch_idx].target_gain = 0; // the next poly-ch become the cur poly-ch p->cur_poly_ch_idx = p->next_poly_ch_idx; // the next poly-ch advances p->next_poly_ch_idx = p->next_poly_ch_idx+1 >= p->poly_ch_cnt ? 0 : p->next_poly_ch_idx+1; - - // j selects a block of 'net_proc_cnt' slots in the proxy network which will become the 'next' channel - unsigned j = p->next_poly_ch_idx * p->net_proc_cnt; - - // set the [j:j+poly_proc_cnt] pointers in the proxy net to the actual proc instances in the source net - for(unsigned i=0; inet_proc->internal_net->proc_arrayN; ++i) - if( p->net_proc->internal_net->proc_array[i]->label_sfx_id == p->next_poly_ch_idx ) - { - assert( p->next_poly_ch_idx * p->net_proc_cnt <= j - && j < p->next_poly_ch_idx * p->net_proc_cnt + p->net_proc_cnt - && j < p->net.proc_arrayN ); - - p->net.proc_array[j++] = p->net_proc->internal_net->proc_array[i]; - } - + // begin fading in the new cur channel - p->target_gainA[ p->cur_poly_ch_idx ] = 1; + p->netA[p->cur_poly_ch_idx].target_gain = 1; // if the next channel is not already at 0 send it in that direction - p->target_gainA[ p->next_poly_ch_idx ] = 0; + p->netA[p->next_poly_ch_idx].target_gain = 0; //printf("xfad:%i %i : %i\n",p->cur_poly_ch_idx, p->next_poly_ch_idx,p->poly_ch_cnt); @@ -3398,24 +3388,23 @@ namespace cw const char* netLabel = nullptr; const char* presetLabel = nullptr; unsigned netLabelSfxId = kBaseSfxId; - bool trigFl = false; - variable_t* gainVar = nullptr; abuf_t* srateSrc = nullptr; - double dum_dbl; + coeff_t dum_dbl; inst_t* p = mem::allocZ(); ctx->userPtr = p; - - + + if((rc = var_register(ctx,kAnyChIdx,kTriggerPId,"trigger", kBaseSfxId )) != kOkRC ) + goto errLabel; + if((rc = var_register_and_get(ctx,kAnyChIdx, - kNetLabelPId, "net", kBaseSfxId, netLabel, - kNetLabelSfxPId, "netSfxId", kBaseSfxId, netLabelSfxId, - kSrateRefPId, "srateSrc", kBaseSfxId, srateSrc, - kDurMsPId, "durMs", kBaseSfxId, p->xfadeDurMs, - kTriggerPId, "trigger", kBaseSfxId, p->trigVal, - kPresetPId, "preset", kBaseSfxId, presetLabel, - kGainPId, "gain", kBaseSfxId, dum_dbl)) != kOkRC ) + kNetLabelPId, "net", kBaseSfxId, netLabel, + kNetLabelSfxPId, "netSfxId", kBaseSfxId, netLabelSfxId, + kSrateRefPId, "srateSrc", kBaseSfxId, srateSrc, + kDurMsPId, "durMs", kBaseSfxId, p->xfadeDurMs, + kPresetPId, "preset", kBaseSfxId, presetLabel, + kGainPId, "gain", kBaseSfxId, dum_dbl)) != kOkRC ) { goto errLabel; } @@ -3435,9 +3424,8 @@ namespace cw p->poly_ch_cnt = p->net_proc->internal_net->poly_cnt; - // create the gain output variables - one output for each poly-channel - for(unsigned i=1; inet_proc->internal_net->poly_cnt; ++i) + for(unsigned i=1; ipoly_ch_cnt; ++i) { variable_t* dum; if((rc = var_create(ctx, "gain", i, kGainPId+i, kAnyChIdx, nullptr, kInvalidTFl, dum )) != kOkRC ) @@ -3450,17 +3438,29 @@ namespace cw // count of proc's in one poly-ch of the poly network p->net_proc_cnt = p->net_proc->internal_net->proc_arrayN / p->net_proc->internal_net->poly_cnt; - // create the proxy network - p->net.proc_arrayAllocN = p->net_proc_cnt * p->poly_ch_cnt; - p->net.proc_arrayN = p->net.proc_arrayAllocN; - p->net.proc_array = mem::allocZ(p->net.proc_arrayAllocN); - p->target_gainA = mem::allocZ(p->net_proc->internal_net->poly_cnt); - p->cur_gainA = mem::allocZ(p->net_proc->internal_net->poly_cnt); - p->srate = srateSrc->srate; + p->netA = mem::allocZ(p->poly_ch_cnt); - // make the proxy network public - xfad_ctl now looks like the source network - // because it has the same proc instances - ctx->internal_net = &p->net; + // create the proxy network networks + for(unsigned i=0; ipoly_ch_cnt; ++i) + { + p->netA[i].net.proc_arrayAllocN = p->net_proc_cnt; + p->netA[i].net.proc_arrayN = p->netA[i].net.proc_arrayAllocN; + p->netA[i].net.proc_array = mem::allocZ(p->netA[i].net.proc_arrayAllocN); + p->netA[i].net.presetsCfg = p->net_proc->internal_net->presetsCfg; + + for(unsigned j=0,k=0; jnet_proc->internal_net->proc_arrayN; ++j) + if( p->net_proc->internal_net->proc_array[j]->label_sfx_id == i ) + { + assert( k < p->net_proc_cnt ); + p->netA[i].net.proc_array[k++] = p->net_proc->internal_net->proc_array[j]; + } + } + + if( srateSrc == nullptr ) + p->srate = ctx->ctx->sample_rate; + else + p->srate = srateSrc->srate; + // setup the channels such that the first active channel after _trigger_xfade() // will be channel 0 @@ -3468,8 +3468,6 @@ namespace cw p->next_poly_ch_idx = 2; _trigger_xfade(p); // cur=2 nxt=0 initialize inst ptrs in range: p->net[0:net_proc_cnt] _trigger_xfade(p); // cur=0 nxt=1 initialize inst ptrs in range: p->net[net_proc_cnt:2*net_proc_cnt] - - errLabel: return rc; @@ -3478,9 +3476,10 @@ namespace cw rc_t destroy( instance_t* ctx ) { inst_t* p = (inst_t*)ctx->userPtr; - mem::release(p->net.proc_array); - mem::release(p->target_gainA); - mem::release(p->cur_gainA); + for(unsigned i=0; ipoly_ch_cnt; ++i) + mem::release(p->netA[i].net.proc_array); + + mem::release(p->netA); mem::release(ctx->userPtr); return kOkRC; @@ -3488,24 +3487,20 @@ namespace cw rc_t value( instance_t* ctx, variable_t* var ) { - rc_t rc = kOkRC; - inst_t* p = (inst_t*)ctx->userPtr; - - if(var->vid == kTriggerPId ) + rc_t rc = kOkRC; + inst_t* p = (inst_t*)ctx->userPtr; + + switch( var->vid ) { - bool v; - if((rc = var_get(var,v)) == kOkRC ) - { - if( !p->trigFl ) - p->trigFl = p->trigVal != v; - - p->trigVal = v; - } - //printf("tr:%i %i %i\n",v,p->trigVal,p->trigFl); + case kTriggerPId: + p->trigFl = true; + break; - + case kPresetPId: + p->preset_delta_fl = true; + break; } - + return kOkRC; } @@ -3517,29 +3512,52 @@ namespace cw rc_t rc = kOkRC; inst_t* p = (inst_t*)ctx->userPtr; - // check if a cross-fade has been triggered - if(p->trigFl ) - { - p->trigFl = false; - _trigger_xfade(p); - } - // time in sample frames to complete a xfade double xfade_dur_smp = p->xfadeDurMs * p->srate / 1000.0; // fraction of a xfade which will be completed in on exec() cycle float delta_gain_per_cycle = (float)(ctx->ctx->framesPerCycle / xfade_dur_smp); + + if( p->preset_delta_fl ) + { + const char* preset_label = nullptr; + + p->preset_delta_fl = false; + + if((rc = var_get(ctx,kPresetPId,kAnyChIdx,preset_label)) != kOkRC ) + { + rc = cwLogError(rc,"Preset label access failed."); + goto errLabel; + } + + if((rc = network_apply_preset(p->netA[p->next_poly_ch_idx].net, preset_label,p->next_poly_ch_idx)) != kOkRC ) + { + rc = cwLogError(rc,"Appy preset '%s' failed.",cwStringNullGuard(preset_label)); + goto errLabel; + } + } + + // check if a cross-fade has been triggered + if(p->trigFl ) + { + p->trigFl = false; + _trigger_xfade(p); + } + // update the cross-fade gain outputs for(unsigned i=0; inet_proc->internal_net->poly_cnt; ++i) { - p->cur_gainA[i] += _signum(p->target_gainA[i] - p->cur_gainA[i]) * delta_gain_per_cycle; + p->netA[i].cur_gain += _signum(p->netA[i].target_gain - p->netA[i].cur_gain) * delta_gain_per_cycle; - p->cur_gainA[i] = std::min(1.0f, std::max(0.0f, p->cur_gainA[i])); + p->netA[i].cur_gain = std::min(1.0f, std::max(0.0f, p->netA[i].cur_gain)); - var_set(ctx,kGainPId+i,kAnyChIdx,p->cur_gainA[i]); + var_set(ctx,kGainPId+i,kAnyChIdx,p->netA[i].cur_gain); } + + + errLabel: return rc; } @@ -4402,7 +4420,8 @@ namespace cw { kInPId, kListPId, - kOutPId + kOutPId, + kValueBasePId }; typedef struct @@ -4509,7 +4528,7 @@ namespace cw } template< typename T > - rc_t _set_out_tmpl( instance_t* proc, inst_t* p, unsigned idx, T& v ) + rc_t _set_out_tmpl( instance_t* proc, inst_t* p, unsigned idx, unsigned vid, T& v ) { rc_t rc; const object_t* ele; @@ -4529,7 +4548,7 @@ namespace cw } // set the output - if((rc = var_set(proc,kOutPId,kAnyChIdx,v)) != kOkRC ) + if((rc = var_set(proc,vid,kAnyChIdx,v)) != kOkRC ) { rc = cwLogError(rc,"List output failed on index %i",idx); goto errLabel; @@ -4539,6 +4558,64 @@ namespace cw return rc; } + rc_t _set_output( instance_t* proc, inst_t* p, unsigned idx, unsigned vid ) + { + rc_t rc; + + switch( p->typeFl ) + { + case kUIntTFl: + { + unsigned v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + case kIntTFl: + { + int v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + case kFloatTFl: + { + float v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + case kDoubleTFl: + { + double v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + case kStringTFl: + { + const char* v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + case kCfgTFl: + { + const object_t* v; + rc = _set_out_tmpl(proc,p,idx,vid,v); + } + break; + + default: + rc = cwLogError(kInvalidArgRC,"The list type flag %s (0x%x) is not valid.",value_type_flag_to_label(p->typeFl),p->typeFl); + break; + + } + + errLabel: + return rc; + } + rc_t _set_output( instance_t* proc, inst_t* p ) { rc_t rc; @@ -4554,64 +4631,16 @@ namespace cw if( idx == p->index ) goto errLabel; - switch( p->typeFl ) - { - case kUIntTFl: - { - unsigned v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - case kIntTFl: - { - int v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - case kFloatTFl: - { - float v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - case kDoubleTFl: - { - double v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - case kStringTFl: - { - const char* v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - case kCfgTFl: - { - const object_t* v; - rc = _set_out_tmpl(proc,p,idx,v); - } - break; - - default: - rc = cwLogError(kInvalidArgRC,"The list type flag %s (0x%x) is not valid.",value_type_flag_to_label(p->typeFl),p->typeFl); - break; - - } - - if(rc != kOkRC ) + if((rc = _set_output(proc,p,idx, kOutPId )) != kOkRC ) goto errLabel; p->index = idx; - + errLabel: return rc; } + + rc_t create( instance_t* proc ) { @@ -4656,6 +4685,24 @@ namespace cw // set the initial value of the output if((rc = _set_output(proc,p)) != kOkRC ) goto errLabel; + + // create the output variable + for(unsigned i=0; ilistN; ++i) + { + if((rc = var_create( proc, "value", i, kValueBasePId+i, kAnyChIdx, nullptr, p->typeFl, dum )) != kOkRC ) + { + rc = cwLogError(rc,"'value%i' var create failed.",i); + goto errLabel; + } + + if((rc = _set_output(proc, p, i, kValueBasePId+i )) != kOkRC ) + { + rc = cwLogError(rc,"'value%i' output failed.",i); + goto errLabel; + } + + } + errLabel: return rc;