cwPresetSel.h/cpp : Added probabilistic preset selection via prob_select_preset_index().
This commit is contained in:
parent
ca6f444b0d
commit
15b83c1a5f
321
cwPresetSel.cpp
321
cwPresetSel.cpp
@ -69,6 +69,7 @@ namespace cw
|
||||
|
||||
unsigned cur_alt_idx;
|
||||
|
||||
unsigned dryPresetIdx;
|
||||
|
||||
} preset_sel_t;
|
||||
|
||||
@ -142,7 +143,7 @@ namespace cw
|
||||
mem::release(f->note);
|
||||
mem::release(f->presetA);
|
||||
mem::release(f->altPresetIdxA);
|
||||
//mem::release(f->multiPresetA);
|
||||
mem::release(f->probDomA);
|
||||
mem::release(f);
|
||||
goto errLabel;
|
||||
}
|
||||
@ -180,6 +181,250 @@ namespace cw
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Probabilistic selection
|
||||
//
|
||||
unsigned _get_preset_order( const preset_t* p, unsigned max_valid_order )
|
||||
{
|
||||
if( (p->order == 0 && p->playFl == false) || p->order > max_valid_order )
|
||||
return 0;
|
||||
|
||||
if( p->order == 0 && p->playFl )
|
||||
return 1;
|
||||
|
||||
assert( 1 <= p->order && p->order <= max_valid_order );
|
||||
return p->order;
|
||||
}
|
||||
|
||||
rc_t _pre_calc_for_prob_select( preset_sel_t* p, frag_t * f)
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
unsigned activeOrderA[ f->presetN ] = {};
|
||||
unsigned activeIdxA[ f->presetN ] = {};
|
||||
unsigned common_mult = 1;
|
||||
f->probDomN = 0;
|
||||
f->probDomainMax = 0;
|
||||
|
||||
for(unsigned i=0; i<f->presetN; ++i)
|
||||
{
|
||||
unsigned order = _get_preset_order(f->presetA + i, f->presetN-1);
|
||||
|
||||
if( order > 0 )
|
||||
{
|
||||
if( order> 0 && activeOrderA[order]==0 )
|
||||
common_mult *= order;
|
||||
|
||||
activeIdxA[f->probDomN] = i;
|
||||
f->probDomN += 1;
|
||||
|
||||
activeOrderA[ order ] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if no preset was selected in this fragment then
|
||||
// select the 'dry' preset.
|
||||
if( f->probDomN == 0 )
|
||||
{
|
||||
assert( p->dryPresetIdx != kInvalidIdx && p->dryPresetIdx < f->presetN );
|
||||
|
||||
f->probDomN = 1;
|
||||
activeIdxA[0] = p->dryPresetIdx;
|
||||
|
||||
if(activeIdxA[0] == kInvalidIdx )
|
||||
{
|
||||
cwLogError(kEleNotFoundRC,"No preset was selected at end loc:%i and 'dry' preset exists as a default.",f->endLoc);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
f->probDomA = mem::allocZ<prob_domain_t>(f->probDomN);
|
||||
|
||||
for(unsigned i=0; i<f->probDomN; ++i)
|
||||
{
|
||||
preset_t* preset = f->presetA + activeIdxA[i];
|
||||
unsigned order = _get_preset_order( preset, f->presetN-1);
|
||||
|
||||
preset->prob_dom_idx = i;
|
||||
|
||||
f->probDomA[i].index = activeIdxA[i];
|
||||
f->probDomA[i].order = preset->playFl ? 0 : order;
|
||||
f->probDomA[i].domain = order==0 ? 1 : common_mult / order;
|
||||
|
||||
f->probDomainMax += f->probDomA[i].domain;
|
||||
}
|
||||
|
||||
std::sort(f->probDomA,
|
||||
f->probDomA + f->probDomN,
|
||||
[](const prob_domain_t& a,const prob_domain_t& b){ return a.order<b.order; } );
|
||||
|
||||
assert( f->probDomN>=1 && f->probDomA != nullptr );
|
||||
|
||||
errLabel:
|
||||
|
||||
if( rc != kOkRC )
|
||||
rc = cwLogError(rc,"Pre-calculations for probabilistic preset selection failed.");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
unsigned _prob_select_uniform_preset( const preset_sel_t* p,
|
||||
const frag_t* f,
|
||||
bool dry_on_play_fl, // select dry if dry has the 'playFl' selected
|
||||
bool dry_on_selected_fl, // select dry if it has order > 0
|
||||
bool allow_all_fl, // select from among all presets - not just the ones in probDomA[]
|
||||
unsigned skip_preset_idx=kInvalidIdx )
|
||||
{
|
||||
assert( p->dryPresetIdx != kInvalidIdx && p->dryPresetIdx < f->presetN );
|
||||
unsigned preset_idx = kInvalidIdx;
|
||||
unsigned domN = allow_all_fl ? f->presetN : f->probDomN;
|
||||
unsigned skipProbDomIdx = kInvalidIdx;
|
||||
unsigned pdi = kInvalidIdx;
|
||||
|
||||
|
||||
// if dry_on_play_fl is set and the dry preset playFl is set
|
||||
if( dry_on_play_fl && f->drySelectedFl )
|
||||
{
|
||||
//printf("PS:DOP!\n");
|
||||
preset_idx = p->dryPresetIdx;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if dry_on_selected_fl is set and the dry preset has a non-zero order
|
||||
if( dry_on_selected_fl && (f->presetA[ p->dryPresetIdx ].playFl || f->presetA[ p->dryPresetIdx ].order > 0) )
|
||||
{
|
||||
//printf("PS:DOS!\n");
|
||||
preset_idx = p->dryPresetIdx;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if no options exist then return the dry preset
|
||||
if( f->probDomN == 0 )
|
||||
{
|
||||
//printf("PS:NO OPTS!\n");
|
||||
preset_idx = p->dryPresetIdx;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if only one option exists
|
||||
if( f->probDomN == 1 && allow_all_fl==false )
|
||||
{
|
||||
//printf("PS:ONE OPT!\n");
|
||||
assert( allow_all_fl == false );
|
||||
preset_idx = f->probDomA[0].index;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
// if skip-preset was given and it is included in the candidate set
|
||||
if( skip_preset_idx != kInvalidIdx && (f->presetA[ skip_preset_idx ].playFl || f->presetA[ skip_preset_idx ].order>0) )
|
||||
{
|
||||
domN -= 1;
|
||||
if( !allow_all_fl )
|
||||
skipProbDomIdx = f->presetA[ skip_preset_idx ].prob_dom_idx;
|
||||
}
|
||||
|
||||
// if only one option exists after removing the skip-preset
|
||||
if( domN == 1 )
|
||||
{
|
||||
|
||||
//printf("PS:ONE non-SKIP!\n");
|
||||
assert( allow_all_fl == false );
|
||||
preset_idx = skipProbDomIdx==0 ? 1 : 0;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
pdi = std::min(domN-1,(unsigned)floor(((double)std::rand() * domN / RAND_MAX)));
|
||||
|
||||
if( allow_all_fl )
|
||||
{
|
||||
if( skip_preset_idx != kInvalidIdx && pdi >= skip_preset_idx && pdi < f->presetN-1 )
|
||||
pdi += 1;
|
||||
|
||||
preset_idx = pdi;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( skipProbDomIdx!=kInvalidIdx && pdi >= skipProbDomIdx && pdi < f->probDomN-1 )
|
||||
pdi += 1;
|
||||
|
||||
preset_idx = f->probDomA[ pdi ].index;
|
||||
}
|
||||
|
||||
|
||||
errLabel:
|
||||
|
||||
//if( preset_idx == kInvalidIdx || preset_idx >= f->presetN || preset_idx == skip_preset_idx )
|
||||
// printf("PS: INVALIDATED! %i pdi:%i N:%i domN:%i procDomN:%i skip:%i\n",preset_idx,pdi,f->presetN,domN,f->probDomN, skip_preset_idx);
|
||||
|
||||
return preset_idx == kInvalidIdx || preset_idx >= f->presetN || preset_idx == skip_preset_idx ? kInvalidIdx : preset_idx;
|
||||
|
||||
}
|
||||
|
||||
unsigned _prob_select_weighted_preset( const preset_sel_t* p,
|
||||
const frag_t* f,
|
||||
bool dry_on_play_fl, // select dry if dry has the 'playFl' selected
|
||||
unsigned skip_preset_idx = kInvalidIdx )
|
||||
{
|
||||
unsigned domMax = f->probDomainMax;
|
||||
unsigned preset_idx = kInvalidIdx;
|
||||
unsigned x = 0;
|
||||
unsigned x_acc = 0;
|
||||
|
||||
assert( f->probDomN>=1 && f->probDomA != nullptr );
|
||||
|
||||
// if dry_on_play_fl is set and the dry preset playFl is set
|
||||
if( dry_on_play_fl && f->drySelectedFl )
|
||||
{
|
||||
preset_idx = p->dryPresetIdx;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if there is only one possible preset to select
|
||||
if( f->probDomN == 1 )
|
||||
{
|
||||
preset_idx = f->probDomA[0].index;
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if a preset should be left out of consideration
|
||||
if( skip_preset_idx != kInvalidIdx )
|
||||
{
|
||||
assert( skip_preset_idx <= f->presetN );
|
||||
assert( f->presetA[ skip_preset_idx ].prob_dom_idx < f->probDomN );
|
||||
assert( domMax >= f->probDomA[ f->presetA[ skip_preset_idx].prob_dom_idx ].domain );
|
||||
|
||||
domMax -= f->probDomA[ f->presetA[ skip_preset_idx].prob_dom_idx ].domain;
|
||||
}
|
||||
|
||||
|
||||
// generate random integer between 0 and domMax
|
||||
x = (unsigned)floor(((double)std::rand() * domMax / RAND_MAX));
|
||||
|
||||
for(unsigned i=0; i<f->probDomN; ++i)
|
||||
if( f->probDomA[i].index != skip_preset_idx )
|
||||
{
|
||||
x_acc += f->probDomA[i].domain;
|
||||
|
||||
if( x < x_acc || (f->probDomN==2 && skip_preset_idx != kInvalidIdx) )
|
||||
{
|
||||
assert( f->presetA[ f->probDomA[i].index ].prob_dom_idx == i );
|
||||
preset_idx = f->probDomA[i].index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
return preset_idx == kInvalidIdx || preset_idx >= f->presetN ? kInvalidIdx : preset_idx;
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// 'Alt' related
|
||||
//
|
||||
void _print_preset_alts( preset_sel_t* p, const frag_t* f, const char* label )
|
||||
{
|
||||
printf("%s : ",label);
|
||||
@ -287,6 +532,10 @@ namespace cw
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
||||
frag_t* _find_frag( preset_sel_t* p, unsigned fragId )
|
||||
{
|
||||
frag_t* f;
|
||||
@ -909,6 +1158,7 @@ cw::rc_t cw::preset_sel::create( handle_t& hRef, const object_t* cfg )
|
||||
return rc;
|
||||
|
||||
p = mem::allocZ<preset_sel_t>();
|
||||
p->dryPresetIdx = kInvalidIdx;
|
||||
|
||||
// parse the cfg
|
||||
if((rc = cfg->getv( "preset_labelL", preset_labelL,
|
||||
@ -982,6 +1232,7 @@ cw::rc_t cw::preset_sel::create( handle_t& hRef, const object_t* cfg )
|
||||
|
||||
|
||||
p->defaultPresetIdx = kInvalidIdx;
|
||||
|
||||
if( default_preset_label != nullptr )
|
||||
if((p->defaultPresetIdx = _preset_label_to_index(p,default_preset_label)) ==kInvalidIdx )
|
||||
cwLogError(kInvalidIdRC,"The default preset label '%s' could not be found.",cwStringNullGuard(default_preset_label));
|
||||
@ -990,8 +1241,17 @@ cw::rc_t cw::preset_sel::create( handle_t& hRef, const object_t* cfg )
|
||||
cwLogError(kInvalidStateRC,"No default preset was set.");
|
||||
|
||||
if( p->dryPresetOrder == nullptr )
|
||||
{
|
||||
rc = cwLogError(kInvalidStateRC,"The 'dry' preset was not found.");
|
||||
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((p->dryPresetIdx = _preset_label_to_index(p,"dry")) == kInvalidIdx )
|
||||
{
|
||||
rc = cwLogError(kEleNotFoundRC,"The 'dry' preset does not exist.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
hRef.set(p);
|
||||
|
||||
@ -1564,6 +1824,52 @@ const cw::flow::preset_order_t* cw::preset_sel::fragment_active_presets( handle
|
||||
return preset_order;
|
||||
}
|
||||
|
||||
unsigned cw::preset_sel::prob_select_preset_index( handle_t h,
|
||||
const frag_t* f,
|
||||
unsigned flags,
|
||||
unsigned skip_preset_idx )
|
||||
{
|
||||
preset_sel_t* p = _handleToPtr(h);
|
||||
unsigned preset_idx = kInvalidIdx;
|
||||
bool dry_on_play_fl = cwIsFlag(flags,kDryOnPlayFl);
|
||||
|
||||
// if selecting deterministically ...
|
||||
if( cwIsNotFlag(flags,kUseProbFl) )
|
||||
{
|
||||
//printf("ps: deterministic skip:%i\n",skip_preset_idx);
|
||||
|
||||
for(unsigned i=0; i<f->probDomN; ++i)
|
||||
if( f->probDomA[i].index != skip_preset_idx )
|
||||
{
|
||||
// ... pick the first available preset
|
||||
preset_idx = f->probDomA[i].index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if using a uniform distribution
|
||||
if( cwIsFlag(flags,kUniformFl) )
|
||||
{
|
||||
bool dry_on_selected_fl = cwIsFlag(flags,kDryOnSelFl);
|
||||
bool allow_all_fl = cwIsFlag(flags,kAllowAllFl);
|
||||
|
||||
//printf("ps: uniform dop:%i all:%i sel-dry:%i skip:%i\n",dry_on_play_fl,allow_all_fl,dry_on_selected_fl,skip_preset_idx);
|
||||
|
||||
preset_idx = _prob_select_uniform_preset(p,f,dry_on_play_fl, dry_on_selected_fl, allow_all_fl, skip_preset_idx );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//printf("ps: weighted dop:%i skip:%i\n",dry_on_play_fl,skip_preset_idx);
|
||||
|
||||
preset_idx = _prob_select_weighted_preset( p, f, dry_on_play_fl, skip_preset_idx );
|
||||
}
|
||||
}
|
||||
|
||||
return preset_idx;
|
||||
}
|
||||
|
||||
|
||||
cw::rc_t cw::preset_sel::write( handle_t h, const char* fn )
|
||||
{
|
||||
@ -1649,7 +1955,7 @@ cw::rc_t cw::preset_sel::read( handle_t h, const char* fn )
|
||||
preset_sel_t* p = _handleToPtr(h);
|
||||
object_t* root = nullptr;
|
||||
const object_t* fragL_obj = nullptr;
|
||||
unsigned dryPresetIdx = _preset_label_to_index(p,"dry");
|
||||
|
||||
|
||||
// parse the preset file
|
||||
if((rc = objectFromFile(fn,root)) != kOkRC )
|
||||
@ -1712,7 +2018,6 @@ cw::rc_t cw::preset_sel::read( handle_t h, const char* fn )
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
|
||||
// create a new fragment
|
||||
if((rc = create_fragment( h, endLoc, end_ts, fragId)) != kOkRC )
|
||||
{
|
||||
@ -1782,15 +2087,19 @@ cw::rc_t cw::preset_sel::read( handle_t h, const char* fn )
|
||||
f->altPresetIdxA[0] = preset_idx;
|
||||
|
||||
// if the dry preset is selected
|
||||
if( preset_idx == dryPresetIdx )
|
||||
if( preset_idx == p->dryPresetIdx )
|
||||
f->drySelectedFl = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if only one preset is active and the dry preset is active
|
||||
f->dryOnlyFl = activePresetN==1 && (f->presetA[dryPresetIdx].order>0 || f->presetA[dryPresetIdx].playFl);
|
||||
f->dryOnlyFl = activePresetN==1 && (f->presetA[p->dryPresetIdx].order>0 || f->presetA[p->dryPresetIdx].playFl);
|
||||
|
||||
// setup for prob. preset selection
|
||||
if((rc = _pre_calc_for_prob_select(p, f)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,9 +16,17 @@ namespace cw
|
||||
bool seqFl; // play this preset during sequencing.
|
||||
unsigned preset_idx; // preset index into preset_labelA[].
|
||||
unsigned order; // selection label
|
||||
char* alt_str; // 'alt' label
|
||||
char* alt_str; // 'alt' label
|
||||
unsigned prob_dom_idx; // index of this preset in probDomA[]
|
||||
} preset_t;
|
||||
|
||||
typedef struct prob_domain_str
|
||||
{
|
||||
unsigned index; // index of preset into frag.presetA[]
|
||||
unsigned order; // preset order value or 0 if the playFl is set on presetA[index] and presetA[index].order==0
|
||||
unsigned domain; // probability domain area (greater for more likely preset values)
|
||||
} prob_domain_t;
|
||||
|
||||
typedef struct frag_str
|
||||
{
|
||||
unsigned fragId; // Unique fragment id
|
||||
@ -46,6 +54,10 @@ namespace cw
|
||||
bool uiSelectFl;
|
||||
bool seqAllFl; // Set if all preset.seqFl's should be treated as though they are set to true.
|
||||
|
||||
prob_domain_t* probDomA; // probDomA[ probDomN ] ascending order on 'order' - preset with playFl set is always first
|
||||
unsigned probDomN;
|
||||
unsigned probDomainMax; // sum(probDomA.domain)
|
||||
|
||||
struct frag_str* link;
|
||||
struct frag_str* prev;
|
||||
} frag_t;
|
||||
@ -150,6 +162,20 @@ namespace cw
|
||||
};
|
||||
|
||||
const flow::preset_order_t* fragment_active_presets( handle_t h, const frag_t* f, unsigned flags, unsigned& count_ref );
|
||||
|
||||
enum {
|
||||
kUseProbFl = 0x01, // True=Select the preset probalistically. False=Select the preset with the lowest non-zero order.
|
||||
kUniformFl = 0x02, // Ignored if kUseProbFl is not set. True=Use uniform PDF to select preset. False=Use 'order' weightings to select preset.
|
||||
kDryOnPlayFl = 0x04, // Ignored if kUseProbFl is not set. True=Select 'dry' if marked with 'play-fl'. False=Choose probabilistically.
|
||||
kAllowAllFl = 0x08, // Ignored if kUseProbFl is not set. True=Select from all presets. False=Select from presets with order>0 or play_fl set.
|
||||
kDryOnSelFl = 0x10, // Ignored if kUseProbFl and kUniformFl is not set. True=Select 'dry' if dry order>0 or play_fl set. Otherwise choose with uniform prob.
|
||||
};
|
||||
|
||||
unsigned prob_select_preset_index( handle_t h,
|
||||
const frag_t* f,
|
||||
unsigned flags,
|
||||
unsigned skip_preset_idx = kInvalidIdx );
|
||||
|
||||
|
||||
rc_t write( handle_t h, const char* fn );
|
||||
rc_t read( handle_t h, const char* fn );
|
||||
|
Loading…
Reference in New Issue
Block a user