From 14a6a9b2d1de9664765cd17dea6a1171688d5f23 Mon Sep 17 00:00:00 2001 From: kevin Date: Sun, 18 Feb 2024 08:41:19 -0500 Subject: [PATCH] Multi-preset configurations flags 'kPriPresetProbFl,kSecPresetProbFl,kPresetInterpFl` can now be used to configure preset application from the cwIoPresetSelApp UI. --- cwFlow.cpp | 252 ++++++++++++++++++++++++++++++++++++++--- cwFlow.h | 1 + cwFlowCross.cpp | 9 ++ cwFlowCross.h | 2 + cwFlowDecl.h | 10 +- cwFlowTypes.h | 3 +- cwIoFlow.cpp | 8 +- cwIoFlow.h | 2 + cwIoPresetSelApp.cpp | 50 ++++++-- html/preset_sel/ui.cfg | 6 + 10 files changed, 318 insertions(+), 25 deletions(-) diff --git a/cwFlow.cpp b/cwFlow.cpp index f8a0ede..126c22e 100644 --- a/cwFlow.cpp +++ b/cwFlow.cpp @@ -1305,6 +1305,88 @@ namespace cw return rc; } + unsigned _select_ranked_ele_by_rank_prob( const preset_order_t* presetA, const bool* selV , unsigned presetN ) + { + + // get a count of the candidate presets + unsigned rankN = selV==nullptr ? presetN : std::count_if(selV,selV+presetN,[](const bool& x){ return x; }); + + if( rankN == 0 ) + { + cwLogWarning("All preset candidates have been eliminated."); + return kInvalidIdx; + } + + unsigned rankV[ rankN ]; + unsigned idxMapA[ rankN ]; + + // fill rankV[] with candidates 'order' value + for(unsigned i=0,j=0; i 1 ); + + unsigned threshV[ rankN ]; + unsigned uniqueRankV[ rankN ]; + unsigned uniqueRankN = 0; + unsigned sel_idx = rankN - 1; // + + // for each possible rank value + for(unsigned i=0; iframesPerCycle, - "multiPresetProbFl", p->multiPresetProbFl, + "multiPriPresetProbFl", p->multiPriPresetProbFl, + "multiSecPresetProbFl", p->multiSecPresetProbFl, "multiPresetInterpFl", p->multiPresetInterpFl, "network", network)) != kOkRC ) { @@ -1553,6 +1652,23 @@ cw::rc_t cw::flow::destroy( handle_t& hRef ) return rc; } +unsigned cw::flow::preset_cfg_flags( handle_t h ) +{ + flow_t* p = _handleToPtr(h); + unsigned flags = 0; + + if( p->multiPriPresetProbFl ) + flags |= kPriPresetProbFl; + + if( p->multiSecPresetProbFl ) + flags |= kSecPresetProbFl; + + if( p->multiPresetInterpFl ) + flags |= kInterpPresetFl; + + return flags; +} + cw::rc_t cw::flow::exec_cycle( handle_t h ) { @@ -1657,7 +1773,7 @@ cw::rc_t cw::flow::apply_dual_preset( handle_t h, const char* presetLabel_0, con flow_t* p = _handleToPtr(h); const object_t* net_preset_value_0; - printf("*** Applying dual: %s %s : %f\n",presetLabel_0, presetLabel_1, coeff ); + cwLogInfo("*** Applying dual: %s %s : %f\n",presetLabel_0, presetLabel_1, coeff ); // locate the cfg of the requested preset if((net_preset_value_0 = _find_network_preset(p, presetLabel_0 )) == nullptr ) @@ -1746,14 +1862,122 @@ cw::rc_t cw::flow::apply_dual_preset( handle_t h, const char* presetLabel_0, con return rc; } +cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& mps ) +{ + rc_t rc = kOkRC; + const char* label0 = nullptr; + const char* label1 = nullptr; + bool priProbFl = cwIsFlag(mps.flags, kPriPresetProbFl ); + bool secProbFl = cwIsFlag(mps.flags, kSecPresetProbFl ); + bool interpFl = cwIsFlag(mps.flags, kInterpPresetFl ); + + printf("preset flags: pri:%i sec:%i interp:%i\n",priProbFl,secProbFl,interpFl); + + // verify that the set of candidate presets is not empty + if( mps.presetN == 0 ) + { + cwLogError(kInvalidArgRC,"A multi-preset application was requested but no presets were provided."); + goto errLabel; + } + + // if only a single candidate preset exists or needs to be selected + if( interpFl==false || mps.presetN==1 ) + { + // if only a single candidate preset is available or pri. probablity is not enabled + if( mps.presetN == 1 || priProbFl==false ) + label0 = mps.presetA[0].preset_label; + else + { + if( priProbFl ) + label0 = _select_ranked_ele_label_by_rank_prob( mps.presetA, nullptr, mps.presetN ); + else + label0 = mps.presetA[0].preset_label; + } + } + else // interpolation has been selected and at least 2 presets exist + { + unsigned pri_sel_idx = 0; + + // select the primary preset + if( priProbFl ) + pri_sel_idx = _select_ranked_ele_by_rank_prob( mps.presetA, nullptr, mps.presetN ); + else + { + // select all presets assigned to order == 1 + bool selA[ mps.presetN ]; + for(unsigned i=0; imultiPresetProbFl && multi_preset_sel.presetN > 1 ) + if( multiPresetProbFl && multi_preset_sel.presetN > 1 ) { auto presetA = multi_preset_sel.presetA; auto presetN = multi_preset_sel.presetN; // if we are interpolating then the base preset is always the first one in presetA[] // so do not include it as a candidate for probabilistic selection - if( p->multiPresetInterpFl ) + if( multiPresetInterpFl ) { presetA += 1; presetN -= 1; @@ -1820,12 +2044,12 @@ cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& mult if( prob_label == nullptr ) { label0 = multi_preset_sel.presetA[0].preset_label; - label1 = p->multiPresetInterpFl ? multi_preset_sel.presetA[1].preset_label : nullptr; + label1 = multiPresetInterpFl ? multi_preset_sel.presetA[1].preset_label : nullptr; } else // ... and a prob. selection exists { // if we need two presets - if( p->multiPresetInterpFl ) + if( multiPresetInterpFl ) { label0 = multi_preset_sel.presetA[0].preset_label; label1 = prob_label; @@ -1857,7 +2081,7 @@ cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& mult errLabel: return rc; } - +*/ cw::rc_t cw::flow::set_variable_value( handle_t h, const char* inst_label, const char* var_label, unsigned chIdx, bool value ) { return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); } diff --git a/cwFlow.h b/cwFlow.h index e7f95a9..d45df47 100644 --- a/cwFlow.h +++ b/cwFlow.h @@ -59,6 +59,7 @@ namespace cw rc_t destroy( handle_t& hRef ); + unsigned preset_cfg_flags( handle_t h ); // Run one cycle of the network. rc_t exec_cycle( handle_t h ); diff --git a/cwFlowCross.cpp b/cwFlowCross.cpp index 7f29c1f..2839273 100644 --- a/cwFlowCross.cpp +++ b/cwFlowCross.cpp @@ -356,6 +356,15 @@ cw::rc_t cw::flow_cross::destroy( handle_t& hRef ) return rc; } +unsigned cw::flow_cross::preset_cfg_flags( handle_t h ) +{ + flow_cross_t* p = _handleToPtr(h); + if( p->netN > 0 ) + return preset_cfg_flags( p->netA[0].flowH ); + + return 0; +} + cw::rc_t cw::flow_cross::exec_cycle( handle_t h ) { diff --git a/cwFlowCross.h b/cwFlowCross.h index a9a24a4..00ce5b2 100644 --- a/cwFlowCross.h +++ b/cwFlowCross.h @@ -25,6 +25,8 @@ namespace cw rc_t destroy( handle_t& hRef ); + unsigned preset_cfg_flags( handle_t h ); + // Run one cycle of the network. rc_t exec_cycle( handle_t h ); diff --git a/cwFlowDecl.h b/cwFlowDecl.h index 52d166a..c08f5cf 100644 --- a/cwFlowDecl.h +++ b/cwFlowDecl.h @@ -5,15 +5,21 @@ namespace cw { namespace flow { + enum { + kPriPresetProbFl = 0x01, + kSecPresetProbFl = 0x02, + kInterpPresetFl = 0x04 + }; + typedef struct preset_order_str { const char* preset_label; - unsigned order; + unsigned order; } preset_order_t; typedef struct multi_preset_selector_str { - unsigned type_id; + unsigned flags; const double* coeffV; const double* coeffMinV; const double* coeffMaxV; diff --git a/cwFlowTypes.h b/cwFlowTypes.h index 8afe1bd..eb1ffbf 100644 --- a/cwFlowTypes.h +++ b/cwFlowTypes.h @@ -211,7 +211,8 @@ namespace cw const object_t* presetCfg; // presets designed for this network unsigned framesPerCycle; // sample frames per cycle (64) - bool multiPresetProbFl; // If set then probability is used to choose presets on multi-preset application + bool multiPriPresetProbFl; // If set then probability is used to choose presets on multi-preset application + bool multiSecPresetProbFl; // bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application unsigned cycleIndex; // Incremented with each processing cycle unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit. diff --git a/cwIoFlow.cpp b/cwIoFlow.cpp index c2a16cc..7d3bf79 100644 --- a/cwIoFlow.cpp +++ b/cwIoFlow.cpp @@ -387,7 +387,13 @@ cw::rc_t cw::io_flow::destroy( handle_t& hRef ) return rc; } - + +unsigned cw::io_flow::preset_cfg_flags( handle_t h ) +{ + io_flow_t* p = _handleToPtr(h); + return preset_cfg_flags(p->crossFlowH); +} + cw::rc_t cw::io_flow::exec( handle_t h, const io::msg_t& msg ) { diff --git a/cwIoFlow.h b/cwIoFlow.h index e652fbf..8ccb4d1 100644 --- a/cwIoFlow.h +++ b/cwIoFlow.h @@ -10,6 +10,8 @@ namespace cw rc_t create( handle_t& hRef, io::handle_t ioH, double srate, unsigned crossFadeCnt, const object_t& flow_class_dict, const object_t& cfg ); rc_t destroy( handle_t& hRef ); + unsigned preset_cfg_flags( handle_t h ); + rc_t exec( handle_t h, const io::msg_t& msg ); diff --git a/cwIoPresetSelApp.cpp b/cwIoPresetSelApp.cpp index c38c9b7..79adfa5 100644 --- a/cwIoPresetSelApp.cpp +++ b/cwIoPresetSelApp.cpp @@ -50,6 +50,7 @@ namespace cw kNetPrintBtnId, kReportBtnId, kLatencyBtnId, + kStartBtnId, kStopBtnId, @@ -76,7 +77,12 @@ namespace cw kLoadBtnId, kPerfSelId, kAltSelId, + + kPriPresetProbCheckId, + kSecPresetProbCheckId, + kPresetInterpCheckId, + kEnaRecordCheckId, kMidiSaveBtnId, kMidiLoadBtnId, @@ -176,6 +182,9 @@ namespace cw { kPanelDivId, kLoadBtnId, "loadBtnId" }, { kPanelDivId, kPerfSelId, "perfSelId" }, { kPanelDivId, kAltSelId, "altSelId" }, + { kPanelDivId, kPriPresetProbCheckId, "presetProbPriCheckId" }, + { kPanelDivId, kSecPresetProbCheckId, "presetProbSecCheckId" }, + { kPanelDivId, kPresetInterpCheckId, "presetInterpCheckId" }, { kPanelDivId, kEnaRecordCheckId, "enaRecordCheckId" }, { kPanelDivId, kMidiSaveBtnId, "midiSaveBtnId" }, @@ -322,6 +331,8 @@ namespace cw bool printMidiFl; + unsigned multiPresetFlags; + bool seqActiveFl; // true if the sequence is currently active (set by 'Play Seq' btn) unsigned seqStartedFl; // set by the first seq idle callback unsigned seqFragId; // @@ -899,13 +910,13 @@ namespace cw //unsigned coeffN = sizeof(coeffV)/sizeof(coeffV[0]); flow::multi_preset_selector_t mp_sel = - { .type_id=0, - .coeffV=score_evt->featV, - .coeffMinV=score_evt->featMinV, - .coeffMaxV=score_evt->featMaxV, - .coeffN=perf_meas::kValCnt, - .presetA=frag->multiPresetA, - .presetN=frag->multiPresetN + { .flags = app->multiPresetFlags, + .coeffV = score_evt->featV, + .coeffMinV = score_evt->featMinV, + .coeffMaxV = score_evt->featMaxV, + .coeffN = perf_meas::kValCnt, + .presetA = frag->multiPresetA, + .presetN = frag->multiPresetN }; if( app->ioFlowH.isValid() ) @@ -3001,6 +3012,18 @@ namespace cw case kAltSelId: _on_alt_select(app,m.value->u.u); break; + + case kPriPresetProbCheckId: + app->multiPresetFlags = cwEnaFlag(app->multiPresetFlags,flow::kPriPresetProbFl,m.value->u.b); + break; + + case kSecPresetProbCheckId: + app->multiPresetFlags = cwEnaFlag(app->multiPresetFlags,flow::kSecPresetProbFl,m.value->u.b); + break; + + case kPresetInterpCheckId: + app->multiPresetFlags = cwEnaFlag(app->multiPresetFlags,flow::kInterpPresetFl,m.value->u.b); + break; case kMidiThruCheckId: cwLogInfo("MIDI thru:%i",m.value->u.b); @@ -3237,6 +3260,18 @@ namespace cw case kSamplerMidiCheckId: _on_echo_midi_enable( app, m.uuId, midi_record_play::kSampler_MRP_DevIdx ); break; + + case kPriPresetProbCheckId: + io::uiSendValue( app->ioH, m.uuId, preset_cfg_flags(app->ioFlowH) & flow::kPriPresetProbFl ); + break; + + case kSecPresetProbCheckId: + io::uiSendValue( app->ioH, m.uuId, preset_cfg_flags(app->ioFlowH) & flow::kSecPresetProbFl ); + break; + + case kPresetInterpCheckId: + io::uiSendValue( app->ioH, m.uuId, preset_cfg_flags(app->ioFlowH) & flow::kInterpPresetFl ); + break; case kWetInGainId: _on_echo_master_value( app, preset_sel::kMasterWetInGainVarId, m.uuId ); @@ -3594,6 +3629,7 @@ cw::rc_t cw::preset_sel_app::main( const object_t* cfg, int argc, const char* ar rc = cwLogError(rc,"The IO Flow controller create failed."); goto errLabel; } + app.multiPresetFlags = preset_cfg_flags(app.ioFlowH); } printf("ioFlow is %s valid.\n",app.ioFlowH.isValid() ? "" : "not"); diff --git a/html/preset_sel/ui.cfg b/html/preset_sel/ui.cfg index 78ccf5f..134f213 100644 --- a/html/preset_sel/ui.cfg +++ b/html/preset_sel/ui.cfg @@ -20,6 +20,12 @@ }, + row: { + check: { name: presetProbPriCheckId, title: "Pri Prob::" }, + check: { name: presetProbSecCheckId, title: "Sec Prob:" }, + check: { name: presetInterpCheckId, title: "Interp:"} + }, + row: { check: { name: printMidiCheckId, title: "Print MIDI" }, check: { name: pianoMidiCheckId, title: "Piano MIDI" },