Pārlūkot izejas kodu

cmProc4.h/c cmDspKr.c Score follower tweeking.

master
kpl 12 gadus atpakaļ
vecāks
revīzija
24bcde77ac
4 mainītis faili ar 152 papildinājumiem un 109 dzēšanām
  1. 133
    69
      cmProc4.c
  2. 11
    32
      cmProc4.h
  3. 7
    7
      dsp/cmDspKr.c
  4. 1
    1
      dsp/cmDspPgmKr.c

+ 133
- 69
cmProc4.c Parādīt failu

@@ -90,7 +90,11 @@ cmRC_t   cmScFolInit(  cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs
90 90
   p->msln           = 7;
91 91
   p->mswn           = 30;
92 92
   p->edWndMtx       = cmVOU_LevEditDistAllocMtx(p->bufN);
93
-
93
+  p->minVel         = 5;
94
+  p->missCnt        = 0;
95
+  p->matchCnt       = 0;
96
+  p->printFl        = true;
97
+  p->eventIdx       = 0;
94 98
 
95 99
   int i,n;
96 100
   double        maxDSecs = 0;   // max time between score entries to be considered simultaneous
@@ -208,6 +212,18 @@ bool  _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
208 212
   return false;
209 213
 }
210 214
 
215
+int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const unsigned* pitch, unsigned pi )
216
+{
217
+  if( _cmScFolIsMatch(loc+li,pitch[pi]) )
218
+    return 0;
219
+  
220
+  if( li>0 && pi>0 )
221
+    if( _cmScFolIsMatch(loc+li-1,pitch[pi]) && _cmScFolIsMatch(loc+li,pitch[pi-1]) )
222
+      return 0;
223
+
224
+  return 1;
225
+}
226
+
211 227
 int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n )
