libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmProc4.h 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. #ifndef cmProc4_h
  2. #define cmProc4_h
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. typedef struct
  7. {
  8. unsigned smpIdx; // time tag sample index for val
  9. cmMidiByte_t val; //
  10. bool validFl; //
  11. } cmScFolBufEle_t;
  12. typedef struct
  13. {
  14. unsigned pitch;
  15. unsigned scEvtIdx;
  16. } cmScFolEvt_t;
  17. typedef struct
  18. {
  19. unsigned evtCnt; //
  20. cmScFolEvt_t* evtV; // pitchV[pitchCnt]
  21. unsigned scIdx; // index of the score loc (into cmScoreEvt[]) at this location
  22. int barNumb; // bar number of this location
  23. } cmScFolLoc_t;
  24. typedef struct
  25. {
  26. cmObj obj;
  27. cmReal_t srate; //
  28. cmScH_t scH; // score handle
  29. unsigned bufN; // event buffer count
  30. cmScFolBufEle_t* bufV; // event buffer bufV[bufN] - bufV[bufN-1] newest event, bufV[boi] oldest event
  31. int locN; // count of score locations
  32. cmScFolLoc_t* loc; // score loc[locN]
  33. unsigned sbi; // oldest score window index
  34. unsigned sei; // newest score window index
  35. unsigned msln; // minimum score look ahead count
  36. unsigned mswn; // maximum score window length
  37. 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
  38. unsigned maxDist; // max. dist allowed to still consider matching
  39. unsigned minVel; // notes < minVel are ignored
  40. bool printFl; // true if pitch tracker reporting should be included
  41. bool noBackFl; // prevent the tracker from going backwards in time
  42. unsigned* edWndMtx;
  43. unsigned missCnt; // current consecutive unmatched notes
  44. unsigned matchCnt; // current consecutive matched notes
  45. unsigned eventIdx; // events since reset
  46. unsigned skipCnt; // notes skipped due to velocity
  47. unsigned ret_idx; // last tracked location
  48. } cmScFol;
  49. cmScFol* cmScFolAlloc( cmCtx* ctx, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
  50. cmRC_t cmScFolFree( cmScFol** pp );
  51. cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
  52. cmRC_t cmScFolFinal( cmScFol* p );
  53. // Jump to a score location and reset the internal state of the follower.
  54. cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex );
  55. // Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
  56. // all others are ignored.
  57. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  58. //=======================================================================================================================
  59. typedef struct
  60. {
  61. unsigned pitch;
  62. unsigned scEvtIdx;
  63. bool matchFl;
  64. } cmScTrkEvt_t;
  65. typedef struct
  66. {
  67. unsigned evtCnt; //
  68. cmScTrkEvt_t* evtV; // evtV[evtCnt]
  69. unsigned scIdx; // index of the score event (into cmScoreEvt[]) at this location
  70. int barNumb; // bar number of this location
  71. } cmScTrkLoc_t;
  72. typedef struct
  73. {
  74. cmObj obj;
  75. cmScFol* sfp;
  76. double srate;
  77. cmScH_t scH;
  78. unsigned locN;
  79. cmScTrkLoc_t* loc;
  80. unsigned minVel;
  81. unsigned maxWndCnt;
  82. unsigned minWndLookAhead;
  83. bool printFl;
  84. int curLocIdx;
  85. unsigned evtIndex;
  86. } cmScTrk;
  87. cmScTrk* cmScTrkAlloc( cmCtx* ctx, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
  88. cmRC_t cmScTrkFree( cmScTrk** pp );
  89. cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel );
  90. cmRC_t cmScTrkFinal( cmScTrk* p );
  91. // Jump to a score location and reset the internal state of the follower.
  92. cmRC_t cmScTrkReset( cmScTrk* p, unsigned scoreIndex );
  93. // Give the follower a MIDI performance event. Only MIDI note-on events are acted upon;
  94. // all others are ignored.
  95. unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  96. //=======================================================================================================================
  97. //
  98. // Simplified string alignment function based on Levenshtein edit distance.
  99. //
  100. enum { kEdMinIdx, kEdSubIdx, kEdDelIdx, kEdInsIdx, kEdCnt };
  101. typedef struct
  102. {
  103. unsigned v[kEdCnt];
  104. bool matchFl;
  105. bool transFl;
  106. } ed_val;
  107. typedef struct ed_path_str
  108. {
  109. unsigned code;
  110. unsigned ri;
  111. unsigned ci;
  112. bool matchFl;
  113. bool transFl;
  114. struct ed_path_str* next;
  115. } ed_path;
  116. /*
  117. Backtracking:
  118. m[rn,cn] is organized to indicate the mutation operations
  119. on s0[0:rn-1] or s1[0:cn-1] during backtracking.
  120. Backtracking begins at cell m[rn-1,cn-1] and proceeds
  121. up and left toward m[0,0]. The action to perform during
  122. backtracking is determined by examinging which values
  123. int m[].v[1:3] match m[].v[0].
  124. Match Next Cell
  125. Index Operation Location
  126. ----- ------------------------ ------------------------
  127. 1 Substitute char s0[ri-1] move diagonally; up-left
  128. 2 Delete char s0[ri-1] move up.
  129. 3 Delete char s1[ci-1] move left.
  130. (same as inserting blank
  131. into after s[ri-1]
  132. Note that more than one value in m[].v[1:3] may match
  133. m[].v[0]. In this case the candidate solution branches
  134. at this point in the candidate selection processes.
  135. */
  136. typedef struct
  137. {
  138. const char* s0; // forms rows of m[] - mutate to match s1 - rn=strlen(s0)
  139. const char* s1; // forms columns of m[] - target string - cn=strlen(s1)
  140. unsigned rn; // length of s0 + 1
  141. unsigned cn; // length of s1 + 1
  142. ed_val* m; // m[rn,cn]
  143. unsigned pn; // rn+cn
  144. ed_path* p_mem; // pmem[ 2*pn ];
  145. ed_path* p_avl; // available path record linked list
  146. ed_path* p_cur; // current path linked list
  147. ed_path* p_opt; // p_opt[pn] current best alignment
  148. double s_opt; // score of the current best alignment
  149. } ed_r;
  150. // print the DP matrix ed_r.m[rn,cn].
  151. void ed_print_mtx( ed_r* r );
  152. // Initialize ed_r.
  153. void ed_init( ed_r* r, const char* s0, const char* s1 );
  154. // Fill in the DP matrix.
  155. void ed_calc_mtx( ed_r* r );
  156. // Traverse the possible alignments in the DP matrix and determine the optimal alignment.
  157. void ed_align( ed_r* r );
  158. // Print the optimal alignment p_opt[]
  159. void ed_print_opt( ed_r* r );
  160. // Free resource allocated by ed_init().
  161. void ed_free(ed_r* r);
  162. // Main test function.
  163. void ed_main();
  164. //=======================================================================================================================
  165. enum
  166. {
  167. kSmMinIdx,
  168. kSmSubIdx, // 'substitute' - may or may not match
  169. kSmDelIdx, // 'delete' - delete a MIDI note
  170. kSmInsIdx, // 'insert' - insert a space in the score
  171. kSmCnt
  172. };
  173. enum
  174. {
  175. kSmMatchFl = 0x01,
  176. kSmTransFl = 0x02,
  177. kSmTruePosFl = 0x04,
  178. kSmFalsePosFl = 0x08,
  179. kSmBarFl = 0x10,
  180. kSmNoteFl = 0x20
  181. };
  182. // Dynamic Programming (DP) matrix element
  183. typedef struct
  184. {
  185. unsigned v[kSmCnt]; //
  186. unsigned flags;
  187. } cmScMatchVal_t;
  188. // List record used to track a path through the DP matrix p->m[,]
  189. typedef struct cmScMatchPath_str
  190. {
  191. unsigned code;
  192. unsigned ri;
  193. unsigned ci;
  194. unsigned flags;
  195. unsigned locIdx;
  196. struct cmScMatchPath_str* next;
  197. } cmScMatchPath_t;
  198. typedef struct cmScMatchEvt_str
  199. {
  200. unsigned pitch;
  201. } cmScMatchEvt_t;
  202. // Score location record.
  203. typedef struct
  204. {
  205. unsigned evtCnt; //
  206. cmScMatchEvt_t* evtV; // evtV[evtCnt]
  207. unsigned scLocIdx; // scH score location index
  208. int barNumb; // bar number of this location
  209. } cmScMatchLoc_t;
  210. typedef struct
  211. {
  212. cmObj obj;
  213. cmScH_t scH; //
  214. unsigned locN; //
  215. cmScMatchLoc_t* loc; // loc[locN]
  216. unsigned mrn; // max row count (midi)
  217. unsigned rn; // cur row count
  218. unsigned mcn; // max column count (score)
  219. unsigned cn; // cur column count
  220. unsigned mmn; // max length of midiBuf[] (mrn-1)
  221. unsigned msn; // max length of score window (mcn-1)
  222. cmScMatchVal_t* m; // m[mrn,mcn] DP matrix
  223. unsigned pn; // mrn+mcn
  224. cmScMatchPath_t* p_mem; // pmem[ 2*pn ];
  225. cmScMatchPath_t* p_avl; // available path record linked list
  226. cmScMatchPath_t* p_cur; // current path linked list
  227. cmScMatchPath_t* p_opt; // p_opt[pn] current best alignment
  228. double opt_cost; // p_opt cost set by cmScMatchExec()
  229. } cmScMatch;
  230. cmScMatch* cmScMatchAlloc( cmCtx* c, cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
  231. cmRC_t cmScMatchFree( cmScMatch** pp );
  232. cmRC_t cmScMatchInit( cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN );
  233. cmRC_t cmScMatchFinal( cmScMatch* p );
  234. // Returns cmEofRC if scLocIdx + locN > p->locN - note that this is not necessarily an error.
  235. // The optimal path p_opt[] will only be updated if the edit cost is less than min_cost.
  236. // Set min_cost to DBL_MAX to force p_opt[] to be updated.
  237. cmRC_t cmScMatchExec( cmScMatch* p, unsigned scLocIdx, unsigned locN, const unsigned* midiPitchV, unsigned midiPitchN, double min_cost );
  238. //=======================================================================================================================
  239. typedef struct
  240. {
  241. unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
  242. unsigned cbCnt; // count of times this event has been sent via the callback
  243. unsigned mni; // unique identifier for this event since previous call to cmScAlignReset().
  244. unsigned smpIdx; // time stamp of this event
  245. unsigned pitch; // MIDI note pitch
  246. unsigned vel; // " " velocity
  247. } cmScMatcherMidi_t;
  248. typedef struct
  249. {
  250. unsigned locIdx;
  251. unsigned mni;
  252. unsigned pitch;
  253. unsigned vel;
  254. unsigned flags;
  255. } cmScMatcherResult_t;
  256. typedef struct
  257. {
  258. cmObj obj;
  259. cmScMatch* mp;
  260. unsigned mn;
  261. cmScMatcherMidi_t* midiBuf; // midiBuf[mn]
  262. cmScMatcherResult_t* res; // res[rn]
  263. unsigned rn; // length of res[]
  264. unsigned ri; // next avail res[] recd.
  265. double s_opt; //
  266. unsigned missCnt; // count of consecutive trailing non-matches
  267. unsigned esi; // index into loc[] of the last positive match.
  268. unsigned mni; // track the count of MIDI events since the last call to cmScMatcherReset()
  269. unsigned mbi; // index of oldest MIDI event in midiBuf[]; 0 when the buffer is full.
  270. unsigned begSyncLocIdx; // start of score window, in mp->loc[], of best match in previous scan
  271. unsigned stepCnt; // count of forward/backward score loc's to examine for a match during cmScMatcherStep().
  272. unsigned maxMissCnt; // max. number of consecutive non-matches during step prior to executing a scan.
  273. unsigned scanCnt; // count of time scan was executed inside cmScMatcherStep()
  274. } cmScMatcher;
  275. cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
  276. cmRC_t cmScMatcherFree( cmScMatcher** pp );
  277. cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN );
  278. cmRC_t cmScMatcherFinal( cmScMatcher* p );
  279. void cmScMatcherReset( cmScMatcher* p );
  280. bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  281. // Slide a score window scanCnt times, beginning at 'bsi',
  282. // looking for the best match to p->midiBuf[]. The score window
  283. // contain scWndN (p->mp->mcn-1) score locations.
  284. // Returns the index into p->mp->loc[] of the start of the best
  285. // match score window. The score associated
  286. // with this match is stored in s_opt.
  287. unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt );
  288. // Step forward/back by p->stepCnt from p->esi.
  289. // p->esi must therefore be valid prior to calling this function.
  290. // If more than p->maxMissCnt consecutive MIDI events are
  291. // missed then automatically run cmScAlignScan().
  292. // Return cmEofRC if the end of the score is encountered.
  293. // Return cmSubSysFailRC if an internal scan resync. failed.
  294. cmRC_t cmScMatcherStep( cmScMatcher* p );
  295. cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  296. //=======================================================================================================================
  297. enum
  298. {
  299. kSaMinIdx,
  300. kSaSubIdx, // 'substitute' - may or may not match
  301. kSaDelIdx, // 'delete' - delete a MIDI note
  302. kSaInsIdx, // 'insert' - insert a space in the score
  303. kSaCnt
  304. };
  305. // Dynamic Programming (DP) matrix element
  306. typedef struct
  307. {
  308. unsigned v[kSaCnt]; //
  309. bool matchFl; // if this is a substitute; is it also a match?
  310. bool transFl; // if this is a substitute; is this the second element in a reversed pair?
  311. } cmScAlignVal_t;
  312. // List record used to track a path through the DP matrix p->m[,]
  313. typedef struct cmScAlignPath_str
  314. {
  315. unsigned code;
  316. unsigned ri;
  317. unsigned ci;
  318. bool matchFl;
  319. bool transFl;
  320. unsigned locIdx;
  321. struct cmScAlignPath_str* next;
  322. } cmScAlignPath_t;
  323. // Score note event record
  324. typedef struct
  325. {
  326. unsigned pitch;
  327. } cmScAlignScEvt_t;
  328. // Score location record.
  329. typedef struct
  330. {
  331. unsigned evtCnt; //
  332. cmScAlignScEvt_t* evtV; // evtV[evtCnt]
  333. unsigned scLocIdx; // scH score location index
  334. int barNumb; // bar number of this location
  335. } cmScAlignLoc_t;
  336. typedef struct
  337. {
  338. unsigned locIdx; // location assoc'd with this MIDI evt (cmInvalidIdx if not a positive-match)
  339. unsigned cbCnt; // count of times this event has been sent via the callback
  340. unsigned mni; // unique identifier for this event since previous call to cmScAlignReset().
  341. unsigned smpIdx; // time stamp of this event
  342. unsigned pitch; // MIDI note pitch
  343. unsigned vel; // " " velocity
  344. } cmScAlignMidiEvt_t;
  345. typedef struct
  346. {
  347. unsigned locIdx; // loc[] sync. location
  348. unsigned smpIdx; //
  349. unsigned mni; // MIDI event unique index
  350. unsigned pitch; // MIDI event pitch which may not match the score event pitch
  351. unsigned vel; // " " velocity
  352. bool matchFl;
  353. bool transFl;
  354. bool foundFl;
  355. } cmScAlignResult_t;
  356. //
  357. typedef void (*cmScAlignCb_t)( void* cbArg, unsigned scLocIdx, unsigned mni, unsigned pitch, unsigned vel );
  358. typedef struct
  359. {
  360. cmObj obj;
  361. cmScAlignCb_t cbFunc; //
  362. void* cbArg; //
  363. cmScH_t scH; //
  364. double srate; //
  365. unsigned locN; // length of loc[]
  366. cmScAlignLoc_t* loc; // loc[locN] score array
  367. unsigned rn; // length of midiBuf[] (mn+1)
  368. unsigned cn; // length of score window (scWndN+1)
  369. unsigned mn; // length of midiBuf[] (rn-1)
  370. cmScAlignMidiEvt_t* midiBuf; // midiBuf[ mn ]
  371. unsigned mbi; // index of first element in midiBuf[] - this is required because the MIDI buf fills from the end to the beginning
  372. unsigned mni; // index of event in midiBuf[p->mn] - increments on each note inserted into midiBuf[] - zeroed by cmScAlignReset().
  373. cmScAlignVal_t* m; // m[rn,cn]
  374. unsigned pn; // rn+cn
  375. cmScAlignPath_t* p_mem; // pmem[ 2*pn ];
  376. cmScAlignPath_t* p_avl; // available path record linked list
  377. cmScAlignPath_t* p_cur; // current path linked list
  378. cmScAlignPath_t* p_opt; // p_opt[pn] current best alignment
  379. double s_opt; // score of the current best alignment
  380. unsigned esi; // loc[] index of latest positive match
  381. unsigned missCnt; // count of consecutive trailing MIDI events without positive matches
  382. unsigned scanCnt;
  383. bool printFl;
  384. unsigned begScanLocIdx; // begin the search at this score locations scWnd[begScanLocIdx:begScanLocIdx+p->cn-1]
  385. unsigned begSyncLocIdx; // initial sync location
  386. unsigned resN; // count of records in res[] == 2*cmScoreEvtCount()
  387. cmScAlignResult_t* res; // res[resN]
  388. unsigned ri; //
  389. int stepCnt; // count of loc[] locations to step ahead/back during a cmScAlignStep() operation.
  390. int maxStepMissCnt; // max. consecutive trailing non-positive matches before a scan takes place.
  391. } cmScAlign;
  392. cmScAlign* cmScAlignAlloc( cmCtx* ctx, cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
  393. cmRC_t cmScAlignFree( cmScAlign** pp );
  394. cmRC_t cmScAlignInit( cmScAlign* p, cmScAlignCb_t cbFunc, void* cbArg, cmReal_t srate, cmScH_t scH, unsigned midiN, unsigned scWndN );
  395. cmRC_t cmScAlignFinal( cmScAlign* p );
  396. void cmScAlignReset( cmScAlign* p, unsigned begScanLocIdx );
  397. cmRC_t cmScAlignExec( cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  398. bool cmScAlignInputMidi( cmScAlign* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 );
  399. // Scan from p->begScanLocIdx to the end of the score looking
  400. // for the best match to p->midiBuf[].
  401. // Returns the score location index which best matches the
  402. // first note p->midiBuf[]. The score associated
  403. // with this match is stored in s_opt.
  404. unsigned cmScAlignScan( cmScAlign* p, unsigned scanCnt );
  405. // Step forward/back by p->stepCnt from p->esi.
  406. // If more than p->maxStepMissCnt consecutive MIDI events are
  407. // missed then automatically run cmScAlignScan().
  408. // Return cmEofRC if the end of the score is encountered.
  409. // Return cmSubSysFailRC if an internal scan resync. failed.
  410. cmRC_t cmScAlignStep( cmScAlign* p );
  411. unsigned cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx );
  412. // Given a score, a time-line, and a marker on the time line scan the
  413. // entire score looking for the best match between the first 'midiN'
  414. // notes in each marker region and the score.
  415. void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH );
  416. //=======================================================================================================================
  417. typedef struct
  418. {
  419. unsigned mni;
  420. unsigned locIdx;
  421. unsigned pitch;
  422. unsigned vel;
  423. unsigned smpIdx;
  424. } cmScMeasMidi_t;
  425. typedef struct
  426. {
  427. cmScoreSet_t* set; // A pointer to defining score set
  428. unsigned bli; // Begin index into sap->loc[].
  429. unsigned eli; // End index into sap->loc[].
  430. unsigned bmi; // Begin index into midi[].
  431. unsigned emi; // End index into midi[].
  432. double* val; // val[sap->eleCnt]
  433. } cmScMeasSet_t;
  434. typedef struct
  435. {
  436. cmObj obj;
  437. cmScAlign* sap;
  438. unsigned mn;
  439. cmScMeasMidi_t* midi;
  440. } cmScMeas;
  441. cmScMeas* cmScMeasAlloc( cmCtx* c, cmScMeas* p, double srate, cmScH_t scH );
  442. cmRC_t cmScMeasFree( cmScMeas** pp );
  443. cmRC_t cmScMeasInit( cmScMeas* p, double srate, cmScH_t scH );
  444. cmRC_t cmScMeasFinal( cmScMeas* p );
  445. cmRC_t cmScMeasExec( cmScMeas* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned scLocIdx );
  446. #ifdef __cplusplus
  447. }
  448. #endif
  449. #endif