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 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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, unsigned bufN, cmReal_t wndMs, cmScH_t scH )
  26. {
  27. cmScFol* op = cmObjAlloc(cmScFol,c,p);
  28. if( srate != 0 )
  29. if( cmScFolInit(op,srate,bufN,wndMs,scH) != 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].pitchV);
  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].pitchCnt; ++j)
  61. printf("%s ",cmMidiToSciPitch(p->loc[i].pitchV[j],NULL,0));
  62. printf("\n");
  63. }
  64. }
  65. cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, unsigned bufN, cmReal_t wndMs, cmScH_t scH )
  66. {
  67. cmRC_t rc;
  68. if((rc = cmScFolFinal(p)) != cmOkRC )
  69. return rc;
  70. p->srate = srate;
  71. p->scH = scH;
  72. p->bufN = bufN;
  73. p->bufV = cmMemResizeZ(cmScFolBufEle_t,p->bufV,bufN);
  74. p->locN = cmScoreEvtCount(scH);
  75. p->loc = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
  76. p->sbi = cmInvalidIdx;
  77. p->sei = cmInvalidIdx;
  78. p->msln = 7;
  79. p->mswn = 30;
  80. p->edWndMtx = cmVOU_LevEditDistAllocMtx(p->bufN);
  81. p->minVel = 5;
  82. p->missCnt = 0;
  83. p->matchCnt = 0;
  84. p->printFl = true;
  85. p->eventIdx = 0;
  86. int i,n;
  87. double maxDSecs = 0; // max time between score entries to be considered simultaneous
  88. cmScoreEvt_t* e0p = NULL;
  89. int j0 = 0;
  90. // for each score event
  91. for(i=0,n=0; i<p->locN; ++i)
  92. {
  93. cmScoreEvt_t* ep = cmScoreEvt(scH,i);
  94. // if the event is not a note then ignore it
  95. if( ep->type == kNonEvtScId )
  96. {
  97. assert( j0+n < p->locN );
  98. p->loc[j0+n].scIdx = i;
  99. p->loc[j0+n].barNumb = ep->barNumb;
  100. // if the first event has not yet been selected
  101. if( e0p == NULL )
  102. {
  103. e0p = ep;
  104. n = 1;
  105. }
  106. else
  107. {
  108. // time can never reverse
  109. assert( ep->secs >= e0p->secs );
  110. // calc seconds between first event and current event
  111. double dsecs = ep->secs - e0p->secs;
  112. // if the first event and current event are simultaneous...
  113. if( dsecs <= maxDSecs )
  114. ++n; // ... incr. the count of simultaneous events
  115. else
  116. {
  117. int k;
  118. // ... a complete set of simultaneous events have been located
  119. // duplicate all the events at each of their respective time locations
  120. for(k=0; k<n; ++k)
  121. {
  122. int m;
  123. assert( j0+k < p->locN );
  124. p->loc[j0+k].pitchCnt = n;
  125. p->loc[j0+k].pitchV = cmMemAllocZ(unsigned,n);
  126. for(m=0; m<n; ++m)
  127. {
  128. cmScoreEvt_t* tp = cmScoreEvt(scH,p->loc[j0+m].scIdx);
  129. assert(tp!=NULL);
  130. p->loc[j0+k].pitchV[m] = tp->pitch;
  131. }
  132. }
  133. e0p = ep;
  134. j0 += n;
  135. n = 1;
  136. }
  137. }
  138. }
  139. }
  140. p->locN = j0;
  141. //_cmScFolPrint(p);
  142. return rc;
  143. }
  144. cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex )
  145. {
  146. int i;
  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( scoreIndex < p->loc[0].scIdx )
  151. scoreIndex = p->loc[0].scIdx;
  152. p->sei = cmInvalidIdx;
  153. p->sbi = cmInvalidIdx;
  154. // locate the score element in svV[] that is closest to,
  155. // and possibly after, scoreIndex.
  156. for(i=0; i<p->locN-1; ++i)
  157. if( p->loc[i].scIdx <= scoreIndex && scoreIndex < p->loc[i+1].scIdx )
  158. {
  159. p->sbi = i;
  160. break;
  161. }
  162. // locate the score element at the end of the look-ahead region
  163. for(; i<p->locN-1; ++i)
  164. if( p->loc[i].scIdx <= scoreIndex + p->msln && scoreIndex + p->msln < p->loc[i+1].scIdx )
  165. {
  166. p->sei = i;
  167. break;
  168. }
  169. return cmOkRC;
  170. }
  171. bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
  172. {
  173. unsigned i;
  174. for(i=0; i<loc->pitchCnt; ++i)
  175. if( loc->pitchV[i] == pitch )
  176. return true;
  177. return false;
  178. }
  179. int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const unsigned* pitch, unsigned pi )
  180. {
  181. if( _cmScFolIsMatch(loc+li,pitch[pi]) )
  182. return 0;
  183. if( li>0 && pi>0 )
  184. if( _cmScFolIsMatch(loc+li-1,pitch[pi]) && _cmScFolIsMatch(loc+li,pitch[pi-1]) )
  185. return 0;
  186. return 1;
  187. }
  188. int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n )
  189. {
  190. mtxMaxN += 1;
  191. assert( n < mtxMaxN );
  192. int v = 0;
  193. unsigned i;
  194. // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices.
  195. for(i=1; i<n+1; ++i)
  196. {
  197. unsigned ii = i * mtxMaxN; // current row
  198. unsigned i_1 = ii - mtxMaxN; // previous row
  199. unsigned j;
  200. for( j=1; j<n+1; ++j)
  201. {
  202. //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
  203. //int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
  204. int cost = _cmScFolMatchCost(s0,i-1,s1,j-1);
  205. //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
  206. m[ ii + j ] = v = cmMin( m[ i_1 + j] + 1, cmMin( m[ ii + j - 1] + 1, m[ i_1 + j - 1 ] + cost ) );
  207. }
  208. }
  209. return v;
  210. }
  211. void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, unsigned* b, unsigned bn, unsigned min_idx )
  212. {
  213. unsigned i;
  214. int n;
  215. printf("--------------- event:%i ------------- \n",p->eventIdx);
  216. printf("loc: ");
  217. for(i=0; i<locN; ++i)
  218. printf("%4i ",i+locIdx);
  219. printf("\n");
  220. for(n=0,i=0; i<locN; ++i)
  221. if( p->loc[locIdx+i].pitchCnt > n )
  222. n = p->loc[locIdx+i].pitchCnt;
  223. --n;
  224. for(; n>=0; --n)
  225. {
  226. printf("sc%1i: ",n);
  227. for(i=0; i<locN; ++i)
  228. {
  229. if( n < p->loc[locIdx+i].pitchCnt )
  230. printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].pitchV[n],NULL,0));
  231. else
  232. printf(" ");
  233. }
  234. printf("\n");
  235. }
  236. printf("perf:");
  237. for(i=0; i<min_idx; ++i)
  238. printf(" ");
  239. for(i=0; i<bn; ++i)
  240. printf("%4s ",cmMidiToSciPitch(b[i],NULL,0));
  241. printf("\n");
  242. }
  243. void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
  244. {
  245. printf("dist:%i miss:%i match:%i ",minDist,missCnt,matchCnt);
  246. if( ret_idx == cmInvalidIdx )
  247. printf("vel:%i ", d1 );
  248. else
  249. printf("ret_idx:%i ",ret_idx);
  250. printf("\n");
  251. }
  252. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  253. {
  254. unsigned ret_idx = cmInvalidIdx;
  255. unsigned ebuf[ p->bufN ];
  256. if( status != kNoteOnMdId )
  257. return ret_idx;
  258. ++p->eventIdx;
  259. // reject notes with very low velocity
  260. if( d1 < p->minVel )
  261. return ret_idx;
  262. // left shift bufV[] to make the right-most element available - then copy in the new element
  263. memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
  264. p->bufV[ p->bufN-1 ].smpIdx = smpIdx;
  265. p->bufV[ p->bufN-1 ].val = d0;
  266. p->bufV[ p->bufN-1 ].validFl= true;
  267. // fill in ebuf[] with the valid values in bufV[]
  268. int i = p->bufN-1;
  269. int en = 0;
  270. for(; i>=0; --i,++en)
  271. {
  272. if( p->bufV[i].validFl)
  273. ebuf[i] = p->bufV[i].val;
  274. else
  275. break;
  276. }
  277. ++i; // increment i to the first valid element in ebuf[].
  278. // en is the count of valid elements in ebuf[].
  279. // ebuf[p->boi] is the first valid element
  280. int j = 0;
  281. int minDist = INT_MAX;
  282. int minIdx = cmInvalidIdx;
  283. int dist;
  284. // the score wnd must always be as long as the buffer n
  285. // at the end of the score this may not be the case
  286. // (once sei hits locN - at this point we must begin
  287. // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements)
  288. assert( p->sei-p->sbi+1 >= en );
  289. for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
  290. {
  291. // use <= minDist to choose the latest window with the lowest match
  292. if((dist = _cmScFolDist(p->bufN, p->edWndMtx, ebuf+i, p->loc + p->sbi+j, en )) <= minDist )
  293. {
  294. minDist = dist;
  295. minIdx = j;
  296. }
  297. }
  298. // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
  299. if( p->printFl )
  300. _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, ebuf+i, en, minIdx );
  301. // save current missCnt for later printing
  302. unsigned missCnt = p->missCnt;
  303. // if a perfect match occurred
  304. if( minDist == 0 )
  305. {
  306. // we had a perfect match - shrink the window to it's minumum size
  307. p->sbi += (en==p->bufN) ? minIdx + 1 : 0; // move wnd begin forward to just past first match
  308. p->sei = p->sbi + minIdx + en + p->msln; // move wnd end forward to just past last match
  309. // BUG BUG BUG - is the window length valid -
  310. // - sbi and sei must be inside 0:locN
  311. // - sei-sbi + 1 must be >= en
  312. ret_idx = p->sbi + minIdx + en - 1;
  313. p->missCnt = 0;
  314. }
  315. else
  316. {
  317. // if the last event matched - then return the match location as the current score location
  318. if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ebuf[p->bufN-1]) )
  319. {
  320. ret_idx = p->sbi + minIdx + en - 1;
  321. p->missCnt = 0;
  322. if( en >= p->bufN-1 && (en+2) <= ret_idx )
  323. p->sbi = ret_idx - (en+2);
  324. }
  325. else // the last event does not match based on the optimal edit-distance alignment
  326. {
  327. // Look backward from the closest match location for a match to the current pitch.
  328. // The backward search scope is limited by the current value of 'missCnt'.
  329. j = p->sbi+minIdx+en-2;
  330. for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
  331. {
  332. // if this look-back location already matched then stop the backward search
  333. if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1-i]))
  334. break;
  335. // does this look-back location match the current pitch
  336. if(_cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]))
  337. {
  338. ret_idx = j;
  339. p->missCnt = i; // set missCnt to the cnt of steps backward necessary for a match
  340. break;
  341. }
  342. }
  343. // If the backward search did not find a match - look forward
  344. if( ret_idx == cmInvalidIdx )
  345. {
  346. j = p->sbi+minIdx+en;
  347. for(i=0; j<=p->sei && i<2; ++i,++j)
  348. if( _cmScFolIsMatch(p->loc+j,ebuf[p->bufN-1]) )
  349. {
  350. ret_idx = j;
  351. break;
  352. }
  353. p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0;
  354. }
  355. }
  356. // even though we didn't match move the end of the score window forward
  357. // this will enlarge the score window by one
  358. p->sei += 1;
  359. assert( p->sei > p->sbi );
  360. // if the score window length surpasses the max score window size
  361. // move the beginning index forward
  362. if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
  363. p->sbi = p->sei - p->mswn + 1;
  364. // BUG BUG BUG - is the window length valid -
  365. // - sbi and sei must be inside 0:locN
  366. // - sei-sbi + 1 must be >= en
  367. }
  368. if( p->printFl )
  369. _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
  370. if( ret_idx == cmInvalidIdx )
  371. p->matchCnt = 0;
  372. else
  373. ++p->matchCnt;
  374. // BUG BUG BUG - this is not currently guarded against
  375. assert( p->sei < p->locN );
  376. assert( p->sbi < p->locN );
  377. return ret_idx;
  378. }