소스 검색

cmProc4.h/c Major score-follower development.

master
kevin 11 년 전
부모
커밋
698f987558
2개의 변경된 파일156개의 추가작업 그리고 74개의 파일을 삭제
  1. 128
    52
      cmProc4.c
  2. 28
    22
      cmProc4.h

+ 128
- 52
cmProc4.c 파일 보기

25
 
25
 
26
 
26
 
27
 
27
 
28
-cmScFol* cmScFolAlloc( cmCtx* c, cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH )
28
+cmScFol* cmScFolAlloc( cmCtx* c, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
29
 {
29
 {
30
   cmScFol* op = cmObjAlloc(cmScFol,c,p);
30
   cmScFol* op = cmObjAlloc(cmScFol,c,p);
31
   if( srate != 0 )
31
   if( srate != 0 )
32
-    if( cmScFolInit(op,srate,bufN,wndMs,scH) != cmOkRC )
32
+    if( cmScFolInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC )
33
       cmScFolFree(&op);
33
       cmScFolFree(&op);
34
   return op;
34
   return op;
35
 }
35
 }
73
   }
73
   }
74
 }
74
 }
75
 
75
 
76
-cmRC_t   cmScFolInit(  cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH )
76
+unsigned* _cmScFolAllocEditDistMtx(unsigned maxN)
77
+{
78
+  maxN += 1;
79
+
80
+  unsigned* m = cmMemAllocZ(unsigned,maxN*maxN);
81
+  unsigned* p = m;
82
+  unsigned i;
83
+
84
+  // initialize the comparison matrix with the default costs in the
85
+  // first row and column
86
+  // (Note that this matrix is not oriented in column major order like most 'cm' matrices.)
87
+  for(i=0; i<maxN; ++i)
88
+  {
89
+    p[i]          = i;		// 0th row
90
+    p[ i * maxN ] = i;		// 0th col
91
+  }
92
+
93
+  return m;
94
+}
95
+
96
+cmRC_t   cmScFolInit(  cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
77
 {
97
 {
78
   cmRC_t rc;
98
   cmRC_t rc;
79
   if((rc = cmScFolFinal(p)) != cmOkRC )
99
   if((rc = cmScFolFinal(p)) != cmOkRC )
80
     return rc;
100
     return rc;
81
 
101
 
102
+  if( bufN > maxWndCnt )
103
+    return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower buffer count (%i) must be less than the max. window length (%i).",bufN,maxWndCnt );
104
+
105
+  if( minWndLookAhead > maxWndCnt )
106
+    return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt); 
107
+
82
   p->srate          = srate;
108
   p->srate          = srate;
83
   p->scH            = scH;
109
   p->scH            = scH;
84
   p->bufN           = bufN;
110
   p->bufN           = bufN;
87
   p->loc            = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
113
   p->loc            = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
88
   p->sbi            = cmInvalidIdx;
114
   p->sbi            = cmInvalidIdx;
89
   p->sei            = cmInvalidIdx;
115
   p->sei            = cmInvalidIdx;
90
-  p->msln           = 7;
91
-  p->mswn           = 30;
92
-  p->edWndMtx       = cmVOU_LevEditDistAllocMtx(p->bufN);
93
-  p->minVel         = 5;
116
+  p->msln           = minWndLookAhead;
117
+  p->mswn           = maxWndCnt;
118
+  p->forwardCnt     = 2;
119
+  p->maxDist        = 4;
120
+  p->edWndMtx       = _cmScFolAllocEditDistMtx(p->bufN);
121
+  p->minVel         = minVel;
122
+  p->printFl        = true;
123
+  p->noBackFl       = true;
94
   p->missCnt        = 0;
124
   p->missCnt        = 0;
95
   p->matchCnt       = 0;
125
   p->matchCnt       = 0;
96
-  p->printFl        = true;
97
   p->eventIdx       = 0;
126
   p->eventIdx       = 0;
127
+  p->skipCnt        = 0;
128
+  p->ret_idx        = cmInvalidIdx;
98
 
129
 
99
   int i,n;
130
   int i,n;
100
   double        maxDSecs = 0;   // max time between score entries to be considered simultaneous
131
   double        maxDSecs = 0;   // max time between score entries to be considered simultaneous
171
 {
202
 {
172
   int i;
203
   int i;
173
 
204
 
174
-
175
   // empty the event buffer
205
   // empty the event buffer
176
   memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN);
206
   memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN);
177
 
207
 
179
   if( scoreIndex < p->loc[0].scIdx )
209
   if( scoreIndex < p->loc[0].scIdx )
180
     scoreIndex = p->loc[0].scIdx;
210
     scoreIndex = p->loc[0].scIdx;
181
 
211
 
182
-  p->sei = cmInvalidIdx;
183
-  p->sbi = cmInvalidIdx;
212
+  p->sei      = cmInvalidIdx;
213
+  p->sbi      = cmInvalidIdx;
214
+  p->missCnt  = 0;
215
+  p->matchCnt = 0;
216
+  p->eventIdx = 0;
217
+  p->skipCnt  = 0;
218
+  p->ret_idx  = cmInvalidIdx;
184
 
219
 
185
   // locate the score element in svV[] that is closest to,
220
   // locate the score element in svV[] that is closest to,
186
   // and possibly after, scoreIndex.
221
   // and possibly after, scoreIndex.
212
   return false;
247
   return false;
213
 }
248
 }