212 228
 {
213 229
   mtxMaxN += 1;
@@ -226,7 +242,8 @@ int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFo
226 242
     for( j=1; j<n+1; ++j)
227 243
     {
228 244
       //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
229
-      int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
245
+      //int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
246
+      int cost = _cmScFolMatchCost(s0,i-1,s1,j-1);
230 247
 
231 248
       //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
232 249
 					
@@ -236,82 +253,57 @@ int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFo
236 253
   return v;		
237 254
 }
238 255
 
239
-/*
240
-unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
256
+void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, unsigned* b, unsigned bn, unsigned min_idx )
241 257
 {
242
-  assert( p->sri != cmInvalidIdx );
243
-
244
-  unsigned ret_idx = cmInvalidIdx;
245
-  unsigned ewnd[ p->wndN ];
246
-
247
-  if( status != kNoteOnMdId && d1>0 )
248
-    return ret_idx;
249
-
250
-  // left shift wndV[] to make the right-most element available - then copy in the new element
251
-  memmove(p->wndV, p->wndV+1, sizeof(cmScFolWndEle_t)*(p->wndN-1));
252
-  p->wndV[ p->wndN-1 ].smpIdx = smpIdx;
253
-  p->wndV[ p->wndN-1 ].val    = d0;
254
-  p->wndV[ p->wndN-1 ].validFl= true;
258
+  unsigned i;
259
+  int      n;
255 260
 
256
-  // fill in ewnd[] with the valid values in wndV[]
257
-  int i = p->wndN-1;
258
-  int en = 0;
259
-  for(; i>=0; --i,++en)
260
-  {
261
-    //if( p->wndV[i].validFl && ((smpIdx-p->wnd[i].smpIdx)<=maxWndSmp))
262
-    if( p->wndV[i].validFl )
263
-      ewnd[i] = p->wndV[i].val;
264
-    else
265
-      break;
266
-  }
267
-  ++i; // increment i to the first valid element in ewnd[].
261
+  printf("--------------- event:%i -------------  \n",p->eventIdx);
268 262
 
269
-  int k;
270
-  printf("en:%i sbi:%i sei:%i pitch:%s : ",en,p->sbi,p->sei,cmMidiToSciPitch(d0,NULL,0));
271
-  for(k=i; k<p->wndN; ++k)
272
-    printf("%s ", cmMidiToSciPitch(ewnd[k],NULL,0));
263
+  printf("loc: ");
264
+  for(i=0; i<locN; ++i)
265
+    printf("%4i ",i+locIdx);
273 266
   printf("\n");
274 267
 
275
-  // en is the count of valid elements in ewnd[].
276
-  // ewnd[i] is the first valid element
268
+  for(n=0,i=0; i<locN; ++i)
269
+    if( p->loc[locIdx+i].pitchCnt > n )
270
+      n = p->loc[locIdx+i].pitchCnt;
277 271
 
278
-  int    j       = 0;
279
-  int    dist;
280
-  int    minDist = INT_MAX;
281
-  int    minIdx  = cmInvalidIdx;
282
-  for(j=0; p->sbi+en+j <= p->sei; ++j)
283
-    if((dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+i, p->loc + p->sbi+j, en )) < minDist )
272
+  --n;
273
+  for(; n>=0; --n)
274
+  {
275
+    printf("sc%1i: ",n);
276
+    for(i=0; i<locN; ++i)
284 277
     {
285
-      minDist = dist;
286
-      minIdx  = j;
278
+      if( n < p->loc[locIdx+i].pitchCnt )
279
+        printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].pitchV[n],NULL,0));
280
+      else
281
+        printf("     ");
287 282
     }
283
+    printf("\n");
284
+  }
288 285
 
289
-  // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
290
-   
291
-  int evalWndN = cmMin(en,p->evalWndN);
286
+  printf("perf:");
287
+  for(i=0; i<min_idx; ++i)
288
+    printf("     ");
292 289
 
293
-  assert(evalWndN<p->wndN);
294
-  
295
-  j = p->sbi+minIdx+en - evalWndN;
290
+  for(i=0; i<bn; ++i)
291
+    printf("%4s ",cmMidiToSciPitch(b[i],NULL,0));
296 292
 
297
-  // Determine how many of the last evalWndN elements match
298
-  dist =  _cmScFolDist(p->wndN, p->edWndMtx, ewnd+p->wndN-evalWndN, p->loc+j, evalWndN );
299
-  
300
-  // a successful match has <= allowedMissCnt and an exact match on the last element  
301
-  //if( dist <= p->allowedMissCnt && ewnd[p->wndN-1] == p->loc[p->sbi+minIdx+en-1] )
302
-  //if( dist <= p->allowedMissCnt && _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1]))
303
-  if(  _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1]))
304
-  {
305
-    p->sbi  = p->sbi + minIdx;
306
-    p->sei  = cmMin(p->sei+minIdx,p->locN-1);
307
-    ret_idx = p->sbi+minIdx+en-1;
308
-  }
293
+  printf("\n");
294
+}
309 295
 
310
-  printf("minDist:%i minIdx:%i evalDist:%i sbi:%i sei:%i\n",minDist,minIdx,dist,p->sbi,p->sei);
296
+void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
297
+{
298
+
299
+  printf("dist:%i miss:%i match:%i ",minDist,missCnt,matchCnt);
300
+  if( ret_idx == cmInvalidIdx )
301
+    printf("vel:%i ", d1 );
302
+  else
303
+    printf("ret_idx:%i ",ret_idx);
304
+  printf("\n");
311 305
 
312
-  return ret_idx;
313 306
 }
314
-*/
315 307
 
316 308
 unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
317 309
 {
@@ -319,7 +311,13 @@ unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByt
319 311
   unsigned ret_idx = cmInvalidIdx;
320 312
   unsigned ebuf[ p->bufN ];
321 313
 
322
-  if( status != kNoteOnMdId && d1>0 )
314
+  if( status != kNoteOnMdId )
315
+    return ret_idx;
316
+
317
+  ++p->eventIdx;
318
+
319
+  // reject notes with very low velocity
320
+  if( d1 < p->minVel )
323 321
     return ret_idx;
324 322
 
325 323
   // 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
355 353
   // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements)
356 354
   assert( p->sei-p->sbi+1 >= en );
357 355
 
358
-  for(j=0; p->sbi+en+j <= p->sei; ++j)
359
-    if((dist = _cmScFolDist(p->bufN, p->edWndMtx, ebuf+i, p->loc + p->sbi+j, en )) < minDist )
356
+  for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
357
+  {
358
+    // use <= minDist to choose the latest window with the lowest match
359
+    if((dist = _cmScFolDist(p->bufN, p->edWndMtx, ebuf+i, p->loc + p->sbi+j, en )) <= minDist )
360 360
     {
361 361
       minDist = dist;
362 362
       minIdx  = j;
363 363
     }
364
+  }
364 365
 
365 366
   // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
366 367
 
368
+  if( p->printFl )
369
+    _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, ebuf+i, en, minIdx );
370
+    
371
+  // save current missCnt for later printing
372
+  unsigned missCnt = p->missCnt;
373
+
367 374
   // if a perfect match occurred
368 375
   if( minDist == 0 )
369 376
   {
370 377
     // we had a perfect match - shrink the window to it's minumum size
371 378
     p->sbi += (en==p->bufN) ? minIdx + 1 : 0;  // move wnd begin forward to just past first match
372 379
     p->sei  = p->sbi + minIdx + en + p->msln;  // move wnd end forward to just past last match
373
-    ret_idx = p->sbi + minIdx + en - 1;       
380
+    
374 381
     // BUG BUG BUG - is the window length valid - 
375 382
     //  - sbi and sei must be inside 0:locN
376 383
     //  - sei-sbi + 1 must be >= en
384
+    ret_idx = p->sbi + minIdx + en - 1;       
385
+    p->missCnt = 0;
386
+
377 387
   }
378 388
   else
379 389
   {
380 390
     // if the last event matched - then return the match location as the current score location
381 391
     if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ebuf[p->bufN-1]) )
