diff --git a/cmProc4.c b/cmProc4.c index 2b31ac7..6de6ad6 100644 --- a/cmProc4.c +++ b/cmProc4.c @@ -27,749 +27,6 @@ #include "cmScore.h" #include "cmProc4.h" - -cmScFol* cmScFolAlloc( cmCtx* c, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ) -{ - cmScFol* op = cmObjAlloc(cmScFol,c,p); - if( srate != 0 ) - if( cmScFolInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC ) - cmScFolFree(&op); - return op; -} - -cmRC_t cmScFolFree( cmScFol** pp ) -{ - cmRC_t rc = cmOkRC; - if( pp==NULL || *pp==NULL ) - return rc; - - cmScFol* p = *pp; - if((rc = cmScFolFinal(p)) != cmOkRC ) - return rc; - - unsigned i; - for(i=0; ilocN; ++i) - cmMemFree(p->loc[i].evtV); - - cmMemFree(p->loc); - cmMemFree(p->bufV); - cmObjFree(pp); - return rc; -} - - -cmRC_t cmScFolFinal( cmScFol* p ) -{ - cmMemFree(p->edWndMtx); - return cmOkRC; -} - -void _cmScFolPrint( cmScFol* p ) -{ - int i,j; - for(i=0; ilocN; ++i) - { - printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx); - for(j=0; jloc[i].evtCnt; ++j) - printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0)); - printf("\n"); - } -} - -unsigned* _cmScFolAllocEditDistMtx(unsigned maxN) -{ - maxN += 1; - - unsigned* m = cmMemAllocZ(unsigned,maxN*maxN); - unsigned* p = m; - unsigned i; - - // initialize the comparison matrix with the default costs in the - // first row and column - // (Note that this matrix is not oriented in column major order like most 'cm' matrices.) - for(i=0; i maxWndCnt ) - return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower buffer count (%i) must be less than the max. window length (%i).",bufN,maxWndCnt ); - - if( minWndLookAhead > maxWndCnt ) - return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt); - - p->srate = srate; - p->scH = scH; - p->bufN = bufN; - p->bufV = cmMemResizeZ(cmScFolBufEle_t,p->bufV,bufN); - p->locN = cmScoreEvtCount(scH); - p->loc = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN); - p->sbi = cmInvalidIdx; - p->sei = cmInvalidIdx; - p->msln = minWndLookAhead; - p->mswn = maxWndCnt; - p->forwardCnt = 2; - p->maxDist = 4; - p->edWndMtx = _cmScFolAllocEditDistMtx(p->bufN); - p->minVel = minVel; - p->printFl = true; - p->noBackFl = true; - p->missCnt = 0; - p->matchCnt = 0; - p->eventIdx = 0; - p->skipCnt = 0; - p->ret_idx = cmInvalidIdx; - - // for each score location - unsigned li,ei; - - for(li=0,ei=0; liscH); ++li) - { - unsigned i,n; - - const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li); - - // count the number of note events at location li - for(n=0,i=0; ievtCnt; ++i) - if( lp->evtArray[i]->type == kNonEvtScId ) - ++n; - - assert( ei+n <= p->locN ); - - // duplicate each note at location li n times - for(i=0; iloc[ei+i].evtCnt = n; - p->loc[ei+i].evtV = cmMemAllocZ(cmScFolEvt_t,n); - p->loc[ei+i].scIdx = li; - p->loc[ei+i].barNumb = lp->barNumb; - for(j=0,k=0; jevtCnt; ++j) - if( lp->evtArray[j]->type == kNonEvtScId ) - { - p->loc[ei+i].evtV[k].pitch = lp->evtArray[j]->pitch; - p->loc[ei+i].evtV[k].scEvtIdx = lp->evtArray[j]->index; - ++k; - } - - } - - ei += n; - - } - - p->locN = ei; - - //_cmScFolPrint(p); - - return rc; -} - -cmRC_t cmScFolReset( cmScFol* p, unsigned scEvtIdx ) -{ - int i,j; - - // empty the event buffer - memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN); - - // don't allow the score index to be prior to the first note - //if( scEvtIdx < p->loc[0].scIdx ) - // scEvtIdx = p->loc[0].scIdx; - - p->sei = cmInvalidIdx; - p->sbi = cmInvalidIdx; - p->missCnt = 0; - p->matchCnt = 0; - p->eventIdx = 0; - p->skipCnt = 0; - p->ret_idx = cmInvalidIdx; - - // locate the score element in svV[] that is closest to, - // and possibly after, scEvtIdx. - for(i=0; ilocN-1; ++i) - { - for(j=0; jloc[i].evtCnt; ++j) - if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx ) - p->sbi = i; - else - break; - } - - // locate the score element at the end of the look-ahead region - for(; ilocN; ++i) - { - for(j=0; jloc[i].evtCnt; ++j) - if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx + p->msln ) - p->sei = i; - } - - return cmOkRC; -} - -bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch ) -{ - unsigned i; - for(i=0; ievtCnt; ++i) - if( loc->evtV[i].pitch == pitch ) - return true; - return false; -} - -int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const cmScFolBufEle_t* pitch, unsigned pi ) -{ - if( _cmScFolIsMatch(loc+li,pitch[pi].val) ) - return 0; - - if( li>0 && pi>0 ) - if( _cmScFolIsMatch(loc+li-1,pitch[pi].val) && _cmScFolIsMatch(loc+li,pitch[pi-1].val) ) - return 0; - - return 1; -} - -int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const cmScFolBufEle_t* s1, const cmScFolLoc_t* s0, int n ) -{ - mtxMaxN += 1; - - assert( n < mtxMaxN ); - - int v = 0; - unsigned i; - // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices. - - for(i=1; ieventIdx); - - printf("loc: "); - for(i=0; iloc[locIdx+i].evtCnt > n ) - n = p->loc[locIdx+i].evtCnt; - - --n; - for(; n>=0; --n) - { - printf("sc%1i: ",n); - for(i=0; iloc[locIdx+i].evtCnt ) - printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].evtV[n].pitch,NULL,0)); - else - printf(" "); - } - printf("\n"); - } - - printf("perf:"); - for(i=0; iskipCnt,d1); - if( ret_idx != cmInvalidIdx ) - printf("ret_idx:%i ",ret_idx); - printf("\n"); -} - -unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 ) -{ - unsigned ret_idx = cmInvalidIdx; - - if( p->sbi == cmInvalidIdx ) - { - cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." ); - return ret_idx; - } - - if( (status&0xf0) != kNoteOnMdId ) - return ret_idx; - - ++p->eventIdx; - - // reject notes with very low velocity - if( d1 < p->minVel ) - { - ++p->skipCnt; - return ret_idx; - } - - // left shift bufV[] to make the right-most element available - then copy in the new element - memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1)); - p->bufV[ p->bufN-1 ].smpIdx = smpIdx; - p->bufV[ p->bufN-1 ].val = d0; - p->bufV[ p->bufN-1 ].validFl= true; - - // fill in ebuf[] with the valid values in bufV[] - int en = cmMin(p->eventIdx,p->bufN); - int bbi = p->eventIdx>=p->bufN ? 0 : p->bufN-p->eventIdx; - - - // en is the count of valid elements in ebuf[]. - // ebuf[p->boi] is the first valid element - - int j = 0; - int minDist = INT_MAX; - int minIdx = cmInvalidIdx; - int dist; - - // the score wnd must always be as long as the buffer n - // at the end of the score this may not be the case - // (once sei hits locN - at this point we must begin - // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements) - assert( p->sei-p->sbi+1 >= en ); - - for(j=0; p->sbi+en+j-1 <= p->sei; ++j) - { - // use <= minDist to choose the latest window with the lowest match - if((dist = _cmScFolDist(p->bufN, p->edWndMtx, p->bufV+bbi, p->loc + p->sbi+j, en )) < minDist ) - { - // only make an eql match if the posn is greater than the last location - if( dist==minDist && p->ret_idx != cmInvalidId && p->ret_idx >= p->sbi+minIdx+en-1 ) - continue; - - minDist = dist; - minIdx = j; - } - } - - // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ] - - if( p->printFl ) - _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, p->bufV+bbi, en, minIdx ); - - // save current missCnt for later printing - unsigned missCnt = p->missCnt; - - // if a perfect match occurred - if( minDist == 0 ) - { - ret_idx = p->sbi + minIdx + en - 1; - p->missCnt = 0; - - // we had a perfect match - shrink the window to it's minumum size - p->sbi += (en==p->bufN) ? minIdx + 1 : 0; // move wnd begin forward to just past first match - p->sei = p->sbi + minIdx + en + p->msln; // move wnd end forward to lead by the min look-ahead - - - } - else - { - if( minDist > p->maxDist ) - ret_idx = cmInvalidIdx; - else - // if the last event matched - then return the match location as the current score location - if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),p->bufV[p->bufN-1].val) ) - { - ret_idx = p->sbi + minIdx + en - 1; - p->missCnt = 0; - - // this is probably a pretty good match reduce the part of the window prior to - // the first match (bring the end of the window almost up to the end of the - // buffers sync position) - if( en >= p->bufN-1 && (en+2) <= ret_idx ) - p->sbi = ret_idx - (en+2); - - } - else // the last event does not match based on the optimal edit-distance alignment - { - // Look backward from the closest match location for a match to the current pitch. - // The backward search scope is limited by the current value of 'missCnt'. - unsigned i; - j = p->sbi+minIdx+en-2; - for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j) - { - // if this look-back location already matched then stop the backward search - if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1-i].val)) - break; - - // does this look-back location match the current pitch - if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val)) - { - ret_idx = j; - p->missCnt = i; // set missCnt to the cnt of steps backward necessary for a match - break; - } - } - - // If the backward search did not find a match - look forward - if( ret_idx == cmInvalidIdx ) - { - unsigned i; - j = p->sbi+minIdx+en; - for(i=0; j<=p->sei && iforwardCnt; ++i,++j) - if( _cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val) ) - { - ret_idx = j; - break; - } - - p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0; - } - - } - - // Adjust the end window position (sei) based on the match location - if( ret_idx == cmInvalidIdx ) - { - // even though we didn't match move the end of the score window forward - // this will enlarge the score window by one - p->sei += 1; - } - else - { - assert( p->sei>=ret_idx); - - // force sei to lead by min look-ahead - if( p->sei - ret_idx < p->msln ) - p->sei = ret_idx + p->msln; - - } - - assert( p->sei > p->sbi ); - - // Adjust the begin window position - if( p->noBackFl && ret_idx != cmInvalidIdx && en>=p->bufN && p->sbi > p->bufN ) - p->sbi = ret_idx - p->bufN; - - // if the score window length surpasses the max score window size - // move the beginning index forward - if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn ) - p->sbi = p->sei - p->mswn + 1; - - - } - - if( p->printFl ) - _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt ); - - // don't allow the returned location to repeat or go backwards - if( p->noBackFl && p->ret_idx != cmInvalidIdx && ret_idx <= p->ret_idx ) - ret_idx = cmInvalidIdx; - - - // track the number of consecutive matches - if( ret_idx == cmInvalidIdx ) - p->matchCnt = 0; - else - { - ++p->matchCnt; - - p->ret_idx = ret_idx; - } - - // Force the window to remain valid when it is at the end of the score - // - sbi and sei must be inside 0:locN - // - sei-sbi + 1 must be >= en - if( p->sei >= p->locN ) - { - p->sei = p->locN - 1; - p->sbi = p->sei - p->bufN + 1; - } - - if( ret_idx != cmInvalidIdx ) - ret_idx = p->loc[ret_idx].scIdx; - - return ret_idx; -} - - - -//======================================================================================================================= - -cmScTrk* cmScTrkAlloc( cmCtx* c, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ) -{ - cmScTrk* op = cmObjAlloc(cmScTrk,c,p); - - op->sfp = cmScFolAlloc(c,NULL,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel); - - if( srate != 0 ) - if( cmScTrkInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC ) - cmScTrkFree(&op); - return op; -} - -cmRC_t cmScTrkFree( cmScTrk** pp ) -{ - cmRC_t rc = cmOkRC; - if( pp==NULL || *pp==NULL ) - return rc; - - cmScTrk* p = *pp; - if((rc = cmScTrkFinal(p)) != cmOkRC ) - return rc; - - cmScFolFree(&p->sfp); - - cmObjFree(pp); - return rc; - -} - -void _cmScTrkPrint( cmScTrk* p ) -{ - int i,j; - for(i=0; ilocN; ++i) - { - printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx); - for(j=0; jloc[i].evtCnt; ++j) - printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0)); - printf("\n"); - } -} - -cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ) -{ - cmRC_t rc; - if((rc = cmScTrkFinal(p)) != cmOkRC ) - return rc; - - if( minWndLookAhead > maxWndCnt ) - return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt); - - if((rc = cmScFolInit(p->sfp,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel)) != cmOkRC ) - return rc; - - p->srate = srate; - p->scH = scH; - p->locN = cmScoreLocCount(scH); - p->loc = cmMemResizeZ(cmScTrkLoc_t,p->loc,p->locN); - p->minVel = minVel; - p->maxWndCnt = maxWndCnt; - p->minWndLookAhead= 4; //minWndLookAhead; - p->printFl = true; - p->curLocIdx = cmInvalidIdx; - p->evtIndex = 0; - - // for each score location - unsigned li; - - for(li=0; liscH); ++li) - { - unsigned i,j,k,n; - - const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li); - - // count the number of note events at location li - for(n=0,i=0; ievtCnt; ++i) - if( lp->evtArray[i]->type == kNonEvtScId ) - ++n; - - p->loc[li].evtCnt = n; - p->loc[li].evtV = cmMemAllocZ(cmScTrkEvt_t,n); - p->loc[li].scIdx = li; - p->loc[li].barNumb = lp->barNumb; - for(j=0,k=0; jevtCnt; ++j) - if( lp->evtArray[j]->type == kNonEvtScId ) - { - p->loc[li].evtV[k].pitch = lp->evtArray[j]->pitch; - p->loc[li].evtV[k].scEvtIdx = lp->evtArray[j]->index; - ++k; - } - } - - //_cmScTrkPrint(p); - - return rc; -} - -cmRC_t cmScTrkFinal( cmScTrk* p ) -{ - unsigned i; - for(i=0; ilocN; ++i) - cmMemPtrFree(&p->loc[i].evtV); - - return cmOkRC; -} - -cmRC_t cmScTrkReset( cmScTrk* p, unsigned scEvtIdx ) -{ - unsigned i; - - cmScFolReset(p->sfp,scEvtIdx); - - p->curLocIdx = cmInvalidIdx; - p->evtIndex = 0; - - - // locate the score element in svV[] that is closest to, - // and possibly after, scEvtIdx. - for(i=0; ilocN; ++i) - { - unsigned j; - - for(j=0; jloc[i].evtCnt; ++j) - { - p->loc[i].evtV[j].matchFl = false; - - // it is possible that scEvtIdx is before the first event included in p->loc[0] - // using the p->curLocIdx==cmInvalidIdx forces the first evt in p->loc[0] to be - // selected in this case - if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx || p->curLocIdx==cmInvalidIdx ) - p->curLocIdx = i; - } - } - - if( p->curLocIdx == cmInvalidIdx ) - return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial score search location event %i was not found.", scEvtIdx ); - - return cmOkRC; -} - -unsigned _cmScTrkIsMatch(cmScTrk* p, int d, unsigned pitch ) -{ - if( 0 <= p->curLocIdx + d && p->curLocIdx+1 < p->locN ) - { - unsigned i; - const cmScTrkLoc_t* lp = p->loc + p->curLocIdx + d; - for(i=0; ievtCnt; ++i) - if( lp->evtV[i].pitch == pitch && lp->evtV[i].matchFl==false) - return i; - } - return cmInvalidIdx; -} - -void _cmScTrkRpt0( cmScTrk* p, unsigned pitch, unsigned vel, unsigned nli, unsigned nei ) -{ - bool missFl = nli==cmInvalidIdx || nei==cmInvalidIdx; - - printf("------- event:%i %s vel:%i cur:%i new:%i %s-------\n",p->evtIndex,cmMidiToSciPitch(pitch,NULL,0),vel,p->curLocIdx,nli,missFl?"MISS ":""); - - int bi = p->curLocIdx < p->minWndLookAhead ? 0 : p->curLocIdx - p->minWndLookAhead; - int ei = cmMin(p->locN-1,p->curLocIdx+p->minWndLookAhead); - unsigned i,n=0; - for(i=bi; i<=ei; ++i) - if( p->loc[i].evtCnt>n ) - n = p->loc[i].evtCnt; - - printf("loc "); - for(i=bi; i<=ei; ++i) - printf("%4i ",i); - printf("\n"); - - for(i=0; iloc[j].evtCnt ) - { - char* X = p->loc[j].evtV[i].matchFl ? "__" : " "; - - if( nli==j && nei==i) - { - X = "**"; - assert( p->loc[j].evtV[i].pitch == pitch ); - } - - printf("%4s%s ",cmMidiToSciPitch(p->loc[j].evtV[i].pitch,NULL,0),X); - } - else - printf(" "); - } - printf("\n"); - } - -} - - -unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 ) -{ - unsigned ret_idx = cmInvalidIdx; - - //cmScFolExec(p->sfp, smpIdx, status, d0, d1); - - if( (status&0xf0) != kNoteOnMdId ) - return cmInvalidIdx; - - if( p->curLocIdx == cmInvalidIdx ) - { - cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." ); - return cmInvalidIdx; - } - - int i,nei,nli=cmInvalidIdx; - - // try to match curLocIdx first - if((nei = _cmScTrkIsMatch(p,0,d0)) != cmInvalidIdx ) - nli = p->curLocIdx; - - for(i=1; nei==cmInvalidIdx && iminWndLookAhead; ++i) - { - // go forward - if((nei = _cmScTrkIsMatch(p,i,d0)) != cmInvalidIdx ) - nli = p->curLocIdx + i; - else - // go backward - if((nei = _cmScTrkIsMatch(p,-i,d0)) != cmInvalidIdx ) - nli = p->curLocIdx - i; - } - - if( p->printFl ) - { - _cmScTrkRpt0(p, d0, d1, nli, nei ); - } - - - if( nli != cmInvalidIdx ) - { - p->loc[nli].evtV[nei].matchFl = true; - ret_idx = p->loc[nli].scIdx; - - if( nli > p->curLocIdx ) - p->curLocIdx = nli; - - } - - ++p->evtIndex; - - return ret_idx; -} - //======================================================================================================================= //---------------------------------------------------------------------------------------- void ed_print_mtx( ed_r* r) diff --git a/cmProc4.h b/cmProc4.h index 3731083..d10f0bf 100644 --- a/cmProc4.h +++ b/cmProc4.h @@ -5,114 +5,6 @@ extern "C" { #endif - typedef struct - { - unsigned smpIdx; // time tag sample index for val - cmMidiByte_t val; // - bool validFl; // - } cmScFolBufEle_t; - - typedef struct - { - unsigned pitch; - unsigned scEvtIdx; - } cmScFolEvt_t; - - typedef struct - { - unsigned evtCnt; // - cmScFolEvt_t* evtV; // pitchV[pitchCnt] - unsigned scIdx; // index of the score loc (into cmScoreEvt[]) at this location - int barNumb; // bar number of this location - } cmScFolLoc_t; - - - typedef struct - { - cmObj obj; - cmReal_t srate; // - cmScH_t scH; // score handle - unsigned bufN; // event buffer count - cmScFolBufEle_t* bufV; // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event - int locN; // count of score locations - cmScFolLoc_t* loc; // score loc[locN] - unsigned sbi; // oldest score window index - unsigned sei; // newest score window index - unsigned msln; // minimum score look ahead count - unsigned mswn; // maximum score window length - unsigned forwardCnt; // count of score loc's to look ahead for a match to the current pitch when the optimal edit-dist alignment does not produce a match for the current pitch - unsigned maxDist; // max. dist allowed to still consider matching - unsigned minVel; // notes < minVel are ignored - bool printFl; // true if pitch tracker reporting should be included - bool noBackFl; // prevent the tracker from going backwards in time - unsigned* edWndMtx; - - unsigned missCnt; // current consecutive unmatched notes - unsigned matchCnt; // current consecutive matched notes - unsigned eventIdx; // events since reset - unsigned skipCnt; // notes skipped due to velocity - unsigned ret_idx; // last tracked location - - } cmScFol; - - cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ); - cmRC_t cmScFolFree( cmScFol** pp ); - cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ); - cmRC_t cmScFolFinal( cmScFol* p ); - - // Jump to a score location and reset the internal state of the follower. - cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex ); - - // Give the follower a MIDI performance event. Only MIDI note-on events are acted upon; - // all others are ignored. - unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 ); - - //======================================================================================================================= - - typedef struct - { - unsigned pitch; - unsigned scEvtIdx; - bool matchFl; - } cmScTrkEvt_t; - - typedef struct - { - unsigned evtCnt; // - cmScTrkEvt_t* evtV; // evtV[evtCnt] - unsigned scIdx; // index of the score event (into cmScoreEvt[]) at this location - int barNumb; // bar number of this location - } cmScTrkLoc_t; - - typedef struct - { - cmObj obj; - cmScFol* sfp; - double srate; - cmScH_t scH; - unsigned locN; - cmScTrkLoc_t* loc; - unsigned minVel; - unsigned maxWndCnt; - unsigned minWndLookAhead; - bool printFl; - - int curLocIdx; - unsigned evtIndex; - - } cmScTrk; - - cmScTrk* cmScTrkAlloc( cmCtx* ctx, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ); - cmRC_t cmScTrkFree( cmScTrk** pp ); - cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel ); - cmRC_t cmScTrkFinal( cmScTrk* p ); - - // Jump to a score location and reset the internal state of the follower. - cmRC_t cmScTrkReset( cmScTrk* p, unsigned scoreIndex ); - - // Give the follower a MIDI performance event. Only MIDI note-on events are acted upon; - // all others are ignored. - unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 ); //======================================================================================================================= //