214
 
249
 
215
-int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const unsigned* pitch, unsigned pi )
250
+int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const cmScFolBufEle_t* pitch, unsigned pi )
216
 {
251
 {
217
-  if( _cmScFolIsMatch(loc+li,pitch[pi]) )
252
+  if( _cmScFolIsMatch(loc+li,pitch[pi].val) )
218
     return 0;
253
     return 0;
219
   
254
   
220
   if( li>0 && pi>0 )
255
   if( li>0 && pi>0 )
221
-    if( _cmScFolIsMatch(loc+li-1,pitch[pi]) && _cmScFolIsMatch(loc+li,pitch[pi-1]) )
256
+    if( _cmScFolIsMatch(loc+li-1,pitch[pi].val) && _cmScFolIsMatch(loc+li,pitch[pi-1].val) )
222
       return 0;
257
       return 0;
223
 
258
 
224
   return 1;
259
   return 1;
225
 }
260
 }
226
 
261
 
227
-int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n )
262
+int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const cmScFolBufEle_t* s1, const cmScFolLoc_t* s0, int n )
228
 {
263
 {
229
   mtxMaxN += 1;
264
   mtxMaxN += 1;
230
 
265
 
253
   return v;		
288
   return v;		
254
 }
289
 }
255
 
290
 
256
-void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, unsigned* b, unsigned bn, unsigned min_idx )
291
+void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, const cmScFolBufEle_t* b, unsigned bn, unsigned min_idx )
257
 {
292
 {
258
   unsigned i;
293
   unsigned i;
259
   int      n;
294
   int      n;
288
     printf("     ");
323
     printf("     ");
289
 
324
 
290
   for(i=0; i<bn; ++i)
325
   for(i=0; i<bn; ++i)
291
-    printf("%4s ",cmMidiToSciPitch(b[i],NULL,0));
326
+    printf("%4s ",cmMidiToSciPitch(b[i].val,NULL,0));
292
 
327
 
293
   printf("\n");
328
   printf("\n");
294
 }
329
 }
295
 
330
 
296
 void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
331
 void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
297
 {
332
 {
298
-
299
-  printf("dist:%i miss:%i match:%i ",minDist,missCnt,matchCnt);
300
-  if( ret_idx == cmInvalidIdx )
301
-    printf("vel:%i ", d1 );
302
-  else
333
+  printf("dist:%i miss:%i match:%i skip:%i vel:%i ",minDist,missCnt,matchCnt,p->skipCnt,d1);
334
+  if( ret_idx != cmInvalidIdx )
303
     printf("ret_idx:%i ",ret_idx);
335
     printf("ret_idx:%i ",ret_idx);
304
   printf("\n");
336
   printf("\n");
305
-
306
 }
337
 }
307
 
338
 
308
 unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
339
 unsigned   cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