382
-      ret_idx = p->sbi + minIdx + en - 1;
392
+    {
393
+      ret_idx    = p->sbi + minIdx + en - 1;
394
+      p->missCnt = 0;
395
+
396
+      if( en >= p->bufN-1 && (en+2) <= ret_idx )
397
+        p->sbi = ret_idx - (en+2);
398
+        
399
+      
400
+    }
401
+    else // the last event does not match based on the optimal  edit-distance alignment
402
+    {
403
+      // Look backward from the closest match location for a match to the current pitch.
404
+      // The backward search scope is limited by the current value of 'missCnt'.
405
+
406
+      j = p->sbi+minIdx+en-2;
407
+      for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
408
+      {
409
+        // if this look-back location already matched then stop the backward search
410
+        if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1-i]))
411
+          break;
412
+        
413
+        // does this look-back location match the current pitch
414
+        if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]))
415
+        {
416
+          ret_idx    = j;
417
+          p->missCnt = i;  // set missCnt to the cnt of steps backward necessary for a match
418
+          break;
419
+        }
420
+      }
421
+
422
+      // If the backward search did not find a match - look forward
423
+      if( ret_idx == cmInvalidIdx )
424
+      {
425
+        j = p->sbi+minIdx+en;
426
+        for(i=0; j<=p->sei && i<2; ++i,++j)
427
+          if( _cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]) )
428
+          {
429
+            ret_idx = j;
430
+            break;
431
+          }
432
+
433
+        p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0;
434
+      }
435
+        
436
+    }
383 437
 
384 438
     // even though we didn't match move the end of the score window forward
385 439
     // this will enlarge the score window by one
@@ -398,9 +452,19 @@ unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByt
398 452
 
