|
@@ -196,7 +196,156 @@ void ed_free(ed_r* r);
|
196
|
196
|
|
197
|
197
|
// Main test function.
|
198
|
198
|
void ed_main();
|
|
199
|
+
|
199
|
200
|
//=======================================================================================================================
|
|
201
|
+enum
|
|
202
|
+{
|
|
203
|
+ kSmMinIdx,
|
|
204
|
+ kSmSubIdx, // 'substitute' - may or may not match
|
|
205
|
+ kSmDelIdx, // 'delete' - delete a MIDI note
|
|
206
|
+ kSmInsIdx, // 'insert' - insert a space in the score
|
|
207
|
+ kSmCnt
|
|
208
|
+};
|
|
209
|
+
|
|
210
|
+enum
|
|
211
|
+{
|
|
212
|
+ kSmMatchFl = 0x01,
|
|
213
|
+ kSmTransFl = 0x02
|
|
214
|
+};
|
|
215
|
+
|
|
216
|
+// Dynamic Programming (DP) matrix element
|
|
217
|
+typedef struct
|
|
218
|
+{
|
|
219
|
+ unsigned v[kSmCnt]; //
|
|
220
|
+ unsigned flags;
|
|
221
|
+} cmScMatchVal_t;
|
|
222
|
+
|
|
223
|
+// List record used to track a path through the DP matrix p->m[,]
|
|
224
|
+typedef struct cmScMatchPath_str
|
|
225
|
+{
|
|
226
|
+ unsigned code;
|
|
227
|
+ unsigned ri;
|
|
228
|
+ unsigned ci;
|
|
229
|
+ unsigned flags;
|
|
230
|
+ unsigned locIdx;
|
|
231
|
+ struct cmScMatchPath_str* next;
|
|
232
|
+} cmScMatchPath_t;
|
|
233
|
+
|
|
234
|
+typedef struct cmScMatchEvt_str
|
|
235
|
+{
|
|
236
|
+ unsigned pitch;
|
|
237
|
+} cmScMatchEvt_t;
|
|
238
|
+
|
|
239
|
+// Score location record.
|
|
240
|
+typedef struct
|
|
241
|
+{
|
|
242
|
+ unsigned evtCnt; //
|
|
243
|
+ cmScMatchEvt_t* evtV; // evtV[evtCnt]
|
|
244
|
+ unsigned scLocIdx; // scH score location index
|
|
245
|
+ int barNumb; // bar number of this location
|
|
246
|
+} cmScMatchLoc_t;
|
|
247
|
+
|
|
248
|
+typedef struct
|
|
249
|
+{
|
|
250
|
+ cmObj obj;
|
|
251
|
+ cmScH_t scH; //
|
|
252
|
+ unsigned locN; //
|
|
253
|
+ cmScMatchLoc_t* loc; // loc[locN]
|
|
254
|
+ unsigned mrn; // max row count (midi)
|
|
255
|
+ unsigned rn; // cur row count
|
|
256
|
+ unsigned mcn; // max column count (score)
|
|
257
|
+ unsigned cn; // cur column count
|
|
258
|
+ unsigned mmn; // max length of midiBuf[] (mrn-1)
|
|
259
|
+ unsigned msn; // max length of score window (mcn-1)
|
|
260
|
+ cmScMatchVal_t* m; // m[mrn,mcn] DP matrix
|
|
261
|
+ unsigned pn; // mrn+mcn
|
|
262
|
+ cmScMatchPath_t* p_mem; // pmem[ 2*pn ];
|
|
263
|
+ cmScMatchPath_t* p_avl; // available path record linked list
|
|
264
|
+ cmScMatchPath_t* p_cur; // current path linked list
|
|
265
|
+ cmScMatchPath_t* p_opt; // p_opt[pn] current best alignment
|
|
266
|
+ double opt_cost; // p_opt cost set by cmScMatchExec()
|
|
267
|
+} cmScMatch;
|
|
268
|
+
|
|
269
|
+cmScMatch* cmScMatchAlloc( cmCtx* c, cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
|
|
270
|
+cmRC_t cmScMatchFree( cmScMatch** pp );
|
|
271
|
+cmRC_t cmScMatchInit( cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
|
|
272
|
+cmRC_t cmScMatchFinal( cmScMatch* p );
|
|
273
|
+
|
|
274
|
+// Returns cmEofRC if scLocIdx + locN > p->locN - note that this is not necessarily an error.
|
|
275
|
+// The optimal path p_opt[] will only be updated if the edit cost is less than min_cost.
|
|
276
|
+// Set min_cost to DBL_MAX to force p_opt[] to be updated.
|
|
277
|
+cmRC_t cmScMatchExec( cmScMatch* p, unsigned scLocIdx, unsigned locN, const unsigned* midiPitchV, unsigned midiPitchN, double min_cost );
|
|
278
|
+
|
|
279
|
+ //=======================================================================================================================
|
|
280
|
+
|
|
281
|
+ typedef struct
|
|
282
|
+ {
|
|
283
|
+ unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
|
|
284
|
+ unsigned cbCnt; // count of times this event has been sent via the callback
|
|
285
|
+ unsigned mni; // unique identifier for this event since previous call to cmScAlignReset().
|
|
286
|
+ unsigned smpIdx; // time stamp of this event
|
|
287
|
+ unsigned pitch; // MIDI note pitch
|
|
288
|
+ unsigned vel; // " " velocity
|
|
289
|
+ } cmScMatcherMidi_t;
|
|
290
|
+
|
|
291
|
+ typedef struct
|
|
292
|
+ {
|
|
293
|
+ unsigned locIdx;
|
|
294
|
+ unsigned mni;
|
|
295
|
+ unsigned pitch;
|
|
296
|
+ unsigned vel;
|
|
297
|
+ bool tpFl; // true positive
|
|
298
|
+ bool fpFl; // false positive
|
|
299
|
+ } cmScMatcherResult_t;
|
|
300
|
+
|
|
301
|
+ typedef struct
|
|
302
|
+ {
|
|
303
|
+ cmObj obj;
|
|
304
|
+ cmScMatch* mp;
|
|
305
|
+ unsigned mn;
|
|
306
|
+ cmScMatcherMidi_t* midiBuf; // midiBuf[mn]
|
|
307
|
+
|
|
308
|
+ cmScMatcherResult_t* res; // res[rn]
|
|
309
|
+ unsigned rn; // length of res[]
|
|
310
|
+ unsigned ri; // next avail res[] recd.
|
|
311
|
+
|
|
312
|
+ double s_opt; //
|
|
313
|
+ unsigned missCnt; // count of consecutive trailing non-matches
|
|
314
|
+ unsigned esi; // index into loc[] of the last positive match.
|
|
315
|
+ unsigned mni; // track the count of MIDI events since the last call to cmScMatcherReset()
|
|
316
|
+ unsigned mbi; // index of oldest MIDI event in midiBuf[]; 0 when the buffer is full.
|
|
317
|
+ unsigned begSyncLocIdx; // start of score window, in mp->loc[], of best match in previous scan
|
|
318
|
+ unsigned stepCnt; // count of forward/backward score loc's to examine for a match during cmScMatcherStep().
|
|
319
|
+ unsigned maxMissCnt; // max. number of consecutive non-matches during step prior to executing a scan.
|
|
320
|
+ unsigned scanCnt; // count of time scan was executed inside cmScMatcherStep()
|
|
321
|
+} cmScMatcher;
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
|
|
325
|
+cmRC_t cmScMatcherFree( cmScMatcher** pp );
|
|
326
|
+cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
|
|
327
|
+cmRC_t cmScMatcherFinal( cmScMatcher* p );
|
|
328
|
+void cmScMatcherReset( cmScMatcher* p );
|
|
329
|
+bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
|
|
330
|
+
|
|
331
|
+// Slide a score window scanCnt times, beginning at 'bsi',
|
|
332
|
+// looking for the best match to p->midiBuf[]. The score window
|
|
333
|
+// contain scWndN (p->mp->mcn-1) score locations.
|
|
334
|
+// Returns the index into p->mp->loc[] of the start of the best
|
|
335
|
+// match score window. The score associated
|
|
336
|
+// with this match is stored in s_opt.
|
|
337
|
+unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt );
|
|
338
|
+
|
|
339
|
+// Step forward/back by p->stepCnt from p->esi.
|
|
340
|
+// p->esi must therefore be valid prior to calling this function.
|
|
341
|
+// If more than p->maxMissCnt consecutive MIDI events are
|
|
342
|
+// missed then automatically run cmScAlignScan().
|
|
343
|
+// Return cmEofRC if the end of the score is encountered.
|
|
344
|
+// Return cmSubSysFailRC if an internal scan resync. failed.
|
|
345
|
+cmRC_t cmScMatcherStep( cmScMatcher* p );
|
|
346
|
+
|
|
347
|
+cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
|
|
348
|
+
|
200
|
349
|
|
201
|
350
|
|
202
|
351
|
//=======================================================================================================================
|
|
@@ -335,7 +484,7 @@ unsigned cmScAlignScan( cmScAlign* p, unsigned scanCnt );
|
335
|
484
|
// Return cmSubSysFailRC if an internal scan resync. failed.
|
336
|
485
|
cmRC_t cmScAlignStep( cmScAlign* p );
|
337
|
486
|
|
338
|
|
-unsigned cmScAlignScanToTimeLineEvent( cmScAlign* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx );
|
|
487
|
+unsigned cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx );
|
339
|
488
|
|
340
|
489
|
// Given a score, a time-line, and a marker on the time line scan the
|
341
|
490
|
// entire score looking for the best match between the first 'midiN'
|