Browse Source

cmProc4.h: Added ed_xxx edit dist testing functions and cmScAlign class.

master
kevin 11 years ago
parent
commit
78c9c3064b
2 changed files with 1976 additions and 3 deletions
  1. 1756
    2
      cmProc4.c
  2. 220
    1
      cmProc4.h

+ 1756
- 2
cmProc4.c
File diff suppressed because it is too large
View File


+ 220
- 1
cmProc4.h View File

@@ -115,7 +115,226 @@ cmRC_t   cmScTrkReset( cmScTrk* p, unsigned scoreIndex );
115 115
 // Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
116 116
 // all others are ignored.
117 117
 unsigned cmScTrkExec(  cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
118
-  
118
+
119
+//=======================================================================================================================  
120
+//
121
+// Simplified string alignment function based on Levenshtein edit distance.
122
+//
123
+enum { kEdMinIdx, kEdSubIdx, kEdDelIdx, kEdInsIdx, kEdCnt };
124
+
125
+typedef struct
126
+{
127
+  unsigned v[kEdCnt];
128
+  bool     matchFl;
129
+  bool     transFl;
130
+} ed_val;
131
+
132
+typedef struct ed_path_str
133
+{
134
+  unsigned     code;
135
+  unsigned     ri;
136
+  unsigned     ci;
137
+  bool         matchFl;
138
+  bool         transFl;
139
+  struct ed_path_str* next;
140
+} ed_path;
141
+
142
+/*
143
+Backtracking:
144
+m[rn,cn] is organized to indicate the mutation operations 
145
+on s0[0:rn-1] or s1[0:cn-1] during backtracking.  
146
+Backtracking begins at cell m[rn-1,cn-1] and proceeds 
147
+up and left toward m[0,0].  The action to perform during
148
+backtracking is determined by examinging which values
149
+int m[].v[1:3] match m[].v[0]. 
150
+Match                            Next Cell
151
+Index  Operation                 Location
152
+-----  ------------------------  ------------------------
153
+1      Substitute char s0[ri-1]  move diagonally; up-left
154
+2      Delete char s0[ri-1]      move up.
155
+3      Delete char s1[ci-1]      move left.
156
+       (same as inserting blank
157
+       into after s[ri-1]
158
+
159
+Note that more than one value in m[].v[1:3] may match
160
+m[].v[0]. In this case the candidate solution branches
161
+at this point in the candidate selection processes.
162
+*/
163
+typedef struct
164
+{
165
+  const char*    s0;    // forms rows of m[]    - mutate to match s1 - rn=strlen(s0)
166
+  const char*    s1;    // forms columns of m[] - target string      - cn=strlen(s1)
167
+  unsigned       rn;    // length of s0 + 1
168
+  unsigned       cn;    // length of s1 + 1
169
+  ed_val*        m;     // m[rn,cn]   
170
+  unsigned       pn;    // rn+cn
171
+  ed_path*       p_mem; // pmem[ 2*pn ];
172
+  ed_path*       p_avl; // available path record linked list
173
+  ed_path*       p_cur; // current path linked list
174
+  ed_path*       p_opt; // p_opt[pn] current best alignment 
175
+  double         s_opt; // score of the current best alignment
176
+
177
+} ed_r;
178
+
179
+// print the DP matrix ed_r.m[rn,cn].
180
+void ed_print_mtx( ed_r* r );
181
+
182
+// Initialize ed_r.
183
+void ed_init( ed_r* r, const char* s0, const char* s1 );
184
+
185
+// Fill in the DP matrix.
186
+void ed_calc_mtx( ed_r* r );
187
+
188
+// Traverse the possible alignments in the DP matrix and determine the optimal alignment.
189
+void ed_align( ed_r* r );
190
+
191
+// Print the optimal alignment p_opt[]
192
+void ed_print_opt( ed_r* r );
193
+
194
+// Free resource allocated by ed_init().
195
+void ed_free(ed_r* r);
196
+
197
+// Main test function.
198
+void ed_main();
199
+
200
+//=======================================================================================================================
201
+
202
+enum 
203
+{ 
204
+  kSaMinIdx, 
205
+  kSaSubIdx, // 'substitute' - may or may not match
206
+  kSaDelIdx, // 'delete'     - delete a MIDI note 
207
+  kSaInsIdx, // 'insert'     - insert a space in the score 
208
+  kSaCnt 
209
+};
210
+
211
+typedef struct
212
+{
213
+  unsigned v[kSaCnt];
214
+  bool     matchFl;   // if this is a substitute; is it also a match?
215
+  bool     transFl;   // if this is a substitute; is this the second element in a reversed pair?
216
+} cmScAlignVal_t;
217
+
218
+typedef struct cmScAlignPath_str
219
+{
220
+  unsigned                  code;
221
+  unsigned                  ri;
222
+  unsigned                  ci;
223
+  bool                      matchFl;
224
+  bool                      transFl;
225
+  unsigned                  locIdx;
226
+  struct cmScAlignPath_str* next;
227
+} cmScAlignPath_t;
228
+
229
+typedef struct
230
+{
231
+  unsigned pitch;
232
+  unsigned scEvtIdx;
233
+  bool     matchFl;
234
+} cmScAlignScEvt_t;
235
+
236
+typedef struct
237
+{
238
+  unsigned          evtCnt;         // 
239
+  cmScAlignScEvt_t* evtV;           // evtV[evtCnt]
240
+  unsigned          scLocIdx;       // scH score location index
241
+  int               barNumb;        // bar number of this location
242
+} cmScAlignLoc_t;
243
+
244
+typedef struct
245
+{
246
+  unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
247
+  unsigned cbCnt;  // count of times this event has been sent via the callback
248
+  unsigned mni;    // unique identifier for this event since previous call to cmScAlignReset().
249
+  unsigned smpIdx; // time stamp of this event
250
+  unsigned pitch;  // MIDI note pitch
251
+  unsigned vel;    //  "    "   velocity
252
+} cmScAlignMidiEvt_t;
253
+
254
+typedef struct
255
+{
256
+  unsigned locIdx;    // loc[] sync. location    
257
+  unsigned smpIdx;    // 
258
+  unsigned mni;       // MIDI event unique index  
259
+  unsigned pitch;     // MIDI event pitch which may not match the score event pitch
260
+  unsigned vel;       //  "     "   velocity
261
+  bool     matchFl;
262
+  bool     transFl;
263
+  bool     foundFl; 
264
+} cmScAlignResult_t;
265
+
266
+// 
267
+typedef void (*cmScAlignCb_t)( void* cbArg, unsigned scLocIdx, unsigned mni, unsigned pitch, unsigned vel );
268
+
269
+typedef struct
270
+{
271
+  cmObj               obj;
272
+  cmScAlignCb_t       cbFunc;   // 
273
+  void*               cbArg;    // 
274
+  cmScH_t             scH;      // 
275
+  double              srate;    // 
276
+  unsigned            locN;     // length of loc[]
277
+  cmScAlignLoc_t*     loc;      // loc[locN] score array
278
+  unsigned            rn;       // length of midiBuf[]    (mn+1)
279
+  unsigned            cn;       // length of score window (scWndN+1)
280
+  unsigned            mn;       // length of  midiBuf[] (rn-1)
281
+  cmScAlignMidiEvt_t* midiBuf;  // midiBuf[ mn ]
282
+  unsigned            mbi;      // index of first element in midiBuf[] - this is required because the MIDI buf fills from the end to the beginning
283
+  unsigned            mni;      // index of event in midiBuf[p->mn] - increments on each note inserted into midiBuf[] - zeroed by cmScAlignReset().
284
+
285
+  cmScAlignVal_t*     m;        // m[rn,cn]   
286
+  unsigned            pn;       // rn+cn
287
+  cmScAlignPath_t*    p_mem;    // pmem[ 2*pn ];
288
+  cmScAlignPath_t*    p_avl;    // available path record linked list
289
+  cmScAlignPath_t*    p_cur;    // current path linked list
290
+  cmScAlignPath_t*    p_opt;    // p_opt[pn] current best alignment 
291
+  double              s_opt;    // score of the current best alignment  
292
+  unsigned            esi;      // loc[] index of latest positive match
293
+  unsigned            missCnt;  // count of consecutive trailing MIDI events without positive matches
294
+  unsigned            scanCnt;
295
+
296
+  bool                printFl;
297
+
298
+  unsigned            begScanLocIdx; // begin the search at this score locations scWnd[begScanLocIdx:begScanLocIdx+p->cn-1]
299
+
300
+  unsigned            resN;  // count of records in res[] == 2*cmScoreEvtCount()
301
+  cmScAlignResult_t*  res;   // res[resN]
302
+  unsigned            ri;    // 
303
+
304
+  int                 stepCnt;    // count of loc[] locations to step ahead/back during a cmScAlignStep() operation.
305
+  int                 maxStepMissCnt;  // max. consecutive trailing non-positive matches before a scan takes place.
306
+
307
+
308
+} cmScAlign;
309
+
310
+cmScAlign* cmScAlignAlloc( cmCtx* ctx, cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
311
+cmRC_t     cmScAlignFree( cmScAlign** pp );
312
+cmRC_t     cmScAlignInit( cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
313
+cmRC_t     cmScAlignFinal( cmScAlign* p );
314
+void       cmScAlignReset( cmScAlign* p, unsigned begScanLocIdx );
315
+
316
+bool       cmScAlignExec(  cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
317
+
318
+bool       cmScAlignInputMidi(  cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
319
+
320
+// Scan from p->begScanLocIdx to the end of the score looking
321
+// for the best match to p->midiBuf[].
322
+// Returns the score location index which best matches the 
323
+// first note p->midiBuf[]. The score associated
324
+// with this match is stored in s_opt.
325
+unsigned   cmScAlignScan( cmScAlign* p, unsigned scanCnt );
326
+
327
+// Step forward/back by p->stepCnt from p->esi.
328
+// If more than p->maxStepMissCnt consecutive MIDI events are 
329
+// missed then automatically run cmScAlignScan().
330
+bool cmScAlignStep(  cmScAlign* p );
331
+
332
+unsigned   cmScAlignScanToTimeLineEvent( cmScAlign* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx );
333
+
334
+// Given a score, a time-line, and a marker on the time line scan the
335
+// entire score looking for the best match between the first 'midiN'
336
+// notes in each marker region and the score. 
337
+void       cmScAlignScanMarkers(  cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH );
119 338
 
120 339
 #ifdef __cplusplus
121 340
 }

Loading…
Cancel
Save