399 453
   }
400 454
 
455
+  if( p->printFl )
456
+    _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
457
+
458
+  if( ret_idx == cmInvalidIdx )
459
+    p->matchCnt = 0;
460
+  else
461
+    ++p->matchCnt;
462
+
463
+  
401 464
   // BUG BUG BUG - this is not currently guarded against
402 465
   assert( p->sei < p->locN );
403 466
   assert( p->sbi < p->locN );
404 467
     
468
+
405 469
   return ret_idx;
406 470
 }

+ 11
- 32
cmProc4.h Parādīt failu

@@ -19,33 +19,10 @@ typedef struct
19 19
 {
20 20
   unsigned  pitchCnt; // 
21 21
   unsigned* pitchV;   // pitchV[pitchCnt]
22
-  unsigned  scIdx;   // index of the score event (into cmScoreEvt[]) at this location 
22
+  unsigned  scIdx;    // index of the score event (into cmScoreEvt[]) at this location 
23 23
   int       barNumb;  // bar number of this location
24 24
 } cmScFolLoc_t;
25 25
 
26
-  /*
27
-typedef struct
28
-{
29
-  cmObj            obj;
30
-  cmReal_t         srate;
31
-  cmScH_t          scH;
32
-  unsigned         maxWndSmp;
33
-  unsigned         wndN;
34
-  cmScFolWndEle_t* wndV;    // wnd[wndN]
35
-  int              wni;     // oldest value in wnd[]
36
-  int              locN;
37
-  cmScFolLoc_t*    loc;
38
-  unsigned         sri;     // last reset score index
39
-  unsigned         sbi;     // first (oldest) score index
40
-  unsigned         sei;     // last (newest) score index
41
-
42
-  unsigned         evalWndN; // (dflt:5) count of elements to use for refined match window
43
-  unsigned         allowedMissCnt; // (dflt:1) count of non-match elements in refined match where a match is still signaled
44
-
45
-  unsigned*        edWndMtx;
46
-  
47
-} cmScFol1;
48
-  */
49 26
 
50 27
 typedef struct
51 28
 {
@@ -56,21 +33,23 @@ typedef struct
56 33
   cmScFolBufEle_t* bufV;    // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event
57 34
   int              locN;    // count of score locations
58 35
   cmScFolLoc_t*    loc;     // score loc[locN]
59
-  unsigned         sbi;    // oldest score window index
60
-  unsigned         sei;    // newest score window index
36
+  unsigned         sbi;     // oldest score window index
37
+  unsigned         sei;     // newest score window index
61 38
   unsigned         msln;    // minimum score look ahead count
62 39
   unsigned         mswn;    // maximum score window length
63
-
64
-  //unsigned         evalWndN; // (dflt:5) count of elements to use for refined match window
65
-  //unsigned         allowedMissCnt; // (dflt:1) count of non-match elements in refined match where a match is still signaled
66
-
40
+  unsigned         minVel;  // notes < minVel are ignored
41
+  unsigned         missCnt; // current consecutive unmatched notes
42
+  unsigned         matchCnt;// current consecutive matched notes
43
+  bool             printFl; // true if pitch tracker reporting should be included
44
+  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
45
+  unsigned         eventIdx;// events since init
67 46
   unsigned*        edWndMtx;
68 47
   
69 48
 } cmScFol;
70 49
 
71 50
 
72
-// wndN = max count of elements in the  score following window.
73
-// wndMs     = max length of the score following window in time
51
+// bufN   = max count of elements in the event buffer.
52
+// wndMs  = max length of the score following window in time
74 53
 
75 54
 cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH );
76 55
 cmRC_t   cmScFolFree(  cmScFol** pp );

+ 7
- 7
dsp/cmDspKr.c Parādīt failu

@@ -704,8 +704,8 @@ struct cmDspClass_str* cmMidiFilePlayClassCons( cmDspCtx_t* ctx )
704 704
 enum
