|
@@ -27,749 +27,6 @@
|
27
|
27
|
#include "cmScore.h"
|
28
|
28
|
#include "cmProc4.h"
|
29
|
29
|
|
30
|
|
-
|
31
|
|
-cmScFol* cmScFolAlloc( cmCtx* c, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
|
32
|
|
-{
|
33
|
|
- cmScFol* op = cmObjAlloc(cmScFol,c,p);
|
34
|
|
- if( srate != 0 )
|
35
|
|
- if( cmScFolInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC )
|
36
|
|
- cmScFolFree(&op);
|
37
|
|
- return op;
|
38
|
|
-}
|
39
|
|
-
|
40
|
|
-cmRC_t cmScFolFree( cmScFol** pp )
|
41
|
|
-{
|
42
|
|
- cmRC_t rc = cmOkRC;
|
43
|
|
- if( pp==NULL || *pp==NULL )
|
44
|
|
- return rc;
|
45
|
|
-
|
46
|
|
- cmScFol* p = *pp;
|
47
|
|
- if((rc = cmScFolFinal(p)) != cmOkRC )
|
48
|
|
- return rc;
|
49
|
|
-
|
50
|
|
- unsigned i;
|
51
|
|
- for(i=0; i<p->locN; ++i)
|
52
|
|
- cmMemFree(p->loc[i].evtV);
|
53
|
|
-
|
54
|
|
- cmMemFree(p->loc);
|
55
|
|
- cmMemFree(p->bufV);
|
56
|
|
- cmObjFree(pp);
|
57
|
|
- return rc;
|
58
|
|
-}
|
59
|
|
-
|
60
|
|
-
|
61
|
|
-cmRC_t cmScFolFinal( cmScFol* p )
|
62
|
|
-{
|
63
|
|
- cmMemFree(p->edWndMtx);
|
64
|
|
- return cmOkRC;
|
65
|
|
-}
|
66
|
|
-
|
67
|
|
-void _cmScFolPrint( cmScFol* p )
|
68
|
|
-{
|
69
|
|
- int i,j;
|
70
|
|
- for(i=0; i<p->locN; ++i)
|
71
|
|
- {
|
72
|
|
- printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx);
|
73
|
|
- for(j=0; j<p->loc[i].evtCnt; ++j)
|
74
|
|
- printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0));
|
75
|
|
- printf("\n");
|
76
|
|
- }
|
77
|
|
-}
|
78
|
|
-
|
79
|
|
-unsigned* _cmScFolAllocEditDistMtx(unsigned maxN)
|
80
|
|
-{
|
81
|
|
- maxN += 1;
|
82
|
|
-
|
83
|
|
- unsigned* m = cmMemAllocZ(unsigned,maxN*maxN);
|
84
|
|
- unsigned* p = m;
|
85
|
|
- unsigned i;
|
86
|
|
-
|
87
|
|
- // initialize the comparison matrix with the default costs in the
|
88
|
|
- // first row and column
|
89
|
|
- // (Note that this matrix is not oriented in column major order like most 'cm' matrices.)
|
90
|
|
- for(i=0; i<maxN; ++i)
|
91
|
|
- {
|
92
|
|
- p[i] = i; // 0th row
|
93
|
|
- p[ i * maxN ] = i; // 0th col
|
94
|
|
- }
|
95
|
|
-
|
96
|
|
- return m;
|
97
|
|
-}
|
98
|
|
-
|
99
|
|
-cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
|
100
|
|
-{
|
101
|
|
- cmRC_t rc;
|
102
|
|
- if((rc = cmScFolFinal(p)) != cmOkRC )
|
103
|
|
- return rc;
|
104
|
|
-
|
105
|
|
- if( bufN > maxWndCnt )
|
106
|
|
- return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower buffer count (%i) must be less than the max. window length (%i).",bufN,maxWndCnt );
|
107
|
|
-
|
108
|
|
- if( minWndLookAhead > maxWndCnt )
|
109
|
|
- return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt);
|
110
|
|
-
|
111
|
|
- p->srate = srate;
|
112
|
|
- p->scH = scH;
|
113
|
|
- p->bufN = bufN;
|
114
|
|
- p->bufV = cmMemResizeZ(cmScFolBufEle_t,p->bufV,bufN);
|
115
|
|
- p->locN = cmScoreEvtCount(scH);
|
116
|
|
- p->loc = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
|
117
|
|
- p->sbi = cmInvalidIdx;
|
118
|
|
- p->sei = cmInvalidIdx;
|
119
|
|
- p->msln = minWndLookAhead;
|
120
|
|
- p->mswn = maxWndCnt;
|
121
|
|
- p->forwardCnt = 2;
|
122
|
|
- p->maxDist = 4;
|
123
|
|
- p->edWndMtx = _cmScFolAllocEditDistMtx(p->bufN);
|
124
|
|
- p->minVel = minVel;
|
125
|
|
- p->printFl = true;
|
126
|
|
- p->noBackFl = true;
|
127
|
|
- p->missCnt = 0;
|
128
|
|
- p->matchCnt = 0;
|
129
|
|
- p->eventIdx = 0;
|
130
|
|
- p->skipCnt = 0;
|
131
|
|
- p->ret_idx = cmInvalidIdx;
|
132
|
|
-
|
133
|
|
- // for each score location
|
134
|
|
- unsigned li,ei;
|
135
|
|
-
|
136
|
|
- for(li=0,ei=0; li<cmScoreLocCount(p->scH); ++li)
|
137
|
|
- {
|
138
|
|
- unsigned i,n;
|
139
|
|
-
|
140
|
|
- const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
|
141
|
|
-
|
142
|
|
- // count the number of note events at location li
|
143
|
|
- for(n=0,i=0; i<lp->evtCnt; ++i)
|
144
|
|
- if( lp->evtArray[i]->type == kNonEvtScId )
|
145
|
|
- ++n;
|
146
|
|
-
|
147
|
|
- assert( ei+n <= p->locN );
|
148
|
|
-
|
149
|
|
- // duplicate each note at location li n times
|
150
|
|
- for(i=0; i<n; ++i)
|
151
|
|
- {
|
152
|
|
- unsigned j,k;
|
153
|
|
-
|
154
|
|
- p->loc[ei+i].evtCnt = n;
|
155
|
|
- p->loc[ei+i].evtV = cmMemAllocZ(cmScFolEvt_t,n);
|
156
|
|
- p->loc[ei+i].scIdx = li;
|
157
|
|
- p->loc[ei+i].barNumb = lp->barNumb;
|
158
|
|
- for(j=0,k=0; j<lp->evtCnt; ++j)
|
159
|
|
- if( lp->evtArray[j]->type == kNonEvtScId )
|
160
|
|
- {
|
161
|
|
- p->loc[ei+i].evtV[k].pitch = lp->evtArray[j]->pitch;
|
162
|
|
- p->loc[ei+i].evtV[k].scEvtIdx = lp->evtArray[j]->index;
|
163
|
|
- ++k;
|
164
|
|
- }
|
165
|
|
-
|
166
|
|
- }
|
167
|
|
-
|
168
|
|
- ei += n;
|
169
|
|
-
|
170
|
|
- }
|
171
|
|
-
|
172
|
|
- p->locN = ei;
|
173
|
|
-
|
174
|
|
- //_cmScFolPrint(p);
|
175
|
|
-
|
176
|
|
- return rc;
|
177
|
|
-}
|
178
|
|
-
|
179
|
|
-cmRC_t cmScFolReset( cmScFol* p, unsigned scEvtIdx )
|
180
|
|
-{
|
181
|
|
- int i,j;
|
182
|
|
-
|
183
|
|
- // empty the event buffer
|
184
|
|
- memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN);
|
185
|
|
-
|
186
|
|
- // don't allow the score index to be prior to the first note
|
187
|
|
- //if( scEvtIdx < p->loc[0].scIdx )
|
188
|
|
- // scEvtIdx = p->loc[0].scIdx;
|
189
|
|
-
|
190
|
|
- p->sei = cmInvalidIdx;
|
191
|
|
- p->sbi = cmInvalidIdx;
|
192
|
|
- p->missCnt = 0;
|
193
|
|
- p->matchCnt = 0;
|
194
|
|
- p->eventIdx = 0;
|
195
|
|
- p->skipCnt = 0;
|
196
|
|
- p->ret_idx = cmInvalidIdx;
|
197
|
|
-
|
198
|
|
- // locate the score element in svV[] that is closest to,
|
199
|
|
- // and possibly after, scEvtIdx.
|
200
|
|
- for(i=0; i<p->locN-1; ++i)
|
201
|
|
- {
|
202
|
|
- for(j=0; j<p->loc[i].evtCnt; ++j)
|
203
|
|
- if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx )
|
204
|
|
- p->sbi = i;
|
205
|
|
- else
|
206
|
|
- break;
|
207
|
|
- }
|
208
|
|
-
|
209
|
|
- // locate the score element at the end of the look-ahead region
|
210
|
|
- for(; i<p->locN; ++i)
|
211
|
|
- {
|
212
|
|
- for(j=0; j<p->loc[i].evtCnt; ++j)
|
213
|
|
- if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx + p->msln )
|
214
|
|
- p->sei = i;
|
215
|
|
- }
|
216
|
|
-
|
217
|
|
- return cmOkRC;
|
218
|
|
-}
|
219
|
|
-
|
220
|
|
-bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
|
221
|
|
-{
|
222
|
|
- unsigned i;
|
223
|
|
- for(i=0; i<loc->evtCnt; ++i)
|
224
|
|
- if( loc->evtV[i].pitch == pitch )
|
225
|
|
- return true;
|
226
|
|
- return false;
|
227
|
|
-}
|
228
|
|
-
|
229
|
|
-int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const cmScFolBufEle_t* pitch, unsigned pi )
|
230
|
|
-{
|
231
|
|
- if( _cmScFolIsMatch(loc+li,pitch[pi].val) )
|
232
|
|
- return 0;
|
233
|
|
-
|
234
|
|
- if( li>0 && pi>0 )
|
235
|
|
- if( _cmScFolIsMatch(loc+li-1,pitch[pi].val) && _cmScFolIsMatch(loc+li,pitch[pi-1].val) )
|
236
|
|
- return 0;
|
237
|
|
-
|
238
|
|
- return 1;
|
239
|
|
-}
|
240
|
|
-
|
241
|
|
-int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const cmScFolBufEle_t* s1, const cmScFolLoc_t* s0, int n )
|
242
|
|
-{
|
243
|
|
- mtxMaxN += 1;
|
244
|
|
-
|
245
|
|
- assert( n < mtxMaxN );
|
246
|
|
-
|
247
|
|
- int v = 0;
|
248
|
|
- unsigned i;
|
249
|
|
- // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices.
|
250
|
|
-
|
251
|
|
- for(i=1; i<n+1; ++i)
|
252
|
|
- {
|
253
|
|
- unsigned ii = i * mtxMaxN; // current row
|
254
|
|
- unsigned i_1 = ii - mtxMaxN; // previous row
|
255
|
|
- unsigned j;
|
256
|
|
- for( j=1; j<n+1; ++j)
|
257
|
|
- {
|
258
|
|
- //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
|
259
|
|
- //int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
|
260
|
|
- int cost = _cmScFolMatchCost(s0,i-1,s1,j-1);
|
261
|
|
-
|
262
|
|
- //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
|
263
|
|
-
|
264
|
|
- m[ ii + j ] = v = cmMin( m[ i_1 + j] + 1, cmMin( m[ ii + j - 1] + 1, m[ i_1 + j - 1 ] + cost ) );
|
265
|
|
- }
|
266
|
|
- }
|
267
|
|
- return v;
|
268
|
|
-}
|
269
|
|
-
|
270
|
|
-void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, const cmScFolBufEle_t* b, unsigned bn, unsigned min_idx )
|
271
|
|
-{
|
272
|
|
- unsigned i;
|
273
|
|
- int n;
|
274
|
|
-
|
275
|
|
- printf("--------------- event:%i ------------- \n",p->eventIdx);
|
276
|
|
-
|
277
|
|
- printf("loc: ");
|
278
|
|
- for(i=0; i<locN; ++i)
|
279
|
|
- printf("%4i ",i+locIdx);
|
280
|
|
- printf("\n");
|
281
|
|
-
|
282
|
|
- for(n=0,i=0; i<locN; ++i)
|
283
|
|
- if( p->loc[locIdx+i].evtCnt > n )
|
284
|
|
- n = p->loc[locIdx+i].evtCnt;
|
285
|
|
-
|
286
|
|
- --n;
|
287
|
|
- for(; n>=0; --n)
|
288
|
|
- {
|
289
|
|
- printf("sc%1i: ",n);
|
290
|
|
- for(i=0; i<locN; ++i)
|
291
|
|
- {
|
292
|
|
- if( n < p->loc[locIdx+i].evtCnt )
|
293
|
|
- printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].evtV[n].pitch,NULL,0));
|
294
|
|
- else
|
295
|
|
- printf(" ");
|
296
|
|
- }
|
297
|
|
- printf("\n");
|
298
|
|
- }
|
299
|
|
-
|
300
|
|
- printf("perf:");
|
301
|
|
- for(i=0; i<min_idx; ++i)
|
302
|
|
- printf(" ");
|
303
|
|
-
|
304
|
|
- for(i=0; i<bn; ++i)
|
305
|
|
- printf("%4s ",cmMidiToSciPitch(b[i].val,NULL,0));
|
306
|
|
-
|
307
|
|
- printf("\n");
|
308
|
|
-}
|
309
|
|
-
|
310
|
|
-void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
|
311
|
|
-{
|
312
|
|
- printf("dist:%i miss:%i match:%i skip:%i vel:%i ",minDist,missCnt,matchCnt,p->skipCnt,d1);
|
313
|
|
- if( ret_idx != cmInvalidIdx )
|
314
|
|
- printf("ret_idx:%i ",ret_idx);
|
315
|
|
- printf("\n");
|
316
|
|
-}
|
317
|
|
-
|
318
|
|
-unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
|
319
|
|
-{
|
320
|
|
- unsigned ret_idx = cmInvalidIdx;
|
321
|
|
-
|
322
|
|
- if( p->sbi == cmInvalidIdx )
|
323
|
|
- {
|
324
|
|
- cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." );
|
325
|
|
- return ret_idx;
|
326
|
|
- }
|
327
|
|
-
|
328
|
|
- if( (status&0xf0) != kNoteOnMdId )
|
329
|
|
- return ret_idx;
|
330
|
|
-
|
331
|
|
- ++p->eventIdx;
|
332
|
|
-
|
333
|
|
- // reject notes with very low velocity
|
334
|
|
- if( d1 < p->minVel )
|
335
|
|
- {
|
336
|
|
- ++p->skipCnt;
|
337
|
|
- return ret_idx;
|
338
|
|
- }
|
339
|
|
-
|
340
|
|
- // left shift bufV[] to make the right-most element available - then copy in the new element
|
341
|
|
- memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
|
342
|
|
- p->bufV[ p->bufN-1 ].smpIdx = smpIdx;
|
343
|
|
- p->bufV[ p->bufN-1 ].val = d0;
|
344
|
|
- p->bufV[ p->bufN-1 ].validFl= true;
|
345
|
|
-
|
346
|
|
- // fill in ebuf[] with the valid values in bufV[]
|
347
|
|
- int en = cmMin(p->eventIdx,p->bufN);
|
348
|
|
- int bbi = p->eventIdx>=p->bufN ? 0 : p->bufN-p->eventIdx;
|
349
|
|
-
|
350
|
|
-
|
351
|
|
- // en is the count of valid elements in ebuf[].
|
352
|
|
- // ebuf[p->boi] is the first valid element
|
353
|
|
-
|
354
|
|
- int j = 0;
|
355
|
|
- int minDist = INT_MAX;
|
356
|
|
- int minIdx = cmInvalidIdx;
|
357
|
|
- int dist;
|
358
|
|
-
|
359
|
|
- // the score wnd must always be as long as the buffer n
|
360
|
|
- // at the end of the score this may not be the case
|
361
|
|
- // (once sei hits locN - at this point we must begin
|
362
|
|
- // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements)
|
363
|
|
- assert( p->sei-p->sbi+1 >= en );
|
364
|
|
-
|
365
|
|
- for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
|
366
|
|
- {
|
367
|
|
- // use <= minDist to choose the latest window with the lowest match
|
368
|
|
- if((dist = _cmScFolDist(p->bufN, p->edWndMtx, p->bufV+bbi, p->loc + p->sbi+j, en )) < minDist )
|
369
|
|
- {
|
370
|
|
- // only make an eql match if the posn is greater than the last location
|
371
|
|
- if( dist==minDist && p->ret_idx != cmInvalidId && p->ret_idx >= p->sbi+minIdx+en-1 )
|
372
|
|
- continue;
|
373
|
|
-
|
374
|
|
- minDist = dist;
|
375
|
|
- minIdx = j;
|
376
|
|
- }
|
377
|
|
- }
|
378
|
|
-
|
379
|
|
- // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
|
380
|
|
-
|
381
|
|
- if( p->printFl )
|
382
|
|
- _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, p->bufV+bbi, en, minIdx );
|
383
|
|
-
|
384
|
|
- // save current missCnt for later printing
|
385
|
|
- unsigned missCnt = p->missCnt;
|
386
|
|
-
|
387
|
|
- // if a perfect match occurred
|
388
|
|
- if( minDist == 0 )
|
389
|
|
- {
|
390
|
|
- ret_idx = p->sbi + minIdx + en - 1;
|
391
|
|
- p->missCnt = 0;
|
392
|
|
-
|
393
|
|
- // we had a perfect match - shrink the window to it's minumum size
|
394
|
|
- p->sbi += (en==p->bufN) ? minIdx + 1 : 0; // move wnd begin forward to just past first match
|
395
|
|
- p->sei = p->sbi + minIdx + en + p->msln; // move wnd end forward to lead by the min look-ahead
|
396
|
|
-
|
397
|
|
-
|
398
|
|
- }
|
399
|
|
- else
|
400
|
|
- {
|
401
|
|
- if( minDist > p->maxDist )
|
402
|
|
- ret_idx = cmInvalidIdx;
|
403
|
|
- else
|
404
|
|
- // if the last event matched - then return the match location as the current score location
|
405
|
|
- if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),p->bufV[p->bufN-1].val) )
|
406
|
|
- {
|
407
|
|
- ret_idx = p->sbi + minIdx + en - 1;
|
408
|
|
- p->missCnt = 0;
|
409
|
|
-
|
410
|
|
- // this is probably a pretty good match reduce the part of the window prior to
|
411
|
|
- // the first match (bring the end of the window almost up to the end of the
|
412
|
|
- // buffers sync position)
|
413
|
|
- if( en >= p->bufN-1 && (en+2) <= ret_idx )
|
414
|
|
- p->sbi = ret_idx - (en+2);
|
415
|
|
-
|
416
|
|
- }
|
417
|
|
- else // the last event does not match based on the optimal edit-distance alignment
|
418
|
|
- {
|
419
|
|
- // Look backward from the closest match location for a match to the current pitch.
|
420
|
|
- // The backward search scope is limited by the current value of 'missCnt'.
|
421
|
|
- unsigned i;
|
422
|
|
- j = p->sbi+minIdx+en-2;
|
423
|
|
- for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
|
424
|
|
- {
|
425
|
|
- // if this look-back location already matched then stop the backward search
|
426
|
|
- if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1-i].val))
|
427
|
|
- break;
|
428
|
|
-
|
429
|
|
- // does this look-back location match the current pitch
|
430
|
|
- if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val))
|
431
|
|
- {
|
432
|
|
- ret_idx = j;
|
433
|
|
- p->missCnt = i; // set missCnt to the cnt of steps backward necessary for a match
|
434
|
|
- break;
|
435
|
|
- }
|
436
|
|
- }
|
437
|
|
-
|
438
|
|
- // If the backward search did not find a match - look forward
|
439
|
|
- if( ret_idx == cmInvalidIdx )
|
440
|
|
- {
|
441
|
|
- unsigned i;
|
442
|
|
- j = p->sbi+minIdx+en;
|
443
|
|
- for(i=0; j<=p->sei && i<p->forwardCnt; ++i,++j)
|
444
|
|
- if( _cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val) )
|
445
|
|
- {
|
446
|
|
- ret_idx = j;
|
447
|
|
- break;
|
448
|
|
- }
|
449
|
|
-
|
450
|
|
- p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0;
|
451
|
|
- }
|
452
|
|
-
|
453
|
|
- }
|
454
|
|
-
|
455
|
|
- // Adjust the end window position (sei) based on the match location
|
456
|
|
- if( ret_idx == cmInvalidIdx )
|
457
|
|
- {
|
458
|
|
- // even though we didn't match move the end of the score window forward
|
459
|
|
- // this will enlarge the score window by one
|
460
|
|
- p->sei += 1;
|
461
|
|
- }
|
462
|
|
- else
|
463
|
|
- {
|
464
|
|
- assert( p->sei>=ret_idx);
|
465
|
|
-
|
466
|
|
- // force sei to lead by min look-ahead
|
467
|
|
- if( p->sei - ret_idx < p->msln )
|
468
|
|
- p->sei = ret_idx + p->msln;
|
469
|
|
-
|
470
|
|
- }
|
471
|
|
-
|
472
|
|
- assert( p->sei > p->sbi );
|
473
|
|
-
|
474
|
|
- // Adjust the begin window position
|
475
|
|
- if( p->noBackFl && ret_idx != cmInvalidIdx && en>=p->bufN && p->sbi > p->bufN )
|
476
|
|
- p->sbi = ret_idx - p->bufN;
|
477
|
|
-
|
478
|
|
- // if the score window length surpasses the max score window size
|
479
|
|
- // move the beginning index forward
|
480
|
|
- if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
|
481
|
|
- p->sbi = p->sei - p->mswn + 1;
|
482
|
|
-
|
483
|
|
-
|
484
|
|
- }
|
485
|
|
-
|
486
|
|
- if( p->printFl )
|
487
|
|
- _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
|
488
|
|
-
|
489
|
|
- // don't allow the returned location to repeat or go backwards
|
490
|
|
- if( p->noBackFl && p->ret_idx != cmInvalidIdx && ret_idx <= p->ret_idx )
|
491
|
|
- ret_idx = cmInvalidIdx;
|
492
|
|
-
|
493
|
|
-
|
494
|
|
- // track the number of consecutive matches
|
495
|
|
- if( ret_idx == cmInvalidIdx )
|
496
|
|
- p->matchCnt = 0;
|
497
|
|
- else
|
498
|
|
- {
|
499
|
|
- ++p->matchCnt;
|
500
|
|
-
|
501
|
|
- p->ret_idx = ret_idx;
|
502
|
|
- }
|
503
|
|
-
|
504
|
|
- // Force the window to remain valid when it is at the end of the score
|
505
|
|
- // - sbi and sei must be inside 0:locN
|
506
|
|
- // - sei-sbi + 1 must be >= en
|
507
|
|
- if( p->sei >= p->locN )
|
508
|
|
- {
|
509
|
|
- p->sei = p->locN - 1;
|
510
|
|
- p->sbi = p->sei - p->bufN + 1;
|
511
|
|
- }
|
512
|
|
-
|
513
|
|
- if( ret_idx != cmInvalidIdx )
|
514
|
|
- ret_idx = p->loc[ret_idx].scIdx;
|
515
|
|
-
|
516
|
|
- return ret_idx;
|
517
|
|
-}
|
518
|
|
-
|
519
|
|
-
|
520
|
|
-
|
521
|
|
-//=======================================================================================================================
|
522
|
|
-
|
523
|
|
-cmScTrk* cmScTrkAlloc( cmCtx* c, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
|
524
|
|
-{
|
525
|
|
- cmScTrk* op = cmObjAlloc(cmScTrk,c,p);
|
526
|
|
-
|
527
|
|
- op->sfp = cmScFolAlloc(c,NULL,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel);
|
528
|
|
-
|
529
|
|
- if( srate != 0 )
|
530
|
|
- if( cmScTrkInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC )
|
531
|
|
- cmScTrkFree(&op);
|
532
|
|
- return op;
|
533
|
|
-}
|
534
|
|
-
|
535
|
|
-cmRC_t cmScTrkFree( cmScTrk** pp )
|
536
|
|
-{
|
537
|
|
- cmRC_t rc = cmOkRC;
|
538
|
|
- if( pp==NULL || *pp==NULL )
|
539
|
|
- return rc;
|
540
|
|
-
|
541
|
|
- cmScTrk* p = *pp;
|
542
|
|
- if((rc = cmScTrkFinal(p)) != cmOkRC )
|
543
|
|
- return rc;
|
544
|
|
-
|
545
|
|
- cmScFolFree(&p->sfp);
|
546
|
|
-
|
547
|
|
- cmObjFree(pp);
|
548
|
|
- return rc;
|
549
|
|
-
|
550
|
|
-}
|
551
|
|
-
|
552
|
|
-void _cmScTrkPrint( cmScTrk* p )
|
553
|
|
-{
|
554
|
|
- int i,j;
|
555
|
|
- for(i=0; i<p->locN; ++i)
|
556
|
|
- {
|
557
|
|
- printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx);
|
558
|
|
- for(j=0; j<p->loc[i].evtCnt; ++j)
|
559
|
|
- printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0));
|
560
|
|
- printf("\n");
|
561
|
|
- }
|
562
|
|
-}
|
563
|
|
-
|
564
|
|
-cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
|
565
|
|
-{
|
566
|
|
- cmRC_t rc;
|
567
|
|
- if((rc = cmScTrkFinal(p)) != cmOkRC )
|
568
|
|
- return rc;
|
569
|
|
-
|
570
|
|
- if( minWndLookAhead > maxWndCnt )
|
571
|
|
- return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt);
|
572
|
|
-
|
573
|
|
- if((rc = cmScFolInit(p->sfp,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel)) != cmOkRC )
|
574
|
|
- return rc;
|
575
|
|
-
|
576
|
|
- p->srate = srate;
|
577
|
|
- p->scH = scH;
|
578
|
|
- p->locN = cmScoreLocCount(scH);
|
579
|
|
- p->loc = cmMemResizeZ(cmScTrkLoc_t,p->loc,p->locN);
|
580
|
|
- p->minVel = minVel;
|
581
|
|
- p->maxWndCnt = maxWndCnt;
|
582
|
|
- p->minWndLookAhead= 4; //minWndLookAhead;
|
583
|
|
- p->printFl = true;
|
584
|
|
- p->curLocIdx = cmInvalidIdx;
|
585
|
|
- p->evtIndex = 0;
|
586
|
|
-
|
587
|
|
- // for each score location
|
588
|
|
- unsigned li;
|
589
|
|
-
|
590
|
|
- for(li=0; li<cmScoreLocCount(p->scH); ++li)
|
591
|
|
- {
|
592
|
|
- unsigned i,j,k,n;
|
593
|
|
-
|
594
|
|
- const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
|
595
|
|
-
|
596
|
|
- // count the number of note events at location li
|
597
|
|
- for(n=0,i=0; i<lp->evtCnt; ++i)
|
598
|
|
- if( lp->evtArray[i]->type == kNonEvtScId )
|
599
|
|
- ++n;
|
600
|
|
-
|
601
|
|
- p->loc[li].evtCnt = n;
|
602
|
|
- p->loc[li].evtV = cmMemAllocZ(cmScTrkEvt_t,n);
|
603
|
|
- p->loc[li].scIdx = li;
|
604
|
|
- p->loc[li].barNumb = lp->barNumb;
|
605
|
|
- for(j=0,k=0; j<lp->evtCnt; ++j)
|
606
|
|
- if( lp->evtArray[j]->type == kNonEvtScId )
|
607
|
|
- {
|
608
|
|
- p->loc[li].evtV[k].pitch = lp->evtArray[j]->pitch;
|
609
|
|
- p->loc[li].evtV[k].scEvtIdx = lp->evtArray[j]->index;
|
610
|
|
- ++k;
|
611
|
|
- }
|
612
|
|
- }
|
613
|
|
-
|
614
|
|
- //_cmScTrkPrint(p);
|
615
|
|
-
|
616
|
|
- return rc;
|
617
|
|
-}
|
618
|
|
-
|
619
|
|
-cmRC_t cmScTrkFinal( cmScTrk* p )
|
620
|
|
-{
|
621
|
|
- unsigned i;
|
622
|
|
- for(i=0; i<p->locN; ++i)
|
623
|
|
- cmMemPtrFree(&p->loc[i].evtV);
|
624
|
|
-
|
625
|
|
- return cmOkRC;
|
626
|
|
-}
|
627
|
|
-
|
628
|
|
-cmRC_t cmScTrkReset( cmScTrk* p, unsigned scEvtIdx )
|
629
|
|
-{
|
630
|
|
- unsigned i;
|
631
|
|
-
|
632
|
|
- cmScFolReset(p->sfp,scEvtIdx);
|
633
|
|
-
|
634
|
|
- p->curLocIdx = cmInvalidIdx;
|
635
|
|
- p->evtIndex = 0;
|
636
|
|
-
|
637
|
|
-
|
638
|
|
- // locate the score element in svV[] that is closest to,
|
639
|
|
- // and possibly after, scEvtIdx.
|
640
|
|
- for(i=0; i<p->locN; ++i)
|
641
|
|
- {
|
642
|
|
- unsigned j;
|
643
|
|
-
|
644
|
|
- for(j=0; j<p->loc[i].evtCnt; ++j)
|
645
|
|
- {
|
646
|
|
- p->loc[i].evtV[j].matchFl = false;
|
647
|
|
-
|
648
|
|
- // it is possible that scEvtIdx is before the first event included in p->loc[0]
|
649
|
|
- // using the p->curLocIdx==cmInvalidIdx forces the first evt in p->loc[0] to be
|
650
|
|
- // selected in this case
|
651
|
|
- if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx || p->curLocIdx==cmInvalidIdx )
|
652
|
|
- p->curLocIdx = i;
|
653
|
|
- }
|
654
|
|
- }
|
655
|
|
-
|
656
|
|
- if( p->curLocIdx == cmInvalidIdx )
|
657
|
|
- return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial score search location event %i was not found.", scEvtIdx );
|
658
|
|
-
|
659
|
|
- return cmOkRC;
|
660
|
|
-}
|
661
|
|
-
|
662
|
|
-unsigned _cmScTrkIsMatch(cmScTrk* p, int d, unsigned pitch )
|
663
|
|
-{
|
664
|
|
- if( 0 <= p->curLocIdx + d && p->curLocIdx+1 < p->locN )
|
665
|
|
- {
|
666
|
|
- unsigned i;
|
667
|
|
- const cmScTrkLoc_t* lp = p->loc + p->curLocIdx + d;
|
668
|
|
- for(i=0; i<lp->evtCnt; ++i)
|
669
|
|
- if( lp->evtV[i].pitch == pitch && lp->evtV[i].matchFl==false)
|
670
|
|
- return i;
|
671
|
|
- }
|
672
|
|
- return cmInvalidIdx;
|
673
|
|
-}
|
674
|
|
-
|
675
|
|
-void _cmScTrkRpt0( cmScTrk* p, unsigned pitch, unsigned vel, unsigned nli, unsigned nei )
|
676
|
|
-{
|
677
|
|
- bool missFl = nli==cmInvalidIdx || nei==cmInvalidIdx;
|
678
|
|
-
|
679
|
|
- printf("------- event:%i %s vel:%i cur:%i new:%i %s-------\n",p->evtIndex,cmMidiToSciPitch(pitch,NULL,0),vel,p->curLocIdx,nli,missFl?"MISS ":"");
|
680
|
|
-
|
681
|
|
- int bi = p->curLocIdx < p->minWndLookAhead ? 0 : p->curLocIdx - p->minWndLookAhead;
|
682
|
|
- int ei = cmMin(p->locN-1,p->curLocIdx+p->minWndLookAhead);
|
683
|
|
- unsigned i,n=0;
|
684
|
|
- for(i=bi; i<=ei; ++i)
|
685
|
|
- if( p->loc[i].evtCnt>n )
|
686
|
|
- n = p->loc[i].evtCnt;
|
687
|
|
-
|
688
|
|
- printf("loc ");
|
689
|
|
- for(i=bi; i<=ei; ++i)
|
690
|
|
- printf("%4i ",i);
|
691
|
|
- printf("\n");
|
692
|
|
-
|
693
|
|
- for(i=0; i<n; ++i)
|
694
|
|
- {
|
695
|
|
- unsigned j;
|
696
|
|
- printf("sc%2i ",i);
|
697
|
|
- for(j=bi; j<=ei; ++j)
|
698
|
|
- {
|
699
|
|
- if( i < p->loc[j].evtCnt )
|
700
|
|
- {
|
701
|
|
- char* X = p->loc[j].evtV[i].matchFl ? "__" : " ";
|
702
|
|
-
|
703
|
|
- if( nli==j && nei==i)
|
704
|
|
- {
|
705
|
|
- X = "**";
|
706
|
|
- assert( p->loc[j].evtV[i].pitch == pitch );
|
707
|
|
- }
|
708
|
|
-
|
709
|
|
- printf("%4s%s ",cmMidiToSciPitch(p->loc[j].evtV[i].pitch,NULL,0),X);
|
710
|
|
- }
|
711
|
|
- else
|
712
|
|
- printf(" ");
|
713
|
|
- }
|
714
|
|
- printf("\n");
|
715
|
|
- }
|
716
|
|
-
|
717
|
|
-}
|
718
|
|
-
|
719
|
|
-
|
720
|
|
-unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
|
721
|
|
-{
|
722
|
|
- unsigned ret_idx = cmInvalidIdx;
|
723
|
|
-
|
724
|
|
- //cmScFolExec(p->sfp, smpIdx, status, d0, d1);
|
725
|
|
-
|
726
|
|
- if( (status&0xf0) != kNoteOnMdId )
|
727
|
|
- return cmInvalidIdx;
|
728
|
|
-
|
729
|
|
- if( p->curLocIdx == cmInvalidIdx )
|
730
|
|
- {
|
731
|
|
- cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." );
|
732
|
|
- return cmInvalidIdx;
|
733
|
|
- }
|
734
|
|
-
|
735
|
|
- int i,nei,nli=cmInvalidIdx;
|
736
|
|
-
|
737
|
|
- // try to match curLocIdx first
|
738
|
|
- if((nei = _cmScTrkIsMatch(p,0,d0)) != cmInvalidIdx )
|
739
|
|
- nli = p->curLocIdx;
|
740
|
|
-
|
741
|
|
- for(i=1; nei==cmInvalidIdx && i<p->minWndLookAhead; ++i)
|
742
|
|
- {
|
743
|
|
- // go forward
|
744
|
|
- if((nei = _cmScTrkIsMatch(p,i,d0)) != cmInvalidIdx )
|
745
|
|
- nli = p->curLocIdx + i;
|
746
|
|
- else
|
747
|
|
- // go backward
|
748
|
|
- if((nei = _cmScTrkIsMatch(p,-i,d0)) != cmInvalidIdx )
|
749
|
|
- nli = p->curLocIdx - i;
|
750
|
|
- }
|
751
|
|
-
|
752
|
|
- if( p->printFl )
|
753
|
|
- {
|
754
|
|
- _cmScTrkRpt0(p, d0, d1, nli, nei );
|
755
|
|
- }
|
756
|
|
-
|
757
|
|
-
|
758
|
|
- if( nli != cmInvalidIdx )
|
759
|
|
- {
|
760
|
|
- p->loc[nli].evtV[nei].matchFl = true;
|
761
|
|
- ret_idx = p->loc[nli].scIdx;
|
762
|
|
-
|
763
|
|
- if( nli > p->curLocIdx )
|
764
|
|
- p->curLocIdx = nli;
|
765
|
|
-
|
766
|
|
- }
|
767
|
|
-
|
768
|
|
- ++p->evtIndex;
|
769
|
|
-
|
770
|
|
- return ret_idx;
|
771
|
|
-}
|
772
|
|
-
|
773
|
30
|
//=======================================================================================================================
|
774
|
31
|
//----------------------------------------------------------------------------------------
|
775
|
32
|
void ed_print_mtx( ed_r* r)
|