309
 {
340
 {
310
 
341
 
311
   unsigned ret_idx = cmInvalidIdx;
342
   unsigned ret_idx = cmInvalidIdx;
312
-  unsigned ebuf[ p->bufN ];
343
+  //unsigned ebuf[ p->bufN ];
313
 
344
 
314
   if( status != kNoteOnMdId )
345
   if( status != kNoteOnMdId )
315
     return ret_idx;
346
     return ret_idx;
318
 
349
 
319
   // reject notes with very low velocity
350
   // reject notes with very low velocity
320
   if( d1 < p->minVel )
351
   if( d1 < p->minVel )
352
+  {
353
+    ++p->skipCnt;
321
     return ret_idx;
354
     return ret_idx;
355
+  }
322
 
356
 
323
   // left shift bufV[] to make the right-most element available - then copy in the new element
357
   // left shift bufV[] to make the right-most element available - then copy in the new element
324
   memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
358
   memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
327
   p->bufV[ p->bufN-1 ].validFl= true;
361
   p->bufV[ p->bufN-1 ].validFl= true;
328
 
362
 
329
   // fill in ebuf[] with the valid values in bufV[]
363
   // fill in ebuf[] with the valid values in bufV[]
330
-  int i = p->bufN-1;
364
+  int en = cmMin(p->eventIdx,p->bufN);
365
+  int i  = p->eventIdx>=p->bufN ? 0 : p->bufN-p->eventIdx-1;
366
+
367
+  /*
368
+  int i  = p->bufN-1;
331
   int en = 0;
369
   int en = 0;
332
   for(; i>=0; --i,++en)
370
   for(; i>=0; --i,++en)
333
   {
371
   {
337
       break;
375
       break;
338
   }
376
   }
339
   ++i;  // increment i to the first valid element in ebuf[].
377
   ++i;  // increment i to the first valid element in ebuf[].
378
+  */
379
+
340
 
380
 
341
 
381
 
342
   // en is the count of valid elements in ebuf[].
382
   // en is the count of valid elements in ebuf[].
356
   for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
396
   for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
357
   {
397
   {
358
     // use <= minDist to choose the latest window with the lowest match
398
     // 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 )
399
+    if((dist = _cmScFolDist(p->bufN, p->edWndMtx, p->bufV+i, p->loc + p->sbi+j, en )) < minDist )
360
     {
400
     {
401
+      // only make an eql match if the posn is greater than the last location 
402
+      if( dist==minDist && p->ret_idx != cmInvalidId && p->ret_idx >= p->sbi+minIdx+en-1 )
403
+        continue;
404
+
361
       minDist = dist;
405
       minDist = dist;
362
       minIdx  = j;
406
       minIdx  = j;
363
     }
407
     }
366
   // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
410
   // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
367
 
411
 
368
   if( p->printFl )
412
   if( p->printFl )
369
-    _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, ebuf+i, en, minIdx );
413
+    _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, p->bufV+i, en, minIdx );
370
     
414
     
371
   // save current missCnt for later printing
415
   // save current missCnt for later printing
372
   unsigned missCnt = p->missCnt;
416
   unsigned missCnt = p->missCnt;
374
   // if a perfect match occurred
418
   // if a perfect match occurred
375
   if( minDist == 0 )
419
   if( minDist == 0 )
376
   {
420
   {
421
+    ret_idx = p->sbi + minIdx + en - 1;       
422
+    p->missCnt = 0;
423
+
377
     // we had a perfect match - shrink the window to it's minumum size
424
     // we had a perfect match - shrink the window to it's minumum size
378
     p->sbi += (en==p->bufN) ? minIdx + 1 : 0;  // move wnd begin forward to just past first match
425
     p->sbi += (en==p->bufN) ? minIdx + 1 : 0;  // move wnd begin forward to just past first match
379
-    p->sei  = p->sbi + minIdx + en + p->msln;  // move wnd end forward to just past last match
426
+    p->sei  = p->sbi + minIdx + en + p->msln;  // move wnd end forward to lead by the min look-ahead
380
     
427
     
381
-    // BUG BUG BUG - is the window length valid - 
382
-    //  - sbi and sei must be inside 0:locN
383
-    //  - sei-sbi + 1 must be >= en
384
-    ret_idx = p->sbi + minIdx + en - 1;       
385
-    p->missCnt = 0;
386
 
428
 
387
   }
429
   }
388
   else
430
   else
389
   {
431
   {
432
+    if( minDist > p->maxDist )
433
+      ret_idx = cmInvalidIdx;
434
+    else
390
     // if the last event matched - then return the match location as the current score location
435
     // if the last event matched - then return the match location as the current score location
391
-    if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ebuf[p->bufN-1]) )
436
+    if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),p->bufV[p->bufN-1].val) )
392
     {
437
     {
393
       ret_idx    = p->sbi + minIdx + en - 1;
438
       ret_idx    = p->sbi + minIdx + en - 1;
394
       p->missCnt = 0;
439
       p->missCnt = 0;
395
 
440
 
441
+      // this is probably a pretty good match reduce the part of the window prior to 
442
+      // the first match (bring the end of the window almost up to the end of the 
443
+      // buffers sync position)
396
       if( en >= p->bufN-1 && (en+2) <= ret_idx )
444
       if( en >= p->bufN-1 && (en+2) <= ret_idx )
397
         p->sbi = ret_idx - (en+2);
445
         p->sbi = ret_idx - (en+2);
398
-        
399
-      
446
+              
400
     }
447
     }