705 705
 {
706 706
   kFnSfId,
707
-  kWndCntSfId,
708
-  kWndMsSfId,
707
+  kBufCntSfId,
708
+  kBufMsSfId,
709 709
   kIndexSfId,
710 710
   kStatusSfId,
711 711
   kD0SfId,
@@ -727,8 +727,8 @@ cmDspInst_t*  _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned
727 727
   cmDspVarArg_t args[] =
728 728
   {
729 729
     { "fn",    kFnSfId,     0, 0, kInDsvFl | kStrzDsvFl   | kReqArgDsvFl,   "Score file." },
730
-    { "wndcnt",kWndCntSfId, 0, 0, kInDsvFl | kUIntDsvFl,                    "Event window element count." },
731
-    { "wndms", kWndMsSfId,  0, 0, kInDsvFl | kUIntDsvFl,                    "Event window length milliseconds."},
730
+    { "bufcnt",kBufCntSfId, 0, 0, kInDsvFl | kUIntDsvFl,                    "Event buffer element count." },
731
+    { "bufms", kBufMsSfId,  0, 0, kInDsvFl | kUIntDsvFl,                    "Event buffer length milliseconds."},
732 732
     { "index", kIndexSfId,  0, 0, kInDsvFl | kUIntDsvFl,                    "Tracking start location."},
733 733
     { "status",kStatusSfId, 0, 0, kInDsvFl | kUIntDsvFl,                    "MIDI status byte"},
734 734
     { "d0",    kD0SfId,     0, 0, kInDsvFl | kUIntDsvFl,                    "MIDI data byte 0"},
@@ -745,8 +745,8 @@ cmDspInst_t*  _cmDspScFolAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned
745 745
 
746 746
   p->sfp = cmScFolAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, cmScNullHandle );
747 747
 
748
-  cmDspSetDefaultUInt( ctx, &p->inst,  kWndCntSfId,     0,    10);
749
-  cmDspSetDefaultUInt( ctx, &p->inst,  kWndMsSfId,      0,  5000);
748
+  cmDspSetDefaultUInt( ctx, &p->inst,  kBufCntSfId,     0,    10);
749
+  cmDspSetDefaultUInt( ctx, &p->inst,  kBufMsSfId,      0,  5000);
750 750
   cmDspSetDefaultUInt( ctx, &p->inst,  kIndexSfId,      0,     0);  
751 751
   cmDspSetDefaultUInt( ctx, &p->inst,  kOutSfId,        0,     0);
752 752
 
@@ -785,7 +785,7 @@ cmDspRC_t _cmDspScFolReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t*
785 785
     return rc;
786 786
 
787 787
   if( cmScoreIsValid(p->scH) )
788
-    if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kWndCntSfId), cmDspUInt(inst,kWndMsSfId), p->scH) != cmOkRC )
788
+    if( cmScFolInit(p->sfp, cmDspSampleRate(ctx), cmDspUInt(inst,kBufCntSfId), cmDspUInt(inst,kBufMsSfId), p->scH) != cmOkRC )
789 789
       rc = cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Internal score follower allocation failed.");
790 790
 
791 791
   return rc;  

+ 1
- 1
dsp/cmDspPgmKr.c Parādīt failu

@@ -110,7 +110,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr )
110 110
   cmDspSysInstallCb(h, tlp, "afn",  prp, "in",  NULL );
111 111
   cmDspSysInstallCb(h, tlp, "mfn",  prp, "in",  NULL );
112 112
   cmDspSysInstallCb(h, tlp, "sel",  prp, "in",  NULL );
113
-  cmDspSysInstallCb(h, sfp, "out",  prp, "in",     NULL );
113
+  //cmDspSysInstallCb(h, sfp, "out",  prp, "in",     NULL );
114 114
 
115 115
 
116 116
   return rc;

Notiek ielāde…
Atcelt
Saglabāt