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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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 wndN, cmReal_t wndMs, cmScH_t scH )
  26. {
  27. cmScFol* op = cmObjAlloc(cmScFol,c,p);
  28. if( srate != 0 )
  29. if( cmScFolInit(op,srate,wndN,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].evtIdx);
  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 wndN, 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->maxWndSmp = floor(wndMs * srate / 1000.0);
  69. p->wndN = wndN;
  70. p->wndV = cmMemResizeZ(cmScFolWndEle_t,p->wndV,wndN);
  71. p->locN = cmScoreEvtCount(scH);
  72. p->loc = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
  73. p->sri = cmInvalidIdx;
  74. p->sbi = cmInvalidIdx;
  75. p->sei = cmInvalidIdx;
  76. p->edWndMtx = cmVOU_LevEditDistAllocMtx(p->wndN);
  77. p->evalWndN = 5;
  78. p->allowedMissCnt = 1;
  79. assert(p->evalWndN<p->wndN);
  80. int i,n;
  81. double maxDSecs = 0; // max time between events to be considered simultaneous
  82. cmScoreEvt_t* e0p = NULL;
  83. int j0 = 0;
  84. // for each score event
  85. for(i=0,n=0; i<p->locN; ++i)
  86. {
  87. cmScoreEvt_t* ep = cmScoreEvt(scH,i);
  88. // if the event is not a note then ignore it
  89. if( ep->type == kNonEvtScId )
  90. {
  91. assert( j0+n < p->locN );
  92. p->loc[j0+n].evtIdx = i;
  93. p->loc[j0+n].barNumb = ep->barNumb;
  94. // if the first event has not yet been selected
  95. if( e0p == NULL )
  96. {
  97. e0p = ep;
  98. n = 1;
  99. }
  100. else
  101. {
  102. // time can never reverse
  103. assert( ep->secs >= e0p->secs );
  104. // calc seconds between first event and current event
  105. double dsecs = ep->secs - e0p->secs;
  106. // if the first event and current event are simultaneous...
  107. if( dsecs <= maxDSecs )
  108. ++n; // ... incr. the count of simultaneous events
  109. else
  110. {
  111. int k;
  112. // ... a complete set of simultaneous events have been located
  113. // duplicate all the events at each of their respective time locations
  114. for(k=0; k<n; ++k)
  115. {
  116. int m;
  117. assert( j0+k < p->locN );
  118. p->loc[j0+k].pitchCnt = n;
  119. p->loc[j0+k].pitchV = cmMemAllocZ(unsigned,n);
  120. for(m=0; m<n; ++m)
  121. {
  122. cmScoreEvt_t* tp = cmScoreEvt(scH,p->loc[j0+m].evtIdx);
  123. assert(tp!=NULL);
  124. p->loc[j0+k].pitchV[m] = tp->pitch;
  125. }
  126. }
  127. e0p = ep;
  128. j0 += n;
  129. n = 1;
  130. }
  131. }
  132. }
  133. }
  134. p->locN = j0;
  135. //_cmScFolPrint(p);
  136. return rc;
  137. }
  138. cmRC_t cmScFolReset( cmScFol* p, unsigned scoreIndex )
  139. {
  140. int i;
  141. // zero the event index
  142. memset(p->wndV,0,sizeof(cmScFolWndEle_t)*p->wndN);
  143. // don't allow the score index to be prior to the first note
  144. if( scoreIndex < p->loc[0].evtIdx )
  145. scoreIndex = p->loc[0].evtIdx;
  146. // locate the score element in svV[] that is closest to,
  147. // and possibly after, scoreIndex.
  148. for(i=0; i<p->locN-1; ++i)
  149. if( p->loc[i].evtIdx <= scoreIndex && scoreIndex < p->loc[i+1].evtIdx )
  150. break;
  151. // force scEvtIndex to be valid
  152. assert( i<p->locN );
  153. p->sri = i;
  154. p->sbi = i;
  155. // score event window is dBar bars before and after scEvtIndex;
  156. int dBar = 1;
  157. // backup dBar bars from the 'scoreIndex'
  158. for(; i>=0; --i)
  159. if( p->loc[i].barNumb >= (p->loc[p->sri].barNumb-dBar) )
  160. p->sbi = i;
  161. else
  162. break;
  163. dBar = 3;
  164. // move forward dBar bars from 'scoreIndex'
  165. for(i=p->sri; i<p->locN; ++i)
  166. if( p->loc[i].barNumb <= (p->loc[p->sri].barNumb+dBar) )
  167. p->sei = i;
  168. else
  169. break;
  170. return cmOkRC;
  171. }
  172. bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
  173. {
  174. unsigned i;
  175. for(i=0; i<loc->pitchCnt; ++i)
  176. if( loc->pitchV[i] == pitch )
  177. return true;
  178. return false;
  179. }
  180. int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const unsigned* s1, const cmScFolLoc_t* s0, int n )
  181. {
  182. mtxMaxN += 1;
  183. assert( n < mtxMaxN );
  184. int v = 0;
  185. unsigned i;
  186. // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices.
  187. for(i=1; i<n+1; ++i)
  188. {
  189. unsigned ii = i * mtxMaxN; // current row
  190. unsigned i_1 = ii - mtxMaxN; // previous row
  191. unsigned j;
  192. for( j=1; j<n+1; ++j)
  193. {
  194. //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
  195. int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
  196. //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
  197. m[ ii + j ] = v = cmMin( m[ i_1 + j] + 1, cmMin( m[ ii + j - 1] + 1, m[ i_1 + j - 1 ] + cost ) );
  198. }
  199. }
  200. return v;
  201. }
  202. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  203. {
  204. assert( p->sri != cmInvalidIdx );
  205. unsigned ret_idx = cmInvalidIdx;
  206. unsigned ewnd[ p->wndN ];
  207. if( status != kNoteOnMdId && d1>0 )
  208. return ret_idx;
  209. // left shift wndV[] to make the right-most element available - then copy in the new element
  210. memmove(p->wndV, p->wndV+1, sizeof(cmScFolWndEle_t)*(p->wndN-1));
  211. p->wndV[ p->wndN-1 ].smpIdx = smpIdx;
  212. p->wndV[ p->wndN-1 ].val = d0;
  213. p->wndV[ p->wndN-1 ].validFl= true;
  214. // fill in ewnd[] with the valid values in wndV[]
  215. int i = p->wndN-1;
  216. int en = 0;
  217. for(; i>=0; --i,++en)
  218. {
  219. if( p->wndV[i].validFl /*&& ((smpIdx-p->wnd[i].smpIdx)<=maxWndSmp)*/)
  220. ewnd[i] = p->wndV[i].val;
  221. else
  222. break;
  223. }
  224. ++i; // increment i to the first valid element in ewnd[].
  225. int k;
  226. printf("en:%i sbi:%i sei:%i pitch:%s : ",en,p->sbi,p->sei,cmMidiToSciPitch(d0,NULL,0));
  227. for(k=i; k<p->wndN; ++k)
  228. printf("%s ", cmMidiToSciPitch(ewnd[k],NULL,0));
  229. printf("\n");
  230. // en is the count of valid elements in ewnd[].
  231. // ewnd[i] is the first valid element
  232. int j = 0;
  233. int dist;
  234. int minDist = INT_MAX;
  235. int minIdx = cmInvalidIdx;
  236. for(j=0; p->sbi+en+j <= p->sei; ++j)
  237. if((dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+i, p->loc + p->sbi+j, en )) < minDist )
  238. {
  239. minDist = dist;
  240. minIdx = j;
  241. }
  242. // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
  243. int evalWndN = cmMin(en,p->evalWndN);
  244. assert(evalWndN<p->wndN);
  245. j = p->sbi+minIdx+en - evalWndN;
  246. // Determine how many of the last evalWndN elements match
  247. dist = _cmScFolDist(p->wndN, p->edWndMtx, ewnd+p->wndN-evalWndN, p->loc+j, evalWndN );
  248. // a successful match has <= allowedMissCnt and an exact match on the last element
  249. //if( dist <= p->allowedMissCnt && ewnd[p->wndN-1] == p->loc[p->sbi+minIdx+en-1] )
  250. if( /*dist <= p->allowedMissCnt &&*/ _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),ewnd[p->wndN-1]))
  251. {
  252. p->sbi = p->sbi + minIdx;
  253. p->sei = cmMin(p->sei+minIdx,p->locN-1);
  254. ret_idx = p->sbi+minIdx+en-1;
  255. }
  256. printf("minDist:%i minIdx:%i evalDist:%i sbi:%i sei:%i\n",minDist,minIdx,dist,p->sbi,p->sei);
  257. return ret_idx;
  258. }