401
-    else // the last event does not match based on the optimal  edit-distance alignment
448
+    else // the last event does not match based on the optimal edit-distance alignment
402
     {
449
     {
403
       // Look backward from the closest match location for a match to the current pitch.
450
       // 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'.
451
       // The backward search scope is limited by the current value of 'missCnt'.
407
       for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
454
       for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
408
       {
455
       {
409
         // if this look-back location already matched then stop the backward search
456
         // if this look-back location already matched then stop the backward search
410
-        if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1-i]))
457
+        if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1-i].val))
411
           break;
458
           break;
412
         
459
         
413
         // does this look-back location match the current pitch
460
         // does this look-back location match the current pitch
414
-        if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]))
461
+        if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val))
415
         {
462
         {
416
           ret_idx    = j;
463
           ret_idx    = j;
417
           p->missCnt = i;  // set missCnt to the cnt of steps backward necessary for a match
464
           p->missCnt = i;  // set missCnt to the cnt of steps backward necessary for a match
423
       if( ret_idx == cmInvalidIdx )
470
       if( ret_idx == cmInvalidIdx )
424
       {
471
       {
425
         j = p->sbi+minIdx+en;
472
         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]) )
473
+        for(i=0; j<=p->sei && i<p->forwardCnt; ++i,++j)
474
+          if( _cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val) )
428
           {
475
           {
429
             ret_idx = j;
476
             ret_idx = j;
430
             break;
477
             break;
435
         
482
         
436
     }
483
     }
437
 
484
 
438
-    // even though we didn't match move the end of the score window forward
439
-    // this will enlarge the score window by one
440
-     p->sei += 1;
485
+    // Adjust the end window position (sei)  based on the match location
486
+    if( ret_idx == cmInvalidIdx )
487
+    {
488
+      // even though we didn't match move the end of the score window forward
489
+      // this will enlarge the score window by one
490
+      p->sei += 1;
491
+    }
492
+    else
493
+    {
494
+      assert( p->sei>=ret_idx);
495
+
496
+      // force sei to lead by min look-ahead
497
+      if( p->sei - ret_idx < p->msln )
498
+        p->sei = ret_idx + p->msln;
499
+
500
+    }
441
 
501
 
442
     assert( p->sei > p->sbi );
502
     assert( p->sei > p->sbi );
443
 
503
 
504
+    // Adjust the begin window position
505
+    if( p->noBackFl && ret_idx != cmInvalidIdx && en>=p->bufN && p->sbi > p->bufN )
506
+      p->sbi = ret_idx - p->bufN;
507
+
444
     // if the score window length surpasses the max score window size 
508
     // if the score window length surpasses the max score window size 
445
     // move the beginning index forward 
509
     // move the beginning index forward 
446
     if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
510
     if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
447
       p->sbi = p->sei - p->mswn + 1;
511
       p->sbi = p->sei - p->mswn + 1;
448
 
512
 
449
-    // BUG BUG BUG - is the window length valid - 
450
-    //  - sbi and sei must be inside 0:locN
451
-    //  - sei-sbi + 1 must be >= en
452
 
513
 
453
   }
514
   }
454
 
515
 
455
   if( p->printFl )
516
   if( p->printFl )
456
     _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
517
     _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
457
 
518
 
519
+  // don't allow the returned location to repeat or go backwards
520
+  if( p->noBackFl && p->ret_idx != cmInvalidIdx && ret_idx <= p->ret_idx )
521
+    ret_idx = cmInvalidIdx;
522
+
523
+
524
+  // track the number of consecutive matches
458
   if( ret_idx == cmInvalidIdx )
