libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmProc4.c 20KB

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