From 24bcde77ac4d419b94f77d7d91b77cccfc6f830c Mon Sep 17 00:00:00 2001 From: kpl Date: Tue, 27 Nov 2012 14:20:54 -0800 Subject: [PATCH] cmProc4.h/c cmDspKr.c Score follower tweeking. --- cmProc4.c | 208 +++++++++++++++++++++++++++++++---------------- cmProc4.h | 43 +++------- dsp/cmDspKr.c | 14 ++-- dsp/cmDspPgmKr.c | 2 +- 4 files changed, 155 insertions(+), 112 deletions(-) diff --git a/cmProc4.c b/cmProc4.c index 68b0415..15cf299 100644 --- a/cmProc4.c +++ b/cmProc4.c @@ -90,7 +90,11 @@ cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs p->msln = 7; p->mswn = 30; p->edWndMtx = cmVOU_LevEditDistAllocMtx(p->bufN); - + p->minVel = 5; + p->missCnt = 0; + p->matchCnt = 0; + p->printFl = true; + p->eventIdx = 0; int i,n; double maxDSecs = 0; // max time between score entries to be considered simultaneous @@ -208,6 +212,18 @@ bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch ) return false; } +int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const unsigned* pitch, unsigned pi ) +{ + if( _cmScFolIsMatch(loc+li,pitch[pi]) ) + return 0; + + if( li>0 && pi>0 ) + if( _cmScFolIsMatch(loc+li-1,pitch[pi]) && _cmScFolIsMatch(loc+li,pitch[pi-1]) ) + return 0; + + return 1; +} + int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n ) { mtxMaxN += 1; @@ -226,7 +242,8 @@ int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFo for( j=1; jsri != cmInvalidIdx ); + unsigned i; + int n; - unsigned ret_idx = cmInvalidIdx; - unsigned ewnd[ p->wndN ]; + printf("--------------- event:%i ------------- \n",p->eventIdx); - if( status != kNoteOnMdId && d1>0 ) - return ret_idx; - - // left shift wndV[] to make the right-most element available - then copy in the new element - memmove(p->wndV, p->wndV+1, sizeof(cmScFolWndEle_t)*(p->wndN-1)); - p->wndV[ p->wndN-1 ].smpIdx = smpIdx; - p->wndV[ p->wndN-1 ].val = d0; - p->wndV[ p->wndN-1 ].validFl= true; - - // fill in ewnd[] with the valid values in wndV[] - int i = p->wndN-1; - int en = 0; - for(; i>=0; --i,++en) - { - //if( p->wndV[i].validFl && ((smpIdx-p->wnd[i].smpIdx)<=maxWndSmp)) - if( p->wndV[i].validFl ) - ewnd[i] = p->wndV[i].val; - else - break; - } - ++i; // increment i to the first valid element in ewnd[]. - - int k; - printf("en:%i sbi:%i sei:%i pitch:%s : ",en,p->sbi,p->sei,cmMidiToSciPitch(d0,NULL,0)); - for(k=i; kwndN; ++k) - printf("%s ", cmMidiToSciPitch(ewnd[k],NULL,0)); + printf("loc: "); + for(i=0; iloc[locIdx+i].pitchCnt > n ) + n = p->loc[locIdx+i].pitchCnt; - int j = 0; - int dist; - int minDist = INT_MAX; - int minIdx = cmInvalidIdx; - for(j=0; p->sbi+en+j <= p->sei; ++j) - if((dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+i, p->loc + p->sbi+j, en )) < minDist ) - { - minDist = dist; - minIdx = j; - } - - // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ] - - int evalWndN = cmMin(en,p->evalWndN); - - assert(evalWndNwndN); - - j = p->sbi+minIdx+en - evalWndN; - - // Determine how many of the last evalWndN elements match - dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+p->wndN-evalWndN, p->loc+j, evalWndN ); - - // a successful match has <= allowedMissCnt and an exact match on the last element - //if( dist <= p->allowedMissCnt && ewnd[p->wndN-1] == p->loc[p->sbi+minIdx+en-1] ) - //if( dist <= p->allowedMissCnt && _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1])) - if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1])) + --n; + for(; n>=0; --n) { - p->sbi = p->sbi + minIdx; - p->sei = cmMin(p->sei+minIdx,p->locN-1); - ret_idx = p->sbi+minIdx+en-1; + printf("sc%1i: ",n); + for(i=0; iloc[locIdx+i].pitchCnt ) + printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].pitchV[n],NULL,0)); + else + printf(" "); + } + printf("\n"); } - printf("minDist:%i minIdx:%i evalDist:%i sbi:%i sei:%i\n",minDist,minIdx,dist,p->sbi,p->sei); + printf("perf:"); + for(i=0; ibufN ]; - if( status != kNoteOnMdId && d1>0 ) + if( status != kNoteOnMdId ) + return ret_idx; + + ++p->eventIdx; + + // reject notes with very low velocity + if( d1 < p->minVel ) return ret_idx; // left shift bufV[] to make the right-most element available - then copy in the new element @@ -355,31 +353,87 @@ unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByt // 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 <= p->sei; ++j) - if((dist = _cmScFolDist(p->bufN, p->edWndMtx, ebuf+i, p->loc + p->sbi+j, en )) < minDist ) + 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, ebuf+i, p->loc + p->sbi+j, en )) <= minDist ) { 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, ebuf+i, en, minIdx ); + + // save current missCnt for later printing + unsigned missCnt = p->missCnt; + // if a perfect match occurred if( minDist == 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 just past last match - ret_idx = p->sbi + minIdx + en - 1; + // BUG BUG BUG - is the window length valid - // - sbi and sei must be inside 0:locN // - sei-sbi + 1 must be >= en + ret_idx = p->sbi + minIdx + en - 1; + p->missCnt = 0; + } 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),ebuf[p->bufN-1]) ) - ret_idx = p->sbi + minIdx + en - 1; + { + ret_idx = p->sbi + minIdx + en - 1; + p->missCnt = 0; + + 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'. + + 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,ebuf[p->bufN-1-i])) + break; + + // does this look-back location match the current pitch + if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1])) + { + 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 ) + { + j = p->sbi+minIdx+en; + for(i=0; j<=p->sei && i<2; ++i,++j) + if( _cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]) ) + { + ret_idx = j; + break; + } + + p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0; + } + + } // even though we didn't match move the end of the score window forward // this will enlarge the score window by one @@ -398,9 +452,19 @@ unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByt } + if( p->printFl ) + _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt ); + + if( ret_idx == cmInvalidIdx ) + p->matchCnt = 0; + else + ++p->matchCnt; + + // BUG BUG BUG - this is not currently guarded against assert( p->sei < p->locN ); assert( p->sbi < p->locN ); + return ret_idx; } diff --git a/cmProc4.h b/cmProc4.h index b0ece31..f42f0fa 100644 --- a/cmProc4.h +++ b/cmProc4.h @@ -19,33 +19,10 @@ typedef struct { unsigned pitchCnt; // unsigned* pitchV; // pitchV[pitchCnt] - unsigned scIdx; // index of the score event (into cmScoreEvt[]) at this location + unsigned scIdx; // index of the score event (into cmScoreEvt[]) at this location int barNumb; // bar number of this location } cmScFolLoc_t; - /* -typedef struct -{ - cmObj obj; - cmReal_t srate; - cmScH_t scH; - unsigned maxWndSmp; - unsigned wndN; - cmScFolWndEle_t* wndV; // wnd[wndN] - int wni; // oldest value in wnd[] - int locN; - cmScFolLoc_t* loc; - unsigned sri; // last reset score index - unsigned sbi; // first (oldest) score index - unsigned sei; // last (newest) score index - - unsigned evalWndN; // (dflt:5) count of elements to use for refined match window - unsigned allowedMissCnt; // (dflt:1) count of non-match elements in refined match where a match is still signaled - - unsigned* edWndMtx; - -} cmScFol1; - */ typedef struct { @@ -56,21 +33,23 @@ typedef struct 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 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 evalWndN; // (dflt:5) count of elements to use for refined match window - //unsigned allowedMissCnt; // (dflt:1) count of non-match elements in refined match where a match is still signaled - + unsigned minVel; // notes < minVel are ignored + unsigned missCnt; // current consecutive unmatched notes + unsigned matchCnt;// current consecutive matched notes + bool printFl; // true if pitch tracker reporting should be included + unsigned aheadCnt;// 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 eventIdx;// events since init unsigned* edWndMtx; } cmScFol; -// wndN = max count of elements in the score following window. -// wndMs = max length of the score following window in time +// bufN = max count of elements in the event buffer. +// wndMs = max length of the score following window in time cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH ); cmRC_t cmScFolFree( cmScFol** pp ); diff --git a/dsp/cmDspKr.c b/dsp/cmDspKr.c index 5096ab1..a128d4b 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -704,8 +704,8 @@ struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx ) enum { kFnSfId, - kWndCntSfId, - kWndMsSfId, + kBufCntSfId, + kBufMsSfId, kIndexSfId, kStatusSfId, kD0SfId, @@ -727,8 +727,8 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned cmDspVarArg_t args[] = { { "fn", kFnSfId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." }, - { "wndcnt",kWndCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window element count." }, - { "wndms", kWndMsSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event window length milliseconds."}, + { "bufcnt",kBufCntSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer element count." }, + { "bufms", kBufMsSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Event buffer length milliseconds."}, { "index", kIndexSfId, 0, 0, kInDsvFl | kUIntDsvFl, "Tracking start location."}, { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI status byte"}, { "d0", kD0SfId, 0, 0, kInDsvFl | kUIntDsvFl, "MIDI data byte 0"}, @@ -745,8 +745,8 @@ cmDspInst_t* _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle ); - cmDspSetDefaultUInt( ctx, &p->inst, kWndCntSfId, 0, 10); - cmDspSetDefaultUInt( ctx, &p->inst, kWndMsSfId, 0, 5000); + cmDspSetDefaultUInt( ctx, &p->inst, kBufCntSfId, 0, 10); + cmDspSetDefaultUInt( ctx, &p->inst, kBufMsSfId, 0, 5000); cmDspSetDefaultUInt( ctx, &p->inst, kIndexSfId, 0, 0); cmDspSetDefaultUInt( ctx, &p->inst, kOutSfId, 0, 0); @@ -785,7 +785,7 @@ cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* return rc; if( cmScoreIsValid(p->scH) ) - if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kWndCntSfId), cmDspUInt(inst,kWndMsSfId), p->scH) != cmOkRC ) + if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kBufMsSfId), p->scH) != cmOkRC ) rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed."); return rc; diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index e92719d..79ede7f 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -110,7 +110,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, tlp, "afn", prp, "in", NULL ); cmDspSysInstallCb(h, tlp, "mfn", prp, "in", NULL ); cmDspSysInstallCb(h, tlp, "sel", prp, "in", NULL ); - cmDspSysInstallCb(h, sfp, "out", prp, "in", NULL ); + //cmDspSysInstallCb(h, sfp, "out", prp, "in", NULL ); return rc;