525
   if( ret_idx == cmInvalidIdx )
459
     p->matchCnt = 0;
526
     p->matchCnt = 0;
460
   else
527
   else
528
+  {
461
     ++p->matchCnt;
529
     ++p->matchCnt;
462
 
530
 
463
-  
464
-  // BUG BUG BUG - this is not currently guarded against
465
-  assert( p->sei < p->locN );
466
-  assert( p->sbi < p->locN );
467
-    
531
+    p->ret_idx = ret_idx;
532
+  }
533
+
534
+  // Force the window to remain valid when it is at the end of the score 
535
+  //  - sbi and sei must be inside 0:locN
536
+  //  - sei-sbi + 1 must be >= en
537
+  if( p->sei >= p->locN )
538
+  {
539
+    p->sei = p->locN - 1;
540
+    p->sbi = p->sei  - p->bufN + 1;
541
+  }
542
+
543
+
468
 
544
 
469
   return ret_idx;
545
   return ret_idx;
470
 }
546
 }

+ 28
- 22
cmProc4.h 파일 보기

27
 typedef struct
27
 typedef struct
28
 {
28
 {
29
   cmObj            obj;
29
   cmObj            obj;
30
-  cmReal_t         srate;   //
31
-  cmScH_t          scH;     // score handle
32
-  unsigned         bufN;    // event buffer count 
33
-  cmScFolBufEle_t* bufV;    // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event
34
-  int              locN;    // count of score locations
35
-  cmScFolLoc_t*    loc;     // score loc[locN]
36
-  unsigned         sbi;     // oldest score window index
37
-  unsigned         sei;     // newest score window index
38
-  unsigned         msln;    // minimum score look ahead count
39
-  unsigned         mswn;    // maximum score window length
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
30
+  cmReal_t         srate;      //
31
+  cmScH_t          scH;        // score handle
32
+  unsigned         bufN;       // event buffer count 
33
+  cmScFolBufEle_t* bufV;       // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event
34
+  int              locN;       // count of score locations
35
+  cmScFolLoc_t*    loc;        // score loc[locN]
36
+  unsigned         sbi;        // oldest score window index
37
+  unsigned         sei;        // newest score window index
38
+  unsigned         msln;       // minimum score look ahead count
39
+  unsigned         mswn;       // maximum score window length
40
+  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
41
+  unsigned         maxDist;    // max. dist allowed to still  consider matching
42
+  unsigned         minVel;     // notes < minVel are ignored
43
+  bool             printFl;    // true if pitch tracker reporting should be included
44
+  bool             noBackFl;   // prevent the tracker from going backwards in time
46
   unsigned*        edWndMtx;
45
   unsigned*        edWndMtx;
46
+
47
+  unsigned         missCnt;    // current consecutive unmatched notes
48
+  unsigned         matchCnt;   // current consecutive matched notes
49
+  unsigned         eventIdx;   // events since reset
50
+  unsigned         skipCnt;    // notes skipped due to velocity
51
+  unsigned         ret_idx;    // last tracked location
47
   
52
   
48
 } cmScFol;
53
 } cmScFol;
49
 
54
 
50
-
51
-// bufN   = max count of elements in the event buffer.
52
-// wndMs  = max length of the score following window in time
53
-
54
-cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH );
55
+cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
55
 cmRC_t   cmScFolFree(  cmScFol** pp );
56
 cmRC_t   cmScFolFree(  cmScFol** pp );
56
-cmRC_t   cmScFolInit(  cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH );
57
+cmRC_t   cmScFolInit(  cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
57
 cmRC_t   cmScFolFinal( cmScFol* p );
58
 cmRC_t   cmScFolFinal( cmScFol* p );
59
+
60
+// Jump to a score location and reset the internal state of the follower.
58
 cmRC_t   cmScFolReset( cmScFol* p, unsigned scoreIndex );
61
 cmRC_t   cmScFolReset( cmScFol* p, unsigned scoreIndex );
62
+
63
+// Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
64
+// all others are ignored.
59
 unsigned cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
65
 unsigned cmScFolExec(  cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
60
   
66
   
61
 
67
 

Loading…
취소
저장