cwSfMatch.h/cpp : Updates to better integrate with cwSfScore.

Added loc_to_index().
This commit is contained in:
kevin 2023-09-12 17:59:56 -04:00
parent 16ba4d6a3f
commit 143c7daa91
2 changed files with 85 additions and 60 deletions

View File

@ -15,6 +15,7 @@ namespace cw
{ {
namespace sfmatch namespace sfmatch
{ {
sfmatch_t* _handleToPtr( handle_t h ) sfmatch_t* _handleToPtr( handle_t h )
{ return handleToPtr<handle_t,sfmatch_t>(h); } { return handleToPtr<handle_t,sfmatch_t>(h); }
@ -47,7 +48,7 @@ namespace cw
{ {
unsigned i,n; unsigned i,n;
const sfscore::loc_t* lp = loc(p->scH,li); const sfscore::loc_t* lp = loc_base(p->scH) + li;
// count the number of note events at location li // count the number of note events at location li
for(n=0,i=0; i<lp->evtCnt; ++i) for(n=0,i=0; i<lp->evtCnt; ++i)
@ -408,7 +409,7 @@ namespace cw
void _cmScMatchMidiEvtFlags( sfmatch_t* p, const loc_t* lp, unsigned evtIdx, char* s, unsigned sn ) void _cmScMatchMidiEvtFlags( sfmatch_t* p, const loc_t* lp, unsigned evtIdx, char* s, unsigned sn )
{ {
const sfscore::loc_t* slp = sfscore::loc(p->scH,lp->scLocIdx); const sfscore::loc_t* slp = sfscore::loc_base(p->scH) + lp->scLocIdx;
assert( evtIdx < slp->evtCnt ); assert( evtIdx < slp->evtCnt );
@ -443,7 +444,7 @@ namespace cw
{ {
assert( begLocIdx < sfscore::loc_count(scoreH) ); assert( begLocIdx < sfscore::loc_count(scoreH) );
const sfscore::loc_t* loc = sfscore::loc(scoreH,i); const sfscore::loc_t* loc = sfscore::loc_base(scoreH) + i;
for(unsigned j=0; j<loc->evtCnt; ++j) for(unsigned j=0; j<loc->evtCnt; ++j)
{ {
@ -512,7 +513,7 @@ cw::rc_t cw::sfmatch::destroy( handle_t& hRef )
return rc; return rc;
} }
cw::rc_t cw::sfmatch::exec( handle_t h, unsigned locIdx, unsigned locN, const midi_t* midiV, unsigned midiN, double min_cost ) cw::rc_t cw::sfmatch::exec( handle_t h, unsigned oLocId, unsigned locN, const midi_t* midiV, unsigned midiN, double min_cost )
{ {
rc_t rc; rc_t rc;
unsigned rn = midiN + 1; unsigned rn = midiN + 1;
@ -524,7 +525,7 @@ cw::rc_t cw::sfmatch::exec( handle_t h, unsigned locIdx, unsigned locN, const m
return rc; return rc;
// _cmScMatchCalcMtx() returns false if the score window exceeds the length of the score // _cmScMatchCalcMtx() returns false if the score window exceeds the length of the score
if(!_cmScMatchCalcMtx(p,locIdx, midiV, rn, cn) ) if(!_cmScMatchCalcMtx(p,oLocId, midiV, rn, cn) )
return kEofRC; return kEofRC;
//_cmScMatchPrintMtx(p,rn,cn); //_cmScMatchPrintMtx(p,rn,cn);
@ -535,7 +536,6 @@ cw::rc_t cw::sfmatch::exec( handle_t h, unsigned locIdx, unsigned locN, const m
return rc; return rc;
} }
unsigned cw::sfmatch::sync( handle_t h, unsigned i_opt, midi_t* midiBuf, unsigned midiN, unsigned* missCntPtr ) unsigned cw::sfmatch::sync( handle_t h, unsigned i_opt, midi_t* midiBuf, unsigned midiN, unsigned* missCntPtr )
{ {
sfmatch_t* p = _handleToPtr(h); sfmatch_t* p = _handleToPtr(h);
@ -550,13 +550,13 @@ unsigned cw::sfmatch::sync( handle_t h, unsigned i_opt, midi_t* midiBuf, unsigne
if( cp->code != kSmInsIdx ) if( cp->code != kSmInsIdx )
{ {
assert( cp->ri > 0 ); assert( cp->ri > 0 );
midiBuf[ cp->ri-1 ].locIdx = kInvalidIdx; midiBuf[ cp->ri-1 ].oLocId = kInvalidIdx;
} }
switch( cp->code ) switch( cp->code )
{ {
case kSmSubIdx: case kSmSubIdx:
midiBuf[ cp->ri-1 ].locIdx = i_opt + i; midiBuf[ cp->ri-1 ].oLocId = i_opt + i;
midiBuf[ cp->ri-1 ].scEvtIdx = cp->scEvtIdx; midiBuf[ cp->ri-1 ].scEvtIdx = cp->scEvtIdx;
if( cwIsFlag(cp->flags,kSmMatchFl) ) if( cwIsFlag(cp->flags,kSmMatchFl) )
@ -571,12 +571,12 @@ unsigned cw::sfmatch::sync( handle_t h, unsigned i_opt, midi_t* midiBuf, unsigne
// fall through // fall through
case kSmInsIdx: case kSmInsIdx:
cp->locIdx = i_opt + i; cp->oLocId = i_opt + i;
++i; ++i;
break; break;
case kSmDelIdx: case kSmDelIdx:
cp->locIdx = kInvalidIdx; cp->oLocId = kInvalidIdx;
++missCnt; ++missCnt;
break; break;
} }
@ -592,11 +592,11 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
{ {
assert( bsi != kInvalidIdx ); assert( bsi != kInvalidIdx );
sfmatch_t* p = _handleToPtr(h); sfmatch_t* p = _handleToPtr(h);
path_t* cp = p->p_opt; path_t* cp = p->p_opt;
path_t* pp = cp; path_t* pp = cp;
int polyN = 0; int polyN = 0;
int i; int i;
printf("loc: "); printf("loc: ");
@ -627,9 +627,9 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
if( pp->code!=kSmDelIdx ) if( pp->code!=kSmDelIdx )
{ {
int locIdx = bsi + pp->ci - 1; int oLocId = bsi + pp->ci - 1;
assert(0 <= locIdx && locIdx <= (int)p->locN); assert(0 <= oLocId && oLocId <= (int)p->locN);
loc_t* lp = p->loc + locIdx; loc_t* lp = p->loc + oLocId;
if( lp->evtCnt >= (unsigned) if( lp->evtCnt >= (unsigned)
i ) i )
@ -646,9 +646,9 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
printf("%4s%4s ", (pp->code==kSmDelIdx? "-" : " ")," "); printf("%4s%4s ", (pp->code==kSmDelIdx? "-" : " ")," ");
/* /*
int locIdx = bsi + pp->ci - 1; int oLocId = bsi + pp->ci - 1;
assert(0 <= locIdx && locIdx <= p->locN); assert(0 <= oLocId && oLocId <= p->locN);
loc_t* lp = p->loc + locIdx; loc_t* lp = p->loc + oLocId;
if( pp->code!=kSmDelIdx && lp->evtCnt >= i ) if( pp->code!=kSmDelIdx && lp->evtCnt >= i )
printf("%4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0)); printf("%4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0));
else else
@ -732,10 +732,10 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
// print the stored location index // print the stored location index
for(pp=cp; pp!=NULL; pp=pp->next) for(pp=cp; pp!=NULL; pp=pp->next)
{ {
if( pp->locIdx == kInvalidIdx ) if( pp->oLocId == kInvalidIdx )
printf("%4s%4s "," "," "); printf("%4s%4s "," "," ");
else else
printf("%4i%4s ",p->loc[pp->locIdx].scLocIdx," "); printf("%4i%4s ",p->loc[pp->oLocId].scLocIdx," ");
} }
printf("\nbar: "); printf("\nbar: ");
@ -743,7 +743,7 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
// print the stored location index // print the stored location index
for(pp=cp; pp!=NULL; pp=pp->next) for(pp=cp; pp!=NULL; pp=pp->next)
{ {
if( pp->locIdx==kInvalidIdx || pp->scEvtIdx==kInvalidIdx ) if( pp->oLocId==kInvalidIdx || pp->scEvtIdx==kInvalidIdx )
printf("%4s%4s "," "," "); printf("%4s%4s "," "," ");
else else
{ {
@ -778,24 +778,39 @@ void cw::sfmatch::print_path( handle_t h, unsigned bsi, const midi_t* midiV )
} }
unsigned cw::sfmatch::loc_to_index( handle_t h, unsigned loc )
{
sfmatch_t* p = _handleToPtr(h);
const loc_t* y = std::find_if(p->loc, p->loc+p->locN, [&loc](const loc_t& x){return x.scLocIdx==loc;} );
unsigned idx = y - p->loc;
return idx<p->locN ? idx : kInvalidIdx;
}
cw::rc_t cw::sfmatch::test( const object_t* cfg, sfscore::handle_t scoreH ) cw::rc_t cw::sfmatch::test( const object_t* cfg, sfscore::handle_t scoreH )
{ {
rc_t rc = kOkRC; rc_t rc = kOkRC;
const object_t* perf = nullptr; const object_t* perf = nullptr;
const object_t* gen_perf_example = nullptr; const object_t* gen_perf_example = nullptr;
bool gen_perf_enable_fl = false; bool gen_perf_enable_fl = false;
unsigned gen_perf_beg_loc_idx = 0; unsigned gen_perf_beg_loc_idx = 0;
unsigned gen_perf_loc_cnt = 0; unsigned gen_perf_loc_cnt = 0;
midi_t* midiA = nullptr; midi_t* midiA = nullptr;
unsigned maxScWndN = 10; unsigned maxScWndN = 10;
unsigned maxMidiWndN = 7; unsigned maxMidiWndN = 7;
unsigned init_score_loc = 0;
unsigned beg_perf_idx = 0;
unsigned perf_cnt = 6;
sfmatch::handle_t matchH; sfmatch::handle_t matchH;
// parse the test cfg // parse the test cfg
if((rc = cfg->getv( "maxScWndN", maxScWndN, if((rc = cfg->getv( "maxScWndN", maxScWndN,
"maxMidiWndN", maxMidiWndN, "maxMidiWndN", maxMidiWndN,
"gen_perf_example", gen_perf_example, "gen_perf_example", gen_perf_example,
"init_score_loc",init_score_loc,
"beg_perf_idx", beg_perf_idx,
"perf_cnt", perf_cnt,
"perf", perf)) != kOkRC ) "perf", perf)) != kOkRC )
{ {
rc = cwLogError(rc,"sfscore test parse params failed."); rc = cwLogError(rc,"sfscore test parse params failed.");
@ -816,8 +831,9 @@ cw::rc_t cw::sfmatch::test( const object_t* cfg, sfscore::handle_t scoreH )
} }
else else
{ {
// Parse the cfg. perf[] array
unsigned midiN = perf->child_count(); unsigned midiN = perf->child_count();
midiA = mem::allocZ<midi_t>(midiN); midiA = mem::allocZ<midi_t>(midiN);
for(unsigned i=0; i<midiN; ++i) for(unsigned i=0; i<midiN; ++i)
@ -834,33 +850,39 @@ cw::rc_t cw::sfmatch::test( const object_t* cfg, sfscore::handle_t scoreH )
} }
} }
// Create the cwMatch
if((rc = create(matchH, scoreH, maxScWndN, maxMidiWndN )) != kOkRC ) if((rc = create(matchH, scoreH, maxScWndN, maxMidiWndN )) != kOkRC )
{ {
rc = cwLogError(rc,"Score matcher create failed."); rc = cwLogError(rc,"Score matcher create failed.");
goto errLabel; goto errLabel;
} }
unsigned locIdx = 0; // Set the matcher to the first location to begin matching against
unsigned locN = maxScWndN; unsigned oLocId = loc_to_index(matchH,init_score_loc);
unsigned perf_idx = 3; unsigned locN = maxScWndN;
unsigned perf_cnt = 4;
// Count of MIDI events to track.
if((rc = exec(matchH, locIdx, locN, midiA + perf_idx, perf_cnt, DBL_MAX )) != kOkRC ) perf_cnt = std::min(maxMidiWndN,perf_cnt);
// Align MIDI notes to the score
if((rc = exec(matchH, oLocId, locN, midiA + beg_perf_idx, perf_cnt, DBL_MAX )) != kOkRC )
{ {
rc = cwLogError(rc,"score match failed."); rc = cwLogError(rc,"score match failed.");
goto errLabel; goto errLabel;
} }
unsigned eli = kInvalidIdx; // Update the cwMatch to reflect the alignment found during the exec.
unsigned eli = kInvalidIdx;
unsigned missCnt = 0; unsigned missCnt = 0;
unsigned i_opt = locIdx; unsigned i_opt = oLocId;
if(( eli = cw::sfmatch::sync( matchH, i_opt, midiA + perf_idx, perf_cnt, &missCnt )) == kInvalidIdx ) if(( eli = cw::sfmatch::sync( matchH, i_opt, midiA + beg_perf_idx, perf_cnt, &missCnt )) == kInvalidIdx )
{ {
rc = cwLogError(rc,"score match sync failed."); rc = cwLogError(rc,"score match sync failed.");
goto errLabel; goto errLabel;
} }
unsigned bsi = locIdx; // Print the state alignment.
unsigned bsi = oLocId;
print_path( matchH, bsi, midiA ); print_path( matchH, bsi, midiA );
} }

View File

@ -35,12 +35,12 @@ namespace cw
// List record used to track a path through the DP matrix p->m[,] // List record used to track a path through the DP matrix p->m[,]
typedef struct path_str typedef struct path_str
{ {
unsigned code; // kSmXXXIdx unsigned code; // kSmXXXIdx
unsigned ri; // matrix row index unsigned ri; // matrix row index
unsigned ci; // matrix col index unsigned ci; // matrix col index
unsigned flags; // cmSmMatchFl | cmSmTransFl unsigned flags; // cmSmMatchFl | cmSmTransFl
unsigned locIdx; // p->loc index or cmInvalidIdx unsigned oLocId; // p->loc index or cmInvalidIdx
unsigned scEvtIdx; // scScore event index unsigned scEvtIdx; // scScore event index
struct path_str* next; // struct path_str* next; //
} path_t; } path_t;
@ -63,10 +63,11 @@ namespace cw
{ {
unsigned mni; // unique identifier for this MIDI note - used to recognize when the sfmatcher backtracks. unsigned mni; // unique identifier for this MIDI note - used to recognize when the sfmatcher backtracks.
unsigned muid; // MIDI file event msg unique id (See cmMidiTrackMsg_t.uid) unsigned muid; // MIDI file event msg unique id (See cmMidiTrackMsg_t.uid)
unsigned smpIdx; // time stamp of this event double sec; // time stamp of this event in seconds
unsigned smpIdx; // time stamp of this event in samples
unsigned pitch; // MIDI note pitch unsigned pitch; // MIDI note pitch
unsigned vel; // " " velocity unsigned vel; // " " velocity
unsigned locIdx; // location assoc'd with this MIDI evt (kInvalidIdx if not a matching or non-matching 'substitute') unsigned oLocId; // location assoc'd with this MIDI evt (kInvalidIdx if not a matching or non-matching 'substitute')
unsigned scEvtIdx; // sfscore event index assoc'd with this event unsigned scEvtIdx; // sfscore event index assoc'd with this event
} midi_t; } midi_t;
@ -94,7 +95,7 @@ namespace cw
path_t* p_opt; // p_opt[pn] - current best alignment as a linked list path_t* p_opt; // p_opt[pn] - current best alignment as a linked list
double opt_cost; // last p_opt cost set by exec() double opt_cost; // last p_opt cost set by exec()
} sfmatch_t; } sfmatch_t;
typedef handle<struct sfmatch_str> handle_t; typedef handle<struct sfmatch_str> handle_t;
// This matcher determines the optimal alignment of a short list of MIDI notes // This matcher determines the optimal alignment of a short list of MIDI notes
@ -117,26 +118,25 @@ namespace cw
rc_t create( handle_t& hRef, sfscore::handle_t scoreH, unsigned maxScWndN, unsigned maxMidiWndN ); rc_t create( handle_t& hRef, sfscore::handle_t scoreH, unsigned maxScWndN, unsigned maxMidiWndN );
rc_t destroy( handle_t& hRef ); rc_t destroy( handle_t& hRef );
// Locate the position in p->loc[locIdx:locIdx+locN-1] which bests matches midiV[0:midiN]. // Locate the position in p->loc[oLocId:oLocId+locN-1] which bests matches midiV[0:midiN].
// The result of this function is to update p_opt[] // The result of this function is to update p_opt[]
// The optimal path p_opt[] will only be updated if the edit_cost associated 'midiV[0:midiN]'. // The optimal path p_opt[] will only be updated if the edit_cost associated 'midiV[0:midiN]'.
// with the best match is less than 'min_cost'. // with the best match is less than 'min_cost'.
// Set 'min_cost' to DBL_MAX to force p_opt[] to be updated. // Set 'min_cost' to DBL_MAX to force p_opt[] to be updated.
// Returns kEofRC if locIdx + locN > p->locN - note that this is not necessarily an error. // Returns kEofRC if oLocId + locN > p->locN - note that this is not necessarily an error.
rc_t exec( handle_t h, unsigned locIdx, unsigned locN, const midi_t* midiV, unsigned midiN, double min_cost ); rc_t exec( handle_t h, unsigned oLocId, unsigned locN, const midi_t* midiV, unsigned midiN, double min_cost );
// This function updates the midiBuf[] fields 'oLocId' and 'scEvtIdx' after an alignment
// This function updates the midiBuf[] fields 'locIdx' and 'scEvtIdx' after an alignment
// has been found via an earlier call to 'exec()'. // has been found via an earlier call to 'exec()'.
// //
// Traverse the least cost path and: // Traverse the least cost path and:
// //
// 1) Returns, esi, the score location index of the last MIDI note // 1) Returns, esi, the score location index of the last MIDI note
// which has a positive match with the score and assign // which has a positive match with the score and assign
// the internal score index to cp->locIdx. // the internal score index to cp->oLocId.
// //
// 2) Set cmScAlignPath_t.locIdx - index into p->loc[] associated // 2) Set cmScAlignPath_t.oLocId - index into p->loc[] associated
// with each path element that is a 'substitute' or an 'insert'. // with each path element that is a 'substitute' or an 'insert'.
// //
// 3) Set *missCnPtr: the count of trailing non-positive matches in midiBuf[]. // 3) Set *missCnPtr: the count of trailing non-positive matches in midiBuf[].
@ -151,6 +151,9 @@ namespace cw
// midiV - pointer to the first element of the MIDI buffer used to form the path. // midiV - pointer to the first element of the MIDI buffer used to form the path.
void print_path( handle_t h, unsigned bsi, const midi_t* midiV ); void print_path( handle_t h, unsigned bsi, const midi_t* midiV );
// Given a loc value return the index into p->loc[p->locN].of the associated loc.
unsigned loc_to_index( handle_t h, unsigned loc );
// Returns the index into loc->evtV[] of pitch. // Returns the index into loc->evtV[] of pitch.
inline unsigned match_index( const loc_t* loc, unsigned pitch ) inline unsigned match_index( const loc_t* loc, unsigned pitch )
{ {