libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmProc4.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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. int i,n;
  82. double maxDSecs = 0; // max time between score entries to be considered simultaneous
  83. cmScoreEvt_t* e0p = NULL;
  84. int j0 = 0;
  85. // for each score event
  86. for(i=0,n=0; i<p->locN; ++i)
  87. {
  88. cmScoreEvt_t* ep = cmScoreEvt(scH,i);
  89. // if the event is not a note then ignore it
  90. if( ep->type == kNonEvtScId )
  91. {
  92. assert( j0+n < p->locN );
  93. p->loc[j0+n].scIdx = i;
  94. p->loc[j0+n].barNumb = ep->barNumb;
  95. // if the first event has not yet been selected
  96. if( e0p == NULL )
  97. {
  98. e0p = ep;
  99. n = 1;
  100. }
  101. else
  102. {
  103. // time can never reverse
  104. assert( ep->secs >= e0p->secs );
  105. // calc seconds between first event and current event
  106. double dsecs = ep->secs - e0p->secs;
  107. // if the first event and current event are simultaneous...
  108. if( dsecs <= maxDSecs )
  109. ++n; // ... incr. the count of simultaneous events
  110. else
  111. {
  112. int k;
  113. // ... a complete set of simultaneous events have been located
  114. // duplicate all the events at each of their respective time locations
  115. for(k=0; k<n; ++k)
  116. {
  117. int m;
  118. assert( j0+k < p->locN );
  119. p->loc[j0+k].pitchCnt = n;
  120. p->loc[j0+k].pitchV = cmMemAllocZ(unsigned,n);
  121. for(m=0; m<n; ++m)
  122. {
  123. cmScoreEvt_t* tp = cmScoreEvt(scH,p->loc[j0+m].scIdx);
  124. assert(tp!=NULL);
  125. p->loc[j0+k].pitchV[m] = tp->pitch;
  126. }
  127. }
  128. e0p = ep;
  129. j0 += n;
  130. n = 1;
  131. }
  132. }
  133. }
  134. }
  135. p->locN = j0;
  136. //_cmScFolPrint(p);
  137. return rc;
  138. }
  139. cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex )
  140. {
  141. int i;
  142. // empty the event buffer
  143. memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN);
  144. // don't allow the score index to be prior to the first note
  145. if( scoreIndex < p->loc[0].scIdx )
  146. scoreIndex = p->loc[0].scIdx;
  147. p->sei = cmInvalidIdx;
  148. p->sbi = cmInvalidIdx;
  149. // locate the score element in svV[] that is closest to,
  150. // and possibly after, scoreIndex.
  151. for(i=0; i<p->locN-1; ++i)
  152. if( p->loc[i].scIdx <= scoreIndex && scoreIndex < p->loc[i+1].scIdx )
  153. {
  154. p->sbi = i;
  155. break;
  156. }
  157. // locate the score element at the end of the look-ahead region
  158. for(; i<p->locN-1; ++i)
  159. if( p->loc[i].scIdx <= scoreIndex + p->msln && scoreIndex + p->msln < p->loc[i+1].scIdx )
  160. {
  161. p->sei = i;
  162. break;
  163. }
  164. return cmOkRC;
  165. }
  166. bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
  167. {
  168. unsigned i;
  169. for(i=0; i<loc->pitchCnt; ++i)
  170. if( loc->pitchV[i] == pitch )
  171. return true;
  172. return false;
  173. }
  174. int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n )
  175. {
  176. mtxMaxN += 1;
  177. assert( n < mtxMaxN );
  178. int v = 0;
  179. unsigned i;
  180. // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices.
  181. for(i=1; i<n+1; ++i)
  182. {
  183. unsigned ii = i * mtxMaxN; // current row
  184. unsigned i_1 = ii - mtxMaxN; // previous row
  185. unsigned j;
  186. for( j=1; j<n+1; ++j)
  187. {
  188. //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
  189. int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
  190. //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
  191. m[ ii + j ] = v = cmMin( m[ i_1 + j] + 1, cmMin( m[ ii + j - 1] + 1, m[ i_1 + j - 1 ] + cost ) );
  192. }
  193. }
  194. return v;
  195. }
  196. /*
  197. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  198. {
  199. assert( p->sri != cmInvalidIdx );
  200. unsigned ret_idx = cmInvalidIdx;
  201. unsigned ewnd[ p->wndN ];
  202. if( status != kNoteOnMdId && d1>0 )
  203. return ret_idx;
  204. // left shift wndV[] to make the right-most element available - then copy in the new element
  205. memmove(p->wndV, p->wndV+1, sizeof(cmScFolWndEle_t)*(p->wndN-1));
  206. p->wndV[ p->wndN-1 ].smpIdx = smpIdx;
  207. p->wndV[ p->wndN-1 ].val = d0;
  208. p->wndV[ p->wndN-1 ].validFl= true;
  209. // fill in ewnd[] with the valid values in wndV[]
  210. int i = p->wndN-1;
  211. int en = 0;
  212. for(; i>=0; --i,++en)
  213. {
  214. //if( p->wndV[i].validFl && ((smpIdx-p->wnd[i].smpIdx)<=maxWndSmp))
  215. if( p->wndV[i].validFl )
  216. ewnd[i] = p->wndV[i].val;
  217. else
  218. break;
  219. }
  220. ++i; // increment i to the first valid element in ewnd[].
  221. int k;
  222. printf("en:%i sbi:%i sei:%i pitch:%s : ",en,p->sbi,p->sei,cmMidiToSciPitch(d0,NULL,0));
  223. for(k=i; k<p->wndN; ++k)
  224. printf("%s ", cmMidiToSciPitch(ewnd[k],NULL,0));
  225. printf("\n");
  226. // en is the count of valid elements in ewnd[].
  227. // ewnd[i] is the first valid element
  228. int j = 0;
  229. int dist;
  230. int minDist = INT_MAX;
  231. int minIdx = cmInvalidIdx;
  232. for(j=0; p->sbi+en+j <= p->sei; ++j)
  233. if((dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+i, p->loc + p->sbi+j, en )) < minDist )
  234. {
  235. minDist = dist;
  236. minIdx = j;
  237. }
  238. // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
  239. int evalWndN = cmMin(en,p->evalWndN);
  240. assert(evalWndN<p->wndN);
  241. j = p->sbi+minIdx+en - evalWndN;
  242. // Determine how many of the last evalWndN elements match
  243. dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+p->wndN-evalWndN, p->loc+j, evalWndN );
  244. // a successful match has <= allowedMissCnt and an exact match on the last element
  245. //if( dist <= p->allowedMissCnt && ewnd[p->wndN-1] == p->loc[p->sbi+minIdx+en-1] )
  246. //if( dist <= p->allowedMissCnt && _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1]))
  247. if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1]))
  248. {
  249. p->sbi = p->sbi + minIdx;
  250. p->sei = cmMin(p->sei+minIdx,p->locN-1);
  251. ret_idx = p->sbi+minIdx+en-1;
  252. }
  253. printf("minDist:%i minIdx:%i evalDist:%i sbi:%i sei:%i\n",minDist,minIdx,dist,p->sbi,p->sei);
  254. return ret_idx;
  255. }
  256. */
  257. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  258. {
  259. unsigned ret_idx = cmInvalidIdx;
  260. unsigned ebuf[ p->bufN ];
  261. if( status != kNoteOnMdId && d1>0 )
  262. return ret_idx;
  263. // left shift bufV[] to make the right-most element available - then copy in the new element
  264. memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
  265. p->bufV[ p->bufN-1 ].smpIdx = smpIdx;
  266. p->bufV[ p->bufN-1 ].val = d0;
  267. p->bufV[ p->bufN-1 ].validFl= true;
  268. // fill in ebuf[] with the valid values in bufV[]
  269. int i = p->bufN-1;
  270. int en = 0;
  271. for(; i>=0; --i,++en)
  272. {
  273. if( p->bufV[i].validFl)
  274. ebuf[i] = p->bufV[i].val;
  275. else
  276. break;
  277. }
  278. ++i; // increment i to the first valid element in ebuf[].
  279. // en is the count of valid elements in ebuf[].
  280. // ebuf[p->boi] is the first valid element
  281. int j = 0;
  282. int minDist = INT_MAX;
  283. int minIdx = cmInvalidIdx;
  284. int dist;
  285. // the score wnd must always be as long as the buffer n
  286. // at the end of the score this may not be the case
  287. // (once sei hits locN - at this point we must begin
  288. // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements)
  289. assert( p->sei-p->sbi+1 >= en );
  290. for(j=0; p->sbi+en+j <= p->sei; ++j)
  291. if((dist = _cmScFolDist(p->bufN, p->edWndMtx, ebuf+i, p->loc + p->sbi+j, en )) < minDist )
  292. {
  293. minDist = dist;
  294. minIdx = j;
  295. }
  296. // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
  297. // if a perfect match occurred
  298. if( minDist == 0 )
  299. {
  300. // we had a perfect match - shrink the window to it's minumum size
  301. p->sbi += (en==p->bufN) ? minIdx + 1 : 0; // move wnd begin forward to just past first match
  302. p->sei = p->sbi + minIdx + en + p->msln; // move wnd end forward to just past last match
  303. ret_idx = p->sbi + minIdx + en - 1;
  304. // BUG BUG BUG - is the window length valid -
  305. // - sbi and sei must be inside 0:locN
  306. // - sei-sbi + 1 must be >= en
  307. }
  308. else
  309. {
  310. // if the last event matched - then return the match location as the current score location
  311. if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ebuf[p->bufN-1]) )
  312. ret_idx = p->sbi + minIdx + en - 1;
  313. // even though we didn't match move the end of the score window forward
  314. // this will enlarge the score window by one
  315. p->sei += 1;
  316. assert( p->sei > p->sbi );
  317. // if the score window length surpasses the max score window size
  318. // move the beginning index forward
  319. if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
  320. p->sbi = p->sei - p->mswn + 1;
  321. // BUG BUG BUG - is the window length valid -
  322. // - sbi and sei must be inside 0:locN
  323. // - sei-sbi + 1 must be >= en
  324. }
  325. // BUG BUG BUG - this is not currently guarded against
  326. assert( p->sei < p->locN );
  327. assert( p->sbi < p->locN );
  328. return ret_idx;
  329. }