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

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