|
@@ -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
|
}
|