cwFlowPerf.cpp : Add vel. table to score_player.
This commit is contained in:
parent
56a88e22f6
commit
e4f58311f4
234
cwFlowPerf.cpp
234
cwFlowPerf.cpp
@ -50,7 +50,9 @@ namespace cw
|
||||
namespace score_player
|
||||
{
|
||||
enum {
|
||||
kScoreFileNamePId,
|
||||
kScoreFNamePId,
|
||||
kVelTblFnamePId,
|
||||
kVelTblLabelPId,
|
||||
kDoneFlPId,
|
||||
kOutPId,
|
||||
kLocPId
|
||||
@ -61,9 +63,18 @@ namespace cw
|
||||
unsigned sample_idx;
|
||||
unsigned loc;
|
||||
unsigned meas;
|
||||
unsigned d1; // inital d1 value before velocity mapping was applied
|
||||
midi::ch_msg_t* midi; // index of associated msg in chMsgA
|
||||
} msg_t;
|
||||
|
||||
typedef struct vel_tbl_str
|
||||
{
|
||||
unsigned* tblA;
|
||||
unsigned tblN;
|
||||
char* label;
|
||||
struct vel_tbl_str* link;
|
||||
} vel_tbl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@ -72,23 +83,34 @@ namespace cw
|
||||
msg_t* msgA; // msgA[ msgN ]
|
||||
midi::ch_msg_t* chMsgA; // chMsgA[ msgN ]
|
||||
|
||||
vel_tbl_t* velTblL; // List of vel. tables.
|
||||
vel_tbl_t* activeVelTbl; // Currently active vel. table or null if no vel. tbl is active.
|
||||
|
||||
|
||||
unsigned sample_idx;
|
||||
unsigned msg_idx;
|
||||
} inst_t;
|
||||
|
||||
rc_t _load_score( proc_t* proc, inst_t* p, const char* fname )
|
||||
rc_t _load_score( proc_t* proc, inst_t* p, const char* score_fname )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
perf_score::handle_t perfScoreH;
|
||||
const perf_score::event_t* score_evt = nullptr;
|
||||
perf_score::handle_t perfScoreH;
|
||||
const perf_score::event_t* score_evt = nullptr;
|
||||
char* fname = nullptr;
|
||||
|
||||
if( fname == nullptr || textLength(fname)==0 )
|
||||
if( score_fname == nullptr || textLength(score_fname)==0 )
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"The score filename is blank.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((fname = proc_expand_filename( proc, score_fname )) == nullptr )
|
||||
{
|
||||
rc = cwLogError(kOpFailRC,"The score filename (%s) is invalid.",score_fname);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc= perf_score::create( perfScoreH, fname )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Score create failed on '%s'.",fname);
|
||||
@ -110,18 +132,17 @@ namespace cw
|
||||
p->msgA = mem::allocZ<msg_t>(p->msgAllocN);
|
||||
p->chMsgA = mem::allocZ<midi::ch_msg_t>(p->msgAllocN);
|
||||
|
||||
for(unsigned i=0; i<p->msgAllocN; ++i,++score_evt)
|
||||
for(; p->msgN<p->msgAllocN && score_evt !=nullptr; score_evt=score_evt->link)
|
||||
{
|
||||
if( score_evt->status != 0 )
|
||||
{
|
||||
msg_t* m = p->msgA + p->msgN;
|
||||
msg_t* m = p->msgA + p->msgN;
|
||||
midi::ch_msg_t* mm = p->chMsgA + p->msgN;
|
||||
|
||||
m->sample_idx = (unsigned)(proc->ctx->sample_rate * score_evt->sec);
|
||||
m->loc = score_evt->loc;
|
||||
m->meas = score_evt->meas;
|
||||
m->midi = mm;
|
||||
|
||||
m->loc = score_evt->loc;
|
||||
m->meas = score_evt->meas;
|
||||
m->midi = mm;
|
||||
|
||||
time::fracSecondsToSpec( mm->timeStamp, score_evt->sec );
|
||||
|
||||
@ -132,25 +153,175 @@ namespace cw
|
||||
mm->status = score_evt->status & 0xf0;
|
||||
mm->d0 = score_evt->d0;
|
||||
mm->d1 = score_evt->d1;
|
||||
m->d1 = score_evt->d1;
|
||||
|
||||
p->msgN += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkRC )
|
||||
rc = cwLogError(rc,"Score load failed on '%s'.",cwStringNullGuard(fname));
|
||||
|
||||
perf_score::destroy(perfScoreH);
|
||||
|
||||
mem::release(fname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t _load_vel_table_file( proc_t* proc, inst_t* p, const char* vel_tbl_fname )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
object_t* cfg = nullptr;
|
||||
const object_t* tblL = nullptr;
|
||||
unsigned tblN = 0;
|
||||
char* fname = nullptr;
|
||||
|
||||
if( vel_tbl_fname == nullptr || textLength(vel_tbl_fname)==0 )
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"The velocity table filename is blank.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((fname = proc_expand_filename( proc, vel_tbl_fname )) == nullptr )
|
||||
{
|
||||
rc = cwLogError(kOpFailRC,"The velocity table filename (%s) is invalid.",vel_tbl_fname);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = objectFromFile(fname,cfg)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Velocity table file parse failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = cfg->getv("tables",tblL)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Velocity table file has no 'tables' field.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
tblN = tblL->child_count();
|
||||
|
||||
for(unsigned i=0; i<tblN; ++i)
|
||||
{
|
||||
const object_t* tbl = tblL->child_ele(i);
|
||||
const object_t* velListCfg = nullptr;
|
||||
vel_tbl_t* vt = nullptr;
|
||||
|
||||
const char* label = nullptr;
|
||||
|
||||
if((rc = tbl->getv("table",velListCfg,
|
||||
"name",label)) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Velocity table at index %i failed.",i);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
vt = mem::allocZ<vel_tbl_t>();
|
||||
vt->link = p->velTblL;
|
||||
p->velTblL = vt;
|
||||
vt->tblN = velListCfg->child_count();
|
||||
vt->label = mem::duplStr(label);
|
||||
|
||||
// if the table is empty
|
||||
if( vt->tblN == 0 )
|
||||
{
|
||||
rc = cwLogError(rc,"The velocity table named '%s' appears to be blank.",cwStringNullGuard(label));
|
||||
continue;
|
||||
}
|
||||
|
||||
vt->tblA = mem::allocZ<unsigned>(vt->tblN);
|
||||
|
||||
for(unsigned j=0; j<vt->tblN; ++j)
|
||||
{
|
||||
const object_t* intCfg;
|
||||
if((intCfg = velListCfg->child_ele(j)) == nullptr )
|
||||
{
|
||||
rc = cwLogError(rc,"Access to the integer value at index %i failed on vel. table '%s'.",j,cwStringNullGuard(label));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
if((rc = intCfg->value(vt->tblA[j])) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Parse failed on integer value at index %i in vel. table '%s'.",j,cwStringNullGuard(label));
|
||||
goto errLabel;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
errLabel:
|
||||
if( rc != kOkRC )
|
||||
rc = cwLogError(rc,"Score velocity table file load failed on '%s'.",cwStringNullGuard(vel_tbl_fname));
|
||||
|
||||
if( cfg != nullptr )
|
||||
cfg->free();
|
||||
|
||||
mem::release(fname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t _activate_vel_table( proc_t* proc, inst_t* p, const char* vel_tbl_label )
|
||||
{
|
||||
for(vel_tbl_t* vt = p->velTblL; vt!=nullptr; vt=vt->link)
|
||||
if( textIsEqual(vt->label,vel_tbl_label))
|
||||
{
|
||||
p->activeVelTbl = vt;
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
cwLogWarning("The requested velocity table '%s' was not found on the score instance '%s:%i'.",vel_tbl_label,proc->label, proc->label_sfx_id);
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
rc_t _apply_vel_table( inst_t* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
if( p->activeVelTbl == nullptr )
|
||||
{
|
||||
cwLogWarning("A velocity table has not been selected.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
for(unsigned i=0; i<p->msgN; ++i)
|
||||
{
|
||||
midi::ch_msg_t* m = p->msgA[i].midi;
|
||||
|
||||
if( midi::isNoteOn(m->status,m->d1) )
|
||||
{
|
||||
if( p->msgA[i].d1 >= p->activeVelTbl->tblN )
|
||||
{
|
||||
rc = cwLogError(kInvalidArgRC,"The pre-mapped velocity value %i is outside of the range (%i) of the velocity table '%s'.",p->msgA[i].d1,p->activeVelTbl->tblN,cwStringNullGuard(p->activeVelTbl->label));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
m->d1 = p->activeVelTbl->tblA[ p->msgA[i].d1 ];
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc_t _create( proc_t* proc, inst_t* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
const char* score_fname = nullptr;
|
||||
const char* vel_tbl_fname = nullptr;
|
||||
const char* vel_tbl_label = nullptr;
|
||||
|
||||
if((rc = var_register_and_get(proc,kAnyChIdx,kScoreFileNamePId, "fname", kBaseSfxId, score_fname)) != kOkRC )
|
||||
if((rc = var_register_and_get(proc,kAnyChIdx,
|
||||
kScoreFNamePId, "fname", kBaseSfxId, score_fname,
|
||||
kVelTblFnamePId, "vel_tbl_fname", kBaseSfxId, vel_tbl_fname,
|
||||
kVelTblLabelPId, "vel_tbl_label", kBaseSfxId, vel_tbl_label)) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
@ -162,6 +333,32 @@ namespace cw
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// load the score
|
||||
if((rc = _load_score( proc, p, score_fname )) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// load p->velTblL from the vel table file
|
||||
if((rc = _load_vel_table_file( proc, p, vel_tbl_fname )) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// activate the selected velocity table
|
||||
if((rc = _activate_vel_table( proc, p, vel_tbl_label )) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// apply the selected velocity table
|
||||
if( p->activeVelTbl != nullptr )
|
||||
{
|
||||
if((rc = _apply_vel_table( p )) != kOkRC )
|
||||
{
|
||||
goto errLabel;
|
||||
}
|
||||
}
|
||||
|
||||
// create one output MIDI buffer
|
||||
rc = var_register_and_set( proc, "out", kBaseSfxId, kOutPId, kAnyChIdx, nullptr, 0 );
|
||||
@ -174,6 +371,14 @@ namespace cw
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
for(vel_tbl_t* vt=p->velTblL; vt!=nullptr; vt=vt->link)
|
||||
{
|
||||
vel_tbl_t* vt0 = vt->link;
|
||||
mem::release(vt->tblA);
|
||||
mem::release(vt);
|
||||
vt = vt0;
|
||||
}
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -203,7 +408,11 @@ namespace cw
|
||||
while( p->msg_idx < p->msgN && p->sample_idx >= p->msgA[p->msg_idx].sample_idx )
|
||||
{
|
||||
if( mbuf->msgA == nullptr )
|
||||
{
|
||||
// Note we only set a pointer to the first msg in p->chMsgA[]
|
||||
// successive messages will be consecutively after it.
|
||||
mbuf->msgA = p->msgA[p->msg_idx].midi;
|
||||
}
|
||||
|
||||
mbuf->msgN += 1;
|
||||
|
||||
@ -213,6 +422,7 @@ namespace cw
|
||||
|
||||
}
|
||||
|
||||
|
||||
if( done_fl )
|
||||
var_set(proc, kDoneFlPId, kAnyChIdx, true );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user