Merge branch 'master' of https://gitea.currawongproject.org/cml/libcw
This commit is contained in:
commit
7b3a79bffc
@ -62,6 +62,7 @@ namespace cw
|
|||||||
{ "poly_voice_ctl", &poly_voice_ctl::members },
|
{ "poly_voice_ctl", &poly_voice_ctl::members },
|
||||||
{ "midi_voice", &midi_voice::members },
|
{ "midi_voice", &midi_voice::members },
|
||||||
{ "piano_voice", &piano_voice::members },
|
{ "piano_voice", &piano_voice::members },
|
||||||
|
{ "voice_detector", &voice_detector::members },
|
||||||
{ "sample_hold", &sample_hold::members },
|
{ "sample_hold", &sample_hold::members },
|
||||||
{ "number", &number::members },
|
{ "number", &number::members },
|
||||||
{ "reg", ®::members },
|
{ "reg", ®::members },
|
||||||
@ -82,6 +83,7 @@ namespace cw
|
|||||||
{ "preset_select", &preset_select::members },
|
{ "preset_select", &preset_select::members },
|
||||||
{ "gutim_ps", &gutim_ps::members },
|
{ "gutim_ps", &gutim_ps::members },
|
||||||
{ "score_follower", &score_follower::members },
|
{ "score_follower", &score_follower::members },
|
||||||
|
{ "score_follower_2",&score_follower_2::members },
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
653
cwFlowPerf.cpp
653
cwFlowPerf.cpp
@ -32,6 +32,9 @@
|
|||||||
#include "cwScoreFollowerPerf.h"
|
#include "cwScoreFollowerPerf.h"
|
||||||
#include "cwScoreFollower.h"
|
#include "cwScoreFollower.h"
|
||||||
|
|
||||||
|
#include "cwPianoScore.h"
|
||||||
|
#include "cwScoreFollow2.h"
|
||||||
|
|
||||||
#include "cwPianoScore.h"
|
#include "cwPianoScore.h"
|
||||||
|
|
||||||
#include "cwPresetSel.h"
|
#include "cwPresetSel.h"
|
||||||
@ -55,6 +58,7 @@ namespace cw
|
|||||||
kScoreFNamePId,
|
kScoreFNamePId,
|
||||||
kStoppingMsPId,
|
kStoppingMsPId,
|
||||||
kDoneFlPId,
|
kDoneFlPId,
|
||||||
|
kMaxLocPId,
|
||||||
kOutPId,
|
kOutPId,
|
||||||
kStartPId,
|
kStartPId,
|
||||||
kStopPId,
|
kStopPId,
|
||||||
@ -131,6 +135,8 @@ namespace cw
|
|||||||
unsigned stopping_ms; // max time in milliseconds to wait for all notes to end before sending all-note-off
|
unsigned stopping_ms; // max time in milliseconds to wait for all notes to end before sending all-note-off
|
||||||
unsigned stopping_sample_idx; // 0 if not 'stopping', otherwise the max sample index after which the player will enter 'idle' state.
|
unsigned stopping_sample_idx; // 0 if not 'stopping', otherwise the max sample index after which the player will enter 'idle' state.
|
||||||
|
|
||||||
|
unsigned maxLocId;
|
||||||
|
|
||||||
} inst_t;
|
} inst_t;
|
||||||
|
|
||||||
rc_t _load_score( proc_t* proc, inst_t* p, const char* score_fname )
|
rc_t _load_score( proc_t* proc, inst_t* p, const char* score_fname )
|
||||||
@ -178,6 +184,7 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->maxLocId = 0;
|
||||||
p->msgA = mem::allocZ<msg_t>(p->msgAllocN);
|
p->msgA = mem::allocZ<msg_t>(p->msgAllocN);
|
||||||
p->chMsgA = mem::allocZ<midi::ch_msg_t>(p->msgAllocN);
|
p->chMsgA = mem::allocZ<midi::ch_msg_t>(p->msgAllocN);
|
||||||
|
|
||||||
@ -185,11 +192,19 @@ namespace cw
|
|||||||
{
|
{
|
||||||
if( score_evt->status != 0 )
|
if( score_evt->status != 0 )
|
||||||
{
|
{
|
||||||
|
bool note_on_fl = false;
|
||||||
msg_t* m = p->msgA + p->msgN;
|
msg_t* m = p->msgA + p->msgN;
|
||||||
midi::ch_msg_t* mm = p->chMsgA + p->msgN;
|
midi::ch_msg_t* mm = p->chMsgA + p->msgN;
|
||||||
|
|
||||||
if( score_evt->loc != kInvalidId )
|
if( score_evt->loc != kInvalidId )
|
||||||
|
{
|
||||||
|
// verify that the score is in order by location
|
||||||
|
assert( score_evt->loc >= last_loc );
|
||||||
last_loc = score_evt->loc;
|
last_loc = score_evt->loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( last_loc > p->maxLocId )
|
||||||
|
p->maxLocId = last_loc;
|
||||||
|
|
||||||
m->sample_idx = (unsigned)(proc->ctx->sample_rate * score_evt->sec);
|
m->sample_idx = (unsigned)(proc->ctx->sample_rate * score_evt->sec);
|
||||||
m->loc = last_loc;
|
m->loc = last_loc;
|
||||||
@ -206,9 +221,11 @@ namespace cw
|
|||||||
|
|
||||||
time::fracSecondsToSpec( mm->timeStamp, score_evt->sec );
|
time::fracSecondsToSpec( mm->timeStamp, score_evt->sec );
|
||||||
|
|
||||||
mm->devIdx = kInvalidIdx;
|
note_on_fl = midi::isNoteOn(score_evt->status,score_evt->d1);
|
||||||
mm->portIdx= kInvalidIdx;
|
|
||||||
mm->uid = uuid++;
|
mm->devIdx = note_on_fl ? m->loc : kInvalidIdx; //BUG BUG BUG: hack to do per chord/note processing in gutim_ps
|
||||||
|
mm->portIdx= note_on_fl ? score_evt->chord_note_idx : kInvalidIdx;
|
||||||
|
mm->uid = note_on_fl ? score_evt->chord_note_cnt : kInvalidId;
|
||||||
mm->ch = score_evt->status & 0x0f;
|
mm->ch = score_evt->status & 0x0f;
|
||||||
mm->status = score_evt->status & 0xf0;
|
mm->status = score_evt->status & 0xf0;
|
||||||
mm->d0 = score_evt->d0;
|
mm->d0 = score_evt->d0;
|
||||||
@ -216,6 +233,7 @@ namespace cw
|
|||||||
m->d1 = score_evt->d1; // track the initial d1 before vel. mapping is applied
|
m->d1 = score_evt->d1; // track the initial d1 before vel. mapping is applied
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if( midi::isSustainPedal( mm->status, mm->d0 ) )
|
if( midi::isSustainPedal( mm->status, mm->d0 ) )
|
||||||
{
|
{
|
||||||
bool down_fl = pedalStateFlags & kDampPedalDownFl;
|
bool down_fl = pedalStateFlags & kDampPedalDownFl;
|
||||||
@ -417,7 +435,8 @@ namespace cw
|
|||||||
|
|
||||||
|
|
||||||
if((rc = var_register_and_set(proc,kAnyChIdx,
|
if((rc = var_register_and_set(proc,kAnyChIdx,
|
||||||
kDoneFlPId,"done_fl", kBaseSfxId, false)) != kOkRC )
|
kDoneFlPId,"done_fl", kBaseSfxId, false,
|
||||||
|
kMaxLocPId,"loc_cnt", kBaseSfxId, p->maxLocId+1 )) != kOkRC )
|
||||||
{
|
{
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
@ -670,6 +689,11 @@ namespace cw
|
|||||||
|
|
||||||
bool note_on_fl = midi::isNoteOn(m->midi->status, m->midi->d1);
|
bool note_on_fl = midi::isNoteOn(m->midi->status, m->midi->d1);
|
||||||
|
|
||||||
|
//if( note_on_fl )
|
||||||
|
//{
|
||||||
|
// printf("sc:%i %i %i %s\n",m->meas,m->loc,m->midi->d0,midi::midiToSciPitch(m->midi->d0));
|
||||||
|
//}
|
||||||
|
|
||||||
// fill the output record with this msg but filter out note-on's when in stopping-state
|
// fill the output record with this msg but filter out note-on's when in stopping-state
|
||||||
if( p->state == kPlayStateId || (p->state==kStoppingStateId && note_on_fl==false) )
|
if( p->state == kPlayStateId || (p->state==kStoppingStateId && note_on_fl==false) )
|
||||||
{
|
{
|
||||||
@ -745,6 +769,7 @@ namespace cw
|
|||||||
vel_tbl_t* velTblL;
|
vel_tbl_t* velTblL;
|
||||||
vel_tbl_t* activeVelTbl;
|
vel_tbl_t* activeVelTbl;
|
||||||
unsigned i_midi_fld_idx;
|
unsigned i_midi_fld_idx;
|
||||||
|
unsigned i_score_vel_fld_idx;
|
||||||
unsigned o_midi_fld_idx;
|
unsigned o_midi_fld_idx;
|
||||||
|
|
||||||
recd_array_t* recd_array; // output record array
|
recd_array_t* recd_array; // output record array
|
||||||
@ -954,6 +979,8 @@ namespace cw
|
|||||||
p->midiN = p->recd_array->allocRecdN;
|
p->midiN = p->recd_array->allocRecdN;
|
||||||
p->midiA = mem::allocZ<midi::ch_msg_t>(p->midiN);
|
p->midiA = mem::allocZ<midi::ch_msg_t>(p->midiN);
|
||||||
|
|
||||||
|
// If the velocity table is being fed by the score follower then there may be a 'score_vel' field in the input record.
|
||||||
|
p->i_score_vel_fld_idx = recd_type_field_index( rbuf->type, "score_vel");
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
@ -1028,6 +1055,10 @@ namespace cw
|
|||||||
|
|
||||||
// if this is a note on
|
// if this is a note on
|
||||||
if( midi::isNoteOn(i_m->status,i_m->d1) )
|
if( midi::isNoteOn(i_m->status,i_m->d1) )
|
||||||
|
{
|
||||||
|
|
||||||
|
// if the 'score_vel' was not given
|
||||||
|
if( p->i_score_vel_fld_idx == kInvalidIdx )
|
||||||
{
|
{
|
||||||
// and the velocity is valid
|
// and the velocity is valid
|
||||||
if( i_m->d1 >= p->activeVelTbl->tblN )
|
if( i_m->d1 >= p->activeVelTbl->tblN )
|
||||||
@ -1038,6 +1069,33 @@ namespace cw
|
|||||||
|
|
||||||
// map the velocity through the active table
|
// map the velocity through the active table
|
||||||
o_m->d1 = p->activeVelTbl->tblA[ i_m->d1 ];
|
o_m->d1 = p->activeVelTbl->tblA[ i_m->d1 ];
|
||||||
|
}
|
||||||
|
else // ... a 'score_vel' exists
|
||||||
|
{
|
||||||
|
unsigned score_vel = -1;
|
||||||
|
|
||||||
|
// get the score_vel
|
||||||
|
if((rc = recd_get(i_rbuf->type,i_r,p->i_score_vel_fld_idx,score_vel)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"'score_velocity access failed in velocity table.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the score_vel is valid (it won't be if this note was not tracked in the score)
|
||||||
|
if( score_vel != (unsigned)-1 )
|
||||||
|
{
|
||||||
|
// verify that the 'score_vel' is inside the range of the table
|
||||||
|
if(score_vel >= p->activeVelTbl->tblN )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The pre-mapped score velocity value %i is outside of the range (%i) of the velocity table '%s'.",score_vel,p->activeVelTbl->tblN,cwStringNullGuard(p->activeVelTbl->label));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply the score_vel to the map
|
||||||
|
o_m->d1 = p->activeVelTbl->tblA[ score_vel ];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//printf("%i %i %s\n",i_m->d1,o_m->d1,p->activeVelTbl->label);
|
//printf("%i %i %s\n",i_m->d1,o_m->d1,p->activeVelTbl->label);
|
||||||
}
|
}
|
||||||
@ -1261,10 +1319,15 @@ namespace cw
|
|||||||
kInitCfgPId,
|
kInitCfgPId,
|
||||||
kPresetMapCfgPId,
|
kPresetMapCfgPId,
|
||||||
kFNamePId,
|
kFNamePId,
|
||||||
|
kLocCntPId,
|
||||||
kInPId,
|
kInPId,
|
||||||
kLocPId,
|
kLocPId,
|
||||||
kResetPId,
|
kResetPId,
|
||||||
|
kPriManualSelPId,
|
||||||
|
kSecManualSelPId,
|
||||||
kPerNoteFlPId,
|
kPerNoteFlPId,
|
||||||
|
kPerLocFlPId,
|
||||||
|
kDryChordFlPId,
|
||||||
|
|
||||||
kPriProbFlPId,
|
kPriProbFlPId,
|
||||||
kPriUniformFlPId,
|
kPriUniformFlPId,
|
||||||
@ -1310,6 +1373,15 @@ namespace cw
|
|||||||
kCoeffPresetValTId,
|
kCoeffPresetValTId,
|
||||||
} value_tid_t;
|
} value_tid_t;
|
||||||
|
|
||||||
|
typedef struct loc_str
|
||||||
|
{
|
||||||
|
unsigned pri_preset_idx;
|
||||||
|
unsigned sec_preset_idx;
|
||||||
|
unsigned note_cnt;
|
||||||
|
unsigned note_idx;
|
||||||
|
unsigned rand;
|
||||||
|
} loc_t;
|
||||||
|
|
||||||
typedef struct var_cfg_str
|
typedef struct var_cfg_str
|
||||||
{
|
{
|
||||||
const char* var_label; // gutim_ps var label
|
const char* var_label; // gutim_ps var label
|
||||||
@ -1391,6 +1463,8 @@ namespace cw
|
|||||||
coeff_t cur_interp_dist;
|
coeff_t cur_interp_dist;
|
||||||
|
|
||||||
bool per_note_fl;
|
bool per_note_fl;
|
||||||
|
bool per_loc_fl;
|
||||||
|
bool dry_chord_fl;
|
||||||
bool pri_prob_fl;
|
bool pri_prob_fl;
|
||||||
bool pri_uniform_fl;
|
bool pri_uniform_fl;
|
||||||
bool pri_dry_on_play_fl;
|
bool pri_dry_on_play_fl;
|
||||||
@ -1406,9 +1480,31 @@ namespace cw
|
|||||||
bool interp_fl;
|
bool interp_fl;
|
||||||
bool interp_rand_fl;
|
bool interp_rand_fl;
|
||||||
|
|
||||||
|
list_t* manual_sel_list;
|
||||||
|
unsigned cur_manual_pri_preset_idx;
|
||||||
|
unsigned cur_manual_sec_preset_idx;
|
||||||
|
|
||||||
|
loc_t* locA;
|
||||||
|
unsigned locN;
|
||||||
|
unsigned dry_preset_idx;
|
||||||
|
|
||||||
} inst_t;
|
} inst_t;
|
||||||
|
|
||||||
|
void _init_loc_array( inst_t* p )
|
||||||
|
{
|
||||||
|
if( p->locN > 0 && p->locA == nullptr )
|
||||||
|
p->locA = mem::allocZ<loc_t>(p->locN);
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->locN; ++i)
|
||||||
|
{
|
||||||
|
p->locA[i].pri_preset_idx = kInvalidIdx;
|
||||||
|
p->locA[i].sec_preset_idx = kInvalidIdx;
|
||||||
|
p->locA[i].note_cnt = 0;
|
||||||
|
p->locA[i].note_idx = kInvalidIdx;
|
||||||
|
p->locA[i].rand = rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* _preset_index_to_label( inst_t* p, unsigned preset_idx )
|
const char* _preset_index_to_label( inst_t* p, unsigned preset_idx )
|
||||||
{
|
{
|
||||||
const char* label = "<none>";
|
const char* label = "<none>";
|
||||||
@ -1419,6 +1515,46 @@ namespace cw
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_t _create_manual_select_list( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* var_labelA[] = { "pri_manual_sel", "sec_manual_sel" };
|
||||||
|
const unsigned var_labelN = sizeof(var_labelA)/sizeof(var_labelA[0]);
|
||||||
|
|
||||||
|
p->cur_manual_pri_preset_idx = kInvalidIdx;
|
||||||
|
p->cur_manual_sec_preset_idx = kInvalidIdx;
|
||||||
|
|
||||||
|
// create the list of values for the 'manual_sel' variable
|
||||||
|
if((rc = list_create(p->manual_sel_list, p->presetN+1 )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = list_append(p->manual_sel_list,"auto",kInvalidIdx)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<p->presetN; ++i)
|
||||||
|
if((rc = list_append( p->manual_sel_list, _preset_index_to_label(p,i), i)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
for(unsigned i=0; i<var_labelN; ++i)
|
||||||
|
{
|
||||||
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
|
if((rc = var_find(proc, var_labelA[i], kBaseSfxId, kAnyChIdx, var )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The '%s' variable could not be found.",var_labelA[i]);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->value_list = p->manual_sel_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"The 'gutim_ps' manual selection list create failed.");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
rc_t _read_class_preset_value( proc_t* proc, preset_t* preset, var_cfg_t* var_cfg, unsigned ch_idx, T& val_ref )
|
rc_t _read_class_preset_value( proc_t* proc, preset_t* preset, var_cfg_t* var_cfg, unsigned ch_idx, T& val_ref )
|
||||||
{
|
{
|
||||||
@ -1547,11 +1683,11 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _apply_preset_no_interp(proc_t* proc, inst_t* p, unsigned voice_idx)
|
rc_t _apply_preset_no_interp(proc_t* proc, inst_t* p, unsigned voice_idx, unsigned preset_idx)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
if( p->cur_pri_preset_idx == kInvalidIdx || p->cur_pri_preset_idx >= p->presetN )
|
if( preset_idx == kInvalidIdx || preset_idx >= p->presetN )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The primary preset is invalid.");
|
rc = cwLogError(kInvalidArgRC,"The primary preset is invalid.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -1561,11 +1697,11 @@ namespace cw
|
|||||||
{
|
{
|
||||||
const var_cfg_t* var_cfg = _var_cfgA + var_idx;
|
const var_cfg_t* var_cfg = _var_cfgA + var_idx;
|
||||||
|
|
||||||
assert( p->cur_pri_preset_idx < p->presetN );
|
assert( preset_idx < p->presetN );
|
||||||
|
|
||||||
for(unsigned ch_idx=0; ch_idx<kMaxChN; ++ch_idx )
|
for(unsigned ch_idx=0; ch_idx<kMaxChN; ++ch_idx )
|
||||||
{
|
{
|
||||||
const preset_value_t* v = p->presetA[ p->cur_pri_preset_idx ].varA[ var_idx ].chA + ch_idx;
|
const preset_value_t* v = p->presetA[ preset_idx ].varA[ var_idx ].chA + ch_idx;
|
||||||
|
|
||||||
variable_t* varb;
|
variable_t* varb;
|
||||||
var_find(proc, p->base[var_cfg->var_pid] + voice_idx,ch_idx, varb);
|
var_find(proc, p->base[var_cfg->var_pid] + voice_idx,ch_idx, varb);
|
||||||
@ -1600,17 +1736,17 @@ namespace cw
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rc_t _apply_preset_with_interp(proc_t* proc, inst_t* p, unsigned voice_idx)
|
rc_t _apply_preset_with_interp(proc_t* proc, inst_t* p, unsigned voice_idx, unsigned pri_preset_idx, unsigned sec_preset_idx)
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
if( p->cur_pri_preset_idx == kInvalidIdx || p->cur_pri_preset_idx >= p->presetN )
|
if( pri_preset_idx == kInvalidIdx || pri_preset_idx >= p->presetN )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The primary preset is invalid.");
|
rc = cwLogError(kInvalidArgRC,"The primary preset is invalid.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p->cur_sec_preset_idx == kInvalidIdx || p->cur_sec_preset_idx >= p->presetN )
|
if( sec_preset_idx == kInvalidIdx || sec_preset_idx >= p->presetN )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The secondary preset is invalid.");
|
rc = cwLogError(kInvalidArgRC,"The secondary preset is invalid.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -1620,13 +1756,13 @@ namespace cw
|
|||||||
{
|
{
|
||||||
const var_cfg_t* var_cfg = _var_cfgA + var_idx;
|
const var_cfg_t* var_cfg = _var_cfgA + var_idx;
|
||||||
|
|
||||||
assert( p->cur_pri_preset_idx < p->presetN );
|
assert( pri_preset_idx < p->presetN );
|
||||||
|
|
||||||
for(unsigned ch_idx=0; ch_idx<kMaxChN; ++ch_idx )
|
for(unsigned ch_idx=0; ch_idx<kMaxChN; ++ch_idx )
|
||||||
{
|
{
|
||||||
|
|
||||||
const preset_value_t* c0 = p->presetA[ p->cur_pri_preset_idx ].varA[ var_idx ].chA + ch_idx;
|
const preset_value_t* c0 = p->presetA[ pri_preset_idx ].varA[ var_idx ].chA + ch_idx;
|
||||||
const preset_value_t* c1 = p->presetA[ p->cur_sec_preset_idx ].varA[ var_idx ].chA + ch_idx;
|
const preset_value_t* c1 = p->presetA[ sec_preset_idx ].varA[ var_idx ].chA + ch_idx;
|
||||||
|
|
||||||
switch( var_cfg->tid )
|
switch( var_cfg->tid )
|
||||||
{
|
{
|
||||||
@ -1697,23 +1833,26 @@ namespace cw
|
|||||||
_report_preset( proc, p, "Sec", p->cur_sec_preset_idx );
|
_report_preset( proc, p, "Sec", p->cur_sec_preset_idx );
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _apply_preset( proc_t* proc, inst_t* p, const midi::ch_msg_t* m, unsigned voice_idx )
|
// apply the preset assoc'd with p->cur_pri_preset_idx and p->cur_sec_preset_idx
|
||||||
|
rc_t _apply_preset( proc_t* proc, inst_t* p, const midi::ch_msg_t* m, unsigned voice_idx, unsigned pri_preset_idx, unsigned sec_preset_idx )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
pri_preset_idx = p->cur_manual_pri_preset_idx == kInvalidIdx ? pri_preset_idx : p->cur_manual_pri_preset_idx;
|
||||||
|
sec_preset_idx = p->cur_manual_sec_preset_idx == kInvalidIdx ? sec_preset_idx : p->cur_manual_sec_preset_idx;
|
||||||
|
|
||||||
if( p->cur_frag == nullptr || p->cur_pri_preset_idx == kInvalidIdx )
|
if( pri_preset_idx == kInvalidIdx )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidStateRC,"No current preset has been selected.");
|
rc = cwLogError(kInvalidStateRC,"No current preset has been selected.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( p->cur_sec_preset_idx == kInvalidIdx )
|
if( !p->interp_fl || sec_preset_idx == kInvalidIdx )
|
||||||
{
|
{
|
||||||
rc = _apply_preset_no_interp(proc, p, voice_idx);
|
rc = _apply_preset_no_interp(proc, p, voice_idx, pri_preset_idx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = _apply_preset_with_interp(proc, p, voice_idx);
|
rc = _apply_preset_with_interp(proc, p, voice_idx, pri_preset_idx, sec_preset_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
@ -1795,13 +1934,20 @@ namespace cw
|
|||||||
const object_t* cfg = nullptr;
|
const object_t* cfg = nullptr;
|
||||||
bool resetFl = false;
|
bool resetFl = false;
|
||||||
|
|
||||||
|
p->dry_preset_idx = kInvalidIdx;
|
||||||
|
|
||||||
if((rc = var_register_and_get(proc,kAnyChIdx,
|
if((rc = var_register_and_get(proc,kAnyChIdx,
|
||||||
kInitCfgPId, "cfg", kBaseSfxId, cfg, // TODO: clean up the contents of this CFG
|
kInitCfgPId, "cfg", kBaseSfxId, cfg, // TODO: clean up the contents of this CFG
|
||||||
kInPId, "in", kBaseSfxId, rbuf,
|
kInPId, "in", kBaseSfxId, rbuf,
|
||||||
kFNamePId, "fname", kBaseSfxId, fname,
|
kFNamePId, "fname", kBaseSfxId, fname,
|
||||||
|
kLocCntPId, "loc_cnt", kBaseSfxId, p->locN,
|
||||||
kLocPId, "loc", kBaseSfxId, loc,
|
kLocPId, "loc", kBaseSfxId, loc,
|
||||||
kResetPId, "reset", kBaseSfxId, resetFl,
|
kResetPId, "reset", kBaseSfxId, resetFl,
|
||||||
kPerNoteFlPId, "per_note_fl",kBaseSfxId, p->per_note_fl,
|
kPriManualSelPId, "pri_manual_sel", kBaseSfxId, p->cur_manual_pri_preset_idx,
|
||||||
|
kSecManualSelPId, "sec_manual_sel", kBaseSfxId, p->cur_manual_sec_preset_idx,
|
||||||
|
kPerNoteFlPId, "per_note_fl", kBaseSfxId, p->per_note_fl,
|
||||||
|
kPerLocFlPId, "per_loc_fl", kBaseSfxId, p->per_loc_fl,
|
||||||
|
kDryChordFlPId, "dry_chord_fl", kBaseSfxId, p->dry_chord_fl,
|
||||||
|
|
||||||
kPriProbFlPId, "pri_prob_fl", kBaseSfxId, p->pri_prob_fl,
|
kPriProbFlPId, "pri_prob_fl", kBaseSfxId, p->pri_prob_fl,
|
||||||
kPriUniformFlPId, "pri_uniform_fl", kBaseSfxId, p->pri_uniform_fl,
|
kPriUniformFlPId, "pri_uniform_fl", kBaseSfxId, p->pri_uniform_fl,
|
||||||
@ -1841,6 +1987,8 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->dry_preset_idx = preset_sel::dry_preset_index(p->psH);
|
||||||
|
|
||||||
// read in the loc->preset map file
|
// read in the loc->preset map file
|
||||||
if((rc = preset_sel::read(p->psH,exp_fname)) != kOkRC )
|
if((rc = preset_sel::read(p->psH,exp_fname)) != kOkRC )
|
||||||
{
|
{
|
||||||
@ -1854,8 +2002,9 @@ namespace cw
|
|||||||
// The location is coming from a 'record', get the location field.
|
// The location is coming from a 'record', get the location field.
|
||||||
if((p->loc_fld_idx = recd_type_field_index( rbuf->type, "loc")) == kInvalidIdx )
|
if((p->loc_fld_idx = recd_type_field_index( rbuf->type, "loc")) == kInvalidIdx )
|
||||||
{
|
{
|
||||||
rc = cwLogError(kInvalidArgRC,"The 'in' record does not have a 'loc' field.");
|
cwLogWarning("The incoming record to the 'gutim_ps' object does not have a 'loc' field. Score tracking is disabled.");
|
||||||
goto errLabel;
|
//rc = cwLogError(kInvalidArgRC,"The 'in' record does not have a 'loc' field.");
|
||||||
|
//goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1895,9 +2044,17 @@ namespace cw
|
|||||||
p->psPresetCnt = preset_count(p->psH); // get the count of preset class (~13)
|
p->psPresetCnt = preset_count(p->psH); // get the count of preset class (~13)
|
||||||
|
|
||||||
// Get the values for all the presets required by the transform parameter variables
|
// Get the values for all the presets required by the transform parameter variables
|
||||||
rc = _create_and_fill_preset_array( proc, p );
|
if((rc = _create_and_fill_preset_array( proc, p )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
|
||||||
|
// create the 'manual_sel' list based on the available preset labels
|
||||||
|
if((rc = _create_manual_select_list(proc, p )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// initialize locA[]
|
||||||
|
_init_loc_array(p);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
mem::release(exp_fname);
|
mem::release(exp_fname);
|
||||||
return rc;
|
return rc;
|
||||||
@ -1907,7 +2064,8 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
// Custom clean-up code goes here
|
list_destroy(p->manual_sel_list);
|
||||||
|
mem::release(p->locA);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1916,15 +2074,78 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
bool per_note_fl = false;
|
bool per_note_fl = false;
|
||||||
|
bool per_loc_fl = false;
|
||||||
|
bool chord_dry_fl = false;
|
||||||
|
bool apply_dry_fl = false;
|
||||||
|
bool update_preset_fl = false;
|
||||||
|
unsigned loc_idx = kInvalidIdx;
|
||||||
|
unsigned pri_preset_idx = p->cur_pri_preset_idx;
|
||||||
|
unsigned sec_preset_idx = p->cur_sec_preset_idx;
|
||||||
|
|
||||||
if( var_get(proc,kPerNoteFlPId,kAnyChIdx,per_note_fl) != kOkRC )
|
if((rc = var_get(proc,kPerLocFlPId,kAnyChIdx,per_loc_fl)) != kOkRC)
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
|
// if we are selecting a new preset per location
|
||||||
|
if( per_loc_fl && p->locN > 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned loc = m->devIdx;
|
||||||
|
unsigned note_idx = m->portIdx;
|
||||||
|
unsigned note_cnt = m->uid;
|
||||||
|
assert( loc < p->locN );
|
||||||
|
|
||||||
|
// if this is the first note received for this location
|
||||||
|
if( p->locA[ loc ].note_cnt == 0 )
|
||||||
|
{
|
||||||
|
p->locA[ loc ].note_cnt = note_cnt;
|
||||||
|
loc_idx = loc;
|
||||||
|
update_preset_fl = true;
|
||||||
|
}
|
||||||
|
else // ... select the preset based on the preset previously picked for this location
|
||||||
|
{
|
||||||
|
pri_preset_idx = p->locA[ loc ].pri_preset_idx;
|
||||||
|
sec_preset_idx = p->locA[ loc ].sec_preset_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->locA[ loc ].note_idx += 1;
|
||||||
|
|
||||||
|
|
||||||
|
var_get(proc,kDryChordFlPId,kAnyChIdx,chord_dry_fl);
|
||||||
|
|
||||||
|
apply_dry_fl = chord_dry_fl && (((note_idx % 2)==0) == (p->locA[ loc ].rand > RAND_MAX/2));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((rc = var_get(proc,kPerNoteFlPId,kAnyChIdx,per_note_fl)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// if we are selecting presets per note
|
||||||
if( per_note_fl )
|
if( per_note_fl )
|
||||||
|
update_preset_fl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a new preset should be selected
|
||||||
|
if( update_preset_fl )
|
||||||
|
{
|
||||||
if((rc = _update_cur_preset_idx( proc, p, p->cur_frag )) != kOkRC )
|
if((rc = _update_cur_preset_idx( proc, p, p->cur_frag )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
rc = _apply_preset( proc, p, m, voice_idx );
|
// if this is the first note for this 'loc' then cache the selected presets
|
||||||
|
if( loc_idx != kInvalidIdx )
|
||||||
|
{
|
||||||
|
p->locA[ loc_idx ].pri_preset_idx = p->cur_pri_preset_idx;
|
||||||
|
p->locA[ loc_idx ].sec_preset_idx = p->cur_sec_preset_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( apply_dry_fl )
|
||||||
|
{
|
||||||
|
pri_preset_idx = p->dry_preset_idx;
|
||||||
|
sec_preset_idx = p->dry_preset_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _apply_preset( proc, p, m, voice_idx, pri_preset_idx, sec_preset_idx );
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
@ -1956,15 +2177,16 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _exec_on_new_location( proc_t* proc, inst_t* p )
|
rc_t _exec_on_new_fragment( proc_t* proc, inst_t* p )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
bool per_note_fl = false;
|
bool per_note_fl = false;
|
||||||
|
bool per_loc_fl = false;;
|
||||||
|
var_get(proc,kPerNoteFlPId,kAnyChIdx,per_note_fl);
|
||||||
|
var_get(proc,kPerLocFlPId,kAnyChIdx,per_loc_fl);
|
||||||
|
|
||||||
if( var_get(proc,kPerNoteFlPId,kAnyChIdx,per_note_fl) != kOkRC )
|
// if we are not assigning presets per note - then select p->cur_pri/sec_preset_idx for all following notes
|
||||||
goto errLabel;
|
if( per_note_fl == false && per_loc_fl == false )
|
||||||
|
|
||||||
if( !per_note_fl )
|
|
||||||
if((rc = _update_cur_preset_idx( proc, p, p->cur_frag )) != kOkRC )
|
if((rc = _update_cur_preset_idx( proc, p, p->cur_frag )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
@ -1979,6 +2201,10 @@ namespace cw
|
|||||||
rbuf_t* in_rbuf = nullptr;
|
rbuf_t* in_rbuf = nullptr;
|
||||||
unsigned loc = kInvalidIdx;
|
unsigned loc = kInvalidIdx;
|
||||||
|
|
||||||
|
// if score tracking is disabled
|
||||||
|
if( p->loc_fld_idx == kInvalidIdx )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = var_get(proc,kInPId,kAnyChIdx,in_rbuf)) != kOkRC)
|
if((rc = var_get(proc,kInPId,kAnyChIdx,in_rbuf)) != kOkRC)
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
@ -2001,13 +2227,17 @@ namespace cw
|
|||||||
{
|
{
|
||||||
const preset_sel::frag_t* frag = nullptr;
|
const preset_sel::frag_t* frag = nullptr;
|
||||||
|
|
||||||
// lookup the fragment associated with the location
|
// if this location is associated with a new set of preset selections ...
|
||||||
if( preset_sel::track_loc( p->psH, loc, frag ) && frag != nullptr )
|
if( preset_sel::track_loc( p->psH, loc, frag ) && frag != nullptr )
|
||||||
{
|
{
|
||||||
|
// p->cur_frag maintains a reference to the preset selections
|
||||||
p->cur_frag = frag;
|
p->cur_frag = frag;
|
||||||
|
|
||||||
cwLogInfo("LOC:%i",loc);
|
cwLogInfo("LOC:%i ",loc);
|
||||||
rc = _exec_on_new_location(proc,p);
|
//cwLogPrint("LOC:%i ",loc);
|
||||||
|
//fragment_report( p->psH, frag );
|
||||||
|
|
||||||
|
rc = _exec_on_new_fragment(proc,p);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2015,90 +2245,27 @@ namespace cw
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
rc_t _update_manual_preset_index( inst_t* p, variable_t* var, unsigned& preset_idx_ref )
|
||||||
bool _update( proc_t* proc, unsigned vid, bool& fl_ref, rc_t rc_ref)
|
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
bool fl_value = false;
|
unsigned list_idx;
|
||||||
bool value_changed_fl = false;
|
|
||||||
|
|
||||||
if((rc = var_get(proc, vid, kAnyChIdx, fl_value)) != kOkRC )
|
if((rc = var_get(var,list_idx)) != kOkRC )
|
||||||
{
|
goto errLabel;
|
||||||
rc_ref = rc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_changed_fl = (fl_value != fl_ref);
|
|
||||||
|
|
||||||
//if( vid == kPriProbFlPId )
|
|
||||||
// printf("%i : %i %i %i\n",vid,fl_value,fl_ref,value_changed_fl);
|
|
||||||
|
|
||||||
fl_ref = fl_value;
|
|
||||||
|
|
||||||
return value_changed_fl;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_t _exec_update_state( proc_t* proc, inst_t* p )
|
|
||||||
{
|
|
||||||
rc_t rc = kOkRC;
|
|
||||||
|
|
||||||
if( _update( proc, kPriProbFlPId, p->pri_prob_fl, rc) )
|
|
||||||
{
|
|
||||||
var_send_to_ui_enable(proc, kPriUniformFlPId, kAnyChIdx, p->pri_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kPriDryOnPlayFlPId, kAnyChIdx, p->pri_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kPriAllowAllFlPId, kAnyChIdx, p->pri_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kPriDryOnSelFlPId, kAnyChIdx, p->pri_prob_fl && p->pri_allow_all_fl );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = list_ele_value(p->manual_sel_list,list_idx,preset_idx_ref)) != kOkRC )
|
||||||
if( _update( proc, kPriAllowAllFlPId, p->pri_allow_all_fl, rc ) )
|
goto errLabel;
|
||||||
{
|
|
||||||
var_send_to_ui_enable(proc, kPriDryOnSelFlPId, kAnyChIdx, p->pri_allow_all_fl );
|
|
||||||
}
|
|
||||||
|
|
||||||
_update( proc, kSecUniformFlPId, p->pri_uniform_fl, rc);
|
|
||||||
_update( proc, kPriDryOnPlayFlPId, p->pri_dry_on_play_fl, rc);
|
|
||||||
_update( proc, kPriDryOnSelFlPId, p->pri_dry_on_sel_fl, rc);
|
|
||||||
|
|
||||||
|
|
||||||
if( _update( proc, kInterpFlPId, p->interp_fl, rc ) )
|
errLabel:
|
||||||
{
|
if( rc != kOkRC )
|
||||||
var_send_to_ui_enable(proc, kInterpRandFlPId, kAnyChIdx, p->interp_fl );
|
preset_idx_ref = kInvalidIdx;
|
||||||
var_send_to_ui_enable(proc, kInterpDistPId, kAnyChIdx, p->interp_fl & (!p->interp_rand_fl) );
|
|
||||||
|
|
||||||
var_send_to_ui_enable(proc, kSecProbFlPId, kAnyChIdx, p->interp_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecUniformFlPId, kAnyChIdx, p->interp_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecDryOnPlayFlPId, kAnyChIdx, p->interp_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecAllowAllFlPId, kAnyChIdx, p->interp_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecDryOnSelFlPId, kAnyChIdx, p->interp_fl && p->sec_allow_all_fl );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _update( proc, kInterpRandFlPId, p->interp_rand_fl, rc ) )
|
|
||||||
{
|
|
||||||
var_send_to_ui_enable(proc, kInterpDistPId, kAnyChIdx, p->interp_fl & (!p->interp_rand_fl) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _update( proc, kSecProbFlPId, p->sec_prob_fl, rc) )
|
|
||||||
{
|
|
||||||
var_send_to_ui_enable(proc, kSecUniformFlPId, kAnyChIdx, p->sec_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecDryOnPlayFlPId, kAnyChIdx, p->sec_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecAllowAllFlPId, kAnyChIdx, p->sec_prob_fl );
|
|
||||||
var_send_to_ui_enable(proc, kSecDryOnSelFlPId, kAnyChIdx, p->sec_prob_fl && p->sec_allow_all_fl );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _update( proc, kSecAllowAllFlPId, p->sec_allow_all_fl, rc ) )
|
|
||||||
{
|
|
||||||
var_send_to_ui_enable(proc, kSecDryOnSelFlPId, kAnyChIdx, p->sec_allow_all_fl );
|
|
||||||
}
|
|
||||||
|
|
||||||
_update( proc, kSecUniformFlPId, p->sec_uniform_fl, rc);
|
|
||||||
_update( proc, kSecDryOnPlayFlPId, p->sec_dry_on_play_fl, rc);
|
|
||||||
_update( proc, kSecDryOnSelFlPId, p->sec_dry_on_sel_fl, rc);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
rc_t _update_ui_state( proc_t* proc, inst_t* p, variable_t* var )
|
rc_t _update_ui_state( proc_t* proc, inst_t* p, variable_t* var )
|
||||||
{
|
{
|
||||||
@ -2110,6 +2277,16 @@ namespace cw
|
|||||||
|
|
||||||
switch(var->vid)
|
switch(var->vid)
|
||||||
{
|
{
|
||||||
|
case kPriManualSelPId:
|
||||||
|
if((rc = _update_manual_preset_index(p,var,p->cur_manual_pri_preset_idx)) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Manual primary selected preset index update failed.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kSecManualSelPId:
|
||||||
|
if((rc = _update_manual_preset_index(p,var,p->cur_manual_sec_preset_idx)) != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Manual secondary selected preset index update failed.");
|
||||||
|
break;
|
||||||
|
|
||||||
case kPriProbFlPId:
|
case kPriProbFlPId:
|
||||||
var_get(var,p->pri_prob_fl);
|
var_get(var,p->pri_prob_fl);
|
||||||
var_send_to_ui_enable(proc, kPriUniformFlPId, kAnyChIdx, p->pri_prob_fl );
|
var_send_to_ui_enable(proc, kPriUniformFlPId, kAnyChIdx, p->pri_prob_fl );
|
||||||
@ -2188,8 +2365,6 @@ namespace cw
|
|||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
//if((rc = _exec_update_state(proc, p )) != kOkRC )
|
|
||||||
// goto errLabel;
|
|
||||||
_update_ui_state( proc, p, var );
|
_update_ui_state( proc, p, var );
|
||||||
|
|
||||||
if( var->vid == kResetPId )
|
if( var->vid == kResetPId )
|
||||||
@ -2197,6 +2372,7 @@ namespace cw
|
|||||||
if( p->psH.isValid() )
|
if( p->psH.isValid() )
|
||||||
track_loc_reset( p->psH);
|
track_loc_reset( p->psH);
|
||||||
|
|
||||||
|
_init_loc_array(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
//errLabel:
|
//errLabel:
|
||||||
@ -2431,6 +2607,265 @@ namespace cw
|
|||||||
} // score_follower
|
} // score_follower
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Score Follower 2
|
||||||
|
//
|
||||||
|
namespace score_follower_2
|
||||||
|
{
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kInPId,
|
||||||
|
kFnamePId,
|
||||||
|
kBegLocPId,
|
||||||
|
kEndLocPId,
|
||||||
|
kResetTrigPId,
|
||||||
|
kPrintFlPId,
|
||||||
|
kOutPId,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
cw::perf_score::handle_t scoreH;
|
||||||
|
cw::score_follow_2::handle_t sfH;
|
||||||
|
unsigned i_midi_field_idx;
|
||||||
|
unsigned o_midi_field_idx;
|
||||||
|
unsigned loc_field_idx;
|
||||||
|
unsigned vel_field_idx;
|
||||||
|
recd_array_t* recd_array; // output record array
|
||||||
|
|
||||||
|
} inst_t;
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _alloc_recd_array( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned chIdx, const recd_type_t* base, recd_array_t*& recd_array_ref )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
|
// find the record variable
|
||||||
|
if((rc = var_find( proc, var_label, sfx_id, chIdx, var )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The record variable '%s:%i' could was not found.",cwStringNullGuard(var_label),sfx_id);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the variable has a record format
|
||||||
|
if( !var_has_recd_format(var) )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The variable does not have a valid record format.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recd_fmt_t* recd_fmt = var->varDesc->fmt.recd_fmt;
|
||||||
|
|
||||||
|
// create the recd_array
|
||||||
|
if((rc = recd_array_create( recd_array_ref, recd_fmt->recd_type, base, recd_fmt->alloc_cnt )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Record array create failed on the variable '%s:%i ch:%i.",cwStringNullGuard(var_label),sfx_id,chIdx);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _create( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
rbuf_t* in_rbuf = nullptr;
|
||||||
|
const char* c_score_fname = nullptr;
|
||||||
|
char* score_fname = nullptr;
|
||||||
|
bool printParseWarningsFl = true;
|
||||||
|
unsigned beg_loc_id = kInvalidId;
|
||||||
|
unsigned end_loc_id = kInvalidId;
|
||||||
|
bool reset_trig_fl = false;
|
||||||
|
cw::score_follow_2::args_t sf_args = {
|
||||||
|
.pre_affinity_sec = 1.0,
|
||||||
|
.post_affinity_sec = 3.0,
|
||||||
|
.pre_wnd_sec = 2.0,
|
||||||
|
.post_wnd_sec = 5.0,
|
||||||
|
.decay_coeff = 0.995,
|
||||||
|
.d_sec_err_thresh_lo = 0.4,
|
||||||
|
.d_loc_thresh_lo = 3,
|
||||||
|
.d_sec_err_thresh_hi = 1.5,
|
||||||
|
.d_loc_thresh_hi = 4,
|
||||||
|
.d_loc_stats_thresh = 3,
|
||||||
|
.rpt_fl = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if((rc = var_register_and_get(proc,kAnyChIdx,
|
||||||
|
kInPId, "in", kBaseSfxId, in_rbuf,
|
||||||
|
kFnamePId, "score_fname", kBaseSfxId, c_score_fname,
|
||||||
|
kBegLocPId, "b_loc", kBaseSfxId, beg_loc_id,
|
||||||
|
kEndLocPId, "e_loc", kBaseSfxId, end_loc_id,
|
||||||
|
kResetTrigPId, "reset_trigger", kBaseSfxId, reset_trig_fl,
|
||||||
|
kPrintFlPId, "print_fl", kBaseSfxId, sf_args.rpt_fl )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
if((score_fname = proc_expand_filename( proc, c_score_fname )) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kOpFailRC,"Unable to expand the score filename '%s'.",cwStringNullGuard(c_score_fname));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the SF score
|
||||||
|
if((rc = create( p->scoreH, score_fname)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"SF Score create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the score follower
|
||||||
|
if((rc = create( p->sfH, sf_args, p->scoreH )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Score follower create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = reset( p->sfH, beg_loc_id, end_loc_id )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Score follower reset failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the output recd_array using the 'in' record type as the base type
|
||||||
|
if((rc = _alloc_recd_array( proc, "out", kBaseSfxId, kAnyChIdx, in_rbuf->type, p->recd_array )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create one output record buffer
|
||||||
|
rc = var_register_and_set( proc, "out", kBaseSfxId, kOutPId, kAnyChIdx, p->recd_array->type, nullptr, 0 );
|
||||||
|
|
||||||
|
p->i_midi_field_idx = recd_type_field_index( in_rbuf->type, "midi");
|
||||||
|
p->o_midi_field_idx = recd_type_field_index( p->recd_array->type, "midi");
|
||||||
|
p->loc_field_idx = recd_type_field_index( p->recd_array->type, "loc");
|
||||||
|
p->vel_field_idx = recd_type_field_index( p->recd_array->type, "score_vel");
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(score_fname);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _destroy( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
recd_array_destroy(p->recd_array);
|
||||||
|
destroy(p->sfH);
|
||||||
|
destroy(p->scoreH);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _notify( proc_t* proc, inst_t* p, variable_t* var )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _set_output_record( inst_t* p, rbuf_t* rbuf, const recd_t* base, unsigned loc_id, unsigned vel )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
recd_t* r = p->recd_array->recdA + rbuf->recdN;
|
||||||
|
|
||||||
|
// if the output record array is full
|
||||||
|
if( rbuf->recdN >= p->recd_array->allocRecdN )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kBufTooSmallRC,"The internal record buffer overflowed. (buf recd count:%i).",p->recd_array->allocRecdN);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
recd_set( rbuf->type, base, r, p->loc_field_idx, loc_id );
|
||||||
|
recd_set( rbuf->type, base, r, p->vel_field_idx, vel );
|
||||||
|
rbuf->recdN += 1;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _exec( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
unsigned sample_idx = proc->ctx->cycleIndex * proc->ctx->framesPerCycle;
|
||||||
|
double sec = ((double)sample_idx) / proc->ctx->sample_rate;
|
||||||
|
const rbuf_t* i_rbuf = nullptr;
|
||||||
|
rbuf_t* o_rbuf = nullptr;
|
||||||
|
unsigned result_recd_idx = kInvalidIdx;
|
||||||
|
|
||||||
|
if((rc = var_get(proc,kInPId,kAnyChIdx,i_rbuf)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((rc = var_get(proc,kOutPId,kAnyChIdx,o_rbuf)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
o_rbuf->recdA = p->recd_array->recdA;
|
||||||
|
o_rbuf->recdN = 0;
|
||||||
|
|
||||||
|
// for each incoming record
|
||||||
|
for(unsigned i=0; i<i_rbuf->recdN; ++i)
|
||||||
|
{
|
||||||
|
midi::ch_msg_t* m = nullptr;
|
||||||
|
unsigned loc_id = kInvalidId;
|
||||||
|
unsigned score_vel = -1;
|
||||||
|
|
||||||
|
if((rc = recd_get( i_rbuf->type, i_rbuf->recdA+i, p->i_midi_field_idx, m)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The 'midi' field read failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( midi::isNoteOn( m->status, m->d1 ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
if((rc = on_new_note( p->sfH, m->uid, sec, m->d0, m->d1, loc_id, score_vel )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Score follower note processing failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( loc_id != kInvalidId )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_set_output_record( p, o_rbuf, i_rbuf->recdA+i, loc_id, score_vel );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_exec(p->sfH);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _report( proc_t* proc, inst_t* p )
|
||||||
|
{ return kOkRC; }
|
||||||
|
|
||||||
|
class_members_t members = {
|
||||||
|
.create = std_create<inst_t>,
|
||||||
|
.destroy = std_destroy<inst_t>,
|
||||||
|
.notify = std_notify<inst_t>,
|
||||||
|
.exec = std_exec<inst_t>,
|
||||||
|
.report = std_report<inst_t>
|
||||||
|
};
|
||||||
|
|
||||||
|
} // score_follower_2
|
||||||
|
|
||||||
|
|
||||||
} // flow
|
} // flow
|
||||||
} //cw
|
} //cw
|
||||||
|
@ -7,6 +7,7 @@ namespace cw
|
|||||||
namespace preset_select { extern class_members_t members; }
|
namespace preset_select { extern class_members_t members; }
|
||||||
namespace gutim_ps { extern class_members_t members; }
|
namespace gutim_ps { extern class_members_t members; }
|
||||||
namespace score_follower { extern class_members_t members; }
|
namespace score_follower { extern class_members_t members; }
|
||||||
|
namespace score_follower_2 { extern class_members_t members; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
338
cwFlowProc.cpp
338
cwFlowProc.cpp
@ -809,7 +809,8 @@ namespace cw
|
|||||||
kBufMsgCntPId,
|
kBufMsgCntPId,
|
||||||
kInPId,
|
kInPId,
|
||||||
kRInPId,
|
kRInPId,
|
||||||
kPrintFlPId
|
kPrintFlPId,
|
||||||
|
kEnableFlPId,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -832,13 +833,14 @@ namespace cw
|
|||||||
const char* port_label = nullptr;
|
const char* port_label = nullptr;
|
||||||
rbuf_t* rbuf = nullptr;
|
rbuf_t* rbuf = nullptr;
|
||||||
bool printFl = false;
|
bool printFl = false;
|
||||||
|
bool enableFl = false;
|
||||||
|
|
||||||
// Register variables and get their current value
|
// Register variables and get their current value
|
||||||
if((rc = var_register_and_get( proc, kAnyChIdx,
|
if((rc = var_register_and_get( proc, kAnyChIdx,
|
||||||
kDevLabelPId, "dev_label", kBaseSfxId, dev_label,
|
kDevLabelPId, "dev_label", kBaseSfxId, dev_label,
|
||||||
kPortLabelPId,"port_label", kBaseSfxId, port_label,
|
kPortLabelPId,"port_label", kBaseSfxId, port_label,
|
||||||
kPrintFlPId, "print_fl", kBaseSfxId, printFl,
|
kPrintFlPId, "print_fl", kBaseSfxId, printFl,
|
||||||
|
kEnableFlPId, "enable_fl", kBaseSfxId, enableFl,
|
||||||
kBufMsgCntPId,"buf_cnt", kBaseSfxId, p->msgN )) != kOkRC )
|
kBufMsgCntPId,"buf_cnt", kBaseSfxId, p->msgN )) != kOkRC )
|
||||||
{
|
{
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -907,9 +909,15 @@ namespace cw
|
|||||||
return kOkRC;
|
return kOkRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _send_msg( inst_t* p, bool print_fl, const midi::ch_msg_t* m )
|
void _send_msg( inst_t* p, bool print_fl, bool enable_fl, const midi::ch_msg_t* m )
|
||||||
{
|
{
|
||||||
|
//if( midi::isNoteOn(m->status,m->d1) )
|
||||||
|
// printf("mo:%i %s\n",m->d0,midi::midiToSciPitch(m->d0));
|
||||||
|
|
||||||
|
|
||||||
|
if( enable_fl )
|
||||||
p->ext_dev->u.m.sendTripleFunc( p->ext_dev, m->ch, m->status, m->d0, m->d1 );
|
p->ext_dev->u.m.sendTripleFunc( p->ext_dev, m->ch, m->status, m->d0, m->d1 );
|
||||||
|
|
||||||
if( print_fl )
|
if( print_fl )
|
||||||
{
|
{
|
||||||
cwLogPrint("%2i 0x%2x %3i %3i : %s %s\n",m->ch, m->status, m->d0, m->d1, cwStringNullGuard(p->ext_dev->devLabel),cwStringNullGuard(p->ext_dev->portLabel));
|
cwLogPrint("%2i 0x%2x %3i %3i : %s %s\n",m->ch, m->status, m->d0, m->d1, cwStringNullGuard(p->ext_dev->devLabel),cwStringNullGuard(p->ext_dev->portLabel));
|
||||||
@ -921,9 +929,12 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const rbuf_t* rbuf = nullptr;
|
const rbuf_t* rbuf = nullptr;
|
||||||
bool print_fl = false;
|
bool print_fl = false;
|
||||||
|
bool enable_fl = true;
|
||||||
const mbuf_t* src_mbuf = nullptr;
|
const mbuf_t* src_mbuf = nullptr;
|
||||||
|
|
||||||
var_get(proc,kPrintFlPId,kAnyChIdx,print_fl);
|
var_get(proc,kPrintFlPId,kAnyChIdx,print_fl);
|
||||||
|
var_get(proc,kEnableFlPId,kAnyChIdx,enable_fl);
|
||||||
|
|
||||||
|
|
||||||
if( p->rin_exists_fl )
|
if( p->rin_exists_fl )
|
||||||
{
|
{
|
||||||
@ -937,7 +948,7 @@ namespace cw
|
|||||||
const midi::ch_msg_t* m = nullptr;
|
const midi::ch_msg_t* m = nullptr;
|
||||||
|
|
||||||
if((rc = recd_get(rbuf->type,r,p->midi_fld_idx,m)) == kOkRC )
|
if((rc = recd_get(rbuf->type,r,p->midi_fld_idx,m)) == kOkRC )
|
||||||
_send_msg(p,print_fl,m);
|
_send_msg(p,print_fl,enable_fl,m);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Record 'midi' field read failed.");
|
rc = cwLogError(rc,"Record 'midi' field read failed.");
|
||||||
@ -957,7 +968,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
for(unsigned i=0; i<src_mbuf->msgN; ++i)
|
for(unsigned i=0; i<src_mbuf->msgN; ++i)
|
||||||
{
|
{
|
||||||
_send_msg(p,print_fl,src_mbuf->msgA + i);
|
_send_msg(p,print_fl,enable_fl,src_mbuf->msgA + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4464,6 +4475,7 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
unsigned baseGateFlPId;
|
||||||
unsigned baseDoneFlPId;
|
unsigned baseDoneFlPId;
|
||||||
|
|
||||||
midi_t midiA[ midi::kMidiNoteCnt ];
|
midi_t midiA[ midi::kMidiNoteCnt ];
|
||||||
@ -4497,6 +4509,11 @@ namespace cw
|
|||||||
|
|
||||||
if( p->ns_fl )
|
if( p->ns_fl )
|
||||||
_store_note_state( proc, p, 0, 0, 0, 0, voice_idx );
|
_store_note_state( proc, p, 0, 0, 0, 0, voice_idx );
|
||||||
|
|
||||||
|
// set the gate signal low
|
||||||
|
//printf("pvc:%i off\n",voice_idx);
|
||||||
|
var_set(proc,p->baseGateFlPId + voice_idx,kAnyChIdx,false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _reset_all_voices( proc_t* proc, inst_t* p )
|
void _reset_all_voices( proc_t* proc, inst_t* p )
|
||||||
@ -4523,7 +4540,8 @@ namespace cw
|
|||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->baseDoneFlPId = kBaseOutPId + p->voiceN;
|
p->baseGateFlPId = kBaseOutPId + p->voiceN;
|
||||||
|
p->baseDoneFlPId = p->baseGateFlPId + p->voiceN;
|
||||||
p->voiceMsgN = kVoiceMsgN;
|
p->voiceMsgN = kVoiceMsgN;
|
||||||
p->voiceA = mem::allocZ<voice_t>(p->voiceN);
|
p->voiceA = mem::allocZ<voice_t>(p->voiceN);
|
||||||
|
|
||||||
@ -4539,8 +4557,10 @@ namespace cw
|
|||||||
if((rc = var_register_and_set( proc, "out", i, kBaseOutPId + i, kAnyChIdx, nullptr, 0 )) != kOkRC )
|
if((rc = var_register_and_set( proc, "out", i, kBaseOutPId + i, kAnyChIdx, nullptr, 0 )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
// create one 'done_fl' variable per voice
|
// create one 'done_fl' and 'gate_fl' variable per voice
|
||||||
if((rc = var_register_and_set( proc, kAnyChIdx, p->baseDoneFlPId + i, "done_fl", i, false )) != kOkRC )
|
if((rc = var_register_and_set( proc, kAnyChIdx,
|
||||||
|
p->baseDoneFlPId + i, "done_fl", i, false,
|
||||||
|
p->baseGateFlPId + i, "gate_fl", i, false )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
p->voiceA[i].msgA = mem::allocZ<midi::ch_msg_t>(p->voiceMsgN);
|
p->voiceA[i].msgA = mem::allocZ<midi::ch_msg_t>(p->voiceMsgN);
|
||||||
@ -4734,6 +4754,10 @@ namespace cw
|
|||||||
if( p->ns_fl )
|
if( p->ns_fl )
|
||||||
_store_note_state( proc, p, m->uid, midi::kNoteOnMdId, m->d0, m->d1, voice_idx );
|
_store_note_state( proc, p, m->uid, midi::kNoteOnMdId, m->d0, m->d1, voice_idx );
|
||||||
|
|
||||||
|
// set the gate signal high
|
||||||
|
//printf("pvc:%i on\n",voice_idx);
|
||||||
|
var_set(proc,p->baseGateFlPId + voice_idx,kAnyChIdx,true);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5392,10 +5416,12 @@ namespace cw
|
|||||||
p->gain_coeff = p->kReleaseGain;
|
p->gain_coeff = p->kReleaseGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _on_note_off( inst_t* p )
|
void _on_note_off( proc_t* proc, inst_t* p )
|
||||||
{
|
{
|
||||||
p->noff_fl = true;
|
p->noff_fl = true;
|
||||||
|
|
||||||
|
//printf("nof:%i %i\n",proc->label_sfx_id,p->pitch);
|
||||||
|
|
||||||
if( !p->sustain_fl )
|
if( !p->sustain_fl )
|
||||||
_begin_note_release(p);
|
_begin_note_release(p);
|
||||||
}
|
}
|
||||||
@ -5508,13 +5534,13 @@ namespace cw
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_on_note_off(p);
|
_on_note_off(proc,p);
|
||||||
_store_note_state(proc, p, m->uid, midi::kNoteOffMdId, m->d0, 0 );
|
_store_note_state(proc, p, m->uid, midi::kNoteOffMdId, m->d0, 0 );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case midi::kNoteOffMdId:
|
case midi::kNoteOffMdId:
|
||||||
_on_note_off(p);
|
_on_note_off(proc,p);
|
||||||
_store_note_state(proc, p, m->uid, midi::kNoteOnMdId, m->d0, 0 );
|
_store_note_state(proc, p, m->uid, midi::kNoteOnMdId, m->d0, 0 );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -5570,6 +5596,155 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// voice_detector
|
||||||
|
//
|
||||||
|
namespace voice_detector
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
kInPId,
|
||||||
|
kEnableFlPId,
|
||||||
|
kRlsThreshPId,
|
||||||
|
kDoneFlPId
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kRmsBufN = 30
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool enable_fl;
|
||||||
|
bool above_fl;
|
||||||
|
bool done_fl;
|
||||||
|
bool rls_thresh;
|
||||||
|
unsigned delta_cnt;
|
||||||
|
sample_t rms_buf[ kRmsBufN ];
|
||||||
|
unsigned rms_buf_idx;
|
||||||
|
unsigned rms_buf_cnt;
|
||||||
|
|
||||||
|
} inst_t;
|
||||||
|
|
||||||
|
sample_t _calc_rms( inst_t* p, abuf_t* abuf )
|
||||||
|
{
|
||||||
|
p->rms_buf[ p->rms_buf_idx ] = 0;
|
||||||
|
|
||||||
|
// store the max rms among all channels
|
||||||
|
for( unsigned i=0; i<abuf->chN; ++i)
|
||||||
|
{
|
||||||
|
sample_t rms;
|
||||||
|
if((rms = vop::sum_sq(abuf->buf + (i*abuf->frameN), abuf->frameN )) > p->rms_buf[ p->rms_buf_idx ] )
|
||||||
|
p->rms_buf[ p->rms_buf_idx ] = rms;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ++p->rms_buf_idx >= kRmsBufN )
|
||||||
|
p->rms_buf_idx = 0;
|
||||||
|
|
||||||
|
if( p->rms_buf_cnt++ >= kRmsBufN )
|
||||||
|
p->rms_buf_cnt = kRmsBufN;
|
||||||
|
|
||||||
|
return std::sqrt( vop::mean(p->rms_buf,p->rms_buf_cnt) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _create( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
abuf_t* abuf = nullptr;
|
||||||
|
|
||||||
|
// register the input audio variable
|
||||||
|
if((rc = var_register_and_get(proc,kAnyChIdx,
|
||||||
|
kInPId, "in", kBaseSfxId, abuf,
|
||||||
|
kEnableFlPId, "enable_fl", kBaseSfxId, p->enable_fl,
|
||||||
|
kRlsThreshPId,"rls_thresh",kBaseSfxId, p->rls_thresh,
|
||||||
|
kDoneFlPId, "done_fl", kBaseSfxId, p->done_fl)) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _destroy( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _notify( proc_t* proc, inst_t* p, variable_t* var )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
switch( var->vid )
|
||||||
|
{
|
||||||
|
case kEnableFlPId:
|
||||||
|
var_get(var,p->enable_fl);
|
||||||
|
if( p->enable_fl )
|
||||||
|
{
|
||||||
|
var_set(proc,kDoneFlPId,kAnyChIdx,false);
|
||||||
|
p->above_fl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("vd-ena:%i %i\n",proc->label_sfx_id,p->enable_fl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kRlsThreshPId:
|
||||||
|
var_get(var,p->rls_thresh);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _exec( proc_t* proc, inst_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
abuf_t* abuf = nullptr;
|
||||||
|
sample_t rms;
|
||||||
|
|
||||||
|
if((rc = var_get(proc,kInPId,kAnyChIdx,abuf)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
rms = _calc_rms(p,abuf);
|
||||||
|
|
||||||
|
if( rms > p->rls_thresh )
|
||||||
|
p->above_fl = true;
|
||||||
|
|
||||||
|
if( p->above_fl && rms < p->rls_thresh)
|
||||||
|
p->delta_cnt += 1;
|
||||||
|
else
|
||||||
|
p->delta_cnt = 0;
|
||||||
|
|
||||||
|
if( p->enable_fl && p->delta_cnt >= 3 )
|
||||||
|
{
|
||||||
|
printf("vd:%i off\n",proc->label_sfx_id);
|
||||||
|
p->done_fl = true;
|
||||||
|
var_set(proc,kDoneFlPId,kAnyChIdx,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _report( proc_t* proc, inst_t* p )
|
||||||
|
{ return kOkRC; }
|
||||||
|
|
||||||
|
class_members_t members = {
|
||||||
|
.create = std_create<inst_t>,
|
||||||
|
.destroy = std_destroy<inst_t>,
|
||||||
|
.notify = std_notify<inst_t>,
|
||||||
|
.exec = std_exec<inst_t>,
|
||||||
|
.report = std_report<inst_t>
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// audio_merge
|
// audio_merge
|
||||||
@ -8056,8 +8231,12 @@ namespace cw
|
|||||||
enum {
|
enum {
|
||||||
kMidiFileNamePId,
|
kMidiFileNamePId,
|
||||||
kCsvFileNamePId,
|
kCsvFileNamePId,
|
||||||
|
kCsvFileName2PId,
|
||||||
|
kStartPId,
|
||||||
|
kStopPId,
|
||||||
kDoneFlPId,
|
kDoneFlPId,
|
||||||
kOutPId
|
kOutPId,
|
||||||
|
kROutPId
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct msg_str
|
typedef struct msg_str
|
||||||
@ -8077,14 +8256,60 @@ namespace cw
|
|||||||
|
|
||||||
char* midi_fname;
|
char* midi_fname;
|
||||||
char* csv_fname;
|
char* csv_fname;
|
||||||
|
char* csv_fname_2;
|
||||||
|
|
||||||
|
bool start_trig_fl; // the start btn was clicked
|
||||||
|
bool stop_trig_fl; // the stop btn was clicked
|
||||||
|
|
||||||
|
|
||||||
|
recd_array_t* recd_array; // output record array for 'out'.
|
||||||
|
unsigned midi_fld_idx; // pre-computed record field indexes
|
||||||
|
|
||||||
} inst_t;
|
} inst_t;
|
||||||
|
|
||||||
|
rc_t _alloc_recd_array( proc_t* proc, const char* var_label, unsigned sfx_id, unsigned chIdx, const recd_type_t* base, recd_array_t*& recd_array_ref )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
variable_t* var = nullptr;
|
||||||
|
|
||||||
|
// find the record variable
|
||||||
|
if((rc = var_find( proc, var_label, sfx_id, chIdx, var )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"The record variable '%s:%i' could was not found.",cwStringNullGuard(var_label),sfx_id);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the variable has a record format
|
||||||
|
if( !var_has_recd_format(var) )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The variable does not have a valid record format.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recd_fmt_t* recd_fmt = var->varDesc->fmt.recd_fmt;
|
||||||
|
|
||||||
|
// create the recd_array
|
||||||
|
if((rc = recd_array_create( recd_array_ref, recd_fmt->recd_type, base, recd_fmt->alloc_cnt )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"Record array create failed on the variable '%s:%i ch:%i.",cwStringNullGuard(var_label),sfx_id,chIdx);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
rc_t _create( proc_t* proc, inst_t* p )
|
rc_t _create( proc_t* proc, inst_t* p )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
const char* midi_fname = nullptr;
|
const char* midi_fname = nullptr;
|
||||||
const char* csv_fname = nullptr;
|
const char* csv_fname = nullptr;
|
||||||
|
const char* csv_fname_2= nullptr;
|
||||||
const midi::file::trackMsg_t** tmA = nullptr;
|
const midi::file::trackMsg_t** tmA = nullptr;
|
||||||
unsigned msgAllocN = 0;
|
unsigned msgAllocN = 0;
|
||||||
bool done_fl = false;
|
bool done_fl = false;
|
||||||
@ -8095,11 +8320,28 @@ namespace cw
|
|||||||
if((rc = var_register_and_get(proc,kAnyChIdx,
|
if((rc = var_register_and_get(proc,kAnyChIdx,
|
||||||
kMidiFileNamePId, "fname", kBaseSfxId, midi_fname,
|
kMidiFileNamePId, "fname", kBaseSfxId, midi_fname,
|
||||||
kCsvFileNamePId, "csv_fname", kBaseSfxId, csv_fname,
|
kCsvFileNamePId, "csv_fname", kBaseSfxId, csv_fname,
|
||||||
|
kCsvFileName2PId, "alt_csv_fname", kBaseSfxId, csv_fname_2,
|
||||||
kDoneFlPId, "done_fl", kBaseSfxId, done_fl)) != kOkRC )
|
kDoneFlPId, "done_fl", kBaseSfxId, done_fl)) != kOkRC )
|
||||||
{
|
{
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((rc = var_register(proc,kAnyChIdx,
|
||||||
|
kStartPId, "start", kBaseSfxId,
|
||||||
|
kStopPId, "stop", kBaseSfxId )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( csv_fname_2 != nullptr && textLength(csv_fname_2)>0 )
|
||||||
|
if((p->csv_fname_2 = proc_expand_filename(proc,csv_fname_2)) == nullptr )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidArgRC,"The MIDI CSV 2 filename could not be formed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if( csv_fname != nullptr && textLength(csv_fname)>0 )
|
if( csv_fname != nullptr && textLength(csv_fname)>0 )
|
||||||
if((p->csv_fname = proc_expand_filename(proc,csv_fname)) == nullptr )
|
if((p->csv_fname = proc_expand_filename(proc,csv_fname)) == nullptr )
|
||||||
{
|
{
|
||||||
@ -8127,6 +8369,12 @@ namespace cw
|
|||||||
if((rc = midi::file::open_csv(p->mfH,p->csv_fname)) != kOkRC )
|
if((rc = midi::file::open_csv(p->mfH,p->csv_fname)) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if( p->csv_fname_2 != nullptr && textLength(p->csv_fname_2)>0 )
|
||||||
|
{
|
||||||
|
if((rc = midi::file::open_csv_2(p->mfH,p->csv_fname_2)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = cwLogError(kOpenFailRC,"No MIDI or CSV filename was given.");
|
rc = cwLogError(kOpenFailRC,"No MIDI or CSV filename was given.");
|
||||||
@ -8148,12 +8396,14 @@ namespace cw
|
|||||||
{
|
{
|
||||||
const midi::file::trackMsg_t* tm = tmA[i];
|
const midi::file::trackMsg_t* tm = tmA[i];
|
||||||
msg_t* m = p->msgA + p->msg_idx;
|
msg_t* m = p->msgA + p->msg_idx;
|
||||||
|
double secs;
|
||||||
|
|
||||||
m->m = p->chMsgA + p->msg_idx;
|
m->m = p->chMsgA + p->msg_idx;
|
||||||
|
|
||||||
time::microsecondsToSpec( m->m->timeStamp, tmA[i]->amicro );
|
time::microsecondsToSpec( m->m->timeStamp, tmA[i]->amicro );
|
||||||
|
|
||||||
m->sample_idx = (unsigned)(proc->ctx->sample_rate * time::specToSeconds(m->m->timeStamp));
|
m->sample_idx = (unsigned)(proc->ctx->sample_rate * (secs = time::specToSeconds(m->m->timeStamp)));
|
||||||
|
|
||||||
|
|
||||||
m->m->devIdx = 0;
|
m->m->devIdx = 0;
|
||||||
m->m->portIdx = 0;
|
m->m->portIdx = 0;
|
||||||
@ -8175,6 +8425,18 @@ namespace cw
|
|||||||
p->msgN = p->msg_idx;
|
p->msgN = p->msg_idx;
|
||||||
p->msg_idx = 0;
|
p->msg_idx = 0;
|
||||||
|
|
||||||
|
// allocate the output recd array
|
||||||
|
if((rc = _alloc_recd_array( proc, "r_out", kBaseSfxId, kAnyChIdx, nullptr, p->recd_array )) != kOkRC )
|
||||||
|
{
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create one output record buffer
|
||||||
|
rc = var_register_and_set( proc, "r_out", kBaseSfxId, kROutPId, kAnyChIdx, p->recd_array->type, nullptr, 0 );
|
||||||
|
|
||||||
|
p->midi_fld_idx = recd_type_field_index( p->recd_array->type, "midi");
|
||||||
|
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -8182,9 +8444,10 @@ namespace cw
|
|||||||
rc_t _destroy( proc_t* proc, inst_t* p )
|
rc_t _destroy( proc_t* proc, inst_t* p )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
recd_array_destroy(p->recd_array);
|
||||||
mem::release(p->midi_fname);
|
mem::release(p->midi_fname);
|
||||||
mem::release(p->csv_fname);
|
mem::release(p->csv_fname);
|
||||||
|
mem::release(p->csv_fname_2);
|
||||||
close(p->mfH);
|
close(p->mfH);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -8193,6 +8456,36 @@ namespace cw
|
|||||||
rc_t _notify( proc_t* proc, inst_t* p, variable_t* var )
|
rc_t _notify( proc_t* proc, inst_t* p, variable_t* var )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
switch( var->vid )
|
||||||
|
{
|
||||||
|
case kStartPId:
|
||||||
|
p->start_trig_fl = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kStopPId:
|
||||||
|
p->stop_trig_fl = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _set_output_record( inst_t* p, rbuf_t* rbuf, const midi::ch_msg_t* m )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
// if the output record array is full
|
||||||
|
if( rbuf->recdN >= p->recd_array->allocRecdN )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kBufTooSmallRC,"The internal record buffer overflowed. (buf recd count:%i).",p->recd_array->allocRecdN);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
recd_set( rbuf->type, nullptr, p->recd_array->recdA + rbuf->recdN, p->midi_fld_idx, (midi::ch_msg_t*)m );
|
||||||
|
rbuf->recdN += 1;
|
||||||
|
|
||||||
|
errLabel:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8201,6 +8494,7 @@ namespace cw
|
|||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
mbuf_t* mbuf = nullptr;
|
mbuf_t* mbuf = nullptr;
|
||||||
bool done_fl = false;
|
bool done_fl = false;
|
||||||
|
rbuf_t* rbuf = nullptr;
|
||||||
|
|
||||||
p->sample_idx += proc->ctx->framesPerCycle;
|
p->sample_idx += proc->ctx->framesPerCycle;
|
||||||
|
|
||||||
@ -8227,6 +8521,22 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the output variable
|
||||||
|
if((rc = var_get(proc,kROutPId,kAnyChIdx,rbuf)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(kInvalidStateRC,"The midi-in '%s' does not have a valid output record buffer.",proc->label);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rbuf->recdA = p->recd_array->recdA;
|
||||||
|
rbuf->recdN = 0;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<mbuf->msgN; ++i)
|
||||||
|
_set_output_record(p,rbuf, mbuf->msgA + i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if( done_fl )
|
if( done_fl )
|
||||||
var_set(proc, kDoneFlPId, kAnyChIdx, true );
|
var_set(proc, kDoneFlPId, kAnyChIdx, true );
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ namespace cw
|
|||||||
namespace xfade_ctl { extern class_members_t members; }
|
namespace xfade_ctl { extern class_members_t members; }
|
||||||
namespace midi_voice { extern class_members_t members; }
|
namespace midi_voice { extern class_members_t members; }
|
||||||
namespace piano_voice { extern class_members_t members; }
|
namespace piano_voice { extern class_members_t members; }
|
||||||
|
namespace voice_detector { extern class_members_t members; }
|
||||||
namespace poly_voice_ctl { extern class_members_t members; }
|
namespace poly_voice_ctl { extern class_members_t members; }
|
||||||
namespace sample_hold { extern class_members_t members; }
|
namespace sample_hold { extern class_members_t members; }
|
||||||
namespace number { extern class_members_t members; }
|
namespace number { extern class_members_t members; }
|
||||||
|
105
cwMidiFile.cpp
105
cwMidiFile.cpp
@ -1497,6 +1497,110 @@ errLabel:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::midi::file::open_csv_2( handle_t& hRef, const char* midi_csv_fname )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
file_t* p = nullptr;
|
||||||
|
csv::handle_t csvH;
|
||||||
|
const char* titleA[] = { "UID","trk","dtick","atick","amicro","type","ch","D0","D1" };
|
||||||
|
unsigned titleN = sizeof(titleA)/sizeof(titleA[0]);
|
||||||
|
unsigned line_idx = 0;
|
||||||
|
unsigned lineN = 0;
|
||||||
|
unsigned trkN = 1;
|
||||||
|
unsigned trkIdx = 0;
|
||||||
|
unsigned TpQN = 1260;
|
||||||
|
unsigned BpM = 120;
|
||||||
|
|
||||||
|
if((rc = _create(hRef)) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
if((p = _handleToPtr(hRef)) == nullptr )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
_init( p, trkN, TpQN );
|
||||||
|
|
||||||
|
|
||||||
|
if((rc = csv::create(csvH,midi_csv_fname,titleA,titleN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"MIDI CSV file open failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rc = line_count(csvH,lineN)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"MIDI CSV line count access failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; (rc = next_line(csvH)) == kOkRC; ++line_idx )
|
||||||
|
{
|
||||||
|
unsigned uid;
|
||||||
|
unsigned amicro;
|
||||||
|
unsigned dtick;
|
||||||
|
unsigned atick;
|
||||||
|
const char* type = nullptr;
|
||||||
|
unsigned ch;
|
||||||
|
unsigned d0;
|
||||||
|
unsigned d1;
|
||||||
|
uint8_t status = 0;
|
||||||
|
|
||||||
|
if((rc = getv(csvH,"UID",uid,"dtick",dtick,"atick",atick,"amicro",amicro,"type",type,"ch",ch,"D0",d0,"D1",d1)) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"Error reading CSV line %i.",line_idx+1);
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(textIsEqual(type,"non"))
|
||||||
|
status = midi::kNoteOnMdId;
|
||||||
|
else
|
||||||
|
if(textIsEqual(type,"nof"))
|
||||||
|
status = midi::kNoteOffMdId;
|
||||||
|
else
|
||||||
|
if(textIsEqual(type,"ctl"))
|
||||||
|
status = midi::kCtlMdId;
|
||||||
|
else
|
||||||
|
if(textIsEqual(type,"tempo"))
|
||||||
|
{
|
||||||
|
// note the tempo is taken from the 'ch' column
|
||||||
|
if((rc = insertTrackTempoMsg(hRef, trkIdx, atick, ch )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"BPM insert failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = cwLogError(kSyntaxErrorRC,"Unknown message type:'%s'.",cwStringNullGuard(type));
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( status != 0 )
|
||||||
|
{
|
||||||
|
assert( ch<=15 && d0 <= 127 && d1 <= 127 );
|
||||||
|
|
||||||
|
if((rc = insertTrackChMsg(hRef, trkIdx, atick, ch+status, d0, d1 )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Channel msg insert failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
destroy(csvH);
|
||||||
|
|
||||||
|
if( rc == kEofRC )
|
||||||
|
rc = kOkRC;
|
||||||
|
|
||||||
|
if( rc != kOkRC )
|
||||||
|
rc = cwLogError(rc,"MIDI csv file parse failed on '%s'.",cwStringNullGuard(midi_csv_fname));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
cw::rc_t cw::midi::file::create( handle_t& hRef, unsigned trkN, unsigned ticksPerQN )
|
cw::rc_t cw::midi::file::create( handle_t& hRef, unsigned trkN, unsigned ticksPerQN )
|
||||||
{
|
{
|
||||||
@ -1791,6 +1895,7 @@ cw::rc_t cw::midi::file::insertTrackMsg( handle_t h, unsigned trkIdx, const tra
|
|||||||
// fill the track record
|
// fill the track record
|
||||||
m->uid = p->nextUid++;
|
m->uid = p->nextUid++;
|
||||||
m->atick = msg->atick;
|
m->atick = msg->atick;
|
||||||
|
m->amicro = msg->amicro;
|
||||||
m->status = msg->status;
|
m->status = msg->status;
|
||||||
m->metaId = msg->metaId;
|
m->metaId = msg->metaId;
|
||||||
m->trkIdx = trkIdx;
|
m->trkIdx = trkIdx;
|
||||||
|
@ -122,6 +122,9 @@ namespace cw
|
|||||||
// bpm = beats per minute should be given on the first line. (Defaults to 60).
|
// bpm = beats per minute should be given on the first line. (Defaults to 60).
|
||||||
rc_t open_csv( handle_t& hRef, const char* csv_fname );
|
rc_t open_csv( handle_t& hRef, const char* csv_fname );
|
||||||
|
|
||||||
|
// Open MIDI CSV as generated by 'Workshop' recordings.
|
||||||
|
rc_t open_csv_2( handle_t& hRef, const char* csv_fname );
|
||||||
|
|
||||||
// Create an empty MIDI file object.
|
// Create an empty MIDI file object.
|
||||||
rc_t create( handle_t& hRef, unsigned trkN, unsigned ticksPerQN );
|
rc_t create( handle_t& hRef, unsigned trkN, unsigned ticksPerQN );
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ namespace cw
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_t _trkr_on_new_note( trkr_t* trk, double sec, unsigned pitch, unsigned vel, bool rpt_fl, unsigned& matched_loc_id_ref )
|
rc_t _trkr_on_new_note( trkr_t* trk, double sec, unsigned pitch, unsigned vel, bool rpt_fl, unsigned& matched_loc_id_ref, unsigned& score_vel_ref )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
double d_corr_sec = 0.0;
|
double d_corr_sec = 0.0;
|
||||||
@ -257,6 +257,7 @@ namespace cw
|
|||||||
unsigned match_ni = kInvalidIdx;
|
unsigned match_ni = kInvalidIdx;
|
||||||
double match_val = 0;
|
double match_val = 0;
|
||||||
|
|
||||||
|
score_vel_ref = -1;
|
||||||
matched_loc_id_ref = kInvalidId;
|
matched_loc_id_ref = kInvalidId;
|
||||||
|
|
||||||
assert( trk->exp_loc_idx != kInvalidIdx && trk->exp_loc_idx < trk->sf->locN );
|
assert( trk->exp_loc_idx != kInvalidIdx && trk->exp_loc_idx < trk->sf->locN );
|
||||||
@ -362,6 +363,7 @@ namespace cw
|
|||||||
trk->loc_match_cntA[ match_loc_idx ] += 1;
|
trk->loc_match_cntA[ match_loc_idx ] += 1;
|
||||||
trk->note_match_cntA[ match_ni ] += 1;
|
trk->note_match_cntA[ match_ni ] += 1;
|
||||||
|
|
||||||
|
score_vel_ref = trk->sf->noteA[ match_ni ].vel;
|
||||||
matched_loc_id_ref = match_loc_id;
|
matched_loc_id_ref = match_loc_id;
|
||||||
|
|
||||||
// notice if we arrived at the end of the score tracking range
|
// notice if we arrived at the end of the score tracking range
|
||||||
@ -805,7 +807,7 @@ errLabel:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::score_follow_2::create( handle_t& hRef, const args_t& args )
|
cw::rc_t cw::score_follow_2::create( handle_t& hRef, const args_t& args, perf_score::handle_t scoreH )
|
||||||
{
|
{
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
if((rc = destroy(hRef)) != kOkRC )
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
@ -813,10 +815,10 @@ cw::rc_t cw::score_follow_2::create( handle_t& hRef, const args_t& args )
|
|||||||
|
|
||||||
sf_t* p = mem::allocZ<sf_t>();
|
sf_t* p = mem::allocZ<sf_t>();
|
||||||
|
|
||||||
if((rc = _get_loc_and_note_count( p, args.scoreH )) != kOkRC )
|
if((rc = _get_loc_and_note_count( p, scoreH )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = _alloc_fill_loc_and_note_arrays( p, args.scoreH )) != kOkRC )
|
if((rc = _alloc_fill_loc_and_note_arrays( p, scoreH )) != kOkRC )
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
|
||||||
if((rc = _alloc_and_fill_loc_note_arrays( p )) != kOkRC )
|
if((rc = _alloc_and_fill_loc_note_arrays( p )) != kOkRC )
|
||||||
@ -894,18 +896,19 @@ cw::rc_t cw::score_follow_2::reset( handle_t h, unsigned beg_loc_id, unsigned en
|
|||||||
|
|
||||||
_trkr_reset(p->trk,beg_loc_id);
|
_trkr_reset(p->trk,beg_loc_id);
|
||||||
|
|
||||||
|
cwLogInfo("SF2 reset: %i %i",beg_loc_id,end_loc_id);
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::score_follow_2::on_new_note( handle_t h, unsigned uid, double sec, uint8_t pitch, uint8_t vel, unsigned& loc_id )
|
cw::rc_t cw::score_follow_2::on_new_note( handle_t h, unsigned uid, double sec, uint8_t pitch, uint8_t vel, unsigned& matched_loc_id_ref, unsigned& score_vel_ref )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
sf_t* p = _handleToPtr(h);
|
sf_t* p = _handleToPtr(h);
|
||||||
unsigned matched_loc_id = kInvalidId;
|
|
||||||
|
|
||||||
_trkr_on_new_note(p->trk,sec,pitch,vel, p->args.rpt_fl, matched_loc_id);
|
_trkr_on_new_note(p->trk,sec,pitch,vel, p->args.rpt_fl, matched_loc_id_ref, score_vel_ref);
|
||||||
|
|
||||||
if( p->resultN < p->resultAllocN )
|
if( p->resultN < p->resultAllocN )
|
||||||
{
|
{
|
||||||
@ -913,7 +916,7 @@ cw::rc_t cw::score_follow_2::on_new_note( handle_t h, unsigned uid, double sec,
|
|||||||
r->perf_uid = uid;
|
r->perf_uid = uid;
|
||||||
r->perf_pitch = pitch;
|
r->perf_pitch = pitch;
|
||||||
r->perf_vel = vel;
|
r->perf_vel = vel;
|
||||||
r->match_loc_id = matched_loc_id;
|
r->match_loc_id = matched_loc_id_ref;
|
||||||
p->resultN += 1;
|
p->resultN += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,14 +7,12 @@ namespace cw
|
|||||||
|
|
||||||
typedef struct args_str
|
typedef struct args_str
|
||||||
{
|
{
|
||||||
perf_score::handle_t scoreH;
|
|
||||||
|
|
||||||
double pre_affinity_sec; // 1.0 look back affinity duration
|
double pre_affinity_sec; // 1.0 look back affinity duration
|
||||||
double post_affinity_sec; // 3.0 look forward affinity duration
|
double post_affinity_sec; // 3.0 look forward affinity duration
|
||||||
double pre_wnd_sec; // 2.0 look back search window
|
double pre_wnd_sec; // 2.0 look back search window
|
||||||
double post_wnd_sec; // 5.0 look forward search window
|
double post_wnd_sec; // 5.0 look forward search window
|
||||||
|
|
||||||
double decay_coeff; // 0.995affinity decay coeff
|
double decay_coeff; // 0.995 affinity decay coeff
|
||||||
|
|
||||||
double d_sec_err_thresh_lo; // 0.4 reject if d_loc > d_loc_thresh_lod and d_time > d_time_thresh_lo
|
double d_sec_err_thresh_lo; // 0.4 reject if d_loc > d_loc_thresh_lod and d_time > d_time_thresh_lo
|
||||||
int d_loc_thresh_lo; // 3
|
int d_loc_thresh_lo; // 3
|
||||||
@ -29,13 +27,13 @@ namespace cw
|
|||||||
|
|
||||||
rc_t parse_args( const object_t* cfg, args_t& args );
|
rc_t parse_args( const object_t* cfg, args_t& args );
|
||||||
|
|
||||||
rc_t create( handle_t& hRef, const args_t& args );
|
rc_t create( handle_t& hRef, const args_t& args, perf_score::handle_t scoreH );
|
||||||
|
|
||||||
rc_t destroy( handle_t& hRef );
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
rc_t reset( handle_t h, unsigned beg_loc_id, unsigned end_loc_id );
|
rc_t reset( handle_t h, unsigned beg_loc_id, unsigned end_loc_id );
|
||||||
|
|
||||||
rc_t on_new_note( handle_t h, unsigned uid, double sec, uint8_t pitch, uint8_t vel, unsigned& loc_id );
|
rc_t on_new_note( handle_t h, unsigned uid, double sec, uint8_t pitch, uint8_t vel, unsigned& loc_id_ref, unsigned& score_vel_ref );
|
||||||
|
|
||||||
// Decay the affinity window and if necessary trigger a cycle of async background processing
|
// Decay the affinity window and if necessary trigger a cycle of async background processing
|
||||||
rc_t do_exec( handle_t h );
|
rc_t do_exec( handle_t h );
|
||||||
|
@ -138,10 +138,8 @@ namespace cw
|
|||||||
|
|
||||||
//cwLogInfo("Following: (%i notes found) sample count:%i %s.",mf.evtN,mf.sampleN,midi_csv_fname);
|
//cwLogInfo("Following: (%i notes found) sample count:%i %s.",mf.evtN,mf.sampleN,midi_csv_fname);
|
||||||
|
|
||||||
sf_args.scoreH = scoreH;
|
|
||||||
|
|
||||||
// create the score-follower
|
// create the score-follower
|
||||||
if((rc = score_follow_2::create(sfH,sf_args)) != kOkRC )
|
if((rc = score_follow_2::create(sfH,sf_args,scoreH)) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"Score follower create failed.");
|
rc = cwLogError(rc,"Score follower create failed.");
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
@ -159,11 +157,12 @@ namespace cw
|
|||||||
while( smp_idx <= mf.evtA[midi_evt_idx].sample_idx && mf.evtA[midi_evt_idx].sample_idx < smp_idx + smp_per_cycle )
|
while( smp_idx <= mf.evtA[midi_evt_idx].sample_idx && mf.evtA[midi_evt_idx].sample_idx < smp_idx + smp_per_cycle )
|
||||||
{
|
{
|
||||||
const midi_evt_t* e = mf.evtA + midi_evt_idx++;
|
const midi_evt_t* e = mf.evtA + midi_evt_idx++;
|
||||||
unsigned loc_id;
|
unsigned loc_id = kInvalidId;
|
||||||
|
unsigned score_vel = -1;
|
||||||
|
|
||||||
//printf("%f pitch:%i vel:%i\n",e->sec,e->pitch,e->vel);
|
//printf("%f pitch:%i vel:%i\n",e->sec,e->pitch,e->vel);
|
||||||
|
|
||||||
if((rc = on_new_note( sfH, e->uid, e->sec, e->pitch, e->vel, loc_id )) != kOkRC )
|
if((rc = on_new_note( sfH, e->uid, e->sec, e->pitch, e->vel, loc_id, score_vel )) != kOkRC )
|
||||||
{
|
{
|
||||||
rc = cwLogError(rc,"SF2 note processing failed on note UID:%i.",e->uid);
|
rc = cwLogError(rc,"SF2 note processing failed on note UID:%i.",e->uid);
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
in: { type:midi, doc:"MIDI messages to send."},
|
in: { type:midi, doc:"MIDI messages to send."},
|
||||||
rin: { type:record, fmt:{ required:["midi"]}, doc:"Record input. (must have 'midi' field)"},
|
rin: { type:record, fmt:{ required:["midi"]}, doc:"Record input. (must have 'midi' field)"},
|
||||||
print_fl: { type:bool, value:false, doc:"Print the output to the console."}
|
print_fl: { type:bool, value:false, doc:"Print the output to the console."}
|
||||||
|
enable_fl: { type:bool, value:true, doc:"Enable the output port."}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +736,8 @@
|
|||||||
in: { type:record, fmt:{ required:["midi"]} doc:"MIDI input."},
|
in: { type:record, fmt:{ required:["midi"]} doc:"MIDI input."},
|
||||||
voice_cnt: { type:uint, value:3, flags:["init"], doc:"Count of voices." },
|
voice_cnt: { type:uint, value:3, flags:["init"], doc:"Count of voices." },
|
||||||
out: { type:midi, flags:["mult"], doc:"MIDI output to voices. One per voice." },
|
out: { type:midi, flags:["mult"], doc:"MIDI output to voices. One per voice." },
|
||||||
done_fl: { type:bool, value:false, flags:["mult"], doc:"Voice available feedback triggers from voices. One per voice."},
|
gate_fl: { type:bool, flags:["mult"], doc:"Output: Per voice. Goes true with note-on, false when done_fl is set." },
|
||||||
|
done_fl: { type:bool, value:false, flags:["mult"], doc:"Input: Voice available feedback triggers from voices. One per voice."},
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -746,8 +748,8 @@
|
|||||||
wtb_instr: { type:string, value:"piano", flags:["init"], doc:"Instrument label of the selected wave-table bank."},
|
wtb_instr: { type:string, value:"piano", flags:["init"], doc:"Instrument label of the selected wave-table bank."},
|
||||||
in: { type:midi, doc:"MIDI in" },
|
in: { type:midi, doc:"MIDI in" },
|
||||||
out: { type:audio, doc:"Audio out" },
|
out: { type:audio, doc:"Audio out" },
|
||||||
done_fl: { type:bool, value:false, doc:"Triggers when voice is available."},
|
done_fl: { type:bool, value:false, doc:"Output: True when voice is available, false when active."},
|
||||||
gate_fl: { type:bool, value:false, doc:"True when voice is active, false when inactive." },
|
gate_fl: { type:bool, value:false, doc:"Output: True when voice is active, false when inactive." },
|
||||||
rls_coeff: { type:coeff, value:0.9, doc:"Release decay factor. Increase for longer decays."},
|
rls_coeff: { type:coeff, value:0.9, doc:"Release decay factor. Increase for longer decays."},
|
||||||
rls_thresh:{ type:coeff, value:0.01,doc:"Note off threshold. Decrease for longer decays."},
|
rls_thresh:{ type:coeff, value:0.01,doc:"Note off threshold. Decrease for longer decays."},
|
||||||
|
|
||||||
@ -758,6 +760,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
voice_detector: {
|
||||||
|
vars: {
|
||||||
|
in: { type:audio, doc:"Audio in" },
|
||||||
|
enable_fl: { type:bool, flags:[notify], value:false, doc:"Set when this voice detector is enabled." },
|
||||||
|
rls_thresh: { type:coeff, flags:[notify], value:0.01, doc:"Voice off threshold." },
|
||||||
|
done_fl: { type:bool, value:true, doc:"Output: Set when the voice is inactive, cleared when it is active."}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
print: {
|
print: {
|
||||||
vars: {
|
vars: {
|
||||||
@ -799,8 +810,21 @@
|
|||||||
vars: {
|
vars: {
|
||||||
fname: { type:string, flags:["init"], value:"", doc:"MIDI file name." },
|
fname: { type:string, flags:["init"], value:"", doc:"MIDI file name." },
|
||||||
csv_fname: { type:string, flags:["init"], value:"", doc:"MIDI CSV fname. See: midi::file open_csv()." },
|
csv_fname: { type:string, flags:["init"], value:"", doc:"MIDI CSV fname. See: midi::file open_csv()." },
|
||||||
|
alt_csv_fname: { type:string, flags:["init"], value:"", doc:"MIDI CSV fname. See: midi::file open_csv_2()." },
|
||||||
|
start: { type:all, flags:["notify"], value:false, doc:"Start playback" },
|
||||||
|
stop: { type:all, flags:["notify"], value:false, doc:"Stop playback" },
|
||||||
done_fl: { type:bool, value:false, doc:"Emits true on done." },
|
done_fl: { type:bool, value:false, doc:"Emits true on done." },
|
||||||
out: { type:midi, doc:"MIDI output."}
|
out: { type:midi, doc:"MIDI output."},
|
||||||
|
r_out: { type:record, doc:"MIDI output as records.",
|
||||||
|
fmt: {
|
||||||
|
alloc_cnt:1024,
|
||||||
|
fields: {
|
||||||
|
midi: { type:m3, doc:"MIDI channel event message" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,6 +862,7 @@
|
|||||||
b_meas: { type:uint, flags:["notify"], value:0, doc:"Score begin measure." },
|
b_meas: { type:uint, flags:["notify"], value:0, doc:"Score begin measure." },
|
||||||
e_meas: { type:uint, flags:["notify"], value:0, doc:"Score end measure." },
|
e_meas: { type:uint, flags:["notify"], value:0, doc:"Score end measure." },
|
||||||
done_fl: { type:bool, value:false, doc:"Emits true on done." },
|
done_fl: { type:bool, value:false, doc:"Emits true on done." },
|
||||||
|
loc_cnt: { type:uint, value:0, doc:"Output: Value of max 'loc'."},
|
||||||
out: { type:record, doc:"Score event record.",
|
out: { type:record, doc:"Score event record.",
|
||||||
fmt: {
|
fmt: {
|
||||||
fields: {
|
fields: {
|
||||||
@ -851,7 +876,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
vel_table: {
|
vel_table: {
|
||||||
doc:[ "Remap MIDI velocity values."]
|
doc:[ "Remap MIDI velocity values."
|
||||||
|
"If the incoming record has a 'score_vel' field then this is taken as the source velocity to be mapped and the MIDI message velocity is ignored."
|
||||||
|
]
|
||||||
vars: {
|
vars: {
|
||||||
vel_tbl_fname:{ type:string, flags:["init"], value:"", doc:"Velocity table filename as create by vwVelTableTuner." },
|
vel_tbl_fname:{ type:string, flags:["init"], value:"", doc:"Velocity table filename as create by vwVelTableTuner." },
|
||||||
vel_tbl_label:{ type:string, flags:["init"], value:"", doc:"Name of the active velocity table referenced by 'vel_fname'."},
|
vel_tbl_label:{ type:string, flags:["init"], value:"", doc:"Name of the active velocity table referenced by 'vel_fname'."},
|
||||||
@ -879,6 +906,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
score_follower_2: {
|
||||||
|
doc:[ "MIDI score follower: Sets the 'loc' field of the output record according to the score location." ]
|
||||||
|
vars: {
|
||||||
|
in: { type:record, fmt:{ required:["midi"]} doc:"Input record with 'midi' and 'loc' fields." },
|
||||||
|
score_fname: { type:string, flags:["init"], value:"", doc:"Score file with location information." },
|
||||||
|
b_loc: { type:uint, value:0, doc:"Score begin location." },
|
||||||
|
e_loc: { type:uint, value:0, doc:"Score end location." },
|
||||||
|
reset_trigger { type:all, flags:["notify"], value:false, doc:"Reset the score follower." },
|
||||||
|
print_fl: { type:bool, flags:["init"], value:false, doc:"Set to print log of score follower state." },
|
||||||
|
out:{ type:record, doc:"Pass-through of incoming MIDI with score location and score velocity."
|
||||||
|
fmt: {
|
||||||
|
alloc_cnt:1024, // internal recd_array size
|
||||||
|
fields: {
|
||||||
|
loc: { type:uint, value:-1, doc:"Score location id or if score track failed." } ,
|
||||||
|
score_vel: { type:uint, value:-1, doc:"Score mapped velocity or -1 if 'loc' is -1." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
preset_select: {
|
preset_select: {
|
||||||
doc:[ "Given a score location emit a preset label."],
|
doc:[ "Given a score location emit a preset label."],
|
||||||
@ -922,10 +969,16 @@
|
|||||||
vars: {
|
vars: {
|
||||||
cfg: { type:cfg, flags:["init"], doc:"Initial preset configuration." },
|
cfg: { type:cfg, flags:["init"], doc:"Initial preset configuration." },
|
||||||
fname: { type:string, flags:["init"], value:"", doc:"Preset file name."},
|
fname: { type:string, flags:["init"], value:"", doc:"Preset file name."},
|
||||||
in: { type:record, fmt:{ required:["loc"] }, doc:"Input record with 'loc' field." },
|
loc_cnt: { type:uint, flags:["init"], value:0, doc:"Count of uniq 'loc' id's in the score."},
|
||||||
|
//in: { type:record, fmt:{ required:["loc"] }, doc:"Input record with 'loc' field." },
|
||||||
|
in: { type:record, doc:"Input record with 'loc' field." },
|
||||||
loc: { type:uint, value:0, doc:"Seek to this location." },
|
loc: { type:uint, value:0, doc:"Seek to this location." },
|
||||||
reset: { type:bool, flags:["notify"], value:false, doc:"Reset to initial state."},
|
reset: { type:bool, flags:["notify"], value:false, doc:"Reset to initial state."},
|
||||||
per_note_fl: { type:bool, value:false, doc:"Update the selected preset on every note, otherwise update on new location values." },
|
pri_manual_sel: { type:uint, flags:["notify"], value:-1, doc:"Manually select the presets.", ui:{ type:list} },
|
||||||
|
sec_manual_sel: { type:uint, flags:["notify"], value:-1, doc:"Manually select the presets.", ui:{ type:list} },
|
||||||
|
per_note_fl: { type:bool, value:false, doc:"Change the preset on every note, otherwise change on new preset 'fragments'." },
|
||||||
|
per_loc_fl: { type:bool, value:false, doc:"Change the preset on every score location, change according to 'per_note_fl'." },
|
||||||
|
dry_chord_fl: { type:bool, value:false, doc:"Set to make 50% of all chord notes dry."},
|
||||||
|
|
||||||
pri_prob_fl: { type:bool, flags:["notify"], value: false, doc:"Select primary preset probabilstically." }
|
pri_prob_fl: { type:bool, flags:["notify"], value: false, doc:"Select primary preset probabilstically." }
|
||||||
pri_uniform_fl: { type:bool, flags:["notify","ui_disable"], value: false, doc:"Use a uniform probability distribution rather than an 'order' weighted distribution." },
|
pri_uniform_fl: { type:bool, flags:["notify","ui_disable"], value: false, doc:"Use a uniform probability distribution rather than an 'order' weighted distribution." },
|
||||||
|
9
notes.md
9
notes.md
@ -941,6 +941,10 @@ resolvable without more information.
|
|||||||
|
|
||||||
### TODO:
|
### TODO:
|
||||||
|
|
||||||
|
- Check for duplicate field labels. Particularly when using a base record.
|
||||||
|
It's easy to declare a field named 'midi' and then inherit a record with a field named 'midi' - this is a crash bug.
|
||||||
|
|
||||||
|
|
||||||
- DONE: Why doesn't the C7 on the downbeat of meas. 11 sound? (... it does but is quiet due to velocity table)
|
- DONE: Why doesn't the C7 on the downbeat of meas. 11 sound? (... it does but is quiet due to velocity table)
|
||||||
- DONE: Allow setting the location of the score player. This should also reset the sampler and voice control.
|
- DONE: Allow setting the location of the score player. This should also reset the sampler and voice control.
|
||||||
- DONE: The voice ctl should respond to all-notes-off message and reset each sampler channel.
|
- DONE: The voice ctl should respond to all-notes-off message and reset each sampler channel.
|
||||||
@ -1415,6 +1419,11 @@ The new record effectively inherits the contents of the
|
|||||||
existing record by reference. No data is copied.
|
existing record by reference. No data is copied.
|
||||||
For an example of this see the `vel_table` implementation.
|
For an example of this see the `vel_table` implementation.
|
||||||
|
|
||||||
|
Note that record field values may not be changed in place because
|
||||||
|
this would change the value for all other processors that
|
||||||
|
receive the record. Incoming records must therefore be
|
||||||
|
copied if they are changed.
|
||||||
|
|
||||||
Variable Change Notification
|
Variable Change Notification
|
||||||
----------------------------
|
----------------------------
|
||||||
Processors are not directly notified when one of their connected variables changes.
|
Processors are not directly notified when one of their connected variables changes.
|
||||||
|
Loading…
Reference in New Issue
Block a user