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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285
  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 "cmText.h"
  16. #include "cmProcObj.h"
  17. #include "cmProcTemplate.h"
  18. #include "cmMath.h"
  19. #include "cmProc.h"
  20. #include "cmVectOps.h"
  21. #include "cmMidi.h"
  22. #include "cmMidiFile.h"
  23. #include "cmTimeLine.h"
  24. #include "cmScore.h"
  25. #include "cmProc4.h"
  26. #include "cmTime.h"
  27. cmScFol* cmScFolAlloc( cmCtx* c, cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
  28. {
  29. cmScFol* op = cmObjAlloc(cmScFol,c,p);
  30. if( srate != 0 )
  31. if( cmScFolInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC )
  32. cmScFolFree(&op);
  33. return op;
  34. }
  35. cmRC_t cmScFolFree( cmScFol** pp )
  36. {
  37. cmRC_t rc = cmOkRC;
  38. if( pp==NULL || *pp==NULL )
  39. return rc;
  40. cmScFol* p = *pp;
  41. if((rc = cmScFolFinal(p)) != cmOkRC )
  42. return rc;
  43. unsigned i;
  44. for(i=0; i<p->locN; ++i)
  45. cmMemFree(p->loc[i].evtV);
  46. cmMemFree(p->loc);
  47. cmMemFree(p->bufV);
  48. cmObjFree(pp);
  49. return rc;
  50. }
  51. cmRC_t cmScFolFinal( cmScFol* p )
  52. {
  53. cmMemFree(p->edWndMtx);
  54. return cmOkRC;
  55. }
  56. void _cmScFolPrint( cmScFol* p )
  57. {
  58. int i,j;
  59. for(i=0; i<p->locN; ++i)
  60. {
  61. printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx);
  62. for(j=0; j<p->loc[i].evtCnt; ++j)
  63. printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0));
  64. printf("\n");
  65. }
  66. }
  67. unsigned* _cmScFolAllocEditDistMtx(unsigned maxN)
  68. {
  69. maxN += 1;
  70. unsigned* m = cmMemAllocZ(unsigned,maxN*maxN);
  71. unsigned* p = m;
  72. unsigned i;
  73. // initialize the comparison matrix with the default costs in the
  74. // first row and column
  75. // (Note that this matrix is not oriented in column major order like most 'cm' matrices.)
  76. for(i=0; i<maxN; ++i)
  77. {
  78. p[i] = i; // 0th row
  79. p[ i * maxN ] = i; // 0th col
  80. }
  81. return m;
  82. }
  83. cmRC_t cmScFolInit( cmScFol* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
  84. {
  85. cmRC_t rc;
  86. if((rc = cmScFolFinal(p)) != cmOkRC )
  87. return rc;
  88. if( bufN > maxWndCnt )
  89. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower buffer count (%i) must be less than the max. window length (%i).",bufN,maxWndCnt );
  90. if( minWndLookAhead > maxWndCnt )
  91. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt);
  92. p->srate = srate;
  93. p->scH = scH;
  94. p->bufN = bufN;
  95. p->bufV = cmMemResizeZ(cmScFolBufEle_t,p->bufV,bufN);
  96. p->locN = cmScoreEvtCount(scH);
  97. p->loc = cmMemResizeZ(cmScFolLoc_t,p->loc,p->locN);
  98. p->sbi = cmInvalidIdx;
  99. p->sei = cmInvalidIdx;
  100. p->msln = minWndLookAhead;
  101. p->mswn = maxWndCnt;
  102. p->forwardCnt = 2;
  103. p->maxDist = 4;
  104. p->edWndMtx = _cmScFolAllocEditDistMtx(p->bufN);
  105. p->minVel = minVel;
  106. p->printFl = true;
  107. p->noBackFl = true;
  108. p->missCnt = 0;
  109. p->matchCnt = 0;
  110. p->eventIdx = 0;
  111. p->skipCnt = 0;
  112. p->ret_idx = cmInvalidIdx;
  113. // for each score location
  114. unsigned li,ei;
  115. for(li=0,ei=0; li<cmScoreLocCount(p->scH); ++li)
  116. {
  117. unsigned i,n;
  118. const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
  119. // count the number of note events at location li
  120. for(n=0,i=0; i<lp->evtCnt; ++i)
  121. if( lp->evtArray[i]->type == kNonEvtScId )
  122. ++n;
  123. assert( ei+n <= p->locN );
  124. // duplicate each note at location li n times
  125. for(i=0; i<n; ++i)
  126. {
  127. unsigned j,k;
  128. p->loc[ei+i].evtCnt = n;
  129. p->loc[ei+i].evtV = cmMemAllocZ(cmScFolEvt_t,n);
  130. p->loc[ei+i].scIdx = li;
  131. p->loc[ei+i].barNumb = lp->barNumb;
  132. for(j=0,k=0; j<lp->evtCnt; ++j)
  133. if( lp->evtArray[j]->type == kNonEvtScId )
  134. {
  135. p->loc[ei+i].evtV[k].pitch = lp->evtArray[j]->pitch;
  136. p->loc[ei+i].evtV[k].scEvtIdx = lp->evtArray[j]->index;
  137. ++k;
  138. }
  139. }
  140. ei += n;
  141. }
  142. p->locN = ei;
  143. //_cmScFolPrint(p);
  144. return rc;
  145. }
  146. cmRC_t cmScFolReset( cmScFol* p, unsigned scEvtIdx )
  147. {
  148. int i,j;
  149. // empty the event buffer
  150. memset(p->bufV,0,sizeof(cmScFolBufEle_t)*p->bufN);
  151. // don't allow the score index to be prior to the first note
  152. //if( scEvtIdx < p->loc[0].scIdx )
  153. // scEvtIdx = p->loc[0].scIdx;
  154. p->sei = cmInvalidIdx;
  155. p->sbi = cmInvalidIdx;
  156. p->missCnt = 0;
  157. p->matchCnt = 0;
  158. p->eventIdx = 0;
  159. p->skipCnt = 0;
  160. p->ret_idx = cmInvalidIdx;
  161. // locate the score element in svV[] that is closest to,
  162. // and possibly after, scEvtIdx.
  163. for(i=0; i<p->locN-1; ++i)
  164. {
  165. for(j=0; j<p->loc[i].evtCnt; ++j)
  166. if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx )
  167. p->sbi = i;
  168. else
  169. break;
  170. }
  171. // locate the score element at the end of the look-ahead region
  172. for(; i<p->locN; ++i)
  173. {
  174. for(j=0; j<p->loc[i].evtCnt; ++j)
  175. if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx + p->msln )
  176. p->sei = i;
  177. }
  178. return cmOkRC;
  179. }
  180. bool _cmScFolIsMatch( const cmScFolLoc_t* loc, unsigned pitch )
  181. {
  182. unsigned i;
  183. for(i=0; i<loc->evtCnt; ++i)
  184. if( loc->evtV[i].pitch == pitch )
  185. return true;
  186. return false;
  187. }
  188. int _cmScFolMatchCost( const cmScFolLoc_t* loc, unsigned li, const cmScFolBufEle_t* pitch, unsigned pi )
  189. {
  190. if( _cmScFolIsMatch(loc+li,pitch[pi].val) )
  191. return 0;
  192. if( li>0 && pi>0 )
  193. if( _cmScFolIsMatch(loc+li-1,pitch[pi].val) && _cmScFolIsMatch(loc+li,pitch[pi-1].val) )
  194. return 0;
  195. return 1;
  196. }
  197. int _cmScFolDist(unsigned mtxMaxN, unsigned* m, const cmScFolBufEle_t* s1, const cmScFolLoc_t* s0, int n )
  198. {
  199. mtxMaxN += 1;
  200. assert( n < mtxMaxN );
  201. int v = 0;
  202. unsigned i;
  203. // Note that m[maxN,maxN] is not oriented in column major order like most 'cm' matrices.
  204. for(i=1; i<n+1; ++i)
  205. {
  206. unsigned ii = i * mtxMaxN; // current row
  207. unsigned i_1 = ii - mtxMaxN; // previous row
  208. unsigned j;
  209. for( j=1; j<n+1; ++j)
  210. {
  211. //int cost = s0[i-1] == s1[j-1] ? 0 : 1;
  212. //int cost = _cmScFolIsMatch(s0 + i-1, s1[j-1]) ? 0 : 1;
  213. int cost = _cmScFolMatchCost(s0,i-1,s1,j-1);
  214. //m[i][j] = min( m[i-1][j] + 1, min( m[i][j-1] + 1, m[i-1][j-1] + cost ) );
  215. m[ ii + j ] = v = cmMin( m[ i_1 + j] + 1, cmMin( m[ ii + j - 1] + 1, m[ i_1 + j - 1 ] + cost ) );
  216. }
  217. }
  218. return v;
  219. }
  220. void _cmScFolRpt0( cmScFol* p, unsigned locIdx, unsigned locN, const cmScFolBufEle_t* b, unsigned bn, unsigned min_idx )
  221. {
  222. unsigned i;
  223. int n;
  224. printf("--------------- event:%i ------------- \n",p->eventIdx);
  225. printf("loc: ");
  226. for(i=0; i<locN; ++i)
  227. printf("%4i ",i+locIdx);
  228. printf("\n");
  229. for(n=0,i=0; i<locN; ++i)
  230. if( p->loc[locIdx+i].evtCnt > n )
  231. n = p->loc[locIdx+i].evtCnt;
  232. --n;
  233. for(; n>=0; --n)
  234. {
  235. printf("sc%1i: ",n);
  236. for(i=0; i<locN; ++i)
  237. {
  238. if( n < p->loc[locIdx+i].evtCnt )
  239. printf("%4s ",cmMidiToSciPitch(p->loc[locIdx+i].evtV[n].pitch,NULL,0));
  240. else
  241. printf(" ");
  242. }
  243. printf("\n");
  244. }
  245. printf("perf:");
  246. for(i=0; i<min_idx; ++i)
  247. printf(" ");
  248. for(i=0; i<bn; ++i)
  249. printf("%4s ",cmMidiToSciPitch(b[i].val,NULL,0));
  250. printf("\n");
  251. }
  252. void _cmScFolRpt1( cmScFol*p, unsigned minDist, unsigned ret_idx, unsigned d1, unsigned missCnt, unsigned matchCnt )
  253. {
  254. printf("dist:%i miss:%i match:%i skip:%i vel:%i ",minDist,missCnt,matchCnt,p->skipCnt,d1);
  255. if( ret_idx != cmInvalidIdx )
  256. printf("ret_idx:%i ",ret_idx);
  257. printf("\n");
  258. }
  259. unsigned cmScFolExec( cmScFol* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  260. {
  261. unsigned ret_idx = cmInvalidIdx;
  262. if( p->sbi == cmInvalidIdx )
  263. {
  264. cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." );
  265. return ret_idx;
  266. }
  267. if( status != kNoteOnMdId )
  268. return ret_idx;
  269. ++p->eventIdx;
  270. // reject notes with very low velocity
  271. if( d1 < p->minVel )
  272. {
  273. ++p->skipCnt;
  274. return ret_idx;
  275. }
  276. // left shift bufV[] to make the right-most element available - then copy in the new element
  277. memmove(p->bufV, p->bufV+1, sizeof(cmScFolBufEle_t)*(p->bufN-1));
  278. p->bufV[ p->bufN-1 ].smpIdx = smpIdx;
  279. p->bufV[ p->bufN-1 ].val = d0;
  280. p->bufV[ p->bufN-1 ].validFl= true;
  281. // fill in ebuf[] with the valid values in bufV[]
  282. int en = cmMin(p->eventIdx,p->bufN);
  283. int bbi = p->eventIdx>=p->bufN ? 0 : p->bufN-p->eventIdx;
  284. // en is the count of valid elements in ebuf[].
  285. // ebuf[p->boi] is the first valid element
  286. int j = 0;
  287. int minDist = INT_MAX;
  288. int minIdx = cmInvalidIdx;
  289. int dist;
  290. // the score wnd must always be as long as the buffer n
  291. // at the end of the score this may not be the case
  292. // (once sei hits locN - at this point we must begin
  293. // shrinking ewnd[] to contain only the last p->sei-p->sbi+1 elements)
  294. assert( p->sei-p->sbi+1 >= en );
  295. for(j=0; p->sbi+en+j-1 <= p->sei; ++j)
  296. {
  297. // use <= minDist to choose the latest window with the lowest match
  298. if((dist = _cmScFolDist(p->bufN, p->edWndMtx, p->bufV+bbi, p->loc + p->sbi+j, en )) < minDist )
  299. {
  300. // only make an eql match if the posn is greater than the last location
  301. if( dist==minDist && p->ret_idx != cmInvalidId && p->ret_idx >= p->sbi+minIdx+en-1 )
  302. continue;
  303. minDist = dist;
  304. minIdx = j;
  305. }
  306. }
  307. // The best fit is on the score window: p->loc[sbi+minIdx : sbi+minIdx+en-1 ]
  308. if( p->printFl )
  309. _cmScFolRpt0( p, p->sbi, p->sei-p->sbi+1, p->bufV+bbi, en, minIdx );
  310. // save current missCnt for later printing
  311. unsigned missCnt = p->missCnt;
  312. // if a perfect match occurred
  313. if( minDist == 0 )
  314. {
  315. ret_idx = p->sbi + minIdx + en - 1;
  316. p->missCnt = 0;
  317. // we had a perfect match - shrink the window to it's minumum size
  318. p->sbi += (en==p->bufN) ? minIdx + 1 : 0; // move wnd begin forward to just past first match
  319. p->sei = p->sbi + minIdx + en + p->msln; // move wnd end forward to lead by the min look-ahead
  320. }
  321. else
  322. {
  323. if( minDist > p->maxDist )
  324. ret_idx = cmInvalidIdx;
  325. else
  326. // if the last event matched - then return the match location as the current score location
  327. if( _cmScFolIsMatch(p->loc+(p->sbi+minIdx+en-1),p->bufV[p->bufN-1].val) )
  328. {
  329. ret_idx = p->sbi + minIdx + en - 1;
  330. p->missCnt = 0;
  331. // this is probably a pretty good match reduce the part of the window prior to
  332. // the first match (bring the end of the window almost up to the end of the
  333. // buffers sync position)
  334. if( en >= p->bufN-1 && (en+2) <= ret_idx )
  335. p->sbi = ret_idx - (en+2);
  336. }
  337. else // the last event does not match based on the optimal edit-distance alignment
  338. {
  339. // Look backward from the closest match location for a match to the current pitch.
  340. // The backward search scope is limited by the current value of 'missCnt'.
  341. unsigned i;
  342. j = p->sbi+minIdx+en-2;
  343. for(i=1; i+1 <= p->bufN && j>=p->sbi && i<=p->missCnt; ++i,--j)
  344. {
  345. // if this look-back location already matched then stop the backward search
  346. if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1-i].val))
  347. break;
  348. // does this look-back location match the current pitch
  349. if(_cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val))
  350. {
  351. ret_idx = j;
  352. p->missCnt = i; // set missCnt to the cnt of steps backward necessary for a match
  353. break;
  354. }
  355. }
  356. // If the backward search did not find a match - look forward
  357. if( ret_idx == cmInvalidIdx )
  358. {
  359. unsigned i;
  360. j = p->sbi+minIdx+en;
  361. for(i=0; j<=p->sei && i<p->forwardCnt; ++i,++j)
  362. if( _cmScFolIsMatch(p->loc+j,p->bufV[p->bufN-1].val) )
  363. {
  364. ret_idx = j;
  365. break;
  366. }
  367. p->missCnt = ret_idx == cmInvalidIdx ? p->missCnt + 1 : 0;
  368. }
  369. }
  370. // Adjust the end window position (sei) based on the match location
  371. if( ret_idx == cmInvalidIdx )
  372. {
  373. // even though we didn't match move the end of the score window forward
  374. // this will enlarge the score window by one
  375. p->sei += 1;
  376. }
  377. else
  378. {
  379. assert( p->sei>=ret_idx);
  380. // force sei to lead by min look-ahead
  381. if( p->sei - ret_idx < p->msln )
  382. p->sei = ret_idx + p->msln;
  383. }
  384. assert( p->sei > p->sbi );
  385. // Adjust the begin window position
  386. if( p->noBackFl && ret_idx != cmInvalidIdx && en>=p->bufN && p->sbi > p->bufN )
  387. p->sbi = ret_idx - p->bufN;
  388. // if the score window length surpasses the max score window size
  389. // move the beginning index forward
  390. if( p->sei - p->sbi + 1 > p->mswn && p->sei > p->mswn )
  391. p->sbi = p->sei - p->mswn + 1;
  392. }
  393. if( p->printFl )
  394. _cmScFolRpt1(p, minDist, ret_idx, d1, missCnt, p->matchCnt );
  395. // don't allow the returned location to repeat or go backwards
  396. if( p->noBackFl && p->ret_idx != cmInvalidIdx && ret_idx <= p->ret_idx )
  397. ret_idx = cmInvalidIdx;
  398. // track the number of consecutive matches
  399. if( ret_idx == cmInvalidIdx )
  400. p->matchCnt = 0;
  401. else
  402. {
  403. ++p->matchCnt;
  404. p->ret_idx = ret_idx;
  405. }
  406. // Force the window to remain valid when it is at the end of the score
  407. // - sbi and sei must be inside 0:locN
  408. // - sei-sbi + 1 must be >= en
  409. if( p->sei >= p->locN )
  410. {
  411. p->sei = p->locN - 1;
  412. p->sbi = p->sei - p->bufN + 1;
  413. }
  414. if( ret_idx != cmInvalidIdx )
  415. ret_idx = p->loc[ret_idx].scIdx;
  416. return ret_idx;
  417. }
  418. //=======================================================================================================================
  419. cmScTrk* cmScTrkAlloc( cmCtx* c, cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
  420. {
  421. cmScTrk* op = cmObjAlloc(cmScTrk,c,p);
  422. op->sfp = cmScFolAlloc(c,NULL,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel);
  423. if( srate != 0 )
  424. if( cmScTrkInit(op,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel) != cmOkRC )
  425. cmScTrkFree(&op);
  426. return op;
  427. }
  428. cmRC_t cmScTrkFree( cmScTrk** pp )
  429. {
  430. cmRC_t rc = cmOkRC;
  431. if( pp==NULL || *pp==NULL )
  432. return rc;
  433. cmScTrk* p = *pp;
  434. if((rc = cmScTrkFinal(p)) != cmOkRC )
  435. return rc;
  436. cmScFolFree(&p->sfp);
  437. cmObjFree(pp);
  438. return rc;
  439. }
  440. void _cmScTrkPrint( cmScTrk* p )
  441. {
  442. int i,j;
  443. for(i=0; i<p->locN; ++i)
  444. {
  445. printf("%2i %5i ",p->loc[i].barNumb,p->loc[i].scIdx);
  446. for(j=0; j<p->loc[i].evtCnt; ++j)
  447. printf("%s ",cmMidiToSciPitch(p->loc[i].evtV[j].pitch,NULL,0));
  448. printf("\n");
  449. }
  450. }
  451. cmRC_t cmScTrkInit( cmScTrk* p, cmReal_t srate, cmScH_t scH, unsigned bufN, unsigned minWndLookAhead, unsigned maxWndCnt, unsigned minVel )
  452. {
  453. cmRC_t rc;
  454. if((rc = cmScTrkFinal(p)) != cmOkRC )
  455. return rc;
  456. if( minWndLookAhead > maxWndCnt )
  457. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score follower look-ahead count (%i) must be less than the max. window length (%i).",minWndLookAhead,maxWndCnt);
  458. if((rc = cmScFolInit(p->sfp,srate,scH,bufN,minWndLookAhead,maxWndCnt,minVel)) != cmOkRC )
  459. return rc;
  460. p->srate = srate;
  461. p->scH = scH;
  462. p->locN = cmScoreLocCount(scH);
  463. p->loc = cmMemResizeZ(cmScTrkLoc_t,p->loc,p->locN);
  464. p->minVel = minVel;
  465. p->maxWndCnt = maxWndCnt;
  466. p->minWndLookAhead= 4; //minWndLookAhead;
  467. p->printFl = true;
  468. p->curLocIdx = cmInvalidIdx;
  469. p->evtIndex = 0;
  470. // for each score location
  471. unsigned li;
  472. for(li=0; li<cmScoreLocCount(p->scH); ++li)
  473. {
  474. unsigned i,j,k,n;
  475. const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
  476. // count the number of note events at location li
  477. for(n=0,i=0; i<lp->evtCnt; ++i)
  478. if( lp->evtArray[i]->type == kNonEvtScId )
  479. ++n;
  480. p->loc[li].evtCnt = n;
  481. p->loc[li].evtV = cmMemAllocZ(cmScTrkEvt_t,n);
  482. p->loc[li].scIdx = li;
  483. p->loc[li].barNumb = lp->barNumb;
  484. for(j=0,k=0; j<lp->evtCnt; ++j)
  485. if( lp->evtArray[j]->type == kNonEvtScId )
  486. {
  487. p->loc[li].evtV[k].pitch = lp->evtArray[j]->pitch;
  488. p->loc[li].evtV[k].scEvtIdx = lp->evtArray[j]->index;
  489. ++k;
  490. }
  491. }
  492. //_cmScTrkPrint(p);
  493. return rc;
  494. }
  495. cmRC_t cmScTrkFinal( cmScTrk* p )
  496. {
  497. unsigned i;
  498. for(i=0; i<p->locN; ++i)
  499. cmMemPtrFree(&p->loc[i].evtV);
  500. return cmOkRC;
  501. }
  502. cmRC_t cmScTrkReset( cmScTrk* p, unsigned scEvtIdx )
  503. {
  504. unsigned i;
  505. cmScFolReset(p->sfp,scEvtIdx);
  506. p->curLocIdx = cmInvalidIdx;
  507. p->evtIndex = 0;
  508. // locate the score element in svV[] that is closest to,
  509. // and possibly after, scEvtIdx.
  510. for(i=0; i<p->locN; ++i)
  511. {
  512. unsigned j;
  513. for(j=0; j<p->loc[i].evtCnt; ++j)
  514. {
  515. p->loc[i].evtV[j].matchFl = false;
  516. // it is possible that scEvtIdx is before the first event included in p->loc[0]
  517. // using the p->curLocIdx==cmInvalidIdx forces the first evt in p->loc[0] to be
  518. // selected in this case
  519. if( p->loc[i].evtV[j].scEvtIdx <= scEvtIdx || p->curLocIdx==cmInvalidIdx )
  520. p->curLocIdx = i;
  521. }
  522. }
  523. if( p->curLocIdx == cmInvalidIdx )
  524. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial score search location event %i was not found.", scEvtIdx );
  525. return cmOkRC;
  526. }
  527. unsigned _cmScTrkIsMatch(cmScTrk* p, int d, unsigned pitch )
  528. {
  529. if( 0 <= p->curLocIdx + d && p->curLocIdx+1 < p->locN )
  530. {
  531. unsigned i;
  532. const cmScTrkLoc_t* lp = p->loc + p->curLocIdx + d;
  533. for(i=0; i<lp->evtCnt; ++i)
  534. if( lp->evtV[i].pitch == pitch && lp->evtV[i].matchFl==false)
  535. return i;
  536. }
  537. return cmInvalidIdx;
  538. }
  539. void _cmScTrkRpt0( cmScTrk* p, unsigned pitch, unsigned vel, unsigned nli, unsigned nei )
  540. {
  541. bool missFl = nli==cmInvalidIdx || nei==cmInvalidIdx;
  542. printf("------- event:%i %s vel:%i cur:%i new:%i %s-------\n",p->evtIndex,cmMidiToSciPitch(pitch,NULL,0),vel,p->curLocIdx,nli,missFl?"MISS ":"");
  543. int bi = p->curLocIdx < p->minWndLookAhead ? 0 : p->curLocIdx - p->minWndLookAhead;
  544. int ei = cmMin(p->locN-1,p->curLocIdx+p->minWndLookAhead);
  545. unsigned i,n=0;
  546. for(i=bi; i<=ei; ++i)
  547. if( p->loc[i].evtCnt>n )
  548. n = p->loc[i].evtCnt;
  549. printf("loc ");
  550. for(i=bi; i<=ei; ++i)
  551. printf("%4i ",i);
  552. printf("\n");
  553. for(i=0; i<n; ++i)
  554. {
  555. unsigned j;
  556. printf("sc%2i ",i);
  557. for(j=bi; j<=ei; ++j)
  558. {
  559. if( i < p->loc[j].evtCnt )
  560. {
  561. char* X = p->loc[j].evtV[i].matchFl ? "__" : " ";
  562. if( nli==j && nei==i)
  563. {
  564. X = "**";
  565. assert( p->loc[j].evtV[i].pitch == pitch );
  566. }
  567. printf("%4s%s ",cmMidiToSciPitch(p->loc[j].evtV[i].pitch,NULL,0),X);
  568. }
  569. else
  570. printf(" ");
  571. }
  572. printf("\n");
  573. }
  574. }
  575. unsigned cmScTrkExec( cmScTrk* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  576. {
  577. unsigned ret_idx = cmInvalidIdx;
  578. //cmScFolExec(p->sfp, smpIdx, status, d0, d1);
  579. if( status != kNoteOnMdId )
  580. return cmInvalidIdx;
  581. if( p->curLocIdx == cmInvalidIdx )
  582. {
  583. cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An initial score search location has not been set." );
  584. return cmInvalidIdx;
  585. }
  586. int i,nei,nli=cmInvalidIdx;
  587. // try to match curLocIdx first
  588. if((nei = _cmScTrkIsMatch(p,0,d0)) != cmInvalidIdx )
  589. nli = p->curLocIdx;
  590. for(i=1; nei==cmInvalidIdx && i<p->minWndLookAhead; ++i)
  591. {
  592. // go forward
  593. if((nei = _cmScTrkIsMatch(p,i,d0)) != cmInvalidIdx )
  594. nli = p->curLocIdx + i;
  595. else
  596. // go backward
  597. if((nei = _cmScTrkIsMatch(p,-i,d0)) != cmInvalidIdx )
  598. nli = p->curLocIdx - i;
  599. }
  600. if( p->printFl )
  601. {
  602. _cmScTrkRpt0(p, d0, d1, nli, nei );
  603. }
  604. if( nli != cmInvalidIdx )
  605. {
  606. p->loc[nli].evtV[nei].matchFl = true;
  607. ret_idx = p->loc[nli].scIdx;
  608. if( nli > p->curLocIdx )
  609. p->curLocIdx = nli;
  610. }
  611. ++p->evtIndex;
  612. return ret_idx;
  613. }
  614. //=======================================================================================================================
  615. //----------------------------------------------------------------------------------------
  616. void ed_print_mtx( ed_r* r)
  617. {
  618. unsigned i,j,k;
  619. for(i=0; i<r->rn; ++i)
  620. {
  621. for(j=0; j<r->cn; ++j)
  622. {
  623. printf("(");
  624. const ed_val* vp = r->m + i + (j*r->rn);
  625. for(k=0; k<kEdCnt; ++k)
  626. {
  627. printf("%i",vp->v[k]);
  628. if( k<kEdCnt-1)
  629. printf(", ");
  630. else
  631. printf(" ");
  632. }
  633. printf("%c)",vp->transFl?'t':' ');
  634. }
  635. printf("\n");
  636. }
  637. }
  638. void ed_init( ed_r* r, const char* s0, const char* s1 )
  639. {
  640. unsigned i,j,k;
  641. r->rn = strlen(s0)+1;
  642. r->cn = strlen(s1)+1;
  643. r->m = cmMemAllocZ(ed_val, r->rn*r->cn );
  644. r->pn = r->rn + r->cn;
  645. r->p_mem = cmMemAllocZ(ed_path, 2*r->pn );
  646. r->p_avl = r->p_mem;
  647. r->p_cur = NULL;
  648. r->p_opt = r->p_mem + r->pn;
  649. r->s_opt = DBL_MAX;
  650. r->s0 = s0;
  651. r->s1 = s1;
  652. for(i=0; i<r->rn; ++i)
  653. for(j=0; j<r->cn; ++j)
  654. {
  655. unsigned v[] = {0,0,0,0};
  656. if( i == 0 )
  657. {
  658. v[kEdMinIdx] = j;
  659. v[kEdInsIdx] = j;
  660. }
  661. else
  662. if( j == 0 )
  663. {
  664. v[kEdMinIdx] = i;
  665. v[kEdDelIdx] = i;
  666. }
  667. for(k=0; k<kEdCnt; ++k)
  668. r->m[ i + (j*r->rn) ].v[k] = v[k];
  669. }
  670. // put pn path records on the available list
  671. for(i=0; i<r->pn; ++i)
  672. r->p_mem[i].next = i<r->pn-1 ? r->p_mem + i + 1 : NULL;
  673. }
  674. unsigned _ed_min( ed_r* r, unsigned i, unsigned j )
  675. {
  676. assert( i<r->rn && j<r->cn );
  677. return r->m[ i + (j*r->rn) ].v[kEdMinIdx];
  678. }
  679. bool _ed_is_trans( ed_r* r, const ed_val* v1p, unsigned i, unsigned j )
  680. {
  681. bool fl = false;
  682. ed_val* v0p = r->m + i + (j*r->rn);
  683. if( i>=1 && j>=1 &&
  684. v1p->v[kEdMinIdx] == v1p->v[kEdSubIdx]
  685. && v1p->matchFl == false
  686. && v0p->v[kEdMinIdx] == v0p->v[kEdSubIdx]
  687. && v0p->matchFl == false )
  688. {
  689. char c00 = r->s0[i-1];
  690. char c01 = r->s0[i ];
  691. char c10 = r->s1[j-1];
  692. char c11 = r->s1[j ];
  693. fl = c00==c11 && c01==c10;
  694. }
  695. return fl;
  696. }
  697. void ed_calc_mtx( ed_r* r )
  698. {
  699. unsigned i,j;
  700. for(i=1; i<r->rn; ++i)
  701. for(j=1; j<r->cn; ++j)
  702. {
  703. ed_val* vp = r->m + i + (j*r->rn);
  704. vp->matchFl = r->s0[i-1] == r->s1[j-1];
  705. unsigned cost = vp->matchFl ? 0 : 1;
  706. vp->v[kEdSubIdx] = _ed_min(r,i-1,j-1) + cost;
  707. vp->v[kEdDelIdx] = _ed_min(r,i-1,j ) + 1;
  708. vp->v[kEdInsIdx] = _ed_min(r,i, j-1) + 1;
  709. vp->v[kEdMinIdx] = cmMin( vp->v[kEdSubIdx], cmMin(vp->v[kEdDelIdx],vp->v[kEdInsIdx]));
  710. vp->transFl = _ed_is_trans(r,vp,i-1,j-1);
  711. }
  712. }
  713. void ed_path_push( ed_r* r, unsigned code, unsigned ri, unsigned ci, bool matchFl, bool transFl )
  714. {
  715. assert(r->p_avl != NULL );
  716. ed_path* p = r->p_avl;
  717. r->p_avl = r->p_avl->next;
  718. p->code = code;
  719. p->ri = ri;
  720. p->ci = ci;
  721. p->matchFl = matchFl;
  722. p->transFl = transFl;
  723. p->next = r->p_cur;
  724. r->p_cur = p;
  725. }
  726. void ed_path_pop( ed_r* r )
  727. {
  728. assert( r->p_cur != NULL );
  729. ed_path* tp = r->p_cur->next;
  730. r->p_cur->next = r->p_avl;
  731. r->p_avl = r->p_cur;
  732. r->p_cur = tp;
  733. }
  734. double ed_score_candidate( ed_r* r )
  735. {
  736. ed_path* cp = r->p_cur;
  737. ed_path* bp = r->p_cur;
  738. ed_path* ep = NULL;
  739. for(; cp!=NULL; cp=cp->next)
  740. if( cp->code != kEdInsIdx )
  741. {
  742. bp = cp;
  743. break;
  744. }
  745. for(; cp!=NULL; cp=cp->next)
  746. if( cp->code!=kEdInsIdx )
  747. ep = cp;
  748. assert( ep!=NULL && bp!=ep);
  749. unsigned n=1;
  750. for(cp=bp; cp!=ep; cp=cp->next)
  751. ++n;
  752. double gapCnt = 0;
  753. double penalty = 0;
  754. bool pfl = bp->matchFl;
  755. unsigned i;
  756. cp = bp;
  757. for(i=0; i<n; ++i,cp=cp->next)
  758. {
  759. // a gap is a transition from a matching subst. to an insert or deletion
  760. //if( pc != cp->code && cp->code != kEdSubIdx && pc==kEdSubIdx && pfl==true )
  761. if( pfl==true && cp->matchFl==false )
  762. ++gapCnt;
  763. //
  764. switch( cp->code )
  765. {
  766. case kEdSubIdx:
  767. penalty += cp->matchFl ? 0 : 1;
  768. penalty -= cp->transFl ? 1 : 0;
  769. break;
  770. case kEdDelIdx:
  771. penalty += 1;
  772. break;
  773. case kEdInsIdx:
  774. penalty += 1;
  775. break;
  776. }
  777. pfl = cp->matchFl;
  778. }
  779. double score = gapCnt/n + penalty;
  780. printf("n:%i gaps:%f gap_score:%f penalty:%f score:%f\n",n,gapCnt,gapCnt/n,penalty,score);
  781. return score;
  782. }
  783. void ed_eval_candidate( ed_r* r, double score )
  784. {
  785. if( r->s_opt == DBL_MAX || r->s_opt > score)
  786. {
  787. // copy the p_cur to p_opt[]
  788. ed_path* cp = r->p_cur;
  789. unsigned i;
  790. for(i=0; cp!=NULL && i<r->pn; cp=cp->next,++i)
  791. {
  792. r->p_opt[i].code = cp->code;
  793. r->p_opt[i].ri = cp->ri;
  794. r->p_opt[i].ci = cp->ci;
  795. r->p_opt[i].matchFl = cp->matchFl;
  796. r->p_opt[i].transFl = cp->transFl;
  797. }
  798. assert( i < r->pn );
  799. r->p_opt[i].code = 0; // terminate with code=0
  800. r->s_opt = score;
  801. }
  802. }
  803. void ed_print_opt( ed_r* r )
  804. {
  805. unsigned i;
  806. for(i=0; r->p_opt[i].code!=0; ++i)
  807. {
  808. ed_path* cp = r->p_opt + i;
  809. char c0 = cp->matchFl ? 'm' : ' ';
  810. char c1 = cp->transFl ? 't' : ' ';
  811. printf("%2i code:%i ri:%2i ci:%2i %c%c\n",i,cp->code,cp->ri,cp->ci,c0,c1);
  812. }
  813. printf("score:%f\n",r->s_opt);
  814. }
  815. void ed_print_candidate( ed_r* r )
  816. {
  817. ed_path* cp = r->p_cur;
  818. unsigned pn = r->pn;
  819. unsigned i;
  820. char s0[pn+1];
  821. char s1[pn+1];
  822. char s2[pn+1];
  823. char s3[pn+1];
  824. s0[pn] = 0;
  825. s1[pn] = 0;
  826. s2[pn] = 0;
  827. s3[pn] = 0;
  828. for(i=0; i<pn && cp!=NULL; ++i,cp=cp->next)
  829. {
  830. switch(cp->code)
  831. {
  832. case kEdSubIdx: // subst
  833. assert( 0 <= cp->ri && cp->ri <= r->rn );
  834. assert( 0 <= cp->ci && cp->ci <= r->cn );
  835. s0[i] = r->s0[cp->ri];
  836. s1[i] = r->s1[cp->ci];
  837. s2[i] = 's';
  838. s3[i] = cp->matchFl ? 'm' : ' ';
  839. break;
  840. case kEdDelIdx: // delete
  841. assert( 0 <= cp->ri && cp->ri <= r->rn );
  842. s0[i] = r->s0[cp->ri];
  843. s1[i] = ' ';
  844. s2[i] = 'd';
  845. s3[i] = ' ';
  846. break;
  847. case kEdInsIdx: // insert
  848. assert( 0 <= cp->ci && cp->ci <= r->cn );
  849. s0[i] = ' ';
  850. s1[i] = r->s1[cp->ci];
  851. s2[i] = 'i';
  852. s3[i] = ' ';
  853. break;
  854. }
  855. }
  856. if( i < pn )
  857. {
  858. s0[i] = 0;
  859. s1[i] = 0;
  860. s2[i] = 0;
  861. s3[i] = 0;
  862. }
  863. printf("\ns0:%s\n",s0);
  864. printf("s1:%s\n",s1);
  865. printf("s2:%s\n",s2);
  866. printf("s3:%s\n",s3);
  867. }
  868. // traverse the solution matrix from the lower-right to
  869. // the upper-left.
  870. void ed_node( ed_r* r, int i, int j )
  871. {
  872. unsigned m;
  873. // stop when the upper-right is encountered
  874. if( i==0 && j==0 )
  875. {
  876. ed_print_candidate(r);
  877. ed_eval_candidate(r, ed_score_candidate(r) );
  878. return;
  879. }
  880. ed_val* vp = r->m + i + (j*r->rn);
  881. // for each possible dir: up,left,up-left
  882. for(m=1; m<kEdCnt; ++m)
  883. if( vp->v[m] == vp->v[kEdMinIdx] )
  884. {
  885. unsigned ii = i-1;
  886. unsigned jj = j-1;
  887. switch(m)
  888. {
  889. case kEdSubIdx:
  890. break;
  891. case kEdDelIdx:
  892. jj = j;
  893. break;
  894. case kEdInsIdx:
  895. ii = i;
  896. break;
  897. }
  898. // prepend to the current candidate path: r->p_cur
  899. ed_path_push(r,m,ii,jj,vp->matchFl,vp->transFl);
  900. // recurse!
  901. ed_node(r,ii,jj);
  902. // remove the first element from the current path
  903. ed_path_pop(r);
  904. }
  905. }
  906. void ed_align( ed_r* r )
  907. {
  908. int i = r->rn-1;
  909. int j = r->cn-1;
  910. unsigned m = r->m[i + (j*r->rn)].v[kEdMinIdx];
  911. if( m==cmMax(r->rn,r->cn) )
  912. printf("Edit distance is at max: %i. No Match.\n",m);
  913. else
  914. ed_node(r,i,j);
  915. }
  916. void ed_free( ed_r* r )
  917. {
  918. cmMemFree(r->m);
  919. cmMemFree(r->p_mem);
  920. }
  921. void ed_main()
  922. {
  923. const char* s0 = "YHCQPGK";
  924. const char* s1 = "LAHYQQKPGKA";
  925. s0 = "ABCDE";
  926. s1 = "ABDCE";
  927. //s1 = "FGHIJK";
  928. ed_r r;
  929. ed_init(&r,s0,s1);
  930. ed_calc_mtx(&r);
  931. ed_print_mtx(&r);
  932. ed_align(&r);
  933. ed_print_opt(&r);
  934. ed_free(&r);
  935. }
  936. //=======================================================================================================================
  937. cmScMatch* cmScMatchAlloc( cmCtx* c, cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN )
  938. {
  939. cmScMatch* op = cmObjAlloc(cmScMatch,c,p);
  940. if( cmScoreIsValid(scH) )
  941. if( cmScMatchInit(op,scH,maxScWndN,maxMidiWndN) != cmOkRC )
  942. cmScMatchFree(&op);
  943. return op;
  944. }
  945. cmRC_t cmScMatchFree( cmScMatch** pp )
  946. {
  947. cmRC_t rc = cmOkRC;
  948. if( pp==NULL || *pp==NULL )
  949. return rc;
  950. cmScMatch* p = *pp;
  951. if((rc = cmScMatchFinal(p)) != cmOkRC )
  952. return rc;
  953. cmMemFree(p->loc);
  954. cmMemFree(p->m);
  955. cmMemFree(p->p_mem);
  956. cmObjFree(pp);
  957. return rc;
  958. }
  959. void _cmScMatchInitLoc( cmScMatch* p )
  960. {
  961. unsigned li,ei;
  962. p->locN = cmScoreEvtCount(p->scH);
  963. p->loc = cmMemResizeZ(cmScMatchLoc_t,p->loc,p->locN);
  964. // for each score location
  965. for(li=0,ei=0; li<cmScoreLocCount(p->scH); ++li)
  966. {
  967. unsigned i,n;
  968. const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
  969. // count the number of note events at location li
  970. for(n=0,i=0; i<lp->evtCnt; ++i)
  971. if( lp->evtArray[i]->type == kNonEvtScId )
  972. ++n;
  973. assert( ei+n <= p->locN );
  974. // duplicate each note at location li n times
  975. for(i=0; i<n; ++i)
  976. {
  977. unsigned j,k;
  978. p->loc[ei+i].evtCnt = n;
  979. p->loc[ei+i].evtV = cmMemAllocZ(cmScMatchEvt_t,n);
  980. p->loc[ei+i].scLocIdx = li;
  981. p->loc[ei+i].barNumb = lp->barNumb;
  982. for(j=0,k=0; j<lp->evtCnt; ++j)
  983. if( lp->evtArray[j]->type == kNonEvtScId )
  984. {
  985. p->loc[ei+i].evtV[k].pitch = lp->evtArray[j]->pitch;
  986. p->loc[ei+i].evtV[k].scEvtIdx = lp->evtArray[j]->index;
  987. ++k;
  988. }
  989. }
  990. ei += n;
  991. }
  992. assert(ei<=p->locN);
  993. p->locN = ei;
  994. }
  995. cmRC_t cmScMatchInit( cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN )
  996. {
  997. unsigned i;
  998. cmRC_t rc;
  999. if((rc = cmScMatchFinal(p)) != cmOkRC )
  1000. return rc;
  1001. p->scH = scH;
  1002. p->mrn = maxMidiWndN + 1;
  1003. p->mcn = maxScWndN + 1;
  1004. p->mmn = maxMidiWndN;
  1005. p->msn = maxScWndN;
  1006. _cmScMatchInitLoc(p);
  1007. p->m = cmMemResizeZ(cmScMatchVal_t, p->m, p->mrn*p->mcn );
  1008. p->pn = p->mrn + p->mcn;
  1009. p->p_mem = cmMemResizeZ(cmScMatchPath_t, p->p_mem, 2*p->pn );
  1010. p->p_avl = p->p_mem;
  1011. p->p_cur = NULL;
  1012. p->p_opt = p->p_mem + p->pn;
  1013. // put pn path records on the available list
  1014. for(i=0; i<p->pn; ++i)
  1015. {
  1016. p->p_mem[i].next = i<p->pn-1 ? p->p_mem + i + 1 : NULL;
  1017. p->p_opt[i].next = i<p->pn-1 ? p->p_opt + i + 1 : NULL;
  1018. }
  1019. return rc;
  1020. }
  1021. cmRC_t cmScMatchFinal( cmScMatch* p )
  1022. {
  1023. unsigned i;
  1024. if( p != NULL )
  1025. for(i=0; i<p->locN; ++i)
  1026. cmMemPtrFree(&p->loc[i].evtV);
  1027. return cmOkRC;
  1028. }
  1029. cmRC_t _cmScMatchInitMtx( cmScMatch* p, unsigned rn, unsigned cn )
  1030. {
  1031. if( rn >p->mrn && cn > p->mcn )
  1032. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "MIDI sequence length must be less than %i. Score sequence length must be less than %i.",p->mmn,p->msn);
  1033. // if the size of the mtx is not changing then there is nothing to do
  1034. if( rn == p->rn && cn == p->cn )
  1035. return cmOkRC;
  1036. // update the mtx size
  1037. p->rn = rn;
  1038. p->cn = cn;
  1039. // fill in the default values for the first row
  1040. // and column of the DP matrix
  1041. unsigned i,j,k;
  1042. for(i=0; i<rn; ++i)
  1043. for(j=0; j<cn; ++j)
  1044. {
  1045. unsigned v[] = {0,0,0,0};
  1046. if( i == 0 )
  1047. {
  1048. v[kSmMinIdx] = j;
  1049. v[kSmInsIdx] = j;
  1050. }
  1051. else
  1052. if( j == 0 )
  1053. {
  1054. v[kSmMinIdx] = i;
  1055. v[kSmDelIdx] = i;
  1056. }
  1057. // zero the value field
  1058. for(k=0; k<kSmCnt; ++k)
  1059. p->m[ i + (j*rn) ].v[k] = v[k];
  1060. }
  1061. return cmOkRC;
  1062. }
  1063. cmScMatchVal_t* _cmScMatchValPtr( cmScMatch* p, unsigned i, unsigned j, unsigned rn, unsigned cn )
  1064. {
  1065. assert( i < rn && j < cn );
  1066. return p->m + i + (j*rn);
  1067. }
  1068. unsigned _cmScMatchIsMatchIndex( const cmScMatchLoc_t* loc, unsigned pitch )
  1069. {
  1070. unsigned i;
  1071. for(i=0; i<loc->evtCnt; ++i)
  1072. if( loc->evtV[i].pitch == pitch )
  1073. return i;
  1074. return cmInvalidIdx;
  1075. }
  1076. bool _cmScMatchIsMatch( const cmScMatchLoc_t* loc, unsigned pitch )
  1077. { return _cmScMatchIsMatchIndex(loc,pitch) != cmInvalidIdx; }
  1078. bool _cmScMatchIsTrans( cmScMatch* p, const cmScMatchMidi_t* midiV, const cmScMatchVal_t* v1p, unsigned bsi, unsigned i, unsigned j, unsigned rn, unsigned cn )
  1079. {
  1080. bool fl = false;
  1081. cmScMatchVal_t* v0p = _cmScMatchValPtr(p,i,j,rn,cn);
  1082. if( i>=1 && j>=1
  1083. && v1p->v[kSmMinIdx] == v1p->v[kSmSubIdx]
  1084. && cmIsNotFlag(v1p->flags,kSmMatchFl)
  1085. && v0p->v[kSmMinIdx] == v0p->v[kSmSubIdx]
  1086. && cmIsNotFlag(v0p->flags,kSmMatchFl)
  1087. )
  1088. {
  1089. unsigned c00 = midiV[i-1].pitch;
  1090. unsigned c01 = midiV[i ].pitch;
  1091. cmScMatchLoc_t* c10 = p->loc + bsi + j - 1;
  1092. cmScMatchLoc_t* c11 = p->loc + bsi + j;
  1093. fl = _cmScMatchIsMatch(c11,c00) && _cmScMatchIsMatch(c10,c01);
  1094. }
  1095. return fl;
  1096. }
  1097. unsigned _cmScMatchMin( cmScMatch* p, unsigned i, unsigned j, unsigned rn, unsigned cn )
  1098. {
  1099. return _cmScMatchValPtr(p,i,j,rn,cn)->v[kSmMinIdx];
  1100. }
  1101. // Return false if bsi + cn > p->locN
  1102. // pitchV[rn-1]
  1103. bool _cmScMatchCalcMtx( cmScMatch* p, unsigned bsi, const cmScMatchMidi_t* midiV, unsigned rn, unsigned cn )
  1104. {
  1105. // loc[begScanLocIdx:begScanLocIdx+cn-1] must be valid
  1106. if( bsi + cn > p->locN )
  1107. return false;
  1108. unsigned i,j;
  1109. for(j=1; j<cn; ++j)
  1110. for(i=1; i<rn; ++i)
  1111. {
  1112. cmScMatchLoc_t* loc = p->loc + bsi + j - 1;
  1113. unsigned pitch = midiV[i-1].pitch;
  1114. cmScMatchVal_t* vp = _cmScMatchValPtr(p,i,j,rn,cn);
  1115. unsigned idx = _cmScMatchIsMatchIndex(loc,pitch);
  1116. vp->flags = idx==cmInvalidIdx ? 0 : kSmMatchFl;
  1117. vp->scEvtIdx = idx==cmInvalidIdx ? cmInvalidIdx : loc->evtV[idx].scEvtIdx;
  1118. unsigned cost = cmIsFlag(vp->flags,kSmMatchFl) ? 0 : 1;
  1119. vp->v[kSmSubIdx] = _cmScMatchMin(p,i-1,j-1, rn, cn) + cost;
  1120. vp->v[kSmDelIdx] = _cmScMatchMin(p,i-1,j , rn, cn) + 1;
  1121. vp->v[kSmInsIdx] = _cmScMatchMin(p,i, j-1, rn, cn) + 1;
  1122. vp->v[kSmMinIdx] = cmMin( vp->v[kSmSubIdx], cmMin(vp->v[kSmDelIdx],vp->v[kSmInsIdx]));
  1123. vp->flags |= _cmScMatchIsTrans(p,midiV,vp,bsi,i-1,j-1,rn,cn) ? kSmTransFl : 0;
  1124. }
  1125. return true;
  1126. }
  1127. void _cmScMatchPrintMtx( cmScMatch* r, unsigned rn, unsigned cn)
  1128. {
  1129. unsigned i,j,k;
  1130. for(i=0; i<rn; ++i)
  1131. {
  1132. for(j=0; j<cn; ++j)
  1133. {
  1134. printf("(");
  1135. const cmScMatchVal_t* vp = _cmScMatchValPtr(r,i,j,rn,cn);
  1136. for(k=0; k<kSmCnt; ++k)
  1137. {
  1138. printf("%i",vp->v[k]);
  1139. if( k<kSmCnt-1)
  1140. printf(", ");
  1141. else
  1142. printf(" ");
  1143. }
  1144. printf("%c%c)",cmIsFlag(vp->flags,kSmMatchFl)?'m':' ',cmIsFlag(vp->flags,kSmTransFl)?'t':' ');
  1145. }
  1146. printf("\n");
  1147. }
  1148. }
  1149. void _cmScMatchPathPush( cmScMatch* r, unsigned code, unsigned ri, unsigned ci, unsigned flags, unsigned scEvtIdx )
  1150. {
  1151. assert(r->p_avl != NULL );
  1152. cmScMatchPath_t* p = r->p_avl;
  1153. r->p_avl = r->p_avl->next;
  1154. p->code = code;
  1155. p->ri = ri;
  1156. p->ci = ci;
  1157. p->flags = code==kSmSubIdx && cmIsFlag(flags,kSmMatchFl) ? kSmMatchFl : 0;
  1158. p->flags |= cmIsFlag(flags,kSmTransFl) ? kSmTransFl : 0;
  1159. p->scEvtIdx= scEvtIdx;
  1160. p->next = r->p_cur;
  1161. r->p_cur = p;
  1162. }
  1163. void _cmScMatchPathPop( cmScMatch* r )
  1164. {
  1165. assert( r->p_cur != NULL );
  1166. cmScMatchPath_t* tp = r->p_cur->next;
  1167. r->p_cur->next = r->p_avl;
  1168. r->p_avl = r->p_cur;
  1169. r->p_cur = tp;
  1170. }
  1171. double _cmScMatchCalcCandidateCost( cmScMatch* r )
  1172. {
  1173. cmScMatchPath_t* cp = r->p_cur;
  1174. cmScMatchPath_t* bp = r->p_cur;
  1175. cmScMatchPath_t* ep = NULL;
  1176. // skip leading inserts
  1177. for(; cp!=NULL; cp=cp->next)
  1178. if( cp->code != kSmInsIdx )
  1179. {
  1180. bp = cp;
  1181. break;
  1182. }
  1183. // skip to trailing inserts
  1184. for(; cp!=NULL; cp=cp->next)
  1185. if( cp->code!=kSmInsIdx )
  1186. ep = cp;
  1187. // count remaining path length
  1188. assert( ep!=NULL );
  1189. unsigned n=1;
  1190. for(cp=bp; cp!=ep; cp=cp->next)
  1191. ++n;
  1192. double gapCnt = 0;
  1193. double penalty = 0;
  1194. bool pfl = cmIsFlag(bp->flags,kSmMatchFl);
  1195. unsigned i;
  1196. cp = bp;
  1197. for(i=0; i<n; ++i,cp=cp->next)
  1198. {
  1199. // a gap is a transition from a matching subst. to an insert or deletion
  1200. //if( pc != cp->code && cp->code != kSmSubIdx && pc==kSmSubIdx && pfl==true )
  1201. if( pfl==true && cmIsFlag(cp->flags,kSmMatchFl)==false )
  1202. ++gapCnt;
  1203. //
  1204. switch( cp->code )
  1205. {
  1206. case kSmSubIdx:
  1207. penalty += cmIsFlag(cp->flags,kSmMatchFl) ? 0 : 1;
  1208. penalty -= cmIsFlag(cp->flags,kSmTransFl) ? 1 : 0;
  1209. break;
  1210. case kSmDelIdx:
  1211. penalty += 1;
  1212. break;
  1213. case kSmInsIdx:
  1214. penalty += 1;
  1215. break;
  1216. }
  1217. pfl = cmIsFlag(cp->flags,kSmMatchFl);
  1218. }
  1219. double cost = gapCnt/n + penalty;
  1220. //printf("n:%i gaps:%f gap_score:%f penalty:%f score:%f\n",n,gapCnt,gapCnt/n,penalty,score);
  1221. return cost;
  1222. }
  1223. double _cmScMatchEvalCandidate( cmScMatch* r, double min_cost, double cost )
  1224. {
  1225. if( min_cost == DBL_MAX || cost < min_cost)
  1226. {
  1227. // copy the p_cur to p_opt[]
  1228. cmScMatchPath_t* cp = r->p_cur;
  1229. unsigned i;
  1230. for(i=0; cp!=NULL && i<r->pn; cp=cp->next,++i)
  1231. {
  1232. r->p_opt[i].code = cp->code;
  1233. r->p_opt[i].ri = cp->ri;
  1234. r->p_opt[i].ci = cp->ci;
  1235. r->p_opt[i].flags = cp->flags;
  1236. r->p_opt[i].scEvtIdx= cp->scEvtIdx;
  1237. r->p_opt[i].next = cp->next==NULL ? NULL : r->p_opt + i + 1;
  1238. }
  1239. assert( i < r->pn );
  1240. r->p_opt[i].code = 0; // terminate with code=0
  1241. min_cost = cost;
  1242. }
  1243. return min_cost;
  1244. }
  1245. // NOTE: IF THE COST CALCULATION WAS BUILT INTO THE RECURSION THEN
  1246. // THIS FUNCTION COULD BE MADE MORE EFFICIENT BECAUSE PATHS WHICH
  1247. // EXCEEDED THE min_cost COULD BE SHORT CIRCUITED.
  1248. //
  1249. // traverse the solution matrix from the lower-right to
  1250. // the upper-left.
  1251. double _cmScMatchGenPaths( cmScMatch* r, int i, int j, unsigned rn, unsigned cn, double min_cost )
  1252. {
  1253. unsigned m;
  1254. // stop when the upper-right is encountered
  1255. if( i==0 && j==0 )
  1256. return _cmScMatchEvalCandidate(r, min_cost, _cmScMatchCalcCandidateCost(r) );
  1257. cmScMatchVal_t* vp = _cmScMatchValPtr(r,i,j,rn,cn);
  1258. // for each possible dir: up,left,up-left
  1259. for(m=1; m<kSmCnt; ++m)
  1260. if( vp->v[m] == vp->v[kSmMinIdx] )
  1261. {
  1262. // prepend to the current candidate path: r->p_cur
  1263. _cmScMatchPathPush(r,m,i,j,vp->flags,vp->scEvtIdx);
  1264. int ii = i-1;
  1265. int jj = j-1;
  1266. switch(m)
  1267. {
  1268. case kSmSubIdx:
  1269. break;
  1270. case kSmDelIdx:
  1271. jj = j;
  1272. break;
  1273. case kSmInsIdx:
  1274. ii = i;
  1275. break;
  1276. default:
  1277. { assert(0); }
  1278. }
  1279. // recurse!
  1280. min_cost = _cmScMatchGenPaths(r,ii,jj,rn,cn,min_cost);
  1281. // remove the first element from the current path
  1282. _cmScMatchPathPop(r);
  1283. }
  1284. return min_cost;
  1285. }
  1286. double _cmScMatchAlign( cmScMatch* p, unsigned rn, unsigned cn, double min_cost )
  1287. {
  1288. int i = rn-1;
  1289. int j = cn-1;
  1290. unsigned m = _cmScMatchMin(p,i,j,rn,cn);
  1291. if( m==cmMax(rn,cn) )
  1292. printf("Edit distance is at max: %i. No Match.\n",m);
  1293. else
  1294. min_cost = _cmScMatchGenPaths(p,i,j,rn,cn,min_cost);
  1295. return min_cost;
  1296. }
  1297. cmRC_t cmScMatchExec( cmScMatch* p, unsigned locIdx, unsigned locN, const cmScMatchMidi_t* midiV, unsigned midiN, double min_cost )
  1298. {
  1299. cmRC_t rc;
  1300. unsigned rn = midiN + 1;
  1301. unsigned cn = locN + 1;
  1302. // set the DP matrix default values
  1303. if((rc = _cmScMatchInitMtx(p, rn, cn )) != cmOkRC )
  1304. return rc;
  1305. // _cmScMatchCalcMtx() returns false if the score window exceeds the length of the score
  1306. if(!_cmScMatchCalcMtx(p,locIdx, midiV, rn, cn) )
  1307. return cmEofRC;
  1308. //_cmScMatchPrintMtx(p,rn,cn);
  1309. // locate the path through the DP matrix with the lowest edit distance (cost)
  1310. p->opt_cost = _cmScMatchAlign(p, rn, cn, min_cost);
  1311. return rc;
  1312. }
  1313. // Traverse the least cost path and:
  1314. // 1) Set p->esi to the score location index of the last MIDI note
  1315. // which has a positive match with the score and assign
  1316. // the internal score index to cp->locIdx.
  1317. //
  1318. // 2) Set cmScAlignPath_t.locIdx - index into p->loc[] associated
  1319. // with each path element that is a 'substitute' or an 'insert'.
  1320. //
  1321. // 3) Set p->missCnt: the count of trailing non-positive matches.
  1322. // p->missCnt is eventually used in cmScAlignStep() to track the number
  1323. // of consecutive trailing missed notes.
  1324. //
  1325. // i_opt is index into p->loc[] of p->p_opt.
  1326. unsigned cmScMatchDoSync( cmScMatch* p, unsigned i_opt, cmScMatchMidi_t* midiBuf, unsigned midiN, unsigned* missCntPtr )
  1327. {
  1328. cmScMatchPath_t* cp = p->p_opt;
  1329. unsigned missCnt = 0;
  1330. unsigned esi = cmInvalidIdx;
  1331. unsigned i;
  1332. for(i=0; cp!=NULL; cp=cp->next)
  1333. {
  1334. // there is no MIDI note associated with 'inserts'
  1335. if( cp->code != kSmInsIdx )
  1336. {
  1337. assert( cp->ri > 0 );
  1338. midiBuf[ cp->ri-1 ].locIdx = cmInvalidIdx;
  1339. }
  1340. switch( cp->code )
  1341. {
  1342. case kSmSubIdx:
  1343. midiBuf[ cp->ri-1 ].locIdx = i_opt + i;
  1344. midiBuf[ cp->ri-1 ].scEvtIdx = cp->scEvtIdx;
  1345. if( cmIsFlag(cp->flags,kSmMatchFl) )
  1346. {
  1347. esi = i_opt + i;
  1348. missCnt = 0;
  1349. }
  1350. else
  1351. {
  1352. ++missCnt;
  1353. }
  1354. // fall through
  1355. case kSmInsIdx:
  1356. cp->locIdx = i_opt + i;
  1357. ++i;
  1358. break;
  1359. case kSmDelIdx:
  1360. cp->locIdx = cmInvalidIdx;
  1361. ++missCnt;
  1362. break;
  1363. }
  1364. }
  1365. if( missCntPtr != NULL )
  1366. *missCntPtr = missCnt;
  1367. return esi;
  1368. }
  1369. void _cmScMatchMidiEvtFlags( cmScMatch* p, const cmScMatchLoc_t* lp, unsigned evtIdx, char* s, unsigned sn )
  1370. {
  1371. const cmScoreLoc_t* slp = cmScoreLoc(p->scH,lp->scLocIdx);
  1372. assert( evtIdx < slp->evtCnt );
  1373. const cmScoreEvt_t* ep = slp->evtArray[evtIdx];
  1374. unsigned i = 0;
  1375. s[0] = 0;
  1376. if( cmIsFlag(ep->flags,kEvenScFl) )
  1377. s[i++] = 'e';
  1378. if( cmIsFlag(ep->flags,kTempoScFl) )
  1379. s[i++] = 't';
  1380. if( cmIsFlag(ep->flags,kDynScFl) )
  1381. s[i++] = 'd';
  1382. if( cmIsFlag(ep->flags,kGraceScFl) )
  1383. s[i++] = 'g';
  1384. s[i++] = 0;
  1385. assert( i <= sn );
  1386. }
  1387. void _cmScMatchPrintPath( cmScMatch* p, cmScMatchPath_t* cp, unsigned bsi, const cmScMatchMidi_t* midiV )
  1388. {
  1389. assert( bsi != cmInvalidIdx );
  1390. cmScMatchPath_t* pp = cp;
  1391. int polyN = 0;
  1392. int i;
  1393. printf("loc: ");
  1394. // get the polyphony count for the score window
  1395. for(i=0; pp!=NULL; pp=pp->next)
  1396. {
  1397. cmScMatchLoc_t* lp = p->loc + bsi + pp->ci;
  1398. if( pp->code!=kSmDelIdx )
  1399. {
  1400. if(lp->evtCnt > polyN)
  1401. polyN = lp->evtCnt;
  1402. printf("%4i%4s ",bsi+i," ");
  1403. ++i;
  1404. }
  1405. else
  1406. printf("%4s%4s "," "," ");
  1407. }
  1408. printf("\n");
  1409. // print the score notes
  1410. for(i=polyN; i>0; --i)
  1411. {
  1412. printf("%3i: ",i);
  1413. for(pp=cp; pp!=NULL; pp=pp->next)
  1414. {
  1415. if( pp->code!=kSmDelIdx )
  1416. {
  1417. int locIdx = bsi + pp->ci - 1;
  1418. assert(0 <= locIdx && locIdx <= p->locN);
  1419. cmScMatchLoc_t* lp = p->loc + locIdx;
  1420. if( lp->evtCnt >= i )
  1421. {
  1422. unsigned sn = 6;
  1423. char s[sn];
  1424. _cmScMatchMidiEvtFlags(p,lp,i-1,s,sn );
  1425. printf("%4s%-4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0),s);
  1426. }
  1427. else
  1428. printf("%4s%4s "," "," ");
  1429. }
  1430. else
  1431. printf("%4s%4s ", (pp->code==kSmDelIdx? "-" : " ")," ");
  1432. /*
  1433. int locIdx = bsi + pp->ci - 1;
  1434. assert(0 <= locIdx && locIdx <= p->locN);
  1435. cmScMatchLoc_t* lp = p->loc + locIdx;
  1436. if( pp->code!=kSmDelIdx && lp->evtCnt >= i )
  1437. printf("%4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0));
  1438. else
  1439. printf("%4s ", pp->code==kSmDelIdx? "-" : " ");
  1440. */
  1441. }
  1442. printf("\n");
  1443. }
  1444. printf("mid: ");
  1445. // print the MIDI buffer
  1446. for(pp=cp; pp!=NULL; pp=pp->next)
  1447. {
  1448. if( pp->code!=kSmInsIdx )
  1449. printf("%4s%4s ",cmMidiToSciPitch(midiV[pp->ri-1].pitch,NULL,0)," ");
  1450. else
  1451. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  1452. }
  1453. printf("\nvel: ");
  1454. // print the MIDI velocity
  1455. for(pp=cp; pp!=NULL; pp=pp->next)
  1456. {
  1457. if( pp->code!=kSmInsIdx )
  1458. printf("%4i%4s ",midiV[pp->ri-1].vel," ");
  1459. else
  1460. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  1461. }
  1462. printf("\nmni: ");
  1463. // print the MIDI buffer index (mni)
  1464. for(pp=cp; pp!=NULL; pp=pp->next)
  1465. {
  1466. if( pp->code!=kSmInsIdx )
  1467. printf("%4i%4s ",midiV[pp->ri-1].mni," ");
  1468. else
  1469. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  1470. }
  1471. printf("\n op: ");
  1472. // print the substitute/insert/delete operation
  1473. for(pp=cp; pp!=NULL; pp=pp->next)
  1474. {
  1475. char c = ' ';
  1476. switch( pp->code )
  1477. {
  1478. case kSmSubIdx: c = 's'; break;
  1479. case kSmDelIdx: c = 'd'; break;
  1480. case kSmInsIdx: c = 'i'; break;
  1481. default:
  1482. { assert(0); }
  1483. }
  1484. printf("%4c%4s ",c," ");
  1485. }
  1486. printf("\n ");
  1487. // give substitute attribute (match or transpose)
  1488. for(pp=cp; pp!=NULL; pp=pp->next)
  1489. {
  1490. cmChar_t s[3];
  1491. int k = 0;
  1492. if( cmIsFlag(pp->flags,kSmMatchFl) )
  1493. s[k++] = 'm';
  1494. if( cmIsFlag(pp->flags,kSmTransFl) )
  1495. s[k++] = 't';
  1496. s[k] = 0;
  1497. printf("%4s%4s ",s," ");
  1498. }
  1499. printf("\nscl: ");
  1500. // print the stored location index
  1501. for(pp=cp; pp!=NULL; pp=pp->next)
  1502. {
  1503. if( pp->locIdx == cmInvalidIdx )
  1504. printf("%4s%4s "," "," ");
  1505. else
  1506. printf("%4i%4s ",p->loc[pp->locIdx].scLocIdx," ");
  1507. }
  1508. printf("\nbar: ");
  1509. // print the stored location index
  1510. for(pp=cp; pp!=NULL; pp=pp->next)
  1511. {
  1512. if( pp->locIdx==cmInvalidIdx || pp->scEvtIdx==cmInvalidIdx )
  1513. printf("%4s%4s "," "," ");
  1514. else
  1515. {
  1516. const cmScoreEvt_t* ep = cmScoreEvt(p->scH, pp->scEvtIdx );
  1517. printf("%4i%4s ",ep->barNumb," ");
  1518. }
  1519. }
  1520. printf("\nsec: ");
  1521. // print seconds
  1522. unsigned begSmpIdx = cmInvalidIdx;
  1523. for(pp=cp; pp!=NULL; pp=pp->next)
  1524. {
  1525. if( pp->code!=kSmInsIdx )
  1526. {
  1527. if( begSmpIdx == cmInvalidIdx )
  1528. begSmpIdx = midiV[pp->ri-1].smpIdx;
  1529. printf("%2.2f%4s ", (double)(midiV[pp->ri-1].smpIdx - begSmpIdx)/96000.0," ");
  1530. }
  1531. else
  1532. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  1533. }
  1534. printf("\n\n");
  1535. }
  1536. //=======================================================================================================================
  1537. cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN )
  1538. {
  1539. cmScMatcher* op = cmObjAlloc(cmScMatcher,c,p);
  1540. if( op != NULL )
  1541. op->mp = cmScMatchAlloc(c,NULL,cmScNullHandle,0,0);
  1542. if( srate != 0 )
  1543. {
  1544. if( cmScMatcherInit(op,srate,scH,scWndN,midiWndN) != cmOkRC )
  1545. cmScMatcherFree(&op);
  1546. }
  1547. return op;
  1548. }
  1549. cmRC_t cmScMatcherFree( cmScMatcher** pp )
  1550. {
  1551. cmRC_t rc = cmOkRC;
  1552. if( pp==NULL || *pp==NULL )
  1553. return rc;
  1554. cmScMatcher* p = *pp;
  1555. if((rc = cmScMatcherFinal(p)) != cmOkRC )
  1556. return rc;
  1557. cmScMatchFree(&p->mp);
  1558. cmMemFree(p->midiBuf);
  1559. cmMemFree(p->res);
  1560. cmObjFree(pp);
  1561. return rc;
  1562. }
  1563. cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN )
  1564. {
  1565. cmRC_t rc;
  1566. if((rc = cmScMatcherFinal(p)) != cmOkRC )
  1567. return rc;
  1568. if( midiWndN > scWndN )
  1569. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score alignment MIDI event buffer length (%i) must be less than the score window length (%i).",midiWndN,scWndN);
  1570. if(( rc = cmScMatchInit(p->mp,scH,scWndN,midiWndN)) != cmOkRC )
  1571. return rc;
  1572. p->mn = midiWndN;
  1573. p->midiBuf = cmMemResize(cmScMatchMidi_t,p->midiBuf,p->mn);
  1574. p->stepCnt = 3;
  1575. p->maxMissCnt = p->stepCnt+1;
  1576. p->rn = 2 * cmScoreEvtCount(scH);
  1577. p->res = cmMemResizeZ(cmScMatcherResult_t,p->res,p->rn);
  1578. cmScMatcherReset(p);
  1579. return rc;
  1580. }
  1581. cmRC_t cmScMatcherFinal( cmScMatcher* p )
  1582. {
  1583. return cmScMatchFinal(p->mp);
  1584. }
  1585. void cmScMatcherReset( cmScMatcher* p )
  1586. {
  1587. p->mbi = p->mp->mmn;
  1588. p->mni = 0;
  1589. p->begSyncLocIdx = cmInvalidIdx;
  1590. p->s_opt = DBL_MAX;
  1591. p->missCnt = 0;
  1592. p->scanCnt = 0;
  1593. p->ri = 0;
  1594. }
  1595. bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  1596. {
  1597. if( status != kNoteOnMdId )
  1598. return false;
  1599. unsigned mi = p->mn-1;
  1600. //printf("%3i %5.2f %4s\n",p->mni,(double)smpIdx/p->srate,cmMidiToSciPitch(d0,NULL,0));
  1601. // shift the new MIDI event onto the end of the MIDI buffer
  1602. memmove(p->midiBuf, p->midiBuf+1, sizeof(cmScMatchMidi_t)*mi);
  1603. p->midiBuf[mi].locIdx = cmInvalidIdx;
  1604. p->midiBuf[mi].scEvtIdx = cmInvalidIdx;
  1605. p->midiBuf[mi].mni = p->mni++;
  1606. p->midiBuf[mi].smpIdx = smpIdx;
  1607. p->midiBuf[mi].pitch = d0;
  1608. p->midiBuf[mi].vel = d1;
  1609. if( p->mbi > 0 )
  1610. --p->mbi;
  1611. return true;
  1612. }
  1613. void _cmScMatcherStoreResult( cmScMatcher* p, unsigned locIdx, unsigned scEvtIdx, unsigned flags, const cmScMatchMidi_t* mp )
  1614. {
  1615. // don't store missed score note results
  1616. assert( mp != NULL );
  1617. bool matchFl = cmIsFlag(flags,kSmMatchFl);
  1618. bool tpFl = locIdx!=cmInvalidIdx && matchFl;
  1619. bool fpFl = locIdx==cmInvalidIdx || matchFl==false;
  1620. cmScMatcherResult_t * rp = NULL;
  1621. unsigned i;
  1622. assert( tpFl==false || (tpFl==true && locIdx != cmInvalidIdx ) );
  1623. // it is possible that the same MIDI event is reported more than once
  1624. // (due to step->scan back tracking) - try to find previous result records
  1625. // associated with this MIDI event
  1626. for(i=0; i<p->ri; ++i)
  1627. if( p->res[i].mni == mp->mni )
  1628. {
  1629. // if this is not the first time this note was reported and it is a true positive
  1630. if( tpFl )
  1631. {
  1632. rp = p->res + i;
  1633. break;
  1634. }
  1635. // a match was found but this was not a true-pos so ignore it
  1636. return;
  1637. }
  1638. if( rp == NULL )
  1639. {
  1640. rp = p->res + p->ri;
  1641. ++p->ri;
  1642. }
  1643. rp->locIdx = locIdx;
  1644. rp->scEvtIdx = scEvtIdx;
  1645. rp->mni = mp->mni;
  1646. rp->smpIdx = mp->smpIdx;
  1647. rp->pitch = mp->pitch;
  1648. rp->vel = mp->vel;
  1649. rp->flags = flags | (tpFl ? kSmTruePosFl : 0) | (fpFl ? kSmFalsePosFl : 0);
  1650. if( p->cbFunc != NULL )
  1651. p->cbFunc(p,p->cbArg,rp);
  1652. }
  1653. void cmScMatcherPrintPath( cmScMatcher* p )
  1654. {
  1655. _cmScMatchPrintPath(p->mp, p->mp->p_opt, p->begSyncLocIdx, p->midiBuf );
  1656. }
  1657. unsigned cmScMatcherScan( cmScMatcher* p, unsigned bsi, unsigned scanCnt )
  1658. {
  1659. assert( p->mp != NULL && p->mp->mmn > 0 );
  1660. unsigned i_opt = cmInvalidIdx;
  1661. double s_opt = DBL_MAX;
  1662. cmRC_t rc = cmOkRC;
  1663. unsigned i;
  1664. // initialize the internal values set by this function
  1665. p->missCnt = 0;
  1666. p->esi = cmInvalidIdx;
  1667. p->s_opt = DBL_MAX;
  1668. // if the MIDI buf is not full
  1669. if( p->mbi != 0 )
  1670. return cmInvalidIdx;
  1671. // load a temporary MIDI pitch buffer for use by cmScMatch.
  1672. //unsigned pitchV[p->mp->mmn];
  1673. //for(i=0; i<p->mp->mmn; ++i)
  1674. // pitchV[i] = p->midiBuf[i].pitch;
  1675. // calc the edit distance from pitchV[] to a sliding score window
  1676. for(i=0; rc==cmOkRC && (scanCnt==cmInvalidCnt || i<scanCnt); ++i)
  1677. {
  1678. rc = cmScMatchExec(p->mp, bsi + i, p->mp->msn, p->midiBuf, p->mp->mmn, s_opt );
  1679. switch(rc)
  1680. {
  1681. case cmOkRC: // normal result
  1682. if( p->mp->opt_cost < s_opt )
  1683. {
  1684. s_opt = p->mp->opt_cost;
  1685. i_opt = bsi + i;
  1686. }
  1687. break;
  1688. case cmEofRC: // score window encountered the end of the score
  1689. break;
  1690. default: // error state
  1691. return cmInvalidIdx;
  1692. }
  1693. }
  1694. // store the cost assoc'd with i_opt
  1695. p->s_opt = s_opt;
  1696. if( i_opt == cmInvalidIdx )
  1697. return cmInvalidIdx;
  1698. // set the locIdx field in midiBuf[], trailing miss count and
  1699. // return the latest positive-match locIdx
  1700. p->esi = cmScMatchDoSync(p->mp,i_opt,p->midiBuf,p->mp->mmn,&p->missCnt);
  1701. // if no positive matches were found
  1702. if( p->esi == cmInvalidIdx )
  1703. i_opt = cmInvalidIdx;
  1704. else
  1705. {
  1706. cmScMatchPath_t* cp;
  1707. // record result
  1708. for(cp=p->mp->p_opt; cp!=NULL; cp=cp->next)
  1709. if( cp->code != kSmInsIdx )
  1710. _cmScMatcherStoreResult(p, cp->locIdx, cp->scEvtIdx, cp->flags, p->midiBuf + cp->ri - 1);
  1711. }
  1712. return i_opt;
  1713. }
  1714. cmRC_t cmScMatcherStep( cmScMatcher* p )
  1715. {
  1716. int i;
  1717. unsigned pitch = p->midiBuf[ p->mn-1 ].pitch;
  1718. unsigned locIdx = cmInvalidIdx;
  1719. unsigned pidx = cmInvalidIdx;
  1720. // the tracker must be sync'd to step
  1721. if( p->esi == cmInvalidIdx )
  1722. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The p->esi value must be valid to perform a step operation.");
  1723. // if the end of the score has been reached
  1724. if( p->esi + 1 >= p->mp->locN )
  1725. return cmEofRC;
  1726. // attempt to match to next location first
  1727. if( (pidx = _cmScMatchIsMatchIndex(p->mp->loc + p->esi + 1, pitch)) != cmInvalidIdx )
  1728. {
  1729. locIdx = p->esi + 1;
  1730. }
  1731. else
  1732. {
  1733. //
  1734. for(i=2; i<p->stepCnt; ++i)
  1735. {
  1736. // go forward
  1737. if( p->esi+i < p->mp->locN && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->esi + i, pitch))!=cmInvalidIdx )
  1738. {
  1739. locIdx = p->esi + i;
  1740. break;
  1741. }
  1742. // go backward
  1743. if( p->esi >= (i-1) && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->esi - (i-1), pitch))!=cmInvalidIdx )
  1744. {
  1745. locIdx = p->esi - (i-1);
  1746. break;
  1747. }
  1748. }
  1749. }
  1750. unsigned scEvtIdx = locIdx==cmInvalidIdx ? cmInvalidIdx : p->mp->loc[locIdx].evtV[pidx].scEvtIdx;
  1751. p->midiBuf[ p->mn-1 ].locIdx = locIdx;
  1752. p->midiBuf[ p->mn-1 ].scEvtIdx = scEvtIdx;
  1753. if( locIdx == cmInvalidIdx )
  1754. ++p->missCnt;
  1755. else
  1756. {
  1757. p->missCnt = 0;
  1758. p->esi = locIdx;
  1759. }
  1760. // store the result
  1761. _cmScMatcherStoreResult(p, locIdx, scEvtIdx, locIdx!=cmInvalidIdx ? kSmMatchFl : 0, p->midiBuf + p->mn - 1);
  1762. if( p->missCnt >= p->maxMissCnt )
  1763. {
  1764. unsigned begScanLocIdx = p->esi > p->mn ? p->esi - p->mn : 0;
  1765. p->s_opt = DBL_MAX;
  1766. unsigned bsi = cmScMatcherScan(p,begScanLocIdx,p->mn*2);
  1767. ++p->scanCnt;
  1768. // if the scan failed find a match
  1769. if( bsi == cmInvalidIdx )
  1770. return cmCtxRtCondition( &p->obj, cmSubSysFailRC, "Scan resync. failed.");
  1771. }
  1772. return cmOkRC;
  1773. }
  1774. cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  1775. {
  1776. bool fl = p->mbi > 0;
  1777. cmRC_t rc = cmOkRC;
  1778. // update the MIDI buffer with the incoming note
  1779. cmScMatcherInputMidi(p,smpIdx,status,d0,d1);
  1780. // if the MIDI buffer transitioned to full then perform an initial scan sync.
  1781. if( fl && p->mbi == 0 )
  1782. {
  1783. if( (p->begSyncLocIdx = cmScMatcherScan(p,0,cmInvalidCnt)) == cmInvalidIdx )
  1784. rc = cmInvalidArgRC; // signal init. scan sync. fail
  1785. else
  1786. {
  1787. //cmScMatcherPrintPath(p);
  1788. }
  1789. }
  1790. else
  1791. {
  1792. // if the MIDI buffer is full then perform a step sync.
  1793. if( !fl && p->mbi == 0 )
  1794. rc = cmScMatcherStep(p);
  1795. }
  1796. return rc;
  1797. }
  1798. double cmScMatcherFMeas( cmScMatcher* p )
  1799. {
  1800. unsigned bli = p->mp->locN;
  1801. unsigned eli = 0;
  1802. unsigned scNoteCnt = 0; // total count of score notes
  1803. unsigned matchCnt = 0; // count of matched notes (true positives)
  1804. unsigned wrongCnt = 0; // count of incorrect notes (false positives)
  1805. unsigned missCnt = 0; // count of missed score notes (false negatives)
  1806. unsigned i;
  1807. for(i=0; i<p->ri; ++i)
  1808. if( p->res[i].locIdx != cmInvalidIdx )
  1809. {
  1810. bli = cmMin(bli,p->res[i].locIdx);
  1811. eli = cmMax(eli,p->res[i].locIdx);
  1812. if( cmIsFlag(p->res[i].flags,kSmTruePosFl) )
  1813. ++matchCnt;
  1814. if( cmIsFlag(p->res[i].flags,kSmFalsePosFl) )
  1815. ++wrongCnt;
  1816. }
  1817. scNoteCnt = eli - bli + 1;
  1818. missCnt = scNoteCnt - matchCnt;
  1819. double prec = (double)2.0 * matchCnt / (matchCnt + wrongCnt);
  1820. double rcal = (double)2.0 * matchCnt / (matchCnt + missCnt);
  1821. double fmeas = prec * rcal / (prec + rcal);
  1822. //printf("total:%i match:%i wrong:%i miss:%i\n",scNoteCnt,matchCnt,wrongCnt,missCnt);
  1823. return fmeas;
  1824. }
  1825. typedef struct cmScMatcherPrint_str
  1826. {
  1827. unsigned flags;
  1828. unsigned scLocIdx;
  1829. unsigned mni;
  1830. unsigned pitch;
  1831. unsigned vel;
  1832. } cmScMatcherPrint_t;
  1833. void _cmScMatcherInsertPrint(cmScMatcherPrint_t* a, unsigned i, unsigned* anp, unsigned aan, const cmScMatcherResult_t* rp, unsigned scLocIdx )
  1834. {
  1835. assert( *anp + 1 <= aan );
  1836. memmove(a + i + 1, a + i, (*anp-i)*sizeof(cmScMatcherPrint_t));
  1837. memset( a + i, 0, sizeof(cmScMatcherPrint_t));
  1838. *anp += 1;
  1839. a[i].flags = rp->flags;
  1840. a[i].scLocIdx = scLocIdx;
  1841. a[i].mni = rp->mni;
  1842. a[i].pitch = rp->pitch;
  1843. a[i].vel = rp->vel;
  1844. }
  1845. void cmScMatcherPrint( cmScMatcher* p )
  1846. {
  1847. unsigned bsli = cmScoreEvtCount(p->mp->scH);
  1848. unsigned esli = 0;
  1849. unsigned i,j,k;
  1850. // get first/last scLocIdx from res[]
  1851. for(i=0; i<p->ri; ++i)
  1852. if( p->res[i].locIdx != cmInvalidIdx )
  1853. {
  1854. bsli = cmMin(bsli,p->mp->loc[p->res[i].locIdx].scLocIdx);
  1855. esli = cmMax(esli,p->mp->loc[p->res[i].locIdx].scLocIdx);
  1856. }
  1857. unsigned an = 0;
  1858. unsigned aan = p->ri;
  1859. // calc the count of score events between bsli and esli.
  1860. for(i=bsli; i<=esli; ++i)
  1861. {
  1862. cmScoreLoc_t* lp = cmScoreLoc(p->mp->scH, i);
  1863. assert(lp != NULL);
  1864. aan += lp->evtCnt;
  1865. }
  1866. // allocate an array off 'aan' print records
  1867. cmScMatcherPrint_t* a = cmMemAllocZ(cmScMatcherPrint_t,aan);
  1868. // fill a[] note and bar events from cmScoreLoc()
  1869. for(i=bsli; i<=esli; ++i)
  1870. {
  1871. unsigned scLocIdx = i;
  1872. cmScoreLoc_t* lp = cmScoreLoc(p->mp->scH, scLocIdx );
  1873. for(j=0; j<lp->evtCnt; ++j)
  1874. {
  1875. assert( an < aan );
  1876. cmScoreEvt_t* ep = lp->evtArray[j];
  1877. cmScMatcherPrint_t* pp = a + an;
  1878. an += 1;
  1879. switch( ep->type )
  1880. {
  1881. case kBarEvtScId:
  1882. pp->flags = kSmBarFl;
  1883. break;
  1884. case kNonEvtScId:
  1885. pp->flags = kSmNoteFl;
  1886. break;
  1887. }
  1888. pp->scLocIdx = scLocIdx;
  1889. pp->mni = cmInvalidIdx;
  1890. pp->pitch = ep->pitch;
  1891. pp->vel = kInvalidMidiVelocity;
  1892. }
  1893. }
  1894. // for each result record
  1895. for(i=0; i<p->ri; ++i)
  1896. {
  1897. cmScMatcherResult_t* rp = p->res + i;
  1898. // if this result recd matched a score event
  1899. if( cmIsFlag(rp->flags,kSmTruePosFl) )
  1900. {
  1901. // locate the matching score event
  1902. for(k=0; k<an; ++k)
  1903. if( a[k].scLocIdx==p->mp->loc[rp->locIdx].scLocIdx && a[k].pitch==rp->pitch )
  1904. {
  1905. a[k].mni = rp->mni;
  1906. a[k].vel = rp->vel;
  1907. a[k].flags |= kSmMatchFl;
  1908. break;
  1909. }
  1910. }
  1911. // if this result did not match a score event
  1912. if( cmIsFlag(rp->flags,kSmFalsePosFl) )
  1913. {
  1914. unsigned d_min;
  1915. cmScMatcherPrint_t* dp = NULL;
  1916. unsigned scLocIdx = cmInvalidIdx;
  1917. // if this result does not have a valid locIdx
  1918. // (e.g. errant MIDI notes: scan:'delete' note or a step:mis-match note)
  1919. if( rp->locIdx == cmInvalidIdx )
  1920. {
  1921. // find the print recd with the closet 'mni'
  1922. for(k=0; k<an; ++k)
  1923. if( a[k].mni != cmInvalidIdx )
  1924. {
  1925. unsigned d;
  1926. if( a[k].mni > rp->mni )
  1927. d = a[k].mni - rp->mni;
  1928. else
  1929. d = rp->mni - a[k].mni;
  1930. if( dp==NULL || d < d_min )
  1931. {
  1932. dp = a + k;
  1933. d_min = d;
  1934. }
  1935. }
  1936. k = dp - a;
  1937. assert( k < an );
  1938. scLocIdx = p->mp->loc[k].scLocIdx;
  1939. if( a[k].mni < rp->mni )
  1940. ++k;
  1941. }
  1942. else // result w/ a valid locIdx (e.g. scan 'substitute' with no match)
  1943. {
  1944. scLocIdx = p->mp->loc[rp->locIdx].scLocIdx;
  1945. // find the print recd with the closest scIdx
  1946. for(k=0; k<an; ++k)
  1947. if( a[k].scLocIdx != cmInvalidIdx )
  1948. {
  1949. unsigned d;
  1950. if( a[k].scLocIdx > scLocIdx )
  1951. d = a[k].scLocIdx - scLocIdx;
  1952. else
  1953. d = scLocIdx - a[k].scLocIdx;
  1954. if( dp==NULL || d < d_min )
  1955. {
  1956. dp = a + k;
  1957. d_min = d;
  1958. }
  1959. }
  1960. k = dp - a;
  1961. assert( k < an );
  1962. if( a[k].scLocIdx < scLocIdx )
  1963. ++k;
  1964. }
  1965. // create a new print recd to represent the false-positive result recd
  1966. assert( dp != NULL );
  1967. _cmScMatcherInsertPrint(a, k, &an,aan,rp,scLocIdx);
  1968. }
  1969. }
  1970. for(i=0; i<an; ++i)
  1971. {
  1972. printf("%4i %4i %4s %c%c%c\n",a[i].scLocIdx,a[i].mni,
  1973. cmIsFlag(a[i].flags,kSmBarFl) ? "|" : cmMidiToSciPitch(a[i].pitch,NULL,0),
  1974. cmIsFlag(a[i].flags,kSmNoteFl) ? 'n' : ' ',
  1975. cmIsFlag(a[i].flags,kSmMatchFl) ? 'm' : (cmIsFlag(a[i].flags,kSmTransFl) ? 't' : ' '),
  1976. cmIsFlag(a[i].flags,kSmFalsePosFl) ? '*' : ' '
  1977. );
  1978. }
  1979. }
  1980. //=======================================================================================================================
  1981. cmScMeas* cmScMeasAlloc( cmCtx* c, cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt )
  1982. {
  1983. cmScMeas* op = cmObjAlloc(cmScMeas,c,p);
  1984. op->mp = cmScMatchAlloc( c, NULL, cmScNullHandle, 0, 0 );
  1985. if( cmScoreIsValid(scH) )
  1986. if( cmScMeasInit(op,scH,srate,dynRefArray,dynRefCnt) != cmOkRC )
  1987. cmScMeasFree(&op);
  1988. return op;
  1989. }
  1990. cmRC_t cmScMeasFree( cmScMeas** pp )
  1991. {
  1992. cmRC_t rc = cmOkRC;
  1993. if( pp==NULL || *pp==NULL )
  1994. return rc;
  1995. cmScMeas* p = *pp;
  1996. if((rc = cmScMeasFinal(p)) != cmOkRC )
  1997. return rc;
  1998. cmScMatchFree(&p->mp);
  1999. cmMemFree(p->midiBuf);
  2000. cmMemFree(p->set);
  2001. cmMemFree(p->dynRef);
  2002. cmObjFree(pp);
  2003. return rc;
  2004. }
  2005. void _cmScMeasPrint( cmScMeas* p )
  2006. {
  2007. unsigned i;
  2008. for(i=0; i<p->sn; ++i)
  2009. {
  2010. cmScMeasSet_t* sp = p->set + i;
  2011. printf("%4i: sli:%4i %4i li:%4i %4i\n", i, sp->bsli, sp->esli, sp->bli, sp->eli );
  2012. }
  2013. }
  2014. int _cmScMeasSortFunc( const void* p0, const void* p1 )
  2015. {
  2016. const cmScMeasSet_t* s0 = (const cmScMeasSet_t*)p0;
  2017. const cmScMeasSet_t* s1 = (const cmScMeasSet_t*)p1;
  2018. return s0->esli - s1->esli;
  2019. }
  2020. cmRC_t cmScMeasInit( cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt )
  2021. {
  2022. cmRC_t rc;
  2023. unsigned i,j;
  2024. unsigned si;
  2025. unsigned maxScWndN = 0;
  2026. if((rc = cmScMeasFinal(p)) != cmOkRC )
  2027. return rc;
  2028. p->mii = 0;
  2029. p->mn = 2 * cmScoreEvtCount(scH);
  2030. p->midiBuf = cmMemResizeZ(cmScMatchMidi_t,p->midiBuf,p->mn);
  2031. p->sn = cmScoreSetCount(scH);
  2032. p->set = cmMemResize(cmScMeasSet_t,p->set,p->sn);
  2033. p->dynRef = cmMemResize(unsigned,p->dynRef,dynRefCnt);
  2034. p->dn = dynRefCnt;
  2035. p->srate = srate;
  2036. memcpy(p->dynRef,dynRefArray,sizeof(dynRefArray[0])*dynRefCnt);
  2037. unsigned n = cmScoreLocCount(scH);
  2038. // for each score location
  2039. for(i=0,si=0; i<n; ++i)
  2040. {
  2041. cmScoreLoc_t* lp = cmScoreLoc(scH,i);
  2042. cmScoreSet_t* sp = lp->setList;
  2043. // for each set that ends on this score location
  2044. for(; sp!=NULL; sp=sp->llink,++si)
  2045. {
  2046. assert(si < p->sn);
  2047. cmScMeasSet_t* msp = p->set + si;
  2048. msp->sp = sp;
  2049. msp->bsli = cmScoreLocCount(scH);
  2050. msp->esli = 0;
  2051. msp->bsei = cmScoreEvtCount(scH);
  2052. msp->esei = 0;
  2053. msp->bli = cmInvalidIdx;
  2054. msp->eli = cmInvalidIdx;
  2055. for(j=0; j<sp->eleCnt; ++j)
  2056. {
  2057. msp->bsli = cmMin(msp->bsli,sp->eleArray[j]->locIdx);
  2058. msp->esli = cmMax(msp->esli,sp->eleArray[j]->locIdx);
  2059. msp->bsei = cmMin(msp->bsei,sp->eleArray[j]->index);
  2060. msp->esei = cmMax(msp->esei,sp->eleArray[j]->index);
  2061. }
  2062. }
  2063. }
  2064. // initialize p->mp so that mp->loc[] is loaded - use dummy scWndN and midiN
  2065. if((rc = cmScMatchInit(p->mp, scH, 11, 10 )) != cmOkRC )
  2066. return rc;
  2067. // assign set[].bli and set[].eli
  2068. for(j=0; j<p->sn; ++j)
  2069. {
  2070. cmScMeasSet_t* msp = p->set + j;
  2071. for(i=0; i<p->mp->locN; ++i)
  2072. {
  2073. if( msp->bli==cmInvalidIdx && msp->bsli==p->mp->loc[i].scLocIdx )
  2074. msp->bli = i;
  2075. if( msp->esli==p->mp->loc[i].scLocIdx )
  2076. msp->eli = i;
  2077. }
  2078. assert( msp->eli > msp->bli );
  2079. maxScWndN = cmMax( maxScWndN, msp->eli - msp->bli + 1 );
  2080. }
  2081. // setup the match
  2082. if((rc = cmScMatchInit(p->mp, scH, 2*maxScWndN+1, 2*maxScWndN )) != cmOkRC )
  2083. return rc;
  2084. // sort set[] on cmScMeasSet_t.esli
  2085. qsort(p->set, p->sn, sizeof(cmScMeasSet_t), _cmScMeasSortFunc );
  2086. //_cmScMeasPrint(p);
  2087. return rc;
  2088. }
  2089. cmRC_t cmScMeasFinal( cmScMeas* p )
  2090. { return cmScMatchFinal(p->mp); }
  2091. cmRC_t cmScMeasReset( cmScMeas* p )
  2092. {
  2093. cmRC_t rc = cmOkRC;
  2094. p->mii = 0;
  2095. p->nsi = cmInvalidIdx;
  2096. p->nsli = cmInvalidIdx;
  2097. return rc;
  2098. }
  2099. typedef struct
  2100. {
  2101. unsigned scLocIdx; // score loc index
  2102. double frac; // score based fraction of beat
  2103. unsigned smpIdx; // time of assoc'd MIDI event
  2104. unsigned cnt; //
  2105. double val; //
  2106. } _cmScMeasTimeEle_t;
  2107. typedef struct
  2108. {
  2109. unsigned setN; // set length
  2110. unsigned midiN; // count of MIDI events to match to score
  2111. unsigned alignN; // count of score events in the alignment (<= setN)
  2112. unsigned matchN; // count of positive matches
  2113. double tempo;
  2114. double value;
  2115. } _cmScMeasResult_t;
  2116. double _cmScMeasCalcTempo( const _cmScMeasTimeEle_t* b, unsigned bn, double srate )
  2117. {
  2118. assert( bn >= 2 );
  2119. assert( b[bn-1].smpIdx != cmInvalidIdx );
  2120. assert( b[0].smpIdx != cmInvalidIdx );
  2121. double durSmpCnt = b[bn-1].smpIdx - b[0].smpIdx;
  2122. double beats = 0;
  2123. unsigned i;
  2124. for(i=0; i<bn; ++i)
  2125. beats += b[i].frac;
  2126. assert(beats != 0);
  2127. return beats / (durSmpCnt / (srate * 60.0));
  2128. }
  2129. // Note: On successful completion (return!=0) the first
  2130. // and last record returned in c[cn] will be matched records.
  2131. unsigned _cmScMeasTimeAlign( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasTimeEle_t* c, unsigned cn, _cmScMeasResult_t* rp )
  2132. {
  2133. int i,j,k;
  2134. int an = sp->sp->eleCnt;
  2135. _cmScMeasTimeEle_t* b = NULL;
  2136. int bn = 0;
  2137. bool tempoFl = false;
  2138. unsigned matchN = 0;
  2139. assert( an!=0);
  2140. // alloc a 'score set' element array
  2141. _cmScMeasTimeEle_t a[an];
  2142. // get the scLocIdx of each set element from the score
  2143. for(i=0,j=0; i<an; ++i)
  2144. if( i==0 || sp->sp->eleArray[i-1]->locIdx != sp->sp->eleArray[i]->locIdx )
  2145. {
  2146. assert( sp->sp->eleArray[i]->locIdx != cmInvalidIdx );
  2147. a[j].scLocIdx = sp->sp->eleArray[i]->locIdx;
  2148. a[j].frac = sp->sp->eleArray[i]->frac;
  2149. a[j].smpIdx = cmInvalidIdx;
  2150. a[j].cnt = 0;
  2151. ++j;
  2152. }
  2153. an = j; // set the count of unique score locations (new length of a[])
  2154. // collect the 'smpIdx' for each MIDI event which matches a set element
  2155. for(i=0; i<mn; ++i)
  2156. if( m[i].locIdx != cmInvalidIdx )
  2157. {
  2158. for(j=0; j<an; ++j)
  2159. if( p->mp->loc[m[i].locIdx].scLocIdx == a[j].scLocIdx )
  2160. {
  2161. a[j].smpIdx += m[i].smpIdx;
  2162. a[j].cnt += 1;
  2163. if( a[j].cnt == 1 )
  2164. matchN += 1; // only cnt one match per sc loc.
  2165. break;
  2166. }
  2167. }
  2168. // remove leading missing values
  2169. for(i=0; i<an; ++i)
  2170. if( a[i].smpIdx != cmInvalidIdx )
  2171. {
  2172. b = a + i;
  2173. bn = an - i;
  2174. break;
  2175. }
  2176. // remove trailing missing values
  2177. for(i=bn-1; i>=0; --i,--bn)
  2178. if( b[i].smpIdx != cmInvalidIdx )
  2179. break;
  2180. // can't measure evenness against less than 2 values
  2181. if( bn < 2 )
  2182. {
  2183. return 0;
  2184. }
  2185. assert(b[0].smpIdx != cmInvalidIdx && b[bn-1].smpIdx != cmInvalidIdx);
  2186. // calc avg. smpIdx and insert missing values
  2187. for(i=0,j=0; i<bn; ++i)
  2188. {
  2189. if( b[i].cnt > 1 )
  2190. b[i].smpIdx /= b[i].cnt;
  2191. if( b[i].smpIdx == cmInvalidIdx )
  2192. ++j; // incr missing value count
  2193. else
  2194. {
  2195. if( i > 0 )
  2196. {
  2197. // fill in missing values
  2198. ++j;
  2199. unsigned d = (b[i].smpIdx - b[i-j].smpIdx)/j;
  2200. for(k=0; k<j; ++k)
  2201. b[i-j+k].val = d;
  2202. }
  2203. j=0;
  2204. }
  2205. if( b[i].frac != 0 )
  2206. tempoFl = true;
  2207. }
  2208. rp->setN = an;
  2209. rp->midiN = mn;
  2210. rp->alignN = bn;
  2211. rp->matchN = matchN;
  2212. rp->tempo = 0;
  2213. rp->value = 0;
  2214. // calculate tempo
  2215. if( tempoFl )
  2216. rp->tempo = _cmScMeasCalcTempo(b,bn,p->srate);
  2217. assert(bn<=cn);
  2218. // copy to output
  2219. for(i=0; i<bn && i<cn; ++i)
  2220. c[i] = b[i];
  2221. return bn;
  2222. }
  2223. double _cmScMeasEven( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  2224. {
  2225. unsigned bn = sp->sp->eleCnt;
  2226. _cmScMeasTimeEle_t b[bn];
  2227. unsigned i;
  2228. if((bn = _cmScMeasTimeAlign(p,sp,m,mn,b,bn,rp)) == 0 )
  2229. return DBL_MAX;
  2230. // calc avg. delta time
  2231. double d_avg = 0;
  2232. for(i=0; i<bn-1; ++i)
  2233. d_avg += b[i].val;
  2234. d_avg /= (bn-1);
  2235. // calc std-dev of delta time
  2236. double d_sd = 0;
  2237. for(i=0; i<bn-1; ++i)
  2238. d_sd += (b[i].val-d_avg) * (b[i].val-d_avg);
  2239. // if there is no deviation then we can't compute a z-score
  2240. // (this will happen if we fill in all the missing values based on 2 values)
  2241. if( d_sd == 0 )
  2242. return 1.0;
  2243. d_sd = sqrt(d_sd/(bn-1));
  2244. // calc avg. z-score
  2245. double z = 0;
  2246. for(i=0; i<bn-1; ++i)
  2247. z += fabs(b[i].val - d_avg)/d_sd;
  2248. double val = z / (bn-1);
  2249. rp->value = val;
  2250. return val;
  2251. }
  2252. // return Tempo estimation in BPM
  2253. double _cmScMeasTempo( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  2254. {
  2255. unsigned bn = sp->sp->eleCnt;
  2256. _cmScMeasTimeEle_t b[bn];
  2257. if((bn= _cmScMeasTimeAlign(p,sp,m,mn,b,bn,rp)) == 0 )
  2258. return DBL_MAX;
  2259. return rp->tempo;
  2260. }
  2261. double _cmScMeasDyn( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  2262. {
  2263. typedef struct
  2264. {
  2265. unsigned scEvtIdx;
  2266. unsigned vel;
  2267. double val;
  2268. } ele_t;
  2269. int i,j;
  2270. int n = sp->sp->eleCnt;
  2271. double vv = 0;
  2272. unsigned vn = 0;
  2273. unsigned matchN = 0;
  2274. unsigned alignN = 0;
  2275. assert( n!=0);
  2276. ele_t a[n];
  2277. // get the scEvtIdx of each set element
  2278. for(i=0; i<n; ++i)
  2279. {
  2280. cmScoreEvt_t* ep = cmScoreEvt( p->mp->scH, sp->sp->eleArray[i]->index );
  2281. assert( ep != NULL );
  2282. a[i].scEvtIdx = sp->sp->eleArray[i]->index;
  2283. a[i].vel = 0;
  2284. a[i].val = ep->dynVal;
  2285. }
  2286. // set the performed vel. of each note in the set
  2287. // (if a note was not played it's a[].vel is left at 0)
  2288. for(i=0; i<mn; ++i)
  2289. if( m[i].scEvtIdx != cmInvalidIdx )
  2290. {
  2291. alignN += 1;
  2292. for(j=0; j<n; ++j)
  2293. if( m[i].scEvtIdx == a[j].scEvtIdx )
  2294. {
  2295. matchN += 1;
  2296. a[j].vel = m[i].vel;
  2297. break;
  2298. }
  2299. }
  2300. // assign a dynamics category to each note in the set
  2301. for(i=0; i<n; ++i)
  2302. if( a[i].vel > 0 )
  2303. {
  2304. unsigned mnv = 0; // lower bound for first dyn's category
  2305. for(j=0; j<p->dn; ++j)
  2306. {
  2307. if( mnv <= a[i].vel && a[i].vel < p->dynRef[j] )
  2308. {
  2309. // accum. the diff. between the ref. and performed dyn. category
  2310. vv += fabs(a[i].val - j);
  2311. vn += 1;
  2312. break;
  2313. }
  2314. mnv = p->dynRef[j];
  2315. }
  2316. assert(j<p->dn);
  2317. }
  2318. rp->setN = n;
  2319. rp->midiN = mn;
  2320. rp->alignN = alignN;
  2321. rp->matchN = matchN;
  2322. rp->tempo = 0;
  2323. rp->value = vn == 0 ? DBL_MAX : vv/vn;
  2324. return rp->value;
  2325. }
  2326. unsigned MEAS_MATCH_CNT = 0;
  2327. void _cmScMeasMatch( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
  2328. {
  2329. unsigned mn = 0;
  2330. int i;
  2331. if( n_mii == 0 )
  2332. return;
  2333. // Determine the count of MIDI notes to match to the set score
  2334. // by searching from the MIDI note just recieved (midiBuf[n_mii]
  2335. // back toward the beginning until a MIDI event which occurs just
  2336. // prior to the set's begScLocIdx.
  2337. for(i=n_mii; i>=0; --i)
  2338. {
  2339. ++mn;
  2340. if( p->midiBuf[i].locIdx != cmInvalidIdx )
  2341. {
  2342. unsigned scLocIdx = p->mp->loc[ p->midiBuf[i].locIdx ].scLocIdx;
  2343. if( scLocIdx < sp->bsli )
  2344. break;
  2345. }
  2346. }
  2347. i = cmMax(0,i);
  2348. assert(mn>0);
  2349. // Create a copy of the the MIDI buffer to prevent the
  2350. // p->midiBuf[].locIdx from being overwritten by cmScMatchDoSync().
  2351. cmScMatchMidi_t mb[ mn ];
  2352. unsigned j;
  2353. for(j=0; j<mn; ++j)
  2354. {
  2355. mb[j] = p->midiBuf[i+j];
  2356. mb[j].locIdx = cmInvalidIdx;
  2357. }
  2358. // In general the first and last MIDI event should be assigned
  2359. // to a score location - it's possible however that no MIDI
  2360. // event's prior to the one at p->midiBuf[n_mii] were assigned.
  2361. assert( (i==0 || p->midiBuf[i].locIdx!=cmInvalidIdx) && p->midiBuf[i+mn-1].locIdx!=cmInvalidIdx);
  2362. unsigned bli = p->midiBuf[i].locIdx;
  2363. unsigned ln = p->midiBuf[i+mn-1].locIdx - bli + 1;
  2364. double min_cost = DBL_MAX;
  2365. // match MIDI to score
  2366. if( cmScMatchExec(p->mp, bli, ln, mb, mn, min_cost ) != cmOkRC )
  2367. return;
  2368. // sync the score and MIDI based on the match information
  2369. if( cmScMatchDoSync(p->mp, bli, mb, mn, NULL ) == cmInvalidIdx )
  2370. return;
  2371. // print the match result
  2372. const char* label = "<none>";
  2373. double val = DBL_MAX;
  2374. double tempoBpm = 0;
  2375. _cmScMeasResult_t r;
  2376. memset(&r,0,sizeof(r));
  2377. if( MEAS_MATCH_CNT == 12 )
  2378. {
  2379. //printf("blah\n");
  2380. }
  2381. switch( sp->sp->varId )
  2382. {
  2383. case kEvenVarScId:
  2384. label = "even";
  2385. val = _cmScMeasEven(p, sp, mb, mn, &r );
  2386. break;
  2387. case kDynVarScId:
  2388. label = "dyn";
  2389. val = _cmScMeasDyn(p, sp, mb, mn, &r );
  2390. break;
  2391. case kTempoVarScId:
  2392. label = "tempo";
  2393. tempoBpm = _cmScMeasTempo(p, sp, mb, mn, &r );
  2394. val = tempoBpm;
  2395. break;
  2396. }
  2397. if(1)
  2398. {
  2399. const cmChar_t* msg = "";
  2400. if( val == DBL_MAX )
  2401. {
  2402. msg = "Measure FAILED.";
  2403. val = 0;
  2404. }
  2405. printf("%i set:%i %s bsli:%i esli:%i [set:%i match:%i] cost:%f val:%f %s",MEAS_MATCH_CNT,p->nsi, label, sp->bsli, sp->esli, r.setN, r.matchN, p->mp->opt_cost, val, msg);
  2406. if( r.tempo != 0 )
  2407. printf(" tempo:%f ",r.tempo);
  2408. printf("\n");
  2409. _cmScMatchPrintPath(p->mp, p->mp->p_opt, bli, mb );
  2410. }
  2411. MEAS_MATCH_CNT++;
  2412. }
  2413. /*
  2414. The first note in Bar 1 F4 should be marked with a 'e' - it isn't.
  2415. Marker Set scli Type Note
  2416. 4 8 48 even very bad match produces an evenesss = 0.979
  2417. 10 12 69 even bad match
  2418. 27 29 150 tempo Tempo measured as 0.
  2419. */
  2420. cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtIdx, unsigned flags, unsigned smpIdx, unsigned pitch, unsigned vel )
  2421. {
  2422. cmRC_t rc = cmOkRC;
  2423. // if the midi buffer is full
  2424. if( p->mii >= p->mn )
  2425. return cmCtxRtCondition( &p->obj, cmEofRC, "The MIDI buffer is full.");
  2426. int n_mii = cmInvalidIdx;
  2427. if( p->mii>0 && mni <= p->midiBuf[p->mii-1].mni )
  2428. {
  2429. if( locIdx != cmInvalidIdx )
  2430. {
  2431. for(n_mii=p->mii-1; n_mii>=0; --n_mii)
  2432. if( p->midiBuf[n_mii].mni == mni )
  2433. break;
  2434. if( n_mii<0 )
  2435. n_mii = cmInvalidIdx;
  2436. }
  2437. }
  2438. else
  2439. {
  2440. n_mii = p->mii;
  2441. ++p->mii;
  2442. }
  2443. // store the MIDI event
  2444. p->midiBuf[n_mii].mni = mni;
  2445. p->midiBuf[n_mii].locIdx = locIdx;
  2446. p->midiBuf[n_mii].scEvtIdx = scEvtIdx;
  2447. p->midiBuf[n_mii].smpIdx = smpIdx;
  2448. p->midiBuf[n_mii].pitch = pitch;
  2449. p->midiBuf[n_mii].vel = vel;
  2450. //++p->mi;
  2451. if( locIdx == cmInvalidIdx )
  2452. return cmOkRC;
  2453. //
  2454. unsigned scLocIdx = p->mp->loc[ locIdx ].scLocIdx;
  2455. unsigned maxScLocIdx = cmScoreLocCount(p->mp->scH)-1;
  2456. // if this cmScMeas object has not yet synchronized to the cmScMatcher
  2457. // (if p->nsli is not valid)
  2458. if( p->nsli == cmInvalidIdx )
  2459. {
  2460. unsigned i;
  2461. for(i=0; i<p->sn; ++i)
  2462. if( p->set[i].esli+1 == scLocIdx )
  2463. {
  2464. p->nsli = scLocIdx;
  2465. p->nsi = i;
  2466. break;
  2467. }
  2468. if(i==p->sn)
  2469. return rc;
  2470. }
  2471. // for each cmScore location between p->nsli and scLocIdx
  2472. for(; p->nsli<=scLocIdx && p->nsi < p->sn; ++p->nsli)
  2473. {
  2474. // if this score location index (p->nsli) is one score location
  2475. // ahead of the next sets ending location.
  2476. while( cmMin(maxScLocIdx,p->set[p->nsi].esli+1) == p->nsli )
  2477. {
  2478. _cmScMeasMatch(p, p->set + p->nsi, n_mii );
  2479. // advance the set index
  2480. ++p->nsi;
  2481. }
  2482. }
  2483. return rc;
  2484. }
  2485. //=======================================================================================================================
  2486. cmRC_t cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx )
  2487. {
  2488. assert( top != NULL );
  2489. cmTlMidiEvt_t* mep = NULL;
  2490. cmRC_t rc = cmOkRC;
  2491. // as long as more MIDI events are available get the next MIDI msg
  2492. while( rc==cmOkRC && (mep = cmTlNextMidiEvtObjPtr(tlH, top, top->seqId )) != NULL )
  2493. {
  2494. top = &mep->obj;
  2495. // if the msg falls after the end of the marker then we are through
  2496. if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > endSmpIdx )
  2497. break;
  2498. // if the time line MIDI msg a note-on
  2499. if( mep->msg->status == kNoteOnMdId )
  2500. {
  2501. rc = cmScMatcherExec(p, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1 );
  2502. switch( rc )
  2503. {
  2504. case cmOkRC: // continue processing MIDI events
  2505. break;
  2506. case cmEofRC: // end of the score was encountered
  2507. break;
  2508. case cmInvalidArgRC: // p->esi was not set correctly
  2509. break;
  2510. case cmSubSysFailRC: // scan resync failed
  2511. break;
  2512. }
  2513. }
  2514. }
  2515. if( rc == cmEofRC )
  2516. rc = cmOkRC;
  2517. return rc;
  2518. }
  2519. // This callback connects/feeds the cmScMeas object from the cmScMatcher object.
  2520. // (See _cmScMatcherStoreResult().)
  2521. void cmScMatcherCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
  2522. {
  2523. cmScMeas* mp = (cmScMeas*)arg;
  2524. cmScMeasExec(mp, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel );
  2525. }
  2526. void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH )
  2527. {
  2528. unsigned i;
  2529. double srate = cmTimeLineSampleRate(tlH);
  2530. unsigned midiN = 7;
  2531. unsigned scWndN = 10;
  2532. unsigned markN = 291;
  2533. unsigned dynRefArray[] = { 14, 28, 42, 56, 71, 85, 99, 113,128 };
  2534. unsigned dynRefCnt = sizeof(dynRefArray)/sizeof(dynRefArray[0]);
  2535. cmCtx* ctx = cmCtxAlloc(NULL, rpt, cmLHeapNullHandle, cmSymTblNullHandle );
  2536. cmScMeas* mp = cmScMeasAlloc(ctx,NULL,scH,srate,dynRefArray,dynRefCnt);
  2537. cmScMatcher* p = cmScMatcherAlloc(ctx,NULL,srate,scH,scWndN,midiN);
  2538. double scoreThresh = 0.5;
  2539. unsigned candCnt = 0;
  2540. unsigned initFailCnt = 0;
  2541. unsigned otherFailCnt = 0;
  2542. unsigned scoreFailCnt = 0;
  2543. bool printFl = false;
  2544. unsigned markCharCnt = 31;
  2545. cmChar_t markText[ markCharCnt+1 ];
  2546. cmTimeSpec_t t0,t1;
  2547. cmTimeGet(&t0);
  2548. p->cbArg = mp; // set the callback arg.
  2549. p->cbFunc = cmScMatcherCb;
  2550. // for each marker
  2551. for(i=0; i<markN; ++i)
  2552. {
  2553. // form the marker text
  2554. snprintf(markText,markCharCnt,"Mark %i",i);
  2555. // locate the marker
  2556. cmTlMarker_t* tlmp = cmTimeLineMarkerFind( tlH, markText );
  2557. if( tlmp == NULL )
  2558. {
  2559. if( printFl )
  2560. printf("The marker '%s' was not found.\n\n",markText);
  2561. continue;
  2562. }
  2563. // skip markers which do not contain text
  2564. if( cmTextIsEmpty(tlmp->text) )
  2565. {
  2566. if( printFl )
  2567. printf("The marker '%s' is being skipped because it has no text.\n\n",markText);
  2568. continue;
  2569. }
  2570. printf("=================== MARKER:%s ===================\n",markText);
  2571. cmScMatcherReset(p); // reset the score follower to the beginnig of the score
  2572. cmScMeasReset(mp);
  2573. ++candCnt;
  2574. // scan to the beginning of the marker
  2575. cmRC_t rc = cmScAlignScanToTimeLineEvent(p,tlH,&tlmp->obj,tlmp->obj.seqSmpIdx+tlmp->obj.durSmpCnt);
  2576. bool pfl = true;
  2577. if( rc != cmOkRC || p->begSyncLocIdx==cmInvalidIdx)
  2578. {
  2579. bool fl = printFl;
  2580. printFl = true;
  2581. // if a no alignment was found
  2582. if( p->begSyncLocIdx == cmInvalidIdx )
  2583. rc = cmInvalidArgRC;
  2584. if( p->mni == 0 )
  2585. {
  2586. if( printFl )
  2587. printf("mark:%i midi:%i Not enough MIDI notes to fill the scan buffer.\n",i,p->mni);
  2588. pfl = false;
  2589. }
  2590. else
  2591. {
  2592. switch(rc)
  2593. {
  2594. case cmInvalidArgRC:
  2595. if( printFl )
  2596. printf("mark:%i INITIAL SYNC FAIL\n",i);
  2597. ++initFailCnt;
  2598. pfl = false;
  2599. break;
  2600. case cmSubSysFailRC:
  2601. if( printFl )
  2602. printf("mark:%i SCAN RESYNC FAIL\n",i);
  2603. ++otherFailCnt;
  2604. break;
  2605. default:
  2606. if( printFl )
  2607. printf("mark:%i UNKNOWN FAIL\n",i);
  2608. ++otherFailCnt;
  2609. }
  2610. }
  2611. printFl = fl;
  2612. }
  2613. if( pfl )
  2614. {
  2615. double fmeas = cmScMatcherFMeas(p);
  2616. if( printFl )
  2617. printf("mark:%i midi:%i loc:%i bar:%i cost:%f f-meas:%f text:%s\n",i,p->mni,p->begSyncLocIdx,p->mp->loc[p->begSyncLocIdx].barNumb,p->s_opt,fmeas,tlmp->text);
  2618. if( fmeas < scoreThresh )
  2619. ++scoreFailCnt;
  2620. }
  2621. //print score and match for entire marker
  2622. //cmScMatcherPrint(p);
  2623. // ONLY USE ONE MARKER DURING TESTING
  2624. // break;
  2625. if( printFl )
  2626. printf("\n");
  2627. }
  2628. printf("cand:%i fail:%i - init:%i score:%i other:%i\n\n",candCnt,initFailCnt+scoreFailCnt+otherFailCnt,initFailCnt,scoreFailCnt,otherFailCnt);
  2629. cmTimeGet(&t1);
  2630. printf("elapsed:%f\n", (double)cmTimeElapsedMicros(&t0,&t1)/1000000.0 );
  2631. cmScMatcherFree(&p);
  2632. cmScMeasFree(&mp);
  2633. cmCtxFree(&ctx);
  2634. }