Multi-preset configurations flags 'kPriPresetProbFl,kSecPresetProbFl,kPresetInterpFl`

can now be used to configure preset application from the
cwIoPresetSelApp UI.
This commit is contained in:
kevin 2024-02-18 08:41:19 -05:00
parent 64df75d9aa
commit 14a6a9b2d1
10 changed files with 318 additions and 25 deletions

View File

@ -1305,6 +1305,88 @@ namespace cw
return rc; 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<presetN; ++i)
if( selV==nullptr || selV[i] )
{
assert( j < rankN );
rankV[j] = presetA[i].order;
idxMapA[j] = i;
++j;
}
// if only one element remains to be selected
if( rankN == 1 )
return idxMapA[0];
assert( rankN > 1 );
unsigned threshV[ rankN ];
unsigned uniqueRankV[ rankN ];
unsigned uniqueRankN = 0;
unsigned sel_idx = rankN - 1; //
// for each possible rank value
for(unsigned i=0; i<rankN; ++i)
{
// locate the rank in the uniqueRankV[]
unsigned j=0;
for(; j<uniqueRankN; ++j)
if( uniqueRankV[j]==rankV[i] )
break;
// if the rank was not found then include it here
if( j == uniqueRankN )
uniqueRankV[uniqueRankN++] = rankV[i];
}
// uniqueRankV[] now includes the set of possible rank values
// Take the product of all possible values.
// (this will be evenly divisible by all values)
unsigned prod = vop::prod(uniqueRankV,uniqueRankN);
unsigned thresh = 0;
for(unsigned i=0; i<rankN; ++i)
threshV[i] = (thresh += rankV[i] * prod);
// Thresh is now set to the max possible random value.
// Generate a random number between 0 and thresh
double fval = (double)std::rand() * thresh / RAND_MAX;
unsigned thresh0 = 0;
for(unsigned i=0; i<rankN; ++i)
{
if( thresh0 <= fval && fval < threshV[i] )
{
sel_idx = i;
break;
}
}
assert( sel_idx < rankN );
return idxMapA[sel_idx];
}
/*
unsigned _select_ranked_ele_by_rank_prob( const preset_order_t* rankV, unsigned rankN ) unsigned _select_ranked_ele_by_rank_prob( const preset_order_t* rankV, unsigned rankN )
{ {
unsigned threshV[ rankN ]; unsigned threshV[ rankN ];
@ -1335,7 +1417,7 @@ namespace cw
// uniqueRankV[] now includes the set of possible rank values // uniqueRankV[] now includes the set of possible rank values
// Take the produce of all possible values. // Take the product of all possible values.
// (this will be evenly divisible by all values) // (this will be evenly divisible by all values)
unsigned prod = vop::prod(uniqueRankV,uniqueRankN); unsigned prod = vop::prod(uniqueRankV,uniqueRankN);
@ -1360,6 +1442,22 @@ namespace cw
return sel_idx; return sel_idx;
} }
*/
const char* _select_ranked_ele_label_by_rank_prob( const preset_order_t* rankV, const bool* selA, unsigned rankN )
{
unsigned sel_idx;
if((sel_idx = _select_ranked_ele_by_rank_prob( rankV, selA, rankN )) == kInvalidIdx )
{
cwLogWarning("The multi-preset select function failed. Selecting preset 0.");
sel_idx = 0;
}
return rankV[sel_idx].preset_label;
}
double _calc_multi_preset_dual_coeff( const multi_preset_selector_t& mps ) double _calc_multi_preset_dual_coeff( const multi_preset_selector_t& mps )
{ {
@ -1486,7 +1584,8 @@ cw::rc_t cw::flow::create( handle_t& hRef,
// parse the main audio file processor cfg record // parse the main audio file processor cfg record
if((rc = networkCfg.getv("framesPerCycle", p->framesPerCycle, if((rc = networkCfg.getv("framesPerCycle", p->framesPerCycle,
"multiPresetProbFl", p->multiPresetProbFl, "multiPriPresetProbFl", p->multiPriPresetProbFl,
"multiSecPresetProbFl", p->multiSecPresetProbFl,
"multiPresetInterpFl", p->multiPresetInterpFl, "multiPresetInterpFl", p->multiPresetInterpFl,
"network", network)) != kOkRC ) "network", network)) != kOkRC )
{ {
@ -1553,6 +1652,23 @@ cw::rc_t cw::flow::destroy( handle_t& hRef )
return rc; 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 ) 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); flow_t* p = _handleToPtr(h);
const object_t* net_preset_value_0; 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 // locate the cfg of the requested preset
if((net_preset_value_0 = _find_network_preset(p, presetLabel_0 )) == nullptr ) 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; 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; i<mps.presetN; ++i)
selA[i]= mps.presetA[i].order==1;
// select the preset among all presets marked as 1
pri_sel_idx = _select_ranked_ele_by_rank_prob( mps.presetA, selA, mps.presetN );
}
if( pri_sel_idx == kInvalidIdx )
pri_sel_idx = 0;
// the primary preset has now been selected
// if there is only one candidate secondary preset
if( mps.presetN == 2)
{
assert( pri_sel_idx <= 1 );
label1 = mps.presetA[ pri_sel_idx == 0 ? 1 : 0 ].preset_label;
}
else // at least two remaining presets exist to select between
{
// mark the selected primary preset as not-available
bool selA[ mps.presetN ];
vop::fill(selA,mps.presetN,true);
selA[pri_sel_idx] = false;
// if the second preset should be selected probabilistically
if( secProbFl )
label1 = _select_ranked_ele_label_by_rank_prob( mps.presetA, selA, mps.presetN );
else
{
// select the best preset that is not the primary preset
for(unsigned i=0; i<mps.presetN; ++i)
if( i != pri_sel_idx )
{
label1 = mps.presetA[i].preset_label;
break;
}
}
}
assert( pri_sel_idx != kInvalidIdx );
label0 = mps.presetA[ pri_sel_idx ].preset_label;
}
assert(label0 != nullptr );
if( label1 == nullptr )
{
rc = apply_preset( h, label0 );
}
else
{
double coeff = _calc_multi_preset_dual_coeff(mps);
rc = apply_dual_preset( h, label0, label1, coeff );
}
errLabel:
return rc;
}
/*
cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel ) cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& multi_preset_sel )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const char* label0 = nullptr; const char* label0 = nullptr;
const char* label1 = nullptr; const char* label1 = nullptr;
const char* prob_label = nullptr; const char* prob_label = nullptr;
bool multiPriPresetProbFl = cwIsFlag(multi_preset_sel.flags, kPriPresetProbFl );
flow_t* p = _handleToPtr(h); bool multiSecPresetProbFl = cwIsFlag(multi_preset_sel.flags, kSecPresetProbFl );
bool multiPresetInterpFl = cwIsFlag(multi_preset_sel.flags, kInterpPresetFl );
// verify that the set of presets to select from is not empty // verify that the set of presets to select from is not empty
if( multi_preset_sel.presetN == 0 ) if( multi_preset_sel.presetN == 0 )
@ -1763,14 +1987,14 @@ cw::rc_t cw::flow::apply_preset( handle_t h, const multi_preset_selector_t& mult
} }
// if probabistic selection was requested and is possible // if probabistic selection was requested and is possible
if( p->multiPresetProbFl && multi_preset_sel.presetN > 1 ) if( multiPresetProbFl && multi_preset_sel.presetN > 1 )
{ {
auto presetA = multi_preset_sel.presetA; auto presetA = multi_preset_sel.presetA;
auto presetN = multi_preset_sel.presetN; auto presetN = multi_preset_sel.presetN;
// if we are interpolating then the base preset is always the first one in presetA[] // 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 // so do not include it as a candidate for probabilistic selection
if( p->multiPresetInterpFl ) if( multiPresetInterpFl )
{ {
presetA += 1; presetA += 1;
presetN -= 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 ) if( prob_label == nullptr )
{ {
label0 = multi_preset_sel.presetA[0].preset_label; 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 else // ... and a prob. selection exists
{ {
// if we need two presets // if we need two presets
if( p->multiPresetInterpFl ) if( multiPresetInterpFl )
{ {
label0 = multi_preset_sel.presetA[0].preset_label; label0 = multi_preset_sel.presetA[0].preset_label;
label1 = prob_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: errLabel:
return rc; 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 ) 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 ); } { return _set_variable_value( _handleToPtr(h), inst_label, var_label, chIdx, value ); }

View File

@ -59,6 +59,7 @@ namespace cw
rc_t destroy( handle_t& hRef ); rc_t destroy( handle_t& hRef );
unsigned preset_cfg_flags( handle_t h );
// Run one cycle of the network. // Run one cycle of the network.
rc_t exec_cycle( handle_t h ); rc_t exec_cycle( handle_t h );

View File

@ -356,6 +356,15 @@ cw::rc_t cw::flow_cross::destroy( handle_t& hRef )
return rc; 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 ) cw::rc_t cw::flow_cross::exec_cycle( handle_t h )
{ {

View File

@ -25,6 +25,8 @@ namespace cw
rc_t destroy( handle_t& hRef ); rc_t destroy( handle_t& hRef );
unsigned preset_cfg_flags( handle_t h );
// Run one cycle of the network. // Run one cycle of the network.
rc_t exec_cycle( handle_t h ); rc_t exec_cycle( handle_t h );

View File

@ -5,15 +5,21 @@ namespace cw
{ {
namespace flow namespace flow
{ {
enum {
kPriPresetProbFl = 0x01,
kSecPresetProbFl = 0x02,
kInterpPresetFl = 0x04
};
typedef struct preset_order_str typedef struct preset_order_str
{ {
const char* preset_label; const char* preset_label;
unsigned order; unsigned order;
} preset_order_t; } preset_order_t;
typedef struct multi_preset_selector_str typedef struct multi_preset_selector_str
{ {
unsigned type_id; unsigned flags;
const double* coeffV; const double* coeffV;
const double* coeffMinV; const double* coeffMinV;
const double* coeffMaxV; const double* coeffMaxV;

View File

@ -211,7 +211,8 @@ namespace cw
const object_t* presetCfg; // presets designed for this network const object_t* presetCfg; // presets designed for this network
unsigned framesPerCycle; // sample frames per cycle (64) 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 bool multiPresetInterpFl; // If set then interpolation is applied between two selectedd presets on multi-preset application
unsigned cycleIndex; // Incremented with each processing cycle unsigned cycleIndex; // Incremented with each processing cycle
unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit. unsigned maxCycleCount; // count of cycles to run on flow::exec() or 0 if there is no limit.

View File

@ -387,7 +387,13 @@ cw::rc_t cw::io_flow::destroy( handle_t& hRef )
return rc; 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 ) cw::rc_t cw::io_flow::exec( handle_t h, const io::msg_t& msg )
{ {

View File

@ -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 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 ); rc_t destroy( handle_t& hRef );
unsigned preset_cfg_flags( handle_t h );
rc_t exec( handle_t h, const io::msg_t& msg ); rc_t exec( handle_t h, const io::msg_t& msg );

View File

@ -50,6 +50,7 @@ namespace cw
kNetPrintBtnId, kNetPrintBtnId,
kReportBtnId, kReportBtnId,
kLatencyBtnId, kLatencyBtnId,
kStartBtnId, kStartBtnId,
kStopBtnId, kStopBtnId,
@ -76,7 +77,12 @@ namespace cw
kLoadBtnId, kLoadBtnId,
kPerfSelId, kPerfSelId,
kAltSelId, kAltSelId,
kPriPresetProbCheckId,
kSecPresetProbCheckId,
kPresetInterpCheckId,
kEnaRecordCheckId, kEnaRecordCheckId,
kMidiSaveBtnId, kMidiSaveBtnId,
kMidiLoadBtnId, kMidiLoadBtnId,
@ -176,6 +182,9 @@ namespace cw
{ kPanelDivId, kLoadBtnId, "loadBtnId" }, { kPanelDivId, kLoadBtnId, "loadBtnId" },
{ kPanelDivId, kPerfSelId, "perfSelId" }, { kPanelDivId, kPerfSelId, "perfSelId" },
{ kPanelDivId, kAltSelId, "altSelId" }, { kPanelDivId, kAltSelId, "altSelId" },
{ kPanelDivId, kPriPresetProbCheckId, "presetProbPriCheckId" },
{ kPanelDivId, kSecPresetProbCheckId, "presetProbSecCheckId" },
{ kPanelDivId, kPresetInterpCheckId, "presetInterpCheckId" },
{ kPanelDivId, kEnaRecordCheckId, "enaRecordCheckId" }, { kPanelDivId, kEnaRecordCheckId, "enaRecordCheckId" },
{ kPanelDivId, kMidiSaveBtnId, "midiSaveBtnId" }, { kPanelDivId, kMidiSaveBtnId, "midiSaveBtnId" },
@ -322,6 +331,8 @@ namespace cw
bool printMidiFl; bool printMidiFl;
unsigned multiPresetFlags;
bool seqActiveFl; // true if the sequence is currently active (set by 'Play Seq' btn) bool seqActiveFl; // true if the sequence is currently active (set by 'Play Seq' btn)
unsigned seqStartedFl; // set by the first seq idle callback unsigned seqStartedFl; // set by the first seq idle callback
unsigned seqFragId; // unsigned seqFragId; //
@ -899,13 +910,13 @@ namespace cw
//unsigned coeffN = sizeof(coeffV)/sizeof(coeffV[0]); //unsigned coeffN = sizeof(coeffV)/sizeof(coeffV[0]);
flow::multi_preset_selector_t mp_sel = flow::multi_preset_selector_t mp_sel =
{ .type_id=0, { .flags = app->multiPresetFlags,
.coeffV=score_evt->featV, .coeffV = score_evt->featV,
.coeffMinV=score_evt->featMinV, .coeffMinV = score_evt->featMinV,
.coeffMaxV=score_evt->featMaxV, .coeffMaxV = score_evt->featMaxV,
.coeffN=perf_meas::kValCnt, .coeffN = perf_meas::kValCnt,
.presetA=frag->multiPresetA, .presetA = frag->multiPresetA,
.presetN=frag->multiPresetN .presetN = frag->multiPresetN
}; };
if( app->ioFlowH.isValid() ) if( app->ioFlowH.isValid() )
@ -3001,6 +3012,18 @@ namespace cw
case kAltSelId: case kAltSelId:
_on_alt_select(app,m.value->u.u); _on_alt_select(app,m.value->u.u);
break; 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: case kMidiThruCheckId:
cwLogInfo("MIDI thru:%i",m.value->u.b); cwLogInfo("MIDI thru:%i",m.value->u.b);
@ -3237,6 +3260,18 @@ namespace cw
case kSamplerMidiCheckId: case kSamplerMidiCheckId:
_on_echo_midi_enable( app, m.uuId, midi_record_play::kSampler_MRP_DevIdx ); _on_echo_midi_enable( app, m.uuId, midi_record_play::kSampler_MRP_DevIdx );
break; 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: case kWetInGainId:
_on_echo_master_value( app, preset_sel::kMasterWetInGainVarId, m.uuId ); _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."); rc = cwLogError(rc,"The IO Flow controller create failed.");
goto errLabel; goto errLabel;
} }
app.multiPresetFlags = preset_cfg_flags(app.ioFlowH);
} }
printf("ioFlow is %s valid.\n",app.ioFlowH.isValid() ? "" : "not"); printf("ioFlow is %s valid.\n",app.ioFlowH.isValid() ? "" : "not");

View File

@ -20,6 +20,12 @@
}, },
row: {
check: { name: presetProbPriCheckId, title: "Pri Prob::" },
check: { name: presetProbSecCheckId, title: "Sec Prob:" },
check: { name: presetInterpCheckId, title: "Interp:"}
},
row: { row: {
check: { name: printMidiCheckId, title: "Print MIDI" }, check: { name: printMidiCheckId, title: "Print MIDI" },
check: { name: pianoMidiCheckId, title: "Piano MIDI" }, check: { name: pianoMidiCheckId, title: "Piano MIDI" },