cmProc4.h/c: Add cmMeas.vsi and callback args to cmScMatcher.

This commit is contained in:
kevin 2013-01-30 17:33:44 -08:00
parent 27bae4fca2
commit 56249c2f40
2 changed files with 191 additions and 121 deletions

222
cmProc4.c
View File

@ -1910,7 +1910,7 @@ void _cmScMatchPrintPath( cmScMatch* p, cmScMatchPath_t* cp, unsigned bsi, const
//=======================================================================================================================
cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN )
cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg )
{
cmScMatcher* op = cmObjAlloc(cmScMatcher,c,p);
@ -1919,7 +1919,7 @@ cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t s
if( srate != 0 )
{
if( cmScMatcherInit(op,srate,scH,scWndN,midiWndN) != cmOkRC )
if( cmScMatcherInit(op,srate,scH,scWndN,midiWndN,cbFunc,cbArg) != cmOkRC )
cmScMatcherFree(&op);
}
@ -1944,7 +1944,7 @@ cmRC_t cmScMatcherFree( cmScMatcher** pp )
}
cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN )
cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg )
{
cmRC_t rc;
if((rc = cmScMatcherFinal(p)) != cmOkRC )
@ -1956,14 +1956,17 @@ cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scW
if(( rc = cmScMatchInit(p->mp,scH,scWndN,midiWndN)) != cmOkRC )
return rc;
p->cbFunc = cbFunc;
p->cbArg = cbArg;
p->mn = midiWndN;
p->midiBuf = cmMemResize(cmScMatchMidi_t,p->midiBuf,p->mn);
p->stepCnt = 3;
p->maxMissCnt = p->stepCnt+1;
p->rn = 2 * cmScoreEvtCount(scH);
p->res = cmMemResizeZ(cmScMatcherResult_t,p->res,p->rn);
p->printFl = false;
cmScMatcherReset(p);
cmScMatcherReset(p,0);
return rc;
}
@ -1973,7 +1976,7 @@ cmRC_t cmScMatcherFinal( cmScMatcher* p )
return cmScMatchFinal(p->mp);
}
void cmScMatcherReset( cmScMatcher* p )
cmRC_t cmScMatcherReset( cmScMatcher* p, unsigned scLocIdx )
{
p->mbi = p->mp->mmn;
p->mni = 0;
@ -1982,6 +1985,16 @@ void cmScMatcherReset( cmScMatcher* p )
p->missCnt = 0;
p->scanCnt = 0;
p->ri = 0;
p->eli = cmInvalidIdx;
p->ili = 0;
// convert scLocIdx to an index into p->mp->loc[]
unsigned i;
for(i=0; i<p->mp->locN; ++i)
if( p->mp->loc[i].scLocIdx == scLocIdx )
p->ili = i;
return cmOkRC;
}
bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
@ -2016,6 +2029,7 @@ void _cmScMatcherStoreResult( cmScMatcher* p, unsigned locIdx, unsigned scEvtIdx
bool fpFl = locIdx==cmInvalidIdx || matchFl==false;
cmScMatcherResult_t * rp = NULL;
unsigned i;
cmScMatcherResult_t r;
assert( tpFl==false || (tpFl==true && locIdx != cmInvalidIdx ) );
@ -2037,10 +2051,18 @@ void _cmScMatcherStoreResult( cmScMatcher* p, unsigned locIdx, unsigned scEvtIdx
}
if( rp == NULL )
{
if( p->ri >= p->rn )
{
rp = &r;
memset(rp,0,sizeof(r));
}
else
{
rp = p->res + p->ri;
++p->ri;
}
}
rp->locIdx = locIdx;
rp->scEvtIdx = scEvtIdx;
@ -2060,7 +2082,7 @@ void cmScMatcherPrintPath( cmScMatcher* p )
_cmScMatchPrintPath(p->mp, p->mp->p_opt, p->begSyncLocIdx, p->midiBuf );
}
unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
unsigned cmScMatcherScan( cmScMatcher* p, unsigned bli, unsigned scanCnt )
{
assert( p->mp != NULL && p->mp->mmn > 0 );
@ -2071,22 +2093,17 @@ unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
// initialize the internal values set by this function
p->missCnt = 0;
p->esi = cmInvalidIdx;
p->eli = cmInvalidIdx;
p->s_opt = DBL_MAX;
// if the MIDI buf is not full
if( p->mbi != 0 )
return cmInvalidIdx;
// load a temporary MIDI pitch buffer for use by cmScMatch.
//unsigned pitchV[p->mp->mmn];
//for(i=0; i<p->mp->mmn; ++i)
// pitchV[i] = p->midiBuf[i].pitch;
// calc the edit distance from pitchV[] to a sliding score window
for(i=0; rc==cmOkRC && (scanCnt==cmInvalidCnt || i<scanCnt); ++i)
{
rc = cmScMatchExec(p->mp, bsi + i, p->mp->msn, p->midiBuf, p->mp->mmn, s_opt );
rc = cmScMatchExec(p->mp, bli + i, p->mp->msn, p->midiBuf, p->mp->mmn, s_opt );
switch(rc)
{
@ -2094,7 +2111,7 @@ unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
if( p->mp->opt_cost < s_opt )
{
s_opt = p->mp->opt_cost;
i_opt = bsi + i;
i_opt = bli + i;
}
break;
@ -2104,7 +2121,6 @@ unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
default: // error state
return cmInvalidIdx;
}
}
// store the cost assoc'd with i_opt
@ -2115,10 +2131,10 @@ unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
// set the locIdx field in midiBuf[], trailing miss count and
// return the latest positive-match locIdx
p->esi = cmScMatchDoSync(p->mp,i_opt,p->midiBuf,p->mp->mmn,&p->missCnt);
p->eli = cmScMatchDoSync(p->mp,i_opt,p->midiBuf,p->mp->mmn,&p->missCnt);
// if no positive matches were found
if( p->esi == cmInvalidIdx )
if( p->eli == cmInvalidIdx )
i_opt = cmInvalidIdx;
else
{
@ -2140,18 +2156,19 @@ cmRC_t cmScMatcherStep( cmScMatcher* p )
unsigned pitch = p->midiBuf[ p->mn-1 ].pitch;
unsigned locIdx = cmInvalidIdx;
unsigned pidx = cmInvalidIdx;
// the tracker must be sync'd to step
if( p->esi == cmInvalidIdx )
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The p->esi value must be valid to perform a step operation.");
if( p->eli == cmInvalidIdx )
return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The p->eli value must be valid to perform a step operation.");
// if the end of the score has been reached
if( p->esi + 1 >= p->mp->locN )
if( p->eli + 1 >= p->mp->locN )
return cmEofRC;
// attempt to match to next location first
if( (pidx = _cmScMatchIsMatchIndex(p->mp->loc + p->esi + 1, pitch)) != cmInvalidIdx )
if( (pidx = _cmScMatchIsMatchIndex(p->mp->loc + p->eli + 1, pitch)) != cmInvalidIdx )
{
locIdx = p->esi + 1;
locIdx = p->eli + 1;
}
else
{
@ -2159,16 +2176,16 @@ cmRC_t cmScMatcherStep( cmScMatcher* p )
for(i=2; i<p->stepCnt; ++i)
{
// go forward
if( p->esi+i < p->mp->locN && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->esi + i, pitch))!=cmInvalidIdx )
if( p->eli+i < p->mp->locN && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->eli + i, pitch))!=cmInvalidIdx )
{
locIdx = p->esi + i;
locIdx = p->eli + i;
break;
}
// go backward
if( p->esi >= (i-1) && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->esi - (i-1), pitch))!=cmInvalidIdx )
if( p->eli >= (i-1) && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->eli - (i-1), pitch))!=cmInvalidIdx )
{
locIdx = p->esi - (i-1);
locIdx = p->eli - (i-1);
break;
}
}
@ -2184,7 +2201,7 @@ cmRC_t cmScMatcherStep( cmScMatcher* p )
else
{
p->missCnt = 0;
p->esi = locIdx;
p->eli = locIdx;
}
// store the result
@ -2192,32 +2209,36 @@ cmRC_t cmScMatcherStep( cmScMatcher* p )
if( p->missCnt >= p->maxMissCnt )
{
unsigned begScanLocIdx = p->esi > p->mn ? p->esi - p->mn : 0;
unsigned begScanLocIdx = p->eli > p->mn ? p->eli - p->mn : 0;
p->s_opt = DBL_MAX;
unsigned bsi = cmScMatcherScan(p,begScanLocIdx,p->mn*2);
unsigned bli = cmScMatcherScan(p,begScanLocIdx,p->mn*2);
++p->scanCnt;
// if the scan failed find a match
if( bsi == cmInvalidIdx )
if( bli == cmInvalidIdx )
return cmCtxRtCondition( &p->obj, cmSubSysFailRC, "Scan resync. failed.");
}
return cmOkRC;
}
cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned* scLocIdxPtr )
{
bool fl = p->mbi > 0;
cmRC_t rc = cmOkRC;
unsigned eli = p->eli;
if( scLocIdxPtr != NULL )
*scLocIdxPtr = cmInvalidIdx;
// update the MIDI buffer with the incoming note
cmScMatcherInputMidi(p,smpIdx,status,d0,d1);
if( cmScMatcherInputMidi(p,smpIdx,status,d0,d1) == false )
return rc;
// if the MIDI buffer transitioned to full then perform an initial scan sync.
if( fl && p->mbi == 0 )
{
if( (p->begSyncLocIdx = cmScMatcherScan(p,0,cmInvalidCnt)) == cmInvalidIdx )
if( (p->begSyncLocIdx = cmScMatcherScan(p,p->ili,cmInvalidCnt)) == cmInvalidIdx )
rc = cmInvalidArgRC; // signal init. scan sync. fail
else
{
@ -2231,8 +2252,10 @@ cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, c
rc = cmScMatcherStep(p);
}
return rc;
if( scLocIdxPtr!=NULL && p->eli != eli )
*scLocIdxPtr = p->mp->loc[p->eli].scLocIdx;
return rc;
}
double cmScMatcherFMeas( cmScMatcher* p )
@ -2603,6 +2626,8 @@ cmRC_t cmScMeasInit( cmScMeas* p, cmScH_t scH, double srate, const unsigned*
//_cmScMeasPrint(p);
cmScMeasReset(p);
return rc;
}
@ -2614,7 +2639,12 @@ cmRC_t cmScMeasReset( cmScMeas* p )
cmRC_t rc = cmOkRC;
p->mii = 0;
p->nsi = cmInvalidIdx;
p->vsi = cmInvalidIdx;
p->nsli = cmInvalidIdx;
unsigned i;
for(i=0; i<p->sn; ++i)
p->set[i].value = DBL_MAX;
return rc;
}
@ -2761,6 +2791,7 @@ unsigned _cmScMeasTimeAlign( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m,
assert(bn<=cn);
// TODO: this copy should be eliminated
// copy to output
for(i=0; i<bn && i<cn; ++i)
c[i] = b[i];
@ -2900,9 +2931,47 @@ double _cmScMeasDyn( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigne
return rp->value;
}
unsigned MEAS_MATCH_CNT = 0;
void _cmScMeasMatch( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
void _cmScMeasPrintResult( cmScMeas* p, cmScMeasSet_t* sp, _cmScMeasResult_t* rp, unsigned bli, const cmScMatchMidi_t* mb )
{
const char* label = "<none>";
switch( sp->sp->varId )
{
case kEvenVarScId:
label = "even";
break;
case kDynVarScId:
label = "dyn";
break;
case kTempoVarScId:
label = "tempo";
break;
}
const cmChar_t* msg = "";
if( rp->value == DBL_MAX )
{
msg = "Measure FAILED.";
sp->value = 0;
}
printf("%i set:%i %s bsli:%i esli:%i [set:%i match:%i] cost:%f val:%f %s",MEAS_MATCH_CNT, p->nsi, label, sp->bsli, sp->esli, rp->setN, rp->matchN, p->mp->opt_cost, sp->value, msg);
if( rp->tempo != 0 )
printf(" tempo:%f ",rp->tempo);
printf("\n");
_cmScMatchPrintPath(p->mp, p->mp->p_opt, bli, mb );
}
void _cmScMeasCalcVal( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
{
unsigned mn = 0;
int i;
@ -2930,7 +2999,6 @@ void _cmScMeasMatch( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
assert(mn>0);
// Create a copy of the the MIDI buffer to prevent the
// p->midiBuf[].locIdx from being overwritten by cmScMatchDoSync().
cmScMatchMidi_t mb[ mn ];
@ -2944,11 +3012,13 @@ void _cmScMeasMatch( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
// In general the first and last MIDI event should be assigned
// to a score location - it's possible however that no MIDI
// event's prior to the one at p->midiBuf[n_mii] were assigned.
assert( (i==0 || p->midiBuf[i].locIdx!=cmInvalidIdx) && p->midiBuf[i+mn-1].locIdx!=cmInvalidIdx);
assert( (i==0 || p->midiBuf[i].locIdx!=cmInvalidIdx) && p->midiBuf[i+mn-1].locIdx != cmInvalidIdx);
unsigned bli = p->midiBuf[i].locIdx;
unsigned ln = p->midiBuf[i+mn-1].locIdx - bli + 1;
double min_cost = DBL_MAX;
_cmScMeasResult_t r;
memset(&r,0,sizeof(r));
// match MIDI to score
if( cmScMatchExec(p->mp, bli, ln, mb, mn, min_cost ) != cmOkRC )
@ -2958,65 +3028,32 @@ void _cmScMeasMatch( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
if( cmScMatchDoSync(p->mp, bli, mb, mn, NULL ) == cmInvalidIdx )
return;
// print the match result
const char* label = "<none>";
double val = DBL_MAX;
double tempoBpm = 0;
_cmScMeasResult_t r;
memset(&r,0,sizeof(r));
if( MEAS_MATCH_CNT == 12 )
{
//printf("blah\n");
}
switch( sp->sp->varId )
{
case kEvenVarScId:
label = "even";
val = _cmScMeasEven(p, sp, mb, mn, &r );
sp->value = _cmScMeasEven(p, sp, mb, mn, &r );
break;
case kDynVarScId:
label = "dyn";
val = _cmScMeasDyn(p, sp, mb, mn, &r );
sp->value = _cmScMeasDyn(p, sp, mb, mn, &r );
break;
case kTempoVarScId:
label = "tempo";
tempoBpm = _cmScMeasTempo(p, sp, mb, mn, &r );
val = tempoBpm;
sp->value = _cmScMeasTempo(p, sp, mb, mn, &r );
break;
default:
{ assert(0); }
}
if(1)
{
const cmChar_t* msg = "";
if( val == DBL_MAX )
{
msg = "Measure FAILED.";
val = 0;
}
sp->tempo = r.tempo;
printf("%i set:%i %s bsli:%i esli:%i [set:%i match:%i] cost:%f val:%f %s",MEAS_MATCH_CNT,p->nsi, label, sp->bsli, sp->esli, r.setN, r.matchN, p->mp->opt_cost, val, msg);
if( r.tempo != 0 )
printf(" tempo:%f ",r.tempo);
printf("\n");
_cmScMatchPrintPath(p->mp, p->mp->p_opt, bli, mb );
}
// print the result
_cmScMeasPrintResult(p, sp, &r, bli, mb );
MEAS_MATCH_CNT++;
}
/*
The first note in Bar 1 F4 should be marked with a 'e' - it isn't.
Marker Set scli Type Note
4 8 48 even very bad match produces an evenesss = 0.979
10 12 69 even bad match
27 29 150 tempo Tempo measured as 0.
*/
cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtIdx, unsigned flags, unsigned smpIdx, unsigned pitch, unsigned vel )
{
cmRC_t rc = cmOkRC;
@ -3026,6 +3063,7 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI
return cmCtxRtCondition( &p->obj, cmEofRC, "The MIDI buffer is full.");
int n_mii = cmInvalidIdx;
// locate the MIDI event assoc'd with 'mni' ...
if( p->mii>0 && mni <= p->midiBuf[p->mii-1].mni )
{
if( locIdx != cmInvalidIdx )
@ -3038,7 +3076,7 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI
n_mii = cmInvalidIdx;
}
}
else
else // ... or push a new record onto p->midiBuf[]
{
n_mii = p->mii;
++p->mii;
@ -3052,8 +3090,6 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI
p->midiBuf[n_mii].pitch = pitch;
p->midiBuf[n_mii].vel = vel;
//++p->mi;
if( locIdx == cmInvalidIdx )
return cmOkRC;
@ -3078,6 +3114,8 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI
return rc;
}
p->vsi = p->nsi;
// for each cmScore location between p->nsli and scLocIdx
for(; p->nsli<=scLocIdx && p->nsi < p->sn; ++p->nsli)
{
@ -3085,7 +3123,9 @@ cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtI
// ahead of the next sets ending location.
while( cmMin(maxScLocIdx,p->set[p->nsi].esli+1) == p->nsli )
{
_cmScMeasMatch(p, p->set + p->nsi, n_mii );
// calculate the value assoc'd with p->set[p->nsi]
_cmScMeasCalcVal(p, p->set + p->nsi, n_mii );
// advance the set index
++p->nsi;
@ -3114,7 +3154,7 @@ cmRC_t cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top
// if the time line MIDI msg a note-on
if( mep->msg->status == kNoteOnMdId )
{
rc = cmScMatcherExec(p, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1 );
rc = cmScMatcherExec(p, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
switch( rc )
{
@ -3124,11 +3164,14 @@ cmRC_t cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top
case cmEofRC: // end of the score was encountered
break;
case cmInvalidArgRC: // p->esi was not set correctly
case cmInvalidArgRC: // p->eli was not set correctly
break;
case cmSubSysFailRC: // scan resync failed
break;
default:
{ assert(0); }
}
}
}
@ -3158,7 +3201,7 @@ void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH )
unsigned dynRefCnt = sizeof(dynRefArray)/sizeof(dynRefArray[0]);
cmCtx* ctx = cmCtxAlloc(NULL, rpt, cmLHeapNullHandle, cmSymTblNullHandle );
cmScMeas* mp = cmScMeasAlloc(ctx,NULL,scH,srate,dynRefArray,dynRefCnt);
cmScMatcher* p = cmScMatcherAlloc(ctx,NULL,srate,scH,scWndN,midiN);
cmScMatcher* p = cmScMatcherAlloc(ctx,NULL,srate,scH,scWndN,midiN,cmScMatcherCb,mp);
double scoreThresh = 0.5;
unsigned candCnt = 0;
unsigned initFailCnt = 0;
@ -3171,9 +3214,6 @@ void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH )
cmTimeGet(&t0);
p->cbArg = mp; // set the callback arg.
p->cbFunc = cmScMatcherCb;
// for each marker
for(i=0; i<markN; ++i)
{
@ -3199,7 +3239,7 @@ void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH )
printf("=================== MARKER:%s ===================\n",markText);
cmScMatcherReset(p); // reset the score follower to the beginnig of the score
cmScMatcherReset(p,0); // reset the score follower to the beginnig of the score
cmScMeasReset(mp);
++candCnt;

View File

@ -341,41 +341,60 @@ typedef void (*cmScMatcherCb_t)( struct cmScMatcher_str* p, void* arg, cmScMatch
double s_opt; //
unsigned missCnt; // count of consecutive trailing non-matches
unsigned esi; // index into loc[] of the last positive match.
unsigned ili; // index into loc[] to start scan following reset
unsigned eli; // index into loc[] of the last positive match.
unsigned mni; // track the count of MIDI events since the last call to cmScMatcherReset()
unsigned mbi; // index of oldest MIDI event in midiBuf[]; 0 when the buffer is full.
unsigned begSyncLocIdx; // start of score window, in mp->loc[], of best match in previous scan
unsigned stepCnt; // count of forward/backward score loc's to examine for a match during cmScMatcherStep().
unsigned maxMissCnt; // max. number of consecutive non-matches during step prior to executing a scan.
unsigned scanCnt; // count of time scan was executed inside cmScMatcherStep()
bool printFl;
} cmScMatcher;
cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg );
cmRC_t cmScMatcherFree( cmScMatcher** pp );
cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg );
cmRC_t cmScMatcherFinal( cmScMatcher* p );
void cmScMatcherReset( cmScMatcher* p );
bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
// Slide a score window scanCnt times, beginning at 'bsi',
// looking for the best match to p->midiBuf[]. The score window
// contain scWndN (p->mp->mcn-1) score locations.
// 'scLocIdx' is a score index as used by cmScoreLoc(scH) not into p->mp->loc[].
cmRC_t cmScMatcherReset( cmScMatcher* p, unsigned scLocIdx );
// Slide a score window scanCnt times, beginning at 'bli' (an
// index int p->mp->loc[]) looking for the best match to p->midiBuf[].
// The score window contain scWndN (p->mp->mcn-1) score locations.
// Returns the index into p->mp->loc[] of the start of the best
// match score window. The score associated
// with this match is stored in s_opt.
unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt );
unsigned cmScMatcherScan( cmScMatcher* p, unsigned bli, unsigned scanCnt );
// Step forward/back by p->stepCnt from p->esi.
// p->esi must therefore be valid prior to calling this function.
// Step forward/back by p->stepCnt from p->eli.
// p->eli must therefore be valid prior to calling this function.
// If more than p->maxMissCnt consecutive MIDI events are
// missed then automatically run cmScAlignScan().
// Return cmEofRC if the end of the score is encountered.
// Return cmSubSysFailRC if an internal scan resync. failed.
cmRC_t cmScMatcherStep( cmScMatcher* p );
cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
// This function calls cmScMatcherScan() and cmScMatcherStep() internally.
// If 'status' is not kNonMidiMdId then the function returns without changing the
// state of the object.
// If the MIDI note passed by the call results in a successful match then
// p->eli will be updated to the location in p->mp->loc[] of the latest
// match, the MIDI note in p->midiBuf[] associated with this match
// will be assigned valid locIdx and scLocIdx values, and *scLocIdxPtr
// will be set with the matched scLocIdx of the match.
// If this call does not result in a successful match *scLocIdxPtr is set
// to cmInvalidIdx.
// Return:
// cmOkRC - Continue processing MIDI events.
// cmEofRC - The end of the score was encountered.
// cmInvalidArgRC - scan failed or the object was in an invalid state to attempt a match.
// cmSubSysFailRC - a scan resync failed in cmScMatcherStep().
cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned* scLocIdxPtr );
//=======================================================================================================================
@ -393,11 +412,15 @@ typedef struct
unsigned bli; //
unsigned eli; //
double value; // DBL_MAX if the value has not yet been set
double tempo; // DBL_MAX until set
} cmScMeasSet_t;
typedef struct
{
cmObj obj;
double srate; //
cmScMatch* mp; //
unsigned mii; // next avail recd in midiBuf[]
unsigned mn; // length of of midiBuf[]
@ -412,12 +435,16 @@ typedef struct
unsigned nsi; // next set index
unsigned nsli; // next score location index
double srate; // sample rate from schore
unsigned vsi; // set[vsi:nsi-1] indicates sets with new values following a call to cmScMeasExec()
} cmScMeas;
//
// Notes:
//
// 1) midiBuf[] stores all MIDI notes for the duration of the performance
// it is initialized to 2*score_event_count.
//
// 2) dynRef][ is the gives the MIDI velocity range for each dynamics
// category: pppp-fff
//
@ -428,6 +455,9 @@ cmRC_t cmScMeasFree( cmScMeas** pp );
cmRC_t cmScMeasInit( cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt );
cmRC_t cmScMeasFinal( cmScMeas* p );
// Empty MIDI buffer and set the next set nsi and nsli to zero.
cmRC_t cmScMeasReset( cmScMeas* p );
// This function is called for each input MIDI note which is assigned a
// score location by cmScMatcher.
// 'mni' is the MIDI event index which uniquely identifies this MIDI event.