libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmProc4.c 100KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079
  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 "cmFile.h"
  12. #include "cmFileSys.h"
  13. #include "cmJson.h"
  14. #include "cmSymTbl.h"
  15. #include "cmAudioFile.h"
  16. #include "cmText.h"
  17. #include "cmProcObj.h"
  18. #include "cmProcTemplate.h"
  19. #include "cmMath.h"
  20. #include "cmTime.h"
  21. #include "cmMidi.h"
  22. #include "cmMidiFile.h"
  23. #include "cmProc.h"
  24. #include "cmProc2.h"
  25. #include "cmVectOps.h"
  26. #include "cmTimeLine.h"
  27. #include "cmScore.h"
  28. #include "cmProc4.h"
  29. //=======================================================================================================================
  30. //----------------------------------------------------------------------------------------
  31. void ed_print_mtx( ed_r* r)
  32. {
  33. unsigned i,j,k;
  34. for(i=0; i<r->rn; ++i)
  35. {
  36. for(j=0; j<r->cn; ++j)
  37. {
  38. printf("(");
  39. const ed_val* vp = r->m + i + (j*r->rn);
  40. for(k=0; k<kEdCnt; ++k)
  41. {
  42. printf("%i",vp->v[k]);
  43. if( k<kEdCnt-1)
  44. printf(", ");
  45. else
  46. printf(" ");
  47. }
  48. printf("%c)",vp->transFl?'t':' ');
  49. }
  50. printf("\n");
  51. }
  52. }
  53. void ed_init( ed_r* r, const char* s0, const char* s1 )
  54. {
  55. unsigned i,j,k;
  56. r->rn = strlen(s0)+1;
  57. r->cn = strlen(s1)+1;
  58. r->m = cmMemAllocZ(ed_val, r->rn*r->cn );
  59. r->pn = r->rn + r->cn;
  60. r->p_mem = cmMemAllocZ(ed_path, 2*r->pn );
  61. r->p_avl = r->p_mem;
  62. r->p_cur = NULL;
  63. r->p_opt = r->p_mem + r->pn;
  64. r->s_opt = DBL_MAX;
  65. r->s0 = s0;
  66. r->s1 = s1;
  67. for(i=0; i<r->rn; ++i)
  68. for(j=0; j<r->cn; ++j)
  69. {
  70. unsigned v[] = {0,0,0,0};
  71. if( i == 0 )
  72. {
  73. v[kEdMinIdx] = j;
  74. v[kEdInsIdx] = j;
  75. }
  76. else
  77. if( j == 0 )
  78. {
  79. v[kEdMinIdx] = i;
  80. v[kEdDelIdx] = i;
  81. }
  82. for(k=0; k<kEdCnt; ++k)
  83. r->m[ i + (j*r->rn) ].v[k] = v[k];
  84. }
  85. // put pn path records on the available list
  86. for(i=0; i<r->pn; ++i)
  87. r->p_mem[i].next = i<r->pn-1 ? r->p_mem + i + 1 : NULL;
  88. }
  89. unsigned _ed_min( ed_r* r, unsigned i, unsigned j )
  90. {
  91. assert( i<r->rn && j<r->cn );
  92. return r->m[ i + (j*r->rn) ].v[kEdMinIdx];
  93. }
  94. bool _ed_is_trans( ed_r* r, const ed_val* v1p, unsigned i, unsigned j )
  95. {
  96. bool fl = false;
  97. ed_val* v0p = r->m + i + (j*r->rn);
  98. if( i>=1 && j>=1 &&
  99. v1p->v[kEdMinIdx] == v1p->v[kEdSubIdx]
  100. && v1p->matchFl == false
  101. && v0p->v[kEdMinIdx] == v0p->v[kEdSubIdx]
  102. && v0p->matchFl == false )
  103. {
  104. char c00 = r->s0[i-1];
  105. char c01 = r->s0[i ];
  106. char c10 = r->s1[j-1];
  107. char c11 = r->s1[j ];
  108. fl = c00==c11 && c01==c10;
  109. }
  110. return fl;
  111. }
  112. void ed_calc_mtx( ed_r* r )
  113. {
  114. unsigned i,j;
  115. for(i=1; i<r->rn; ++i)
  116. for(j=1; j<r->cn; ++j)
  117. {
  118. ed_val* vp = r->m + i + (j*r->rn);
  119. vp->matchFl = r->s0[i-1] == r->s1[j-1];
  120. unsigned cost = vp->matchFl ? 0 : 1;
  121. vp->v[kEdSubIdx] = _ed_min(r,i-1,j-1) + cost;
  122. vp->v[kEdDelIdx] = _ed_min(r,i-1,j ) + 1;
  123. vp->v[kEdInsIdx] = _ed_min(r,i, j-1) + 1;
  124. vp->v[kEdMinIdx] = cmMin( vp->v[kEdSubIdx], cmMin(vp->v[kEdDelIdx],vp->v[kEdInsIdx]));
  125. vp->transFl = _ed_is_trans(r,vp,i-1,j-1);
  126. }
  127. }
  128. void ed_path_push( ed_r* r, unsigned code, unsigned ri, unsigned ci, bool matchFl, bool transFl )
  129. {
  130. assert(r->p_avl != NULL );
  131. ed_path* p = r->p_avl;
  132. r->p_avl = r->p_avl->next;
  133. p->code = code;
  134. p->ri = ri;
  135. p->ci = ci;
  136. p->matchFl = matchFl;
  137. p->transFl = transFl;
  138. p->next = r->p_cur;
  139. r->p_cur = p;
  140. }
  141. void ed_path_pop( ed_r* r )
  142. {
  143. assert( r->p_cur != NULL );
  144. ed_path* tp = r->p_cur->next;
  145. r->p_cur->next = r->p_avl;
  146. r->p_avl = r->p_cur;
  147. r->p_cur = tp;
  148. }
  149. double ed_score_candidate( ed_r* r )
  150. {
  151. ed_path* cp = r->p_cur;
  152. ed_path* bp = r->p_cur;
  153. ed_path* ep = NULL;
  154. for(; cp!=NULL; cp=cp->next)
  155. if( cp->code != kEdInsIdx )
  156. {
  157. bp = cp;
  158. break;
  159. }
  160. for(; cp!=NULL; cp=cp->next)
  161. if( cp->code!=kEdInsIdx )
  162. ep = cp;
  163. assert( ep!=NULL && bp!=ep);
  164. unsigned n=1;
  165. for(cp=bp; cp!=ep; cp=cp->next)
  166. ++n;
  167. double gapCnt = 0;
  168. double penalty = 0;
  169. bool pfl = bp->matchFl;
  170. unsigned i;
  171. cp = bp;
  172. for(i=0; i<n; ++i,cp=cp->next)
  173. {
  174. // a gap is a transition from a matching subst. to an insert or deletion
  175. //if( pc != cp->code && cp->code != kEdSubIdx && pc==kEdSubIdx && pfl==true )
  176. if( pfl==true && cp->matchFl==false )
  177. ++gapCnt;
  178. //
  179. switch( cp->code )
  180. {
  181. case kEdSubIdx:
  182. penalty += cp->matchFl ? 0 : 1;
  183. penalty -= cp->transFl ? 1 : 0;
  184. break;
  185. case kEdDelIdx:
  186. penalty += 1;
  187. break;
  188. case kEdInsIdx:
  189. penalty += 1;
  190. break;
  191. }
  192. pfl = cp->matchFl;
  193. }
  194. double score = gapCnt/n + penalty;
  195. printf("n:%i gaps:%f gap_score:%f penalty:%f score:%f\n",n,gapCnt,gapCnt/n,penalty,score);
  196. return score;
  197. }
  198. void ed_eval_candidate( ed_r* r, double score )
  199. {
  200. if( r->s_opt == DBL_MAX || r->s_opt > score)
  201. {
  202. // copy the p_cur to p_opt[]
  203. ed_path* cp = r->p_cur;
  204. unsigned i;
  205. for(i=0; cp!=NULL && i<r->pn; cp=cp->next,++i)
  206. {
  207. r->p_opt[i].code = cp->code;
  208. r->p_opt[i].ri = cp->ri;
  209. r->p_opt[i].ci = cp->ci;
  210. r->p_opt[i].matchFl = cp->matchFl;
  211. r->p_opt[i].transFl = cp->transFl;
  212. }
  213. assert( i < r->pn );
  214. r->p_opt[i].code = 0; // terminate with code=0
  215. r->s_opt = score;
  216. }
  217. }
  218. void ed_print_opt( ed_r* r )
  219. {
  220. unsigned i;
  221. for(i=0; r->p_opt[i].code!=0; ++i)
  222. {
  223. ed_path* cp = r->p_opt + i;
  224. char c0 = cp->matchFl ? 'm' : ' ';
  225. char c1 = cp->transFl ? 't' : ' ';
  226. printf("%2i code:%i ri:%2i ci:%2i %c%c\n",i,cp->code,cp->ri,cp->ci,c0,c1);
  227. }
  228. printf("score:%f\n",r->s_opt);
  229. }
  230. void ed_print_candidate( ed_r* r )
  231. {
  232. ed_path* cp = r->p_cur;
  233. unsigned pn = r->pn;
  234. unsigned i;
  235. char s0[pn+1];
  236. char s1[pn+1];
  237. char s2[pn+1];
  238. char s3[pn+1];
  239. s0[pn] = 0;
  240. s1[pn] = 0;
  241. s2[pn] = 0;
  242. s3[pn] = 0;
  243. for(i=0; i<pn && cp!=NULL; ++i,cp=cp->next)
  244. {
  245. switch(cp->code)
  246. {
  247. case kEdSubIdx: // subst
  248. assert( 0 <= cp->ri && cp->ri <= r->rn );
  249. assert( 0 <= cp->ci && cp->ci <= r->cn );
  250. s0[i] = r->s0[cp->ri];
  251. s1[i] = r->s1[cp->ci];
  252. s2[i] = 's';
  253. s3[i] = cp->matchFl ? 'm' : ' ';
  254. break;
  255. case kEdDelIdx: // delete
  256. assert( 0 <= cp->ri && cp->ri <= r->rn );
  257. s0[i] = r->s0[cp->ri];
  258. s1[i] = ' ';
  259. s2[i] = 'd';
  260. s3[i] = ' ';
  261. break;
  262. case kEdInsIdx: // insert
  263. assert( 0 <= cp->ci && cp->ci <= r->cn );
  264. s0[i] = ' ';
  265. s1[i] = r->s1[cp->ci];
  266. s2[i] = 'i';
  267. s3[i] = ' ';
  268. break;
  269. }
  270. }
  271. if( i < pn )
  272. {
  273. s0[i] = 0;
  274. s1[i] = 0;
  275. s2[i] = 0;
  276. s3[i] = 0;
  277. }
  278. printf("\ns0:%s\n",s0);
  279. printf("s1:%s\n",s1);
  280. printf("s2:%s\n",s2);
  281. printf("s3:%s\n",s3);
  282. }
  283. // traverse the solution matrix from the lower-right to
  284. // the upper-left.
  285. void ed_node( ed_r* r, int i, int j )
  286. {
  287. unsigned m;
  288. // stop when the upper-right is encountered
  289. if( i==0 && j==0 )
  290. {
  291. ed_print_candidate(r);
  292. ed_eval_candidate(r, ed_score_candidate(r) );
  293. return;
  294. }
  295. ed_val* vp = r->m + i + (j*r->rn);
  296. // for each possible dir: up,left,up-left
  297. for(m=1; m<kEdCnt; ++m)
  298. if( vp->v[m] == vp->v[kEdMinIdx] )
  299. {
  300. unsigned ii = i-1;
  301. unsigned jj = j-1;
  302. switch(m)
  303. {
  304. case kEdSubIdx:
  305. break;
  306. case kEdDelIdx:
  307. jj = j;
  308. break;
  309. case kEdInsIdx:
  310. ii = i;
  311. break;
  312. }
  313. // prepend to the current candidate path: r->p_cur
  314. ed_path_push(r,m,ii,jj,vp->matchFl,vp->transFl);
  315. // recurse!
  316. ed_node(r,ii,jj);
  317. // remove the first element from the current path
  318. ed_path_pop(r);
  319. }
  320. }
  321. void ed_align( ed_r* r )
  322. {
  323. int i = r->rn-1;
  324. int j = r->cn-1;
  325. unsigned m = r->m[i + (j*r->rn)].v[kEdMinIdx];
  326. if( m==cmMax(r->rn,r->cn) )
  327. printf("Edit distance is at max: %i. No Match.\n",m);
  328. else
  329. ed_node(r,i,j);
  330. }
  331. void ed_free( ed_r* r )
  332. {
  333. cmMemFree(r->m);
  334. cmMemFree(r->p_mem);
  335. }
  336. void ed_main()
  337. {
  338. const char* s0 = "YHCQPGK";
  339. const char* s1 = "LAHYQQKPGKA";
  340. s0 = "ABCDE";
  341. s1 = "ABDCE";
  342. //s1 = "FGHIJK";
  343. ed_r r;
  344. ed_init(&r,s0,s1);
  345. ed_calc_mtx(&r);
  346. ed_print_mtx(&r);
  347. ed_align(&r);
  348. ed_print_opt(&r);
  349. ed_free(&r);
  350. }
  351. //=======================================================================================================================
  352. cmScMatch* cmScMatchAlloc( cmCtx* c, cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN )
  353. {
  354. cmScMatch* op = cmObjAlloc(cmScMatch,c,p);
  355. if( cmScoreIsValid(scH) )
  356. if( cmScMatchInit(op,scH,maxScWndN,maxMidiWndN) != cmOkRC )
  357. cmScMatchFree(&op);
  358. return op;
  359. }
  360. cmRC_t cmScMatchFree( cmScMatch** pp )
  361. {
  362. cmRC_t rc = cmOkRC;
  363. if( pp==NULL || *pp==NULL )
  364. return rc;
  365. cmScMatch* p = *pp;
  366. if((rc = cmScMatchFinal(p)) != cmOkRC )
  367. return rc;
  368. cmMemFree(p->loc);
  369. cmMemFree(p->m);
  370. cmMemFree(p->p_mem);
  371. cmObjFree(pp);
  372. return rc;
  373. }
  374. void _cmScMatchInitLoc( cmScMatch* p )
  375. {
  376. unsigned li,ei;
  377. p->locN = cmScoreEvtCount(p->scH);
  378. p->loc = cmMemResizeZ(cmScMatchLoc_t,p->loc,p->locN);
  379. // for each score location
  380. for(li=0,ei=0; li<cmScoreLocCount(p->scH); ++li)
  381. {
  382. unsigned i,n;
  383. const cmScoreLoc_t* lp = cmScoreLoc(p->scH,li);
  384. // count the number of note events at location li
  385. for(n=0,i=0; i<lp->evtCnt; ++i)
  386. if( lp->evtArray[i]->type == kNonEvtScId )
  387. ++n;
  388. assert( ei+n <= p->locN );
  389. // duplicate each note at location li n times
  390. for(i=0; i<n; ++i)
  391. {
  392. unsigned j,k;
  393. p->loc[ei+i].evtCnt = n;
  394. p->loc[ei+i].evtV = cmMemAllocZ(cmScMatchEvt_t,n);
  395. p->loc[ei+i].scLocIdx = li;
  396. p->loc[ei+i].barNumb = lp->barNumb;
  397. for(j=0,k=0; j<lp->evtCnt; ++j)
  398. if( lp->evtArray[j]->type == kNonEvtScId )
  399. {
  400. p->loc[ei+i].evtV[k].pitch = lp->evtArray[j]->pitch;
  401. p->loc[ei+i].evtV[k].scEvtIdx = lp->evtArray[j]->index;
  402. ++k;
  403. }
  404. }
  405. ei += n;
  406. }
  407. assert(ei<=p->locN);
  408. p->locN = ei;
  409. }
  410. cmRC_t cmScMatchInit( cmScMatch* p, cmScH_t scH, unsigned maxScWndN, unsigned maxMidiWndN )
  411. {
  412. unsigned i;
  413. cmRC_t rc;
  414. if((rc = cmScMatchFinal(p)) != cmOkRC )
  415. return rc;
  416. p->scH = scH;
  417. p->mrn = maxMidiWndN + 1;
  418. p->mcn = maxScWndN + 1;
  419. p->mmn = maxMidiWndN;
  420. p->msn = maxScWndN;
  421. _cmScMatchInitLoc(p);
  422. p->m = cmMemResizeZ(cmScMatchVal_t, p->m, p->mrn*p->mcn );
  423. p->pn = p->mrn + p->mcn;
  424. p->p_mem = cmMemResizeZ(cmScMatchPath_t, p->p_mem, 2*p->pn );
  425. p->p_avl = p->p_mem;
  426. p->p_cur = NULL;
  427. p->p_opt = p->p_mem + p->pn;
  428. // put pn path records on the available list
  429. for(i=0; i<p->pn; ++i)
  430. {
  431. p->p_mem[i].next = i<p->pn-1 ? p->p_mem + i + 1 : NULL;
  432. p->p_opt[i].next = i<p->pn-1 ? p->p_opt + i + 1 : NULL;
  433. }
  434. return rc;
  435. }
  436. cmRC_t cmScMatchFinal( cmScMatch* p )
  437. {
  438. unsigned i;
  439. if( p != NULL )
  440. for(i=0; i<p->locN; ++i)
  441. cmMemPtrFree(&p->loc[i].evtV);
  442. return cmOkRC;
  443. }
  444. cmRC_t _cmScMatchInitMtx( cmScMatch* p, unsigned rn, unsigned cn )
  445. {
  446. //if( rn >p->mrn && cn > p->mcn )
  447. if( rn*cn > p->mrn*p->mcn )
  448. {
  449. 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);
  450. }
  451. // if the size of the mtx is not changing then there is nothing to do
  452. if( rn == p->rn && cn == p->cn )
  453. return cmOkRC;
  454. // update the mtx size
  455. p->rn = rn;
  456. p->cn = cn;
  457. // fill in the default values for the first row
  458. // and column of the DP matrix
  459. unsigned i,j,k;
  460. for(i=0; i<rn; ++i)
  461. for(j=0; j<cn; ++j)
  462. {
  463. unsigned v[] = {0,0,0,0};
  464. if( i == 0 )
  465. {
  466. v[kSmMinIdx] = j;
  467. v[kSmInsIdx] = j;
  468. }
  469. else
  470. if( j == 0 )
  471. {
  472. v[kSmMinIdx] = i;
  473. v[kSmDelIdx] = i;
  474. }
  475. // zero the value field
  476. for(k=0; k<kSmCnt; ++k)
  477. p->m[ i + (j*rn) ].v[k] = v[k];
  478. }
  479. return cmOkRC;
  480. }
  481. cmScMatchVal_t* _cmScMatchValPtr( cmScMatch* p, unsigned i, unsigned j, unsigned rn, unsigned cn )
  482. {
  483. assert( i < rn && j < cn );
  484. return p->m + i + (j*rn);
  485. }
  486. unsigned _cmScMatchIsMatchIndex( const cmScMatchLoc_t* loc, unsigned pitch )
  487. {
  488. unsigned i;
  489. for(i=0; i<loc->evtCnt; ++i)
  490. if( loc->evtV[i].pitch == pitch )
  491. return i;
  492. return cmInvalidIdx;
  493. }
  494. bool _cmScMatchIsMatch( const cmScMatchLoc_t* loc, unsigned pitch )
  495. { return _cmScMatchIsMatchIndex(loc,pitch) != cmInvalidIdx; }
  496. bool _cmScMatchIsTrans( cmScMatch* p, const cmScMatchMidi_t* midiV, const cmScMatchVal_t* v1p, unsigned bsi, unsigned i, unsigned j, unsigned rn, unsigned cn )
  497. {
  498. bool fl = false;
  499. cmScMatchVal_t* v0p = _cmScMatchValPtr(p,i,j,rn,cn);
  500. if( i>=1 && j>=1
  501. && v1p->v[kSmMinIdx] == v1p->v[kSmSubIdx]
  502. && cmIsNotFlag(v1p->flags,kSmMatchFl)
  503. && v0p->v[kSmMinIdx] == v0p->v[kSmSubIdx]
  504. && cmIsNotFlag(v0p->flags,kSmMatchFl)
  505. )
  506. {
  507. unsigned c00 = midiV[i-1].pitch;
  508. unsigned c01 = midiV[i ].pitch;
  509. cmScMatchLoc_t* c10 = p->loc + bsi + j - 1;
  510. cmScMatchLoc_t* c11 = p->loc + bsi + j;
  511. fl = _cmScMatchIsMatch(c11,c00) && _cmScMatchIsMatch(c10,c01);
  512. }
  513. return fl;
  514. }
  515. unsigned _cmScMatchMin( cmScMatch* p, unsigned i, unsigned j, unsigned rn, unsigned cn )
  516. {
  517. return _cmScMatchValPtr(p,i,j,rn,cn)->v[kSmMinIdx];
  518. }
  519. // Return false if bsi + cn > p->locN
  520. // pitchV[rn-1]
  521. bool _cmScMatchCalcMtx( cmScMatch* p, unsigned bsi, const cmScMatchMidi_t* midiV, unsigned rn, unsigned cn )
  522. {
  523. // loc[begScanLocIdx:begScanLocIdx+cn-1] must be valid
  524. if( bsi + cn > p->locN )
  525. return false;
  526. unsigned i,j;
  527. for(j=1; j<cn; ++j)
  528. for(i=1; i<rn; ++i)
  529. {
  530. cmScMatchLoc_t* loc = p->loc + bsi + j - 1;
  531. unsigned pitch = midiV[i-1].pitch;
  532. cmScMatchVal_t* vp = _cmScMatchValPtr(p,i,j,rn,cn);
  533. unsigned idx = _cmScMatchIsMatchIndex(loc,pitch);
  534. vp->flags = idx==cmInvalidIdx ? 0 : kSmMatchFl;
  535. vp->scEvtIdx = idx==cmInvalidIdx ? cmInvalidIdx : loc->evtV[idx].scEvtIdx;
  536. unsigned cost = cmIsFlag(vp->flags,kSmMatchFl) ? 0 : 1;
  537. vp->v[kSmSubIdx] = _cmScMatchMin(p,i-1,j-1, rn, cn) + cost;
  538. vp->v[kSmDelIdx] = _cmScMatchMin(p,i-1,j , rn, cn) + 1;
  539. vp->v[kSmInsIdx] = _cmScMatchMin(p,i, j-1, rn, cn) + 1;
  540. vp->v[kSmMinIdx] = cmMin( vp->v[kSmSubIdx], cmMin(vp->v[kSmDelIdx],vp->v[kSmInsIdx]));
  541. vp->flags |= _cmScMatchIsTrans(p,midiV,vp,bsi,i-1,j-1,rn,cn) ? kSmTransFl : 0;
  542. }
  543. return true;
  544. }
  545. void _cmScMatchPrintMtx( cmScMatch* r, unsigned rn, unsigned cn)
  546. {
  547. unsigned i,j,k;
  548. for(i=0; i<rn; ++i)
  549. {
  550. for(j=0; j<cn; ++j)
  551. {
  552. printf("(");
  553. const cmScMatchVal_t* vp = _cmScMatchValPtr(r,i,j,rn,cn);
  554. for(k=0; k<kSmCnt; ++k)
  555. {
  556. printf("%i",vp->v[k]);
  557. if( k<kSmCnt-1)
  558. printf(", ");
  559. else
  560. printf(" ");
  561. }
  562. printf("%c%c)",cmIsFlag(vp->flags,kSmMatchFl)?'m':' ',cmIsFlag(vp->flags,kSmTransFl)?'t':' ');
  563. }
  564. printf("\n");
  565. }
  566. }
  567. void _cmScMatchPathPush( cmScMatch* r, unsigned code, unsigned ri, unsigned ci, unsigned flags, unsigned scEvtIdx )
  568. {
  569. assert(r->p_avl != NULL );
  570. cmScMatchPath_t* p = r->p_avl;
  571. r->p_avl = r->p_avl->next;
  572. p->code = code;
  573. p->ri = ri;
  574. p->ci = ci;
  575. p->flags = code==kSmSubIdx && cmIsFlag(flags,kSmMatchFl) ? kSmMatchFl : 0;
  576. p->flags |= cmIsFlag(flags,kSmTransFl) ? kSmTransFl : 0;
  577. p->scEvtIdx= scEvtIdx;
  578. p->next = r->p_cur;
  579. r->p_cur = p;
  580. }
  581. void _cmScMatchPathPop( cmScMatch* r )
  582. {
  583. assert( r->p_cur != NULL );
  584. cmScMatchPath_t* tp = r->p_cur->next;
  585. r->p_cur->next = r->p_avl;
  586. r->p_avl = r->p_cur;
  587. r->p_cur = tp;
  588. }
  589. double _cmScMatchCalcCandidateCost( cmScMatch* r )
  590. {
  591. cmScMatchPath_t* cp = r->p_cur;
  592. cmScMatchPath_t* bp = r->p_cur;
  593. cmScMatchPath_t* ep = NULL;
  594. // skip leading inserts
  595. for(; cp!=NULL; cp=cp->next)
  596. if( cp->code != kSmInsIdx )
  597. {
  598. bp = cp;
  599. break;
  600. }
  601. // skip to trailing inserts
  602. for(; cp!=NULL; cp=cp->next)
  603. if( cp->code!=kSmInsIdx )
  604. ep = cp;
  605. // count remaining path length
  606. assert( ep!=NULL );
  607. unsigned n=1;
  608. for(cp=bp; cp!=ep; cp=cp->next)
  609. ++n;
  610. double gapCnt = 0;
  611. double penalty = 0;
  612. bool pfl = cmIsFlag(bp->flags,kSmMatchFl);
  613. unsigned i;
  614. cp = bp;
  615. for(i=0; i<n; ++i,cp=cp->next)
  616. {
  617. // a gap is a transition from a matching subst. to an insert or deletion
  618. //if( pc != cp->code && cp->code != kSmSubIdx && pc==kSmSubIdx && pfl==true )
  619. if( pfl==true && cmIsFlag(cp->flags,kSmMatchFl)==false )
  620. ++gapCnt;
  621. //
  622. switch( cp->code )
  623. {
  624. case kSmSubIdx:
  625. penalty += cmIsFlag(cp->flags,kSmMatchFl) ? 0 : 1;
  626. penalty -= cmIsFlag(cp->flags,kSmTransFl) ? 1 : 0;
  627. break;
  628. case kSmDelIdx:
  629. penalty += 1;
  630. break;
  631. case kSmInsIdx:
  632. penalty += 1;
  633. break;
  634. }
  635. pfl = cmIsFlag(cp->flags,kSmMatchFl);
  636. }
  637. double cost = gapCnt/n + penalty;
  638. //printf("n:%i gaps:%f gap_score:%f penalty:%f score:%f\n",n,gapCnt,gapCnt/n,penalty,score);
  639. return cost;
  640. }
  641. double _cmScMatchEvalCandidate( cmScMatch* r, double min_cost, double cost )
  642. {
  643. if( min_cost == DBL_MAX || cost < min_cost)
  644. {
  645. // copy the p_cur to p_opt[]
  646. cmScMatchPath_t* cp = r->p_cur;
  647. unsigned i;
  648. for(i=0; cp!=NULL && i<r->pn; cp=cp->next,++i)
  649. {
  650. r->p_opt[i].code = cp->code;
  651. r->p_opt[i].ri = cp->ri;
  652. r->p_opt[i].ci = cp->ci;
  653. r->p_opt[i].flags = cp->flags;
  654. r->p_opt[i].scEvtIdx= cp->scEvtIdx;
  655. r->p_opt[i].next = cp->next==NULL ? NULL : r->p_opt + i + 1;
  656. }
  657. assert( i < r->pn );
  658. r->p_opt[i].code = 0; // terminate with code=0
  659. min_cost = cost;
  660. }
  661. return min_cost;
  662. }
  663. // NOTE: IF THE COST CALCULATION WAS BUILT INTO THE RECURSION THEN
  664. // THIS FUNCTION COULD BE MADE MORE EFFICIENT BECAUSE PATHS WHICH
  665. // EXCEEDED THE min_cost COULD BE SHORT CIRCUITED.
  666. //
  667. // traverse the solution matrix from the lower-right to
  668. // the upper-left.
  669. double _cmScMatchGenPaths( cmScMatch* r, int i, int j, unsigned rn, unsigned cn, double min_cost )
  670. {
  671. unsigned m;
  672. // stop when the upper-right is encountered
  673. if( i==0 && j==0 )
  674. return _cmScMatchEvalCandidate(r, min_cost, _cmScMatchCalcCandidateCost(r) );
  675. cmScMatchVal_t* vp = _cmScMatchValPtr(r,i,j,rn,cn);
  676. // for each possible dir: up,left,up-left
  677. for(m=1; m<kSmCnt; ++m)
  678. if( vp->v[m] == vp->v[kSmMinIdx] )
  679. {
  680. // prepend to the current candidate path: r->p_cur
  681. _cmScMatchPathPush(r,m,i,j,vp->flags,vp->scEvtIdx);
  682. int ii = i-1;
  683. int jj = j-1;
  684. switch(m)
  685. {
  686. case kSmSubIdx:
  687. break;
  688. case kSmDelIdx:
  689. jj = j;
  690. break;
  691. case kSmInsIdx:
  692. ii = i;
  693. break;
  694. default:
  695. { assert(0); }
  696. }
  697. // recurse!
  698. min_cost = _cmScMatchGenPaths(r,ii,jj,rn,cn,min_cost);
  699. // remove the first element from the current path
  700. _cmScMatchPathPop(r);
  701. }
  702. return min_cost;
  703. }
  704. double _cmScMatchAlign( cmScMatch* p, unsigned rn, unsigned cn, double min_cost )
  705. {
  706. int i = rn-1;
  707. int j = cn-1;
  708. unsigned m = _cmScMatchMin(p,i,j,rn,cn);
  709. if( m==cmMax(rn,cn) )
  710. printf("Edit distance is at max: %i. No Match.\n",m);
  711. else
  712. min_cost = _cmScMatchGenPaths(p,i,j,rn,cn,min_cost);
  713. return min_cost;
  714. }
  715. cmRC_t cmScMatchExec( cmScMatch* p, unsigned locIdx, unsigned locN, const cmScMatchMidi_t* midiV, unsigned midiN, double min_cost )
  716. {
  717. cmRC_t rc;
  718. unsigned rn = midiN + 1;
  719. unsigned cn = locN + 1;
  720. // set the DP matrix default values
  721. if((rc = _cmScMatchInitMtx(p, rn, cn )) != cmOkRC )
  722. return rc;
  723. // _cmScMatchCalcMtx() returns false if the score window exceeds the length of the score
  724. if(!_cmScMatchCalcMtx(p,locIdx, midiV, rn, cn) )
  725. return cmEofRC;
  726. //_cmScMatchPrintMtx(p,rn,cn);
  727. // locate the path through the DP matrix with the lowest edit distance (cost)
  728. p->opt_cost = _cmScMatchAlign(p, rn, cn, min_cost);
  729. return rc;
  730. }
  731. // Traverse the least cost path and:
  732. // 1) Return, esi, the score location index of the last MIDI note
  733. // which has a positive match with the score and assign
  734. // the internal score index to cp->locIdx.
  735. //
  736. // 2) Set cmScAlignPath_t.locIdx - index into p->loc[] associated
  737. // with each path element that is a 'substitute' or an 'insert'.
  738. //
  739. // 3) Set *missCnPtr: the count of trailing non-positive matches.
  740. //
  741. // i_opt is index into p->loc[] of p->p_opt.
  742. unsigned cmScMatchDoSync( cmScMatch* p, unsigned i_opt, cmScMatchMidi_t* midiBuf, unsigned midiN, unsigned* missCntPtr )
  743. {
  744. cmScMatchPath_t* cp = p->p_opt;
  745. unsigned missCnt = 0;
  746. unsigned esi = cmInvalidIdx;
  747. unsigned i;
  748. for(i=0; cp!=NULL; cp=cp->next)
  749. {
  750. // there is no MIDI note associated with 'inserts'
  751. if( cp->code != kSmInsIdx )
  752. {
  753. assert( cp->ri > 0 );
  754. midiBuf[ cp->ri-1 ].locIdx = cmInvalidIdx;
  755. }
  756. switch( cp->code )
  757. {
  758. case kSmSubIdx:
  759. midiBuf[ cp->ri-1 ].locIdx = i_opt + i;
  760. midiBuf[ cp->ri-1 ].scEvtIdx = cp->scEvtIdx;
  761. if( cmIsFlag(cp->flags,kSmMatchFl) )
  762. {
  763. esi = i_opt + i;
  764. missCnt = 0;
  765. }
  766. else
  767. {
  768. ++missCnt;
  769. }
  770. // fall through
  771. case kSmInsIdx:
  772. cp->locIdx = i_opt + i;
  773. ++i;
  774. break;
  775. case kSmDelIdx:
  776. cp->locIdx = cmInvalidIdx;
  777. ++missCnt;
  778. break;
  779. }
  780. }
  781. if( missCntPtr != NULL )
  782. *missCntPtr = missCnt;
  783. return esi;
  784. }
  785. void _cmScMatchMidiEvtFlags( cmScMatch* p, const cmScMatchLoc_t* lp, unsigned evtIdx, char* s, unsigned sn )
  786. {
  787. const cmScoreLoc_t* slp = cmScoreLoc(p->scH,lp->scLocIdx);
  788. assert( evtIdx < slp->evtCnt );
  789. const cmScoreEvt_t* ep = slp->evtArray[evtIdx];
  790. unsigned i = 0;
  791. s[0] = 0;
  792. if( cmIsFlag(ep->flags,kEvenScFl) )
  793. s[i++] = 'e';
  794. if( cmIsFlag(ep->flags,kTempoScFl) )
  795. s[i++] = 't';
  796. if( cmIsFlag(ep->flags,kDynScFl) )
  797. s[i++] = 'd';
  798. if( cmIsFlag(ep->flags,kGraceScFl) )
  799. s[i++] = 'g';
  800. s[i++] = 0;
  801. assert( i <= sn );
  802. }
  803. void _cmScMatchPrintPath( cmScMatch* p, cmScMatchPath_t* cp, unsigned bsi, const cmScMatchMidi_t* midiV )
  804. {
  805. assert( bsi != cmInvalidIdx );
  806. cmScMatchPath_t* pp = cp;
  807. int polyN = 0;
  808. int i;
  809. printf("loc: ");
  810. // get the polyphony count for the score window
  811. for(i=0; pp!=NULL; pp=pp->next)
  812. {
  813. cmScMatchLoc_t* lp = p->loc + bsi + pp->ci;
  814. if( pp->code!=kSmDelIdx )
  815. {
  816. if(lp->evtCnt > polyN)
  817. polyN = lp->evtCnt;
  818. printf("%4i%4s ",bsi+i," ");
  819. ++i;
  820. }
  821. else
  822. printf("%4s%4s "," "," ");
  823. }
  824. printf("\n");
  825. // print the score notes
  826. for(i=polyN; i>0; --i)
  827. {
  828. printf("%3i: ",i);
  829. for(pp=cp; pp!=NULL; pp=pp->next)
  830. {
  831. if( pp->code!=kSmDelIdx )
  832. {
  833. int locIdx = bsi + pp->ci - 1;
  834. assert(0 <= locIdx && locIdx <= p->locN);
  835. cmScMatchLoc_t* lp = p->loc + locIdx;
  836. if( lp->evtCnt >= i )
  837. {
  838. unsigned sn = 6;
  839. char s[sn];
  840. _cmScMatchMidiEvtFlags(p,lp,i-1,s,sn );
  841. printf("%4s%-4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0),s);
  842. }
  843. else
  844. printf("%4s%4s "," "," ");
  845. }
  846. else
  847. printf("%4s%4s ", (pp->code==kSmDelIdx? "-" : " ")," ");
  848. /*
  849. int locIdx = bsi + pp->ci - 1;
  850. assert(0 <= locIdx && locIdx <= p->locN);
  851. cmScMatchLoc_t* lp = p->loc + locIdx;
  852. if( pp->code!=kSmDelIdx && lp->evtCnt >= i )
  853. printf("%4s ",cmMidiToSciPitch(lp->evtV[i-1].pitch,NULL,0));
  854. else
  855. printf("%4s ", pp->code==kSmDelIdx? "-" : " ");
  856. */
  857. }
  858. printf("\n");
  859. }
  860. printf("mid: ");
  861. // print the MIDI buffer
  862. for(pp=cp; pp!=NULL; pp=pp->next)
  863. {
  864. if( pp->code!=kSmInsIdx )
  865. printf("%4s%4s ",cmMidiToSciPitch(midiV[pp->ri-1].pitch,NULL,0)," ");
  866. else
  867. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  868. }
  869. printf("\nvel: ");
  870. // print the MIDI velocity
  871. for(pp=cp; pp!=NULL; pp=pp->next)
  872. {
  873. if( pp->code!=kSmInsIdx )
  874. printf("%4i%4s ",midiV[pp->ri-1].vel," ");
  875. else
  876. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  877. }
  878. printf("\nmni: ");
  879. // print the MIDI buffer index (mni)
  880. for(pp=cp; pp!=NULL; pp=pp->next)
  881. {
  882. if( pp->code!=kSmInsIdx )
  883. printf("%4i%4s ",midiV[pp->ri-1].mni," ");
  884. else
  885. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  886. }
  887. printf("\n op: ");
  888. // print the substitute/insert/delete operation
  889. for(pp=cp; pp!=NULL; pp=pp->next)
  890. {
  891. char c = ' ';
  892. switch( pp->code )
  893. {
  894. case kSmSubIdx: c = 's'; break;
  895. case kSmDelIdx: c = 'd'; break;
  896. case kSmInsIdx: c = 'i'; break;
  897. default:
  898. { assert(0); }
  899. }
  900. printf("%4c%4s ",c," ");
  901. }
  902. printf("\n ");
  903. // give substitute attribute (match or transpose)
  904. for(pp=cp; pp!=NULL; pp=pp->next)
  905. {
  906. cmChar_t s[3];
  907. int k = 0;
  908. if( cmIsFlag(pp->flags,kSmMatchFl) )
  909. s[k++] = 'm';
  910. if( cmIsFlag(pp->flags,kSmTransFl) )
  911. s[k++] = 't';
  912. s[k] = 0;
  913. printf("%4s%4s ",s," ");
  914. }
  915. printf("\nscl: ");
  916. // print the stored location index
  917. for(pp=cp; pp!=NULL; pp=pp->next)
  918. {
  919. if( pp->locIdx == cmInvalidIdx )
  920. printf("%4s%4s "," "," ");
  921. else
  922. printf("%4i%4s ",p->loc[pp->locIdx].scLocIdx," ");
  923. }
  924. printf("\nbar: ");
  925. // print the stored location index
  926. for(pp=cp; pp!=NULL; pp=pp->next)
  927. {
  928. if( pp->locIdx==cmInvalidIdx || pp->scEvtIdx==cmInvalidIdx )
  929. printf("%4s%4s "," "," ");
  930. else
  931. {
  932. const cmScoreEvt_t* ep = cmScoreEvt(p->scH, pp->scEvtIdx );
  933. printf("%4i%4s ",ep->barNumb," ");
  934. }
  935. }
  936. printf("\nsec: ");
  937. // print seconds
  938. unsigned begSmpIdx = cmInvalidIdx;
  939. for(pp=cp; pp!=NULL; pp=pp->next)
  940. {
  941. if( pp->code!=kSmInsIdx )
  942. {
  943. if( begSmpIdx == cmInvalidIdx )
  944. begSmpIdx = midiV[pp->ri-1].smpIdx;
  945. printf("%2.2f%4s ", (double)(midiV[pp->ri-1].smpIdx - begSmpIdx)/96000.0," ");
  946. }
  947. else
  948. printf("%4s%4s ",pp->code==kSmInsIdx?"-":" "," ");
  949. }
  950. printf("\n\n");
  951. }
  952. //=======================================================================================================================
  953. cmScMatcher* cmScMatcherAlloc( cmCtx* c, cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg )
  954. {
  955. cmScMatcher* op = cmObjAlloc(cmScMatcher,c,p);
  956. if( op != NULL )
  957. op->mp = cmScMatchAlloc(c,NULL,cmScNullHandle,0,0);
  958. if( srate != 0 )
  959. {
  960. if( cmScMatcherInit(op,srate,scH,scWndN,midiWndN,cbFunc,cbArg) != cmOkRC )
  961. cmScMatcherFree(&op);
  962. }
  963. return op;
  964. }
  965. cmRC_t cmScMatcherFree( cmScMatcher** pp )
  966. {
  967. cmRC_t rc = cmOkRC;
  968. if( pp==NULL || *pp==NULL )
  969. return rc;
  970. cmScMatcher* p = *pp;
  971. if((rc = cmScMatcherFinal(p)) != cmOkRC )
  972. return rc;
  973. cmScMatchFree(&p->mp);
  974. cmMemFree(p->midiBuf);
  975. cmMemFree(p->res);
  976. cmObjFree(pp);
  977. return rc;
  978. }
  979. cmRC_t cmScMatcherInit( cmScMatcher* p, double srate, cmScH_t scH, unsigned scWndN, unsigned midiWndN, cmScMatcherCb_t cbFunc, void* cbArg )
  980. {
  981. cmRC_t rc;
  982. if((rc = cmScMatcherFinal(p)) != cmOkRC )
  983. return rc;
  984. if( midiWndN > scWndN )
  985. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The score alignment MIDI event buffer length (%i) must be less than the score window length (%i).",midiWndN,scWndN);
  986. if(( rc = cmScMatchInit(p->mp,scH,scWndN,midiWndN)) != cmOkRC )
  987. return rc;
  988. p->cbFunc = cbFunc;
  989. p->cbArg = cbArg;
  990. p->mn = midiWndN;
  991. p->midiBuf = cmMemResizeZ(cmScMatchMidi_t,p->midiBuf,p->mn);
  992. p->initHopCnt = 50;
  993. p->stepCnt = 3;
  994. p->maxMissCnt = p->stepCnt+1;
  995. p->rn = 2 * cmScoreEvtCount(scH);
  996. p->res = cmMemResizeZ(cmScMatcherResult_t,p->res,p->rn);
  997. p->printFl = false;
  998. cmScMatcherReset(p,0);
  999. return rc;
  1000. }
  1001. cmRC_t cmScMatcherFinal( cmScMatcher* p )
  1002. {
  1003. return cmScMatchFinal(p->mp);
  1004. }
  1005. cmRC_t cmScMatcherReset( cmScMatcher* p, unsigned scLocIdx )
  1006. {
  1007. p->mbi = p->mp->mmn;
  1008. p->mni = 0;
  1009. p->begSyncLocIdx = cmInvalidIdx;
  1010. p->s_opt = DBL_MAX;
  1011. p->missCnt = 0;
  1012. p->scanCnt = 0;
  1013. p->ri = 0;
  1014. p->eli = cmInvalidIdx;
  1015. p->ili = 0;
  1016. // convert scLocIdx to an index into p->mp->loc[]
  1017. unsigned i = 0;
  1018. while(1)
  1019. {
  1020. for(i=0; i<p->mp->locN; ++i)
  1021. if( p->mp->loc[i].scLocIdx == scLocIdx )
  1022. {
  1023. p->ili = i;
  1024. break;
  1025. }
  1026. assert(p->mp->locN>0);
  1027. if( i!=p->mp->locN || scLocIdx==p->mp->loc[p->mp->locN-1].scLocIdx)
  1028. break;
  1029. scLocIdx += 1;
  1030. }
  1031. if( i==p->mp->locN)
  1032. return cmCtxRtCondition( &p->obj, cmSubSysFailRC, "Score matcher reset failed.");
  1033. return cmOkRC;
  1034. }
  1035. bool cmScMatcherInputMidi( cmScMatcher* p, unsigned smpIdx, unsigned muid, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1 )
  1036. {
  1037. if( (status&0xf0) != kNoteOnMdId)
  1038. return false;
  1039. if( d1 == 0 )
  1040. return false;
  1041. unsigned mi = p->mn-1;
  1042. //printf("%3i %4s\n",p->mni,cmMidiToSciPitch(d0,NULL,0));
  1043. // shift the new MIDI event onto the end of the MIDI buffer
  1044. memmove(p->midiBuf, p->midiBuf+1, sizeof(cmScMatchMidi_t)*mi);
  1045. p->midiBuf[mi].locIdx = cmInvalidIdx;
  1046. p->midiBuf[mi].scEvtIdx = cmInvalidIdx;
  1047. p->midiBuf[mi].mni = p->mni++;
  1048. p->midiBuf[mi].smpIdx = smpIdx;
  1049. p->midiBuf[mi].muid = muid;
  1050. p->midiBuf[mi].pitch = d0;
  1051. p->midiBuf[mi].vel = d1;
  1052. if( p->mbi > 0 )
  1053. --p->mbi;
  1054. return true;
  1055. }
  1056. void _cmScMatcherStoreResult( cmScMatcher* p, unsigned locIdx, unsigned scEvtIdx, unsigned flags, const cmScMatchMidi_t* mp )
  1057. {
  1058. // don't store missed score note results
  1059. assert( mp != NULL );
  1060. bool matchFl = cmIsFlag(flags,kSmMatchFl);
  1061. bool tpFl = locIdx!=cmInvalidIdx && matchFl;
  1062. bool fpFl = locIdx==cmInvalidIdx || matchFl==false;
  1063. cmScMatcherResult_t * rp = NULL;
  1064. unsigned i;
  1065. cmScMatcherResult_t r;
  1066. assert( tpFl==false || (tpFl==true && locIdx != cmInvalidIdx ) );
  1067. // it is possible that the same MIDI event is reported more than once
  1068. // (due to step->scan back tracking) - try to find previous result records
  1069. // associated with this MIDI event
  1070. for(i=0; i<p->ri; ++i)
  1071. if( p->res[i].mni == mp->mni )
  1072. {
  1073. // if this is not the first time this note was reported and it is a true positive
  1074. if( tpFl )
  1075. {
  1076. rp = p->res + i;
  1077. break;
  1078. }
  1079. // a match was found but this was not a true-pos so ignore it
  1080. return;
  1081. }
  1082. if( rp == NULL )
  1083. {
  1084. if( p->ri >= p->rn )
  1085. {
  1086. rp = &r;
  1087. memset(rp,0,sizeof(r));
  1088. }
  1089. else
  1090. {
  1091. rp = p->res + p->ri;
  1092. ++p->ri;
  1093. }
  1094. }
  1095. rp->locIdx = locIdx;
  1096. rp->scEvtIdx = scEvtIdx;
  1097. rp->mni = mp->mni;
  1098. rp->muid = mp->muid;
  1099. rp->smpIdx = mp->smpIdx;
  1100. rp->pitch = mp->pitch;
  1101. rp->vel = mp->vel;
  1102. rp->flags = flags | (tpFl ? kSmTruePosFl : 0) | (fpFl ? kSmFalsePosFl : 0);
  1103. if( p->cbFunc != NULL )
  1104. p->cbFunc(p,p->cbArg,rp);
  1105. }
  1106. void cmScMatcherPrintPath( cmScMatcher* p )
  1107. {
  1108. _cmScMatchPrintPath(p->mp, p->mp->p_opt, p->begSyncLocIdx, p->midiBuf );
  1109. }
  1110. unsigned cmScMatcherScan( cmScMatcher* p, unsigned bli, unsigned hopCnt )
  1111. {
  1112. assert( p->mp != NULL && p->mp->mmn > 0 );
  1113. unsigned i_opt = cmInvalidIdx;
  1114. double s_opt = DBL_MAX;
  1115. cmRC_t rc = cmOkRC;
  1116. unsigned i;
  1117. // initialize the internal values set by this function
  1118. p->missCnt = 0;
  1119. p->eli = cmInvalidIdx;
  1120. p->s_opt = DBL_MAX;
  1121. // if the MIDI buf is not full
  1122. if( p->mbi != 0 )
  1123. return cmInvalidIdx;
  1124. // calc the edit distance from pitchV[] to a sliding score window
  1125. for(i=0; rc==cmOkRC && (hopCnt==cmInvalidCnt || i<hopCnt); ++i)
  1126. {
  1127. rc = cmScMatchExec(p->mp, bli + i, p->mp->msn, p->midiBuf, p->mp->mmn, s_opt );
  1128. switch(rc)
  1129. {
  1130. case cmOkRC: // normal result
  1131. if( p->mp->opt_cost < s_opt )
  1132. {
  1133. s_opt = p->mp->opt_cost;
  1134. i_opt = bli + i;
  1135. }
  1136. break;
  1137. case cmEofRC: // score window encountered the end of the score
  1138. break;
  1139. default: // error state
  1140. return cmInvalidIdx;
  1141. }
  1142. }
  1143. // store the cost assoc'd with i_opt
  1144. p->s_opt = s_opt;
  1145. if( i_opt == cmInvalidIdx )
  1146. return cmInvalidIdx;
  1147. // set the locIdx field in midiBuf[], trailing miss count and
  1148. // return the latest positive-match locIdx
  1149. p->eli = cmScMatchDoSync(p->mp,i_opt,p->midiBuf,p->mp->mmn,&p->missCnt);
  1150. // if no positive matches were found
  1151. if( p->eli == cmInvalidIdx )
  1152. i_opt = cmInvalidIdx;
  1153. else
  1154. {
  1155. cmScMatchPath_t* cp;
  1156. // record result
  1157. for(cp=p->mp->p_opt; cp!=NULL; cp=cp->next)
  1158. if( cp->code != kSmInsIdx )
  1159. _cmScMatcherStoreResult(p, cp->locIdx, cp->scEvtIdx, cp->flags, p->midiBuf + cp->ri - 1);
  1160. }
  1161. return i_opt;
  1162. }
  1163. cmRC_t cmScMatcherStep( cmScMatcher* p )
  1164. {
  1165. int i;
  1166. unsigned pitch = p->midiBuf[ p->mn-1 ].pitch;
  1167. unsigned locIdx = cmInvalidIdx;
  1168. unsigned pidx = cmInvalidIdx;
  1169. // the tracker must be sync'd to step
  1170. if( p->eli == cmInvalidIdx )
  1171. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The p->eli value must be valid to perform a step operation.");
  1172. // if the end of the score has been reached
  1173. if( p->eli + 1 >= p->mp->locN )
  1174. return cmEofRC;
  1175. // attempt to match to next location first
  1176. if( (pidx = _cmScMatchIsMatchIndex(p->mp->loc + p->eli + 1, pitch)) != cmInvalidIdx )
  1177. {
  1178. locIdx = p->eli + 1;
  1179. }
  1180. else
  1181. {
  1182. //
  1183. for(i=2; i<p->stepCnt; ++i)
  1184. {
  1185. // go forward
  1186. if( p->eli+i < p->mp->locN && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->eli + i, pitch))!=cmInvalidIdx )
  1187. {
  1188. locIdx = p->eli + i;
  1189. break;
  1190. }
  1191. // go backward
  1192. if( p->eli >= (i-1) && (pidx=_cmScMatchIsMatchIndex(p->mp->loc + p->eli - (i-1), pitch))!=cmInvalidIdx )
  1193. {
  1194. locIdx = p->eli - (i-1);
  1195. break;
  1196. }
  1197. }
  1198. }
  1199. unsigned scEvtIdx = locIdx==cmInvalidIdx ? cmInvalidIdx : p->mp->loc[locIdx].evtV[pidx].scEvtIdx;
  1200. p->midiBuf[ p->mn-1 ].locIdx = locIdx;
  1201. p->midiBuf[ p->mn-1 ].scEvtIdx = scEvtIdx;
  1202. if( locIdx == cmInvalidIdx )
  1203. ++p->missCnt;
  1204. else
  1205. {
  1206. p->missCnt = 0;
  1207. p->eli = locIdx;
  1208. }
  1209. // store the result
  1210. _cmScMatcherStoreResult(p, locIdx, scEvtIdx, locIdx!=cmInvalidIdx ? kSmMatchFl : 0, p->midiBuf + p->mn - 1);
  1211. if( p->missCnt >= p->maxMissCnt )
  1212. {
  1213. unsigned begScanLocIdx = p->eli > p->mn ? p->eli - p->mn : 0;
  1214. p->s_opt = DBL_MAX;
  1215. unsigned bli = cmScMatcherScan(p,begScanLocIdx,p->mn*2);
  1216. ++p->scanCnt;
  1217. // if the scan failed find a match
  1218. if( bli == cmInvalidIdx )
  1219. return cmCtxRtCondition( &p->obj, cmSubSysFailRC, "Scan resync. failed.");
  1220. }
  1221. return cmOkRC;
  1222. }
  1223. cmRC_t cmScMatcherExec( cmScMatcher* p, unsigned smpIdx, unsigned muid, unsigned status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned* scLocIdxPtr )
  1224. {
  1225. bool fl = p->mbi > 0;
  1226. cmRC_t rc = cmOkRC;
  1227. unsigned org_eli = p->eli;
  1228. if( scLocIdxPtr != NULL )
  1229. *scLocIdxPtr = cmInvalidIdx;
  1230. // update the MIDI buffer with the incoming note
  1231. if( cmScMatcherInputMidi(p,smpIdx,muid,status,d0,d1) == false )
  1232. return rc;
  1233. // if the MIDI buffer transitioned to full then perform an initial scan sync.
  1234. if( fl && p->mbi == 0 )
  1235. {
  1236. if( (p->begSyncLocIdx = cmScMatcherScan(p,p->ili,p->initHopCnt)) == cmInvalidIdx )
  1237. {
  1238. rc = cmInvalidArgRC; // signal init. scan sync. fail
  1239. }
  1240. else
  1241. {
  1242. //cmScMatcherPrintPath(p);
  1243. }
  1244. }
  1245. else
  1246. {
  1247. // if the MIDI buffer is full then perform a step sync.
  1248. if( !fl && p->mbi == 0 )
  1249. rc = cmScMatcherStep(p);
  1250. }
  1251. // if we lost sync
  1252. if( p->eli == cmInvalidIdx )
  1253. {
  1254. // IF WE LOST SYNC THEN WE BETTER DO SOMETHING - LIKE INCREASE THE SCAN HOPS
  1255. // ON THE NEXT EVENT.
  1256. p->eli = org_eli;
  1257. }
  1258. else
  1259. {
  1260. if( scLocIdxPtr!=NULL && p->eli != org_eli )
  1261. {
  1262. //printf("LOC:%i bar:%i\n",p->eli,p->mp->loc[p->eli].barNumb);
  1263. *scLocIdxPtr = p->mp->loc[p->eli].scLocIdx;
  1264. }
  1265. }
  1266. return rc;
  1267. }
  1268. double cmScMatcherFMeas( cmScMatcher* p )
  1269. {
  1270. unsigned bli = p->mp->locN;
  1271. unsigned eli = 0;
  1272. unsigned scNoteCnt = 0; // total count of score notes
  1273. unsigned matchCnt = 0; // count of matched notes (true positives)
  1274. unsigned wrongCnt = 0; // count of incorrect notes (false positives)
  1275. unsigned missCnt = 0; // count of missed score notes (false negatives)
  1276. unsigned i;
  1277. for(i=0; i<p->ri; ++i)
  1278. if( p->res[i].locIdx != cmInvalidIdx )
  1279. {
  1280. bli = cmMin(bli,p->res[i].locIdx);
  1281. eli = cmMax(eli,p->res[i].locIdx);
  1282. if( cmIsFlag(p->res[i].flags,kSmTruePosFl) )
  1283. ++matchCnt;
  1284. if( cmIsFlag(p->res[i].flags,kSmFalsePosFl) )
  1285. ++wrongCnt;
  1286. }
  1287. scNoteCnt = eli - bli + 1;
  1288. missCnt = scNoteCnt - matchCnt;
  1289. double prec = (double)2.0 * matchCnt / (matchCnt + wrongCnt);
  1290. double rcal = (double)2.0 * matchCnt / (matchCnt + missCnt);
  1291. double fmeas = prec * rcal / (prec + rcal);
  1292. //printf("total:%i match:%i wrong:%i miss:%i\n",scNoteCnt,matchCnt,wrongCnt,missCnt);
  1293. return fmeas;
  1294. }
  1295. typedef struct cmScMatcherPrint_str
  1296. {
  1297. unsigned flags;
  1298. unsigned scLocIdx;
  1299. unsigned mni;
  1300. unsigned pitch;
  1301. unsigned vel;
  1302. unsigned barNumb;
  1303. } cmScMatcherPrint_t;
  1304. void _cmScMatcherInsertPrint(cmScMatcherPrint_t* a, unsigned i, unsigned* anp, unsigned aan, const cmScMatcherResult_t* rp, unsigned scLocIdx )
  1305. {
  1306. assert( *anp + 1 <= aan );
  1307. memmove(a + i + 1, a + i, (*anp-i)*sizeof(cmScMatcherPrint_t));
  1308. memset( a + i, 0, sizeof(cmScMatcherPrint_t));
  1309. *anp += 1;
  1310. a[i].flags = rp->flags;
  1311. a[i].scLocIdx = scLocIdx;
  1312. a[i].mni = rp->mni;
  1313. a[i].pitch = rp->pitch;
  1314. a[i].vel = rp->vel;
  1315. }
  1316. void cmScMatcherPrint( cmScMatcher* p )
  1317. {
  1318. unsigned bsli = cmScoreEvtCount(p->mp->scH);
  1319. unsigned esli = 0;
  1320. unsigned i,j,k;
  1321. // get first/last scLocIdx from res[] - this is the range of
  1322. // score events that the score matcher has identified
  1323. for(i=0; i<p->ri; ++i)
  1324. if( p->res[i].locIdx != cmInvalidIdx )
  1325. {
  1326. bsli = cmMin(bsli,p->mp->loc[p->res[i].locIdx].scLocIdx);
  1327. esli = cmMax(esli,p->mp->loc[p->res[i].locIdx].scLocIdx);
  1328. }
  1329. unsigned an = 0;
  1330. unsigned aan = p->ri;
  1331. // calc the count of score events between bsli and esli.
  1332. for(i=bsli; i<=esli; ++i)
  1333. {
  1334. cmScoreLoc_t* lp = cmScoreLoc(p->mp->scH, i);
  1335. assert(lp != NULL);
  1336. aan += lp->evtCnt;
  1337. }
  1338. // allocate an array of 'aan' print records
  1339. cmScMatcherPrint_t* a = cmMemAllocZ(cmScMatcherPrint_t,aan);
  1340. // fill the cmScMatcherPrint_t array with note and bar events from the score
  1341. for(i=bsli; i<=esli; ++i)
  1342. {
  1343. unsigned scLocIdx = i;
  1344. cmScoreLoc_t* lp = cmScoreLoc(p->mp->scH, scLocIdx );
  1345. // for each score event which occurs at this location
  1346. for(j=0; j<lp->evtCnt; ++j)
  1347. {
  1348. assert( an < aan );
  1349. cmScoreEvt_t* ep = lp->evtArray[j];
  1350. cmScMatcherPrint_t* pp = a + an;
  1351. an += 1;
  1352. switch( ep->type )
  1353. {
  1354. case kBarEvtScId:
  1355. pp->flags = kSmBarFl;
  1356. break;
  1357. case kNonEvtScId:
  1358. pp->flags = kSmNoteFl;
  1359. break;
  1360. }
  1361. pp->scLocIdx = scLocIdx;
  1362. pp->mni = cmInvalidIdx;
  1363. pp->pitch = ep->pitch;
  1364. pp->vel = kInvalidMidiVelocity;
  1365. pp->barNumb = ep->barNumb;
  1366. }
  1367. }
  1368. //
  1369. // a[an] now contains a record for each note and bar event in the
  1370. // time range associated with the score matcher's result array.
  1371. //
  1372. // for each result record
  1373. for(i=0; i<p->ri; ++i)
  1374. {
  1375. cmScMatcherResult_t* rp = p->res + i;
  1376. // if this result recd matched a score event
  1377. if( cmIsFlag(rp->flags,kSmTruePosFl) )
  1378. {
  1379. // locate the matching score event in a[an]
  1380. for(k=0; k<an; ++k)
  1381. if( a[k].scLocIdx==p->mp->loc[rp->locIdx].scLocIdx && a[k].pitch==rp->pitch )
  1382. {
  1383. a[k].mni = rp->mni;
  1384. a[k].vel = rp->vel;
  1385. a[k].flags |= kSmMatchFl;
  1386. break;
  1387. }
  1388. }
  1389. // if this result did not match a score event
  1390. if( cmIsFlag(rp->flags,kSmFalsePosFl) )
  1391. {
  1392. unsigned d_min = 0;
  1393. cmScMatcherPrint_t* dp = NULL;
  1394. unsigned scLocIdx = cmInvalidIdx;
  1395. // if this result does not have a valid locIdx
  1396. // (e.g. errant MIDI notes: scan:'delete' note or a step:mis-match note)
  1397. if( rp->locIdx == cmInvalidIdx )
  1398. {
  1399. // find the print recd with the closet 'mni'
  1400. for(k=0; k<an; ++k)
  1401. if( a[k].mni != cmInvalidIdx )
  1402. {
  1403. unsigned d;
  1404. if( a[k].mni > rp->mni )
  1405. d = a[k].mni - rp->mni;
  1406. else
  1407. d = rp->mni - a[k].mni;
  1408. if( dp==NULL || d < d_min )
  1409. {
  1410. dp = a + k;
  1411. d_min = d;
  1412. }
  1413. }
  1414. k = dp - a;
  1415. assert( k < an );
  1416. scLocIdx = p->mp->loc[k].scLocIdx;
  1417. if( a[k].mni < rp->mni )
  1418. ++k;
  1419. }
  1420. else // result w/ a valid locIdx (e.g. scan 'substitute' with no match)
  1421. {
  1422. scLocIdx = p->mp->loc[rp->locIdx].scLocIdx;
  1423. // find the print recd with the closest scIdx
  1424. for(k=0; k<an; ++k)
  1425. if( a[k].scLocIdx != cmInvalidIdx )
  1426. {
  1427. unsigned d;
  1428. if( a[k].scLocIdx > scLocIdx )
  1429. d = a[k].scLocIdx - scLocIdx;
  1430. else
  1431. d = scLocIdx - a[k].scLocIdx;
  1432. if( dp==NULL || d < d_min )
  1433. {
  1434. dp = a + k;
  1435. d_min = d;
  1436. }
  1437. }
  1438. k = dp - a;
  1439. assert( k < an );
  1440. if( a[k].scLocIdx < scLocIdx )
  1441. ++k;
  1442. }
  1443. // create a new print recd to represent the false-positive result recd
  1444. assert( dp != NULL );
  1445. _cmScMatcherInsertPrint(a, k, &an,aan,rp,scLocIdx);
  1446. }
  1447. }
  1448. printf("sloc bar mni ptch flag\n");
  1449. printf("---- ---- ---- ---- ----\n");
  1450. for(i=0; i<an; ++i)
  1451. {
  1452. printf("%4i %4i %4i %4s %c%c%c\n",a[i].scLocIdx,a[i].barNumb,a[i].mni,
  1453. cmIsFlag(a[i].flags,kSmBarFl) ? "|" : cmMidiToSciPitch(a[i].pitch,NULL,0),
  1454. cmIsFlag(a[i].flags,kSmNoteFl) ? 'n' : ' ',
  1455. cmIsFlag(a[i].flags,kSmMatchFl) ? 'm' : (cmIsFlag(a[i].flags,kSmTransFl) ? 't' : ' '),
  1456. cmIsFlag(a[i].flags,kSmFalsePosFl) ? '*' : ' '
  1457. );
  1458. }
  1459. cmMemFree(a);
  1460. }
  1461. //=======================================================================================================================
  1462. cmScMeas* cmScMeasAlloc( cmCtx* c, cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt )
  1463. {
  1464. cmScMeas* op = cmObjAlloc(cmScMeas,c,p);
  1465. op->mp = cmScMatchAlloc( c, NULL, cmScNullHandle, 0, 0 );
  1466. if( cmScoreIsValid(scH) )
  1467. if( cmScMeasInit(op,scH,srate,dynRefArray,dynRefCnt) != cmOkRC )
  1468. cmScMeasFree(&op);
  1469. return op;
  1470. }
  1471. cmRC_t cmScMeasFree( cmScMeas** pp )
  1472. {
  1473. cmRC_t rc = cmOkRC;
  1474. if( pp==NULL || *pp==NULL )
  1475. return rc;
  1476. cmScMeas* p = *pp;
  1477. if((rc = cmScMeasFinal(p)) != cmOkRC )
  1478. return rc;
  1479. cmScMatchFree(&p->mp);
  1480. cmMemFree(p->midiBuf);
  1481. cmMemFree(p->set);
  1482. cmMemFree(p->dynRef);
  1483. cmObjFree(pp);
  1484. return rc;
  1485. }
  1486. void _cmScMeasPrint( cmScMeas* p )
  1487. {
  1488. unsigned i;
  1489. for(i=0; i<p->sn; ++i)
  1490. {
  1491. cmScMeasSet_t* sp = p->set + i;
  1492. printf("%4i: sli:%4i %4i li:%4i %4i\n", i, sp->bsli, sp->esli, sp->bli, sp->eli );
  1493. }
  1494. }
  1495. int _cmScMeasSortFunc( const void* p0, const void* p1 )
  1496. {
  1497. const cmScMeasSet_t* s0 = (const cmScMeasSet_t*)p0;
  1498. const cmScMeasSet_t* s1 = (const cmScMeasSet_t*)p1;
  1499. return s0->esli - s1->esli;
  1500. }
  1501. cmRC_t cmScMeasInit( cmScMeas* p, cmScH_t scH, double srate, const unsigned* dynRefArray, unsigned dynRefCnt )
  1502. {
  1503. cmRC_t rc;
  1504. unsigned i,j;
  1505. unsigned si;
  1506. unsigned maxScWndN = 0;
  1507. if((rc = cmScMeasFinal(p)) != cmOkRC )
  1508. return rc;
  1509. p->mii = 0;
  1510. p->mn = 2 * cmScoreEvtCount(scH);
  1511. p->midiBuf = cmMemResizeZ(cmScMatchMidi_t,p->midiBuf,p->mn);
  1512. p->sn = cmScoreSetCount(scH);
  1513. p->set = cmMemResizeZ(cmScMeasSet_t,p->set,p->sn);
  1514. p->dynRef = cmMemResizeZ(unsigned,p->dynRef,dynRefCnt);
  1515. p->dn = dynRefCnt;
  1516. p->srate = srate;
  1517. memcpy(p->dynRef,dynRefArray,sizeof(dynRefArray[0])*dynRefCnt);
  1518. unsigned n = cmScoreLocCount(scH);
  1519. // for each score location
  1520. for(i=0,si=0; i<n; ++i)
  1521. {
  1522. cmScoreLoc_t* lp = cmScoreLoc(scH,i);
  1523. cmScoreSet_t* sp = lp->setList;
  1524. // for each set that ends on this score location
  1525. for(; sp!=NULL; sp=sp->llink,++si)
  1526. {
  1527. assert(si < p->sn);
  1528. cmScMeasSet_t* msp = p->set + si;
  1529. msp->sp = sp;
  1530. msp->bsli = cmScoreLocCount(scH);
  1531. msp->esli = 0;
  1532. msp->bsei = cmScoreEvtCount(scH);
  1533. msp->esei = 0;
  1534. msp->bli = cmInvalidIdx;
  1535. msp->eli = cmInvalidIdx;
  1536. for(j=0; j<sp->eleCnt; ++j)
  1537. {
  1538. msp->bsli = cmMin(msp->bsli,sp->eleArray[j]->locIdx);
  1539. msp->esli = cmMax(msp->esli,sp->eleArray[j]->locIdx);
  1540. msp->bsei = cmMin(msp->bsei,sp->eleArray[j]->index);
  1541. msp->esei = cmMax(msp->esei,sp->eleArray[j]->index);
  1542. }
  1543. }
  1544. }
  1545. // initialize p->mp so that mp->loc[] is loaded - use dummy scWndN and midiN
  1546. if((rc = cmScMatchInit(p->mp, scH, 11, 10 )) != cmOkRC )
  1547. return rc;
  1548. // assign set[].bli and set[].eli
  1549. // for each measurment set
  1550. for(j=0; j<p->sn; ++j)
  1551. {
  1552. cmScMeasSet_t* msp = p->set + j;
  1553. // for each score location
  1554. for(i=0; i<p->mp->locN; ++i)
  1555. {
  1556. // if this set starts on this score location
  1557. if( msp->bli==cmInvalidIdx && msp->bsli==p->mp->loc[i].scLocIdx )
  1558. msp->bli = i; // store the index of the score location
  1559. // if this set end on this score location
  1560. if( msp->esli==p->mp->loc[i].scLocIdx )
  1561. msp->eli = i; // store the index of the score location
  1562. }
  1563. assert( msp->eli > msp->bli );
  1564. // track the longest set.
  1565. maxScWndN = cmMax( maxScWndN, msp->eli - msp->bli + 1 );
  1566. }
  1567. // setup the match
  1568. if((rc = cmScMatchInit(p->mp, scH, 2*maxScWndN+1, 2*maxScWndN )) != cmOkRC )
  1569. return rc;
  1570. // sort set[] on cmScMeasSet_t.esli
  1571. qsort(p->set, p->sn, sizeof(cmScMeasSet_t), _cmScMeasSortFunc );
  1572. //_cmScMeasPrint(p);
  1573. cmScMeasReset(p);
  1574. return rc;
  1575. }
  1576. cmRC_t cmScMeasFinal( cmScMeas* p )
  1577. { return cmScMatchFinal(p->mp); }
  1578. cmRC_t cmScMeasReset( cmScMeas* p )
  1579. {
  1580. cmRC_t rc = cmOkRC;
  1581. p->mii = 0;
  1582. p->nsi = cmInvalidIdx;
  1583. p->vsi = cmInvalidIdx;
  1584. p->nsli = cmInvalidIdx;
  1585. unsigned i;
  1586. for(i=0; i<p->sn; ++i)
  1587. {
  1588. p->set[i].value = DBL_MAX;
  1589. p->set[i].tempo = 0;
  1590. p->set[i].match_cost = 0;
  1591. }
  1592. return rc;
  1593. }
  1594. typedef struct
  1595. {
  1596. unsigned scLocIdx; // score loc index
  1597. double frac; // score based fraction of beat
  1598. unsigned smpIdx; // time of assoc'd MIDI event
  1599. unsigned cnt; //
  1600. double val; //
  1601. unsigned pitch;
  1602. } _cmScMeasTimeEle_t;
  1603. typedef struct
  1604. {
  1605. unsigned setN; // set length
  1606. unsigned midiN; // count of MIDI events to match to score
  1607. unsigned alignN; // count of score events in the alignment (<= setN)
  1608. unsigned matchN; // count of positive matches
  1609. double tempo;
  1610. double value;
  1611. } _cmScMeasResult_t;
  1612. double _cmScMeasCalcTempo( const _cmScMeasTimeEle_t* b, unsigned bn, double srate )
  1613. {
  1614. assert( bn >= 2 );
  1615. assert( b[bn-1].smpIdx != cmInvalidIdx );
  1616. assert( b[0].smpIdx != cmInvalidIdx );
  1617. double durSmpCnt = b[bn-1].smpIdx - b[0].smpIdx;
  1618. double beats = 0;
  1619. unsigned i;
  1620. for(i=0; i<bn; ++i)
  1621. beats += b[i].frac;
  1622. assert(beats != 0);
  1623. return beats / (durSmpCnt / (srate * 60.0));
  1624. }
  1625. // Note: On successful completion (return!=0) the first
  1626. // and last record returned in c[cn] will be matched records.
  1627. unsigned _cmScMeasTimeAlign( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasTimeEle_t* c, unsigned cn, _cmScMeasResult_t* rp )
  1628. {
  1629. int i,j,k;
  1630. int an = sp->sp->eleCnt;
  1631. _cmScMeasTimeEle_t* b = NULL;
  1632. int bn = 0;
  1633. bool tempoFl = false;
  1634. unsigned matchN = 0;
  1635. assert( an!=0);
  1636. // alloc a 'score set' element array
  1637. _cmScMeasTimeEle_t a[an];
  1638. // get the scLocIdx of each set element from the score
  1639. for(i=0,j=0; i<an; ++i)
  1640. if( i==0 || sp->sp->eleArray[i-1]->locIdx != sp->sp->eleArray[i]->locIdx )
  1641. {
  1642. assert( sp->sp->eleArray[i]->locIdx != cmInvalidIdx );
  1643. a[j].scLocIdx = sp->sp->eleArray[i]->locIdx;
  1644. a[j].frac = sp->sp->eleArray[i]->frac;
  1645. a[j].smpIdx = cmInvalidIdx;
  1646. a[j].cnt = 0;
  1647. ++j;
  1648. }
  1649. an = j; // set the count of unique score locations (new length of a[])
  1650. // collect the 'smpIdx' for each MIDI event which matches a set element
  1651. for(i=0; i<mn; ++i)
  1652. if( m[i].locIdx != cmInvalidIdx )
  1653. {
  1654. for(j=0; j<an; ++j)
  1655. if( p->mp->loc[m[i].locIdx].scLocIdx == a[j].scLocIdx )
  1656. {
  1657. a[j].smpIdx += m[i].smpIdx;
  1658. a[j].cnt += 1;
  1659. a[j].pitch = m[i].pitch;
  1660. if( a[j].cnt == 1 )
  1661. matchN += 1; // only cnt one match per sc loc.
  1662. break;
  1663. }
  1664. }
  1665. // remove leading missing values
  1666. for(i=0; i<an; ++i)
  1667. if( a[i].smpIdx != cmInvalidIdx )
  1668. {
  1669. b = a + i;
  1670. bn = an - i;
  1671. break;
  1672. }
  1673. // remove trailing missing values
  1674. for(i=bn-1; i>=0; --i,--bn)
  1675. if( b[i].smpIdx != cmInvalidIdx )
  1676. break;
  1677. // can't measure evenness against less than 2 values
  1678. if( bn < 2 )
  1679. {
  1680. return 0;
  1681. }
  1682. assert(b[0].smpIdx != cmInvalidIdx && b[bn-1].smpIdx != cmInvalidIdx);
  1683. // calc avg. smpIdx, insert missing values, and convert b[].smpIdx to delta smp index
  1684. for(i=0,j=0; i<bn; ++i)
  1685. {
  1686. if( b[i].cnt > 1 )
  1687. b[i].smpIdx /= b[i].cnt;
  1688. if( b[i].smpIdx == cmInvalidIdx )
  1689. ++j; // incr missing value count
  1690. else
  1691. {
  1692. if( i > 0 )
  1693. {
  1694. // fill in missing values
  1695. ++j;
  1696. unsigned d = (b[i].smpIdx - b[i-j].smpIdx)/j;
  1697. for(k=0; k<j; ++k)
  1698. b[i-j+k].val = d;
  1699. }
  1700. j=0;
  1701. }
  1702. if( b[i].frac != 0 )
  1703. tempoFl = true;
  1704. }
  1705. rp->setN = an;
  1706. rp->midiN = mn;
  1707. rp->alignN = bn;
  1708. rp->matchN = matchN;
  1709. rp->tempo = 0;
  1710. rp->value = 0;
  1711. // calculate tempo
  1712. if( tempoFl )
  1713. rp->tempo = _cmScMeasCalcTempo(b,bn,p->srate);
  1714. assert(bn<=cn);
  1715. // TODO: this copy should be eliminated
  1716. // copy to output
  1717. for(i=0; i<bn && i<cn; ++i)
  1718. c[i] = b[i];
  1719. return bn;
  1720. }
  1721. double _cmScMeasEven( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  1722. {
  1723. unsigned bn = sp->sp->eleCnt;
  1724. _cmScMeasTimeEle_t b[bn];
  1725. unsigned i;
  1726. if((bn = _cmScMeasTimeAlign(p,sp,m,mn,b,bn,rp)) == 0 )
  1727. return DBL_MAX;
  1728. // calc avg. delta time
  1729. double d_avg = 0;
  1730. for(i=0; i<bn-1; ++i)
  1731. {
  1732. d_avg += b[i].val;
  1733. //printf("loc:%i %f\n",b[i].scLocIdx,b[i].val);
  1734. }
  1735. d_avg /= (bn-1);
  1736. // calc std-dev of delta time
  1737. double d_sd = 0;
  1738. for(i=0; i<bn-1; ++i)
  1739. d_sd += (b[i].val-d_avg) * (b[i].val-d_avg);
  1740. // if there is no deviation then we can't compute a z-score
  1741. // (this will happen if we fill in all the missing values based on 2 values)
  1742. if( d_sd == 0 )
  1743. return 1.0;
  1744. d_sd = sqrt(d_sd/(bn-1));
  1745. // calc avg. z-score
  1746. double z = 0;
  1747. for(i=0; i<bn-1; ++i)
  1748. z += fabs(b[i].val - d_avg)/d_sd;
  1749. double val = z / (bn-1);
  1750. rp->value = val;
  1751. return val;
  1752. }
  1753. // return Tempo estimation in BPM
  1754. double _cmScMeasTempo( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  1755. {
  1756. unsigned bn = sp->sp->eleCnt;
  1757. _cmScMeasTimeEle_t b[bn];
  1758. if((bn= _cmScMeasTimeAlign(p,sp,m,mn,b,bn,rp)) == 0 )
  1759. return DBL_MAX;
  1760. return rp->tempo;
  1761. }
  1762. double _cmScMeasDyn( cmScMeas* p, cmScMeasSet_t* sp, cmScMatchMidi_t* m, unsigned mn, _cmScMeasResult_t* rp )
  1763. {
  1764. typedef struct
  1765. {
  1766. unsigned scEvtIdx;
  1767. unsigned vel;
  1768. double val;
  1769. } ele_t;
  1770. int i,j;
  1771. int n = sp->sp->eleCnt;
  1772. double vv = 0;
  1773. unsigned vn = 0;
  1774. unsigned matchN = 0;
  1775. unsigned alignN = 0;
  1776. assert( n!=0);
  1777. ele_t a[n];
  1778. // get the scEvtIdx of each set element
  1779. for(i=0; i<n; ++i)
  1780. {
  1781. cmScoreEvt_t* ep = cmScoreEvt( p->mp->scH, sp->sp->eleArray[i]->index );
  1782. assert( ep != NULL );
  1783. a[i].scEvtIdx = sp->sp->eleArray[i]->index;
  1784. a[i].vel = 0;
  1785. a[i].val = ep->dynVal;
  1786. }
  1787. // set the performed vel. of each note in the set
  1788. // (if a note was not played it's a[].vel is left at 0)
  1789. for(i=0; i<mn; ++i)
  1790. if( m[i].scEvtIdx != cmInvalidIdx )
  1791. {
  1792. alignN += 1;
  1793. for(j=0; j<n; ++j)
  1794. if( m[i].scEvtIdx == a[j].scEvtIdx )
  1795. {
  1796. matchN += 1;
  1797. a[j].vel = m[i].vel;
  1798. break;
  1799. }
  1800. }
  1801. // assign a dynamics category to each note in the set
  1802. for(i=0; i<n; ++i)
  1803. if( a[i].vel > 0 )
  1804. {
  1805. unsigned mnv = 0; // lower bound for first dyn's category
  1806. for(j=0; j<p->dn; ++j)
  1807. {
  1808. if( mnv <= a[i].vel && a[i].vel < p->dynRef[j] )
  1809. {
  1810. // accum. the diff. between the ref. and performed dyn. category
  1811. vv += fabs(a[i].val - j);
  1812. vn += 1;
  1813. break;
  1814. }
  1815. mnv = p->dynRef[j];
  1816. }
  1817. assert(j<p->dn);
  1818. }
  1819. rp->setN = n;
  1820. rp->midiN = mn;
  1821. rp->alignN = alignN;
  1822. rp->matchN = matchN;
  1823. rp->tempo = 0;
  1824. rp->value = vn == 0 ? DBL_MAX : vv/vn;
  1825. return rp->value;
  1826. }
  1827. unsigned MEAS_MATCH_CNT = 0;
  1828. void _cmScMeasPrintResult( cmScMeas* p, cmScMeasSet_t* sp, _cmScMeasResult_t* rp, unsigned bli, const cmScMatchMidi_t* mb )
  1829. {
  1830. const char* label = "<none>";
  1831. switch( sp->sp->varId )
  1832. {
  1833. case kEvenVarScId:
  1834. label = "even";
  1835. break;
  1836. case kDynVarScId:
  1837. label = "dyn";
  1838. break;
  1839. case kTempoVarScId:
  1840. label = "tempo";
  1841. break;
  1842. }
  1843. const cmChar_t* msg = "";
  1844. if( rp->value == DBL_MAX )
  1845. {
  1846. msg = "Measure FAILED.";
  1847. sp->value = 0;
  1848. }
  1849. 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, rp->setN, rp->matchN, p->mp->opt_cost, sp->value, msg);
  1850. if( rp->tempo != 0 )
  1851. printf(" tempo:%f ",rp->tempo);
  1852. printf("\n");
  1853. _cmScMatchPrintPath(p->mp, p->mp->p_opt, bli, mb );
  1854. }
  1855. void _cmScMeasCalcVal( cmScMeas* p, cmScMeasSet_t* sp, int n_mii )
  1856. {
  1857. unsigned mn = 0;
  1858. int i,k = cmInvalidIdx;
  1859. if( n_mii == 0 )
  1860. return;
  1861. // Determine the count of MIDI notes to match to the set score
  1862. // by searching from the MIDI note just recieved (midiBuf[n_mii]
  1863. // back toward the beginning until a MIDI event which occurs just
  1864. // prior to the set's begScLocIdx.
  1865. for(i=n_mii; i>=0; --i)
  1866. {
  1867. if( p->midiBuf[i].locIdx != cmInvalidIdx )
  1868. {
  1869. k = i;
  1870. unsigned scLocIdx = p->mp->loc[ p->midiBuf[i].locIdx ].scLocIdx;
  1871. if( scLocIdx < sp->bsli )
  1872. break;
  1873. }
  1874. }
  1875. assert(k != cmInvalidIdx);
  1876. mn = n_mii - k + 1;
  1877. i = k;
  1878. assert(i>=0);
  1879. assert(mn>0);
  1880. // Create a copy of the the MIDI buffer to prevent the
  1881. // p->midiBuf[].locIdx from being overwritten by cmScMatchDoSync().
  1882. cmScMatchMidi_t mb[ mn ];
  1883. unsigned j;
  1884. for(j=0; j<mn; ++j)
  1885. {
  1886. mb[j] = p->midiBuf[i+j];
  1887. mb[j].locIdx = cmInvalidIdx;
  1888. }
  1889. // In general the first and last MIDI event should be assigned
  1890. // to a score location - it's possible however that no MIDI
  1891. // event's prior to the one at p->midiBuf[n_mii] were assigned.
  1892. assert( (i==0 || p->midiBuf[i].locIdx!=cmInvalidIdx) && p->midiBuf[i+mn-1].locIdx != cmInvalidIdx);
  1893. unsigned l0i = cmMin(p->midiBuf[i].locIdx,p->midiBuf[i+mn-1].locIdx);
  1894. unsigned l1i = cmMax(p->midiBuf[i].locIdx,p->midiBuf[i+mn-1].locIdx);
  1895. unsigned bli = l0i;
  1896. unsigned ln = l1i - bli + 1;
  1897. double min_cost = DBL_MAX;
  1898. _cmScMeasResult_t r;
  1899. memset(&r,0,sizeof(r));
  1900. // match MIDI to score
  1901. if( cmScMatchExec(p->mp, bli, ln, mb, mn, min_cost ) != cmOkRC )
  1902. return;
  1903. // sync the score and MIDI based on the match information
  1904. if( cmScMatchDoSync(p->mp, bli, mb, mn, NULL ) == cmInvalidIdx )
  1905. return;
  1906. if( p->mp->opt_cost != DBL_MAX )
  1907. sp->match_cost = p->mp->opt_cost / sp->sp->eleCnt;
  1908. switch( sp->sp->varId )
  1909. {
  1910. case kEvenVarScId:
  1911. sp->value = _cmScMeasEven(p, sp, mb, mn, &r );
  1912. break;
  1913. case kDynVarScId:
  1914. sp->value = _cmScMeasDyn(p, sp, mb, mn, &r );
  1915. break;
  1916. case kTempoVarScId:
  1917. sp->value = _cmScMeasTempo(p, sp, mb, mn, &r );
  1918. break;
  1919. default:
  1920. { assert(0); }
  1921. }
  1922. sp->tempo = r.tempo;
  1923. // print the result
  1924. //_cmScMeasPrintResult(p, sp, &r, bli, mb );
  1925. MEAS_MATCH_CNT++;
  1926. }
  1927. cmRC_t cmScMeasExec( cmScMeas* p, unsigned mni, unsigned locIdx, unsigned scEvtIdx, unsigned flags, unsigned smpIdx, unsigned pitch, unsigned vel )
  1928. {
  1929. cmRC_t rc = cmOkRC;
  1930. // if the midi buffer is full
  1931. if( p->mii >= p->mn )
  1932. return cmCtxRtCondition( &p->obj, cmEofRC, "The MIDI buffer is full.");
  1933. int n_mii = cmInvalidIdx;
  1934. // locate the MIDI event assoc'd with 'mni' ...
  1935. if( p->mii>0 && mni <= p->midiBuf[p->mii-1].mni )
  1936. {
  1937. if( locIdx != cmInvalidIdx )
  1938. {
  1939. for(n_mii=p->mii-1; n_mii>=0; --n_mii)
  1940. if( p->midiBuf[n_mii].mni == mni )
  1941. break;
  1942. if( n_mii<0 )
  1943. n_mii = cmInvalidIdx;
  1944. }
  1945. }
  1946. else // ... or push a new record onto p->midiBuf[]
  1947. {
  1948. n_mii = p->mii;
  1949. ++p->mii;
  1950. }
  1951. // store the MIDI event
  1952. p->midiBuf[n_mii].mni = mni;
  1953. p->midiBuf[n_mii].locIdx = locIdx;
  1954. p->midiBuf[n_mii].scEvtIdx = scEvtIdx;
  1955. p->midiBuf[n_mii].smpIdx = smpIdx;
  1956. p->midiBuf[n_mii].pitch = pitch;
  1957. p->midiBuf[n_mii].vel = vel;
  1958. // setting vsi=nsi and vsli=nsli will indicate to the calling
  1959. // program that no new sets are ready.
  1960. p->vsi = p->nsi;
  1961. p->vsli = p->nsli;
  1962. if( locIdx == cmInvalidIdx )
  1963. return cmOkRC;
  1964. //
  1965. unsigned scLocIdx = p->mp->loc[ locIdx ].scLocIdx;
  1966. unsigned maxScLocIdx = cmScoreLocCount(p->mp->scH)-1;
  1967. // if this cmScMeas object has not yet synchronized to the cmScMatcher
  1968. // (if p->nsli is not valid)
  1969. if( p->nsli == cmInvalidIdx )
  1970. {
  1971. unsigned i;
  1972. for(i=0; i<p->sn; ++i)
  1973. if( p->set[i].esli+1 == scLocIdx )
  1974. {
  1975. p->nsli = scLocIdx;
  1976. p->nsi = i;
  1977. break;
  1978. }
  1979. if(i==p->sn)
  1980. return rc;
  1981. }
  1982. p->vsi = p->nsi;
  1983. p->vsli = p->nsli;
  1984. // for each cmScore location between p->nsli and scLocIdx
  1985. for(; p->nsli<=scLocIdx && p->nsi < p->sn; ++p->nsli)
  1986. {
  1987. // if this score location index (p->nsli) is one score location
  1988. // ahead of the next sets ending location.
  1989. while( cmMin(maxScLocIdx,p->set[p->nsi].esli+1) == p->nsli )
  1990. {
  1991. // calculate the value assoc'd with p->set[p->nsi]
  1992. _cmScMeasCalcVal(p, p->set + p->nsi, n_mii );
  1993. // advance the set index
  1994. ++p->nsi;
  1995. }
  1996. }
  1997. return rc;
  1998. }
  1999. //=======================================================================================================================
  2000. cmRC_t cmScAlignScanToTimeLineEvent( cmScMatcher* p, cmTlH_t tlH, cmTlObj_t* top, unsigned endSmpIdx )
  2001. {
  2002. assert( top != NULL );
  2003. cmTlMidiEvt_t* mep = NULL;
  2004. cmRC_t rc = cmOkRC;
  2005. // as long as more MIDI events are available get the next MIDI msg
  2006. while( rc==cmOkRC && (mep = cmTlNextMidiEvtObjPtr(tlH, top, top->seqId )) != NULL )
  2007. {
  2008. top = &mep->obj;
  2009. // if the msg falls after the end of the marker then we are through
  2010. if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > endSmpIdx )
  2011. break;
  2012. // if the time line MIDI msg a note-on
  2013. if( (mep->msg->status&0xf0) == kNoteOnMdId )
  2014. {
  2015. rc = cmScMatcherExec(p, mep->obj.seqSmpIdx, mep->msg->uid, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
  2016. switch( rc )
  2017. {
  2018. case cmOkRC: // continue processing MIDI events
  2019. break;
  2020. case cmEofRC: // end of the score was encountered
  2021. break;
  2022. case cmInvalidArgRC: // p->eli was not set correctly
  2023. break;
  2024. case cmSubSysFailRC: // scan resync failed
  2025. break;
  2026. default:
  2027. { assert(0); }
  2028. }
  2029. }
  2030. }
  2031. if( rc == cmEofRC )
  2032. rc = cmOkRC;
  2033. return rc;
  2034. }
  2035. // This callback connects/feeds the cmScMeas object from the cmScMatcher object.
  2036. // (See _cmScMatcherStoreResult().)
  2037. void cmScMatcherCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
  2038. {
  2039. cmScMeas* mp = (cmScMeas*)arg;
  2040. cmScMeasExec(mp, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel );
  2041. }
  2042. void cmScAlignScanMarkers( cmRpt_t* rpt, cmTlH_t tlH, cmScH_t scH )
  2043. {
  2044. unsigned i;
  2045. double srate = cmTimeLineSampleRate(tlH);
  2046. unsigned midiN = 7;
  2047. unsigned scWndN = 10;
  2048. unsigned markN = 291;
  2049. unsigned dynRefArray[] = { 14, 28, 42, 56, 71, 85, 99, 113,128 };
  2050. unsigned dynRefCnt = sizeof(dynRefArray)/sizeof(dynRefArray[0]);
  2051. cmCtx* ctx = cmCtxAlloc(NULL, rpt, cmLHeapNullHandle, cmSymTblNullHandle );
  2052. cmScMeas* mp = cmScMeasAlloc(ctx,NULL,scH,srate,dynRefArray,dynRefCnt);
  2053. cmScMatcher* p = cmScMatcherAlloc(ctx,NULL,srate,scH,scWndN,midiN,cmScMatcherCb,mp);
  2054. double scoreThresh = 0.5;
  2055. unsigned candCnt = 0;
  2056. unsigned initFailCnt = 0;
  2057. unsigned otherFailCnt = 0;
  2058. unsigned scoreFailCnt = 0;
  2059. bool printFl = false;
  2060. unsigned markCharCnt = 31;
  2061. cmChar_t markText[ markCharCnt+1 ];
  2062. cmTimeSpec_t t0,t1;
  2063. cmTimeGet(&t0);
  2064. // for each marker
  2065. for(i=0; i<markN; ++i)
  2066. {
  2067. // form the marker text
  2068. snprintf(markText,markCharCnt,"Mark %i",i);
  2069. // locate the marker
  2070. cmTlMarker_t* tlmp = cmTimeLineMarkerFind( tlH, markText );
  2071. if( tlmp == NULL )
  2072. {
  2073. if( printFl )
  2074. printf("The marker '%s' was not found.\n\n",markText);
  2075. continue;
  2076. }
  2077. // skip markers which do not contain text
  2078. if( cmTextIsEmpty(tlmp->text) )
  2079. {
  2080. if( printFl )
  2081. printf("The marker '%s' is being skipped because it has no text.\n\n",markText);
  2082. continue;
  2083. }
  2084. printf("=================== MARKER:%s ===================\n",markText);
  2085. cmScMatcherReset(p,0); // reset the score follower to the beginnig of the score
  2086. cmScMeasReset(mp);
  2087. ++candCnt;
  2088. // scan to the beginning of the marker
  2089. cmRC_t rc = cmScAlignScanToTimeLineEvent(p,tlH,&tlmp->obj,tlmp->obj.seqSmpIdx+tlmp->obj.durSmpCnt);
  2090. bool pfl = true;
  2091. if( rc != cmOkRC || p->begSyncLocIdx==cmInvalidIdx)
  2092. {
  2093. bool fl = printFl;
  2094. printFl = true;
  2095. // if a no alignment was found
  2096. if( p->begSyncLocIdx == cmInvalidIdx )
  2097. rc = cmInvalidArgRC;
  2098. if( p->mni == 0 )
  2099. {
  2100. if( printFl )
  2101. printf("mark:%i midi:%i Not enough MIDI notes to fill the scan buffer.\n",i,p->mni);
  2102. pfl = false;
  2103. }
  2104. else
  2105. {
  2106. switch(rc)
  2107. {
  2108. case cmInvalidArgRC:
  2109. if( printFl )
  2110. printf("mark:%i INITIAL SYNC FAIL\n",i);
  2111. ++initFailCnt;
  2112. pfl = false;
  2113. break;
  2114. case cmSubSysFailRC:
  2115. if( printFl )
  2116. printf("mark:%i SCAN RESYNC FAIL\n",i);
  2117. ++otherFailCnt;
  2118. break;
  2119. default:
  2120. if( printFl )
  2121. printf("mark:%i UNKNOWN FAIL\n",i);
  2122. ++otherFailCnt;
  2123. }
  2124. }
  2125. printFl = fl;
  2126. }
  2127. if( pfl )
  2128. {
  2129. double fmeas = cmScMatcherFMeas(p);
  2130. if( printFl )
  2131. 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);
  2132. if( fmeas < scoreThresh )
  2133. ++scoreFailCnt;
  2134. }
  2135. //print score and match for entire marker
  2136. //cmScMatcherPrint(p);
  2137. // ONLY USE ONE MARKER DURING TESTING
  2138. // break;
  2139. if( printFl )
  2140. printf("\n");
  2141. }
  2142. printf("cand:%i fail:%i - init:%i score:%i other:%i\n\n",candCnt,initFailCnt+scoreFailCnt+otherFailCnt,initFailCnt,scoreFailCnt,otherFailCnt);
  2143. cmTimeGet(&t1);
  2144. printf("elapsed:%f\n", (double)cmTimeElapsedMicros(&t0,&t1)/1000000.0 );
  2145. cmScMatcherFree(&p);
  2146. cmScMeasFree(&mp);
  2147. cmCtxFree(&ctx);
  2148. }
  2149. //=======================================================================================================================
  2150. cmScModulator* cmScModulatorAlloc( cmCtx* c, cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg )
  2151. {
  2152. cmScModulator* op = cmObjAlloc(cmScModulator,c,p);
  2153. if( ctx != NULL )
  2154. if( cmScModulatorInit(op,ctx,stH,srate,samplesPerCycle,fn,modLabel,cbFunc,cbArg) != cmOkRC )
  2155. cmScModulatorFree(&op);
  2156. return op;
  2157. }
  2158. cmRC_t cmScModulatorFree( cmScModulator** pp )
  2159. {
  2160. cmRC_t rc = cmOkRC;
  2161. if( pp==NULL || *pp==NULL )
  2162. return rc;
  2163. cmScModulator* p = *pp;
  2164. if((rc = cmScModulatorFinal(p)) != cmOkRC )
  2165. return rc;
  2166. //cmMemFree(p->earray);
  2167. //cmMemFree(p->xlist);
  2168. cmObjFree(pp);
  2169. return rc;
  2170. }
  2171. typedef struct
  2172. {
  2173. unsigned typeId;
  2174. unsigned minArgCnt;
  2175. const cmChar_t* label;
  2176. } _cmScModTypeMap_t;
  2177. _cmScModTypeMap_t _cmScModTypeArray[] =
  2178. {
  2179. { kDeclModTId, 0, "decl" },
  2180. { kSetModTId, 1, "set" },
  2181. { kLineModTId, 2, "line" },
  2182. { kSetLineModTId, 3, "sline" },
  2183. { kPostModTId, 4, "post" },
  2184. { kExecModTId, 5, "exec" },
  2185. { kInputModTId, 6, "input" },
  2186. { kCrossModTId, 7, "cross" },
  2187. { kInvalidModTId, 0, "<invalid>"}
  2188. };
  2189. const _cmScModTypeMap_t* _cmScModTypeLabelToMap( const cmChar_t* label )
  2190. {
  2191. unsigned i;
  2192. for(i=0; _cmScModTypeArray[i].typeId!=kInvalidModTId; ++i)
  2193. if( strcmp(_cmScModTypeArray[i].label,label) == 0 )
  2194. return _cmScModTypeArray + i;
  2195. return NULL;
  2196. }
  2197. const _cmScModTypeMap_t* _cmScModTypeIdToMap( unsigned typeId )
  2198. {
  2199. unsigned i;
  2200. for(i=0; _cmScModTypeArray[i].typeId!=kInvalidModTId; ++i)
  2201. if( _cmScModTypeArray[i].typeId == typeId )
  2202. return _cmScModTypeArray + i;
  2203. return NULL;
  2204. }
  2205. cmScModVar_t* _cmScModSymToVar( cmScModulator* p, unsigned varSymId )
  2206. {
  2207. cmScModVar_t* vp = p->vlist;
  2208. for(; vp!=NULL; vp=vp->vlink)
  2209. if( varSymId == vp->varSymId )
  2210. return vp;
  2211. return NULL;
  2212. }
  2213. cmScModVar_t* _cmScModulatorInsertVar( cmScModulator* p, unsigned varSymId, unsigned flags )
  2214. {
  2215. cmScModVar_t* vp = _cmScModSymToVar(p,varSymId);
  2216. // if the specified variable was not found then create one
  2217. if( vp == NULL )
  2218. {
  2219. vp = cmMemAllocZ(cmScModVar_t,1);
  2220. vp->varSymId = varSymId;
  2221. vp->varId = cmInvalidId;
  2222. vp->vlink = p->vlist;
  2223. p->vlist = vp;
  2224. }
  2225. vp->flags = flags;
  2226. vp->value = DBL_MAX;
  2227. vp->min = DBL_MAX;
  2228. vp->max = DBL_MAX;
  2229. vp->rate = DBL_MAX;
  2230. vp->phase = 0;
  2231. vp->entry = NULL;
  2232. vp->alink = NULL;
  2233. return vp;
  2234. }
  2235. cmScModEntry_t* _cmScModulatorInsertEntry(cmScModulator* p, cmScModEntryGroup_t* g, unsigned idx, unsigned scLocIdx, unsigned varSymId, unsigned typeId, unsigned paramCnt )
  2236. {
  2237. assert( idx < g->en );
  2238. g->earray[idx].scLocIdx = scLocIdx;
  2239. g->earray[idx].typeId = typeId;
  2240. return g->earray + idx;
  2241. }
  2242. /*
  2243. {
  2244. [
  2245. { loc:123, mod:modlabel, var:varlabel, param:[ ] }
  2246. ]
  2247. }
  2248. */
  2249. // Parameter values are found as values of the 'data','min' or 'max' fields.
  2250. // A parameter value may be either a symbol identifier (mapped to a variable)
  2251. // or a literal number. This function determines which form the paramter
  2252. // value takes and parses it accordingly.
  2253. cmRC_t _cmScModulatorParseParam( cmScModulator* p, cmSymTblH_t stH, cmJsonNode_t* np, cmScModParam_t* pp )
  2254. {
  2255. cmRC_t rc = cmOkRC;
  2256. switch( np->typeId )
  2257. {
  2258. case kIntTId:
  2259. case kRealTId:
  2260. if( cmJsonRealValue(np, &pp->val ) != kOkJsRC )
  2261. {
  2262. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Error parsing in Modulator literal value." );
  2263. goto errLabel;
  2264. }
  2265. pp->pid = kLiteralModPId;
  2266. break;
  2267. case kStringTId:
  2268. {
  2269. const cmChar_t* label = NULL;
  2270. if( cmJsonStringValue(np, &label) != kOkJsRC )
  2271. {
  2272. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Error parsing in Modulator symbol label." );
  2273. goto errLabel;
  2274. }
  2275. pp->symId = cmSymTblRegisterSymbol(stH,label);
  2276. pp->pid = kSymbolModPId;
  2277. }
  2278. break;
  2279. default:
  2280. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Parameter value is not a number or identifier." );
  2281. goto errLabel;
  2282. break;
  2283. }
  2284. errLabel:
  2285. return rc;
  2286. }
  2287. // If the requested parameter has a value then return it in *valPtr.
  2288. // If it does not then do nothing. This function applies scaling to RHS values.
  2289. cmRC_t _cmScModGetParam( cmScModulator* p, const cmScModParam_t* pp, double* valPtr )
  2290. {
  2291. cmRC_t rc = cmOkRC;
  2292. switch( pp->pid )
  2293. {
  2294. case kInvalidModPId:
  2295. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "An invalid parameter was encountered.");
  2296. goto errLabel;
  2297. break;
  2298. case kLiteralModPId:
  2299. *valPtr = pp->val;
  2300. break;
  2301. case kSymbolModPId:
  2302. {
  2303. cmScModVar_t* vp;
  2304. // get a pointer to the parameter variable
  2305. if((vp = _cmScModSymToVar(p, pp->symId )) == NULL )
  2306. {
  2307. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Variable '%s' not found.",cmSymTblLabel(p->stH,pp->symId));
  2308. goto errLabel;
  2309. }
  2310. // if this is not a 'calculated' paramter then scale it here.
  2311. if( cmIsFlag(vp->flags,kCalcModFl ) && vp->min!=DBL_MAX && vp->max!=DBL_MAX )
  2312. *valPtr = (vp->value - vp->min)/(vp->max-vp->min);
  2313. else
  2314. *valPtr = vp->value;
  2315. }
  2316. break;
  2317. default:
  2318. { assert(0); }
  2319. }
  2320. errLabel:
  2321. return rc;
  2322. }
  2323. void _cmScModDumpParam( cmScModulator* p, const cmChar_t* label, const cmScModParam_t* pp )
  2324. {
  2325. printf("%s: ",label);
  2326. switch( pp->pid )
  2327. {
  2328. case kInvalidModPId:
  2329. printf("<invalid>");
  2330. break;
  2331. case kLiteralModPId:
  2332. if( pp->val == DBL_MAX )
  2333. printf("<max> ");
  2334. else
  2335. printf("%f ",pp->val);
  2336. break;
  2337. case kSymbolModPId:
  2338. printf("%s ",cmSymTblLabel(p->stH,pp->symId));
  2339. break;
  2340. default:
  2341. { assert(0); }
  2342. }
  2343. }
  2344. void _cmScModDumpVal( cmChar_t* label, double val )
  2345. {
  2346. printf("%s:",label);
  2347. if( val == DBL_MAX )
  2348. printf("<max> " );
  2349. else
  2350. printf("%f ",val);
  2351. }
  2352. void _cmScModDumpVar( cmScModulator* p, const cmScModVar_t* vp )
  2353. {
  2354. printf("%7s %3i fl:0x%x entry:%p alink:%p %s",cmSymTblLabel(p->stH,vp->varSymId),vp->varId,vp->flags,vp->entry,vp->alink, cmIsFlag(vp->flags,kInputModFl)?"input":"");
  2355. _cmScModDumpVal("val",vp->value);
  2356. _cmScModDumpVal("min",vp->min);
  2357. _cmScModDumpVal("max",vp->max);
  2358. _cmScModDumpVal("rate",vp->rate);
  2359. _cmScModDumpVal("v0",vp->v0);
  2360. }
  2361. void _cmScModDumpEntry( cmScModulator* p, const cmScModEntry_t* ep)
  2362. {
  2363. const _cmScModTypeMap_t* tm = _cmScModTypeIdToMap( ep->typeId );
  2364. printf("%10i ",ep->scLocIdx);
  2365. printf("%5s %7s", tm==NULL ? "invld" : tm->label, cmSymTblLabel(p->stH,ep->varPtr->varSymId));
  2366. _cmScModDumpParam(p," beg", &ep->beg);
  2367. _cmScModDumpParam(p," end", &ep->end);
  2368. _cmScModDumpParam(p," min", &ep->min);
  2369. _cmScModDumpParam(p," max", &ep->max);
  2370. _cmScModDumpParam(p," rate",&ep->rate);
  2371. printf("\n");
  2372. }
  2373. cmRC_t _cmScModParseEntryGroup( cmScModulator* p, cmCtx_t* ctx, cmJsonH_t jsH, cmSymTblH_t stH, cmJsonNode_t* jnp, cmScModEntryGroup_t* g, const cmChar_t* fn )
  2374. {
  2375. cmRC_t rc = cmOkRC;
  2376. unsigned prvScLocIdx = cmInvalidIdx;
  2377. const cmChar_t* prvVarLabel = "<dummy>";
  2378. const cmChar_t* prvTypeLabel = NULL;
  2379. unsigned i;
  2380. // allocate the entry array
  2381. unsigned entryCnt = cmJsonChildCount(jnp);
  2382. g->earray = cmMemResizeZ(cmScModEntry_t,g->earray,entryCnt);
  2383. g->en = entryCnt;
  2384. for(i=0; i<entryCnt; ++i)
  2385. {
  2386. cmJsRC_t jsRC = kOkJsRC;
  2387. const char* errLabelPtr = NULL;
  2388. unsigned scLocIdx = cmInvalidIdx;
  2389. const cmChar_t* varLabel = NULL;
  2390. const cmChar_t* typeLabel = NULL;
  2391. cmJsonNode_t* onp = cmJsonArrayElement(jnp,i);
  2392. cmJsonNode_t* dnp = NULL;
  2393. const _cmScModTypeMap_t* map = NULL;
  2394. if((jsRC = cmJsonMemberValues( onp, &errLabelPtr,
  2395. "var", kStringTId | kOptArgJsFl, &varLabel,
  2396. "type",kStringTId | kOptArgJsFl, &typeLabel,
  2397. "loc", kIntTId | kOptArgJsFl, &scLocIdx,
  2398. NULL )) != kOkJsRC )
  2399. {
  2400. if( errLabelPtr == NULL )
  2401. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Error:%s on record at index %i in file:%s",errLabelPtr,i,cmStringNullGuard(fn) );
  2402. else
  2403. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Synax error in Modulator record at index %i in file:%s",i,cmStringNullGuard(fn) );
  2404. goto errLabel;
  2405. }
  2406. // if the score location was not given use the previous score location
  2407. if( scLocIdx == cmInvalidIdx )
  2408. scLocIdx = prvScLocIdx;
  2409. else
  2410. prvScLocIdx = scLocIdx;
  2411. // if the var label was not given use the previous one
  2412. if( varLabel == NULL )
  2413. varLabel = prvVarLabel;
  2414. else
  2415. prvVarLabel = varLabel;
  2416. if( varLabel == NULL )
  2417. {
  2418. rc = cmCtxRtCondition(&p->obj, cmInvalidArgRC, "No 'var' label has been set in mod file '%s'.",cmStringNullGuard(fn));
  2419. goto errLabel;
  2420. }
  2421. // if the type label was not given use the previous one
  2422. if( typeLabel == NULL )
  2423. typeLabel = prvTypeLabel;
  2424. else
  2425. prvTypeLabel = typeLabel;
  2426. if( typeLabel == NULL )
  2427. {
  2428. rc = cmCtxRtCondition(&p->obj, cmInvalidArgRC, "No 'type' label has been set in mod file '%s'.",cmStringNullGuard(fn));
  2429. goto errLabel;
  2430. }
  2431. // validate the entry type label
  2432. if((map = _cmScModTypeLabelToMap(typeLabel)) == NULL )
  2433. {
  2434. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Unknown entry type '%s' in Modulator record at index %i in file:%s",cmStringNullGuard(typeLabel),i,cmStringNullGuard(fn) );
  2435. goto errLabel;
  2436. }
  2437. unsigned varSymId = cmSymTblRegisterSymbol(stH,varLabel);
  2438. // get the count of the elmenets in the data array
  2439. unsigned paramCnt = cmJsonChildCount(onp);
  2440. // fill the entry record and find or create the target var
  2441. cmScModEntry_t* ep = _cmScModulatorInsertEntry(p,g,i,scLocIdx,varSymId,map->typeId,paramCnt);
  2442. typedef struct
  2443. {
  2444. const cmChar_t* label;
  2445. cmScModParam_t* param;
  2446. } map_t;
  2447. // parse the var and parameter records
  2448. map_t mapArray[] =
  2449. {
  2450. { "min", &ep->min },
  2451. { "max", &ep->max },
  2452. { "rate",&ep->rate },
  2453. { "val", &ep->beg },
  2454. { "end", &ep->end },
  2455. { "dur", &ep->dur },
  2456. { "arg", &ep->arg },
  2457. { NULL, NULL }
  2458. };
  2459. unsigned j=0;
  2460. for(j=0; mapArray[j].param!=NULL; ++j)
  2461. if((dnp = cmJsonFindValue(jsH,mapArray[j].label, onp, kInvalidTId )) != NULL )
  2462. if((rc = _cmScModulatorParseParam(p,stH,dnp,mapArray[j].param)) != cmOkRC )
  2463. goto errLabel;
  2464. // create the variable associated with this entry
  2465. ep->varPtr = _cmScModulatorInsertVar(p,varSymId, ep->typeId==kInputModTId ? kInputModFl : 0);
  2466. // set the variable id value
  2467. if( ep->varPtr->varId == cmInvalidIdx )
  2468. {
  2469. if( ep->typeId != kInputModTId )
  2470. ep->varPtr->varId = p->outVarCnt++;
  2471. else
  2472. ep->varPtr->varId = p->inVarCnt++;
  2473. }
  2474. }
  2475. errLabel:
  2476. return rc;
  2477. }
  2478. cmRC_t _cmScModulatorParse( cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, const cmChar_t* fn )
  2479. {
  2480. cmRC_t rc = cmOkRC;
  2481. cmJsonNode_t* jnp = NULL;
  2482. cmJsonH_t jsH = cmJsonNullHandle;
  2483. unsigned i = cmInvalidIdx;
  2484. cmScModEntryGroup_t* g0 = NULL;
  2485. cmScModEntryGroup_t* g1 = p->glist;
  2486. // read the JSON file
  2487. if( cmJsonInitializeFromFile(&jsH, fn, ctx ) != kOkJsRC )
  2488. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "JSON file parse failed on the modulator file: %s.",cmStringNullGuard(fn) );
  2489. jnp = cmJsonRoot(jsH);
  2490. unsigned groupCnt = cmJsonChildCount(jnp);
  2491. // for each entry group
  2492. for(i=0; i<groupCnt; ++i)
  2493. {
  2494. // get the entry group record
  2495. if( g1 == NULL )
  2496. {
  2497. g1 = cmMemAllocZ(cmScModEntryGroup_t,1);
  2498. if( g0 == NULL )
  2499. p->glist = g1;
  2500. else
  2501. g0->link = g1;
  2502. }
  2503. // get the entry group pair node
  2504. cmJsonNode_t* gnp = cmJsonMemberAtIndex(jnp,i);
  2505. if( gnp == NULL || !cmJsonIsPair(gnp) )
  2506. {
  2507. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Invalid entry group at index %i in score modulator file:%s",i,cmStringNullGuard(fn) );
  2508. goto errLabel;
  2509. }
  2510. // store the group label
  2511. g1->symId = cmSymTblRegisterSymbol(stH,cmJsonPairLabel(gnp));
  2512. // get and validate the group array value
  2513. if( (gnp = cmJsonPairValue(gnp))==NULL || cmJsonIsArray(gnp)==false )
  2514. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Group entry '%s' does not contain an array of entries in file:%s",cmStringNullGuard(cmJsonPairLabel(gnp)),cmStringNullGuard(fn) );
  2515. // parse the entry group
  2516. if((rc = _cmScModParseEntryGroup( p, ctx, jsH, stH, gnp, g1, fn )) != cmOkRC )
  2517. {
  2518. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Syntax error in entry group at index %i in score modulator file:%s",i,cmStringNullGuard(fn) );
  2519. goto errLabel;
  2520. }
  2521. g0 = g1;
  2522. g1 = g1->link;
  2523. }
  2524. errLabel:
  2525. // release the JSON tree
  2526. if( cmJsonIsValid(jsH) )
  2527. cmJsonFinalize(&jsH);
  2528. return rc;
  2529. }
  2530. cmRC_t _cmScModulatorReset( cmScModulator* p, cmCtx_t* ctx, unsigned scLocIdx, unsigned entryGroupSymId )
  2531. {
  2532. cmRC_t rc = cmOkRC;
  2533. p->alist = NULL;
  2534. p->elist = NULL;
  2535. p->nei = 0;
  2536. p->outVarCnt = 0;
  2537. p->inVarCnt = 0;
  2538. // reload the file
  2539. if((rc = _cmScModulatorParse(p,ctx,p->stH,p->fn)) != cmOkRC )
  2540. goto errLabel;
  2541. // select the entry group to execute
  2542. if( entryGroupSymId != cmInvalidId )
  2543. {
  2544. cmScModEntryGroup_t* g = p->glist;
  2545. for(; g!=NULL; g=g->link)
  2546. if( g->symId == entryGroupSymId )
  2547. {
  2548. cmCtxPrint(p->obj.ctx,"%s selected.\n",cmSymTblLabel(p->stH,entryGroupSymId));
  2549. p->xlist = g;
  2550. break;
  2551. }
  2552. }
  2553. // if an active entry group has not been set - set it to the first entry group
  2554. if( p->xlist == NULL )
  2555. {
  2556. if( entryGroupSymId != cmInvalidId )
  2557. cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The modulator entry group '%s' was not found. The active entry group was set to the first group in the file.",cmSymTblLabel(p->stH,entryGroupSymId) );
  2558. p->xlist = p->glist;
  2559. }
  2560. // clear the active flag on all variables
  2561. cmScModVar_t* vp = p->vlist;
  2562. for(; vp!=NULL; vp=vp->vlink)
  2563. {
  2564. vp->flags = cmClrFlag(vp->flags,kActiveModFl);
  2565. vp->alink = NULL;
  2566. }
  2567. errLabel:
  2568. return rc;
  2569. }
  2570. cmRC_t cmScModulatorInit( cmScModulator* p, cmCtx_t* ctx, cmSymTblH_t stH, double srate, unsigned samplesPerCycle, const cmChar_t* fn, const cmChar_t* modLabel, cmScModCb_t cbFunc, void* cbArg )
  2571. {
  2572. cmRC_t rc;
  2573. if((rc = cmScModulatorFinal(p)) != cmOkRC )
  2574. return rc;
  2575. p->fn = cmMemAllocStr(fn);
  2576. p->stH = stH;
  2577. p->modSymId = cmSymTblRegisterSymbol(stH,modLabel);
  2578. p->cbFunc = cbFunc;
  2579. p->cbArg = cbArg;
  2580. p->samplesPerCycle = samplesPerCycle;
  2581. p->srate = srate;
  2582. if( rc != cmOkRC )
  2583. cmScModulatorFinal(p);
  2584. else
  2585. _cmScModulatorReset(p,ctx,0,cmInvalidId);
  2586. return rc;
  2587. }
  2588. cmRC_t cmScModulatorFinal( cmScModulator* p )
  2589. {
  2590. cmMemFree(p->fn);
  2591. // release each var record
  2592. cmScModVar_t* vp = p->vlist;
  2593. while( vp!=NULL )
  2594. {
  2595. cmScModVar_t* np = vp->vlink;
  2596. cmMemFree(vp);
  2597. vp=np;
  2598. }
  2599. // release each group record
  2600. cmScModEntryGroup_t* g = p->glist;
  2601. while( g != NULL )
  2602. {
  2603. cmScModEntryGroup_t* g0 = g->link;
  2604. cmMemFree(g->earray);
  2605. cmMemFree(g);
  2606. g = g0;
  2607. }
  2608. p->glist = NULL;
  2609. return cmOkRC;
  2610. }
  2611. unsigned cmScModulatorOutVarCount( cmScModulator* p )
  2612. { return p->outVarCnt; }
  2613. cmScModVar_t* cmScModulatorOutVar( cmScModulator* p, unsigned idx )
  2614. {
  2615. unsigned i;
  2616. cmScModEntryGroup_t* g = p->glist;
  2617. for(; g!=NULL; g=g->link)
  2618. for(i=0; i<g->en; ++i)
  2619. if( cmIsNotFlag(g->earray[i].varPtr->flags,kInputModFl) && g->earray[i].varPtr->varId == idx )
  2620. return g->earray[i].varPtr;
  2621. return NULL;
  2622. }
  2623. unsigned cmScModulatorInVarCount( cmScModulator* p )
  2624. { return p->inVarCnt; }
  2625. cmScModVar_t* cmScModulatorInVar( cmScModulator* p, unsigned idx )
  2626. {
  2627. unsigned i;
  2628. cmScModEntryGroup_t* g = p->glist;
  2629. for(; g!=NULL; g=g->link)
  2630. for(i=0; i<g->en; ++i)
  2631. if( cmIsFlag(g->earray[i].varPtr->flags,kInputModFl) && g->earray[i].varPtr->varId == idx )
  2632. return g->earray[i].varPtr;
  2633. return NULL;
  2634. }
  2635. cmScModVar_t* _cmScModSetValuePrefix( cmScModulator* p, unsigned varSymId )
  2636. {
  2637. cmScModVar_t* vp;
  2638. // if the var does not exist ....
  2639. if((vp = _cmScModSymToVar(p, varSymId )) == NULL )
  2640. {
  2641. // ... then create it
  2642. vp = _cmScModulatorInsertVar(p,varSymId,kCalcModFl);
  2643. assert(vp!=NULL);
  2644. }
  2645. return vp;
  2646. }
  2647. cmRC_t cmScModulatorSetValueMinMax( cmScModulator* p, unsigned varSymId, double value, double min, double max )
  2648. {
  2649. cmScModVar_t* vp = _cmScModSetValuePrefix(p, varSymId );
  2650. assert( min <= max);
  2651. vp->min = min;
  2652. vp->max = max;
  2653. vp->value = value;
  2654. return cmOkRC;
  2655. }
  2656. cmRC_t cmScModulatorSetValue( cmScModulator* p, unsigned varSymId, double value )
  2657. {
  2658. cmScModVar_t* vp = _cmScModSetValuePrefix(p, varSymId );
  2659. vp->value = value;
  2660. return cmOkRC;
  2661. }
  2662. cmRC_t cmScModulatorReset( cmScModulator* p, cmCtx_t* ctx, unsigned scLocIdx, unsigned entryGroupSymId )
  2663. {
  2664. _cmScModulatorReset(p,ctx,scLocIdx,entryGroupSymId);
  2665. return cmScModulatorExec(p,scLocIdx);
  2666. }
  2667. void _cmScModUnlinkActive( cmScModulator* p, cmScModVar_t* vp, cmScModVar_t* pp )
  2668. {
  2669. // if vp is the first link on the chain
  2670. if( vp == p->alist )
  2671. p->alist = vp->alink;
  2672. // if vp is the last link on the chain
  2673. if( vp == p->elist )
  2674. p->elist = pp;
  2675. if( pp != NULL )
  2676. pp->alink = vp->alink;
  2677. vp->flags = cmClrFlag(vp->flags,kActiveModFl);
  2678. vp->alink = NULL;
  2679. vp->entry = NULL;
  2680. }
  2681. cmRC_t _cmScModActivateEntries( cmScModulator* p, cmScModEntry_t* earray, unsigned* idxRef, unsigned cnt, unsigned scLocIdx );
  2682. cmRC_t _cmScModActivateGroup( cmScModulator* p, cmScModEntry_t* ep )
  2683. {
  2684. cmScModEntryGroup_t* g = p->glist;
  2685. for(; g!=NULL; g=g->link)
  2686. if( g->symId == ep->beg.symId )
  2687. {
  2688. unsigned idx = 0;
  2689. printf("Activating:%s\n",cmSymTblLabel(p->stH,ep->beg.symId));
  2690. return _cmScModActivateEntries( p, g->earray, &idx, g->en, ep->beg.symId );
  2691. }
  2692. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Entry group '%s' not found.",cmSymTblLabel(p->stH,ep->beg.symId));
  2693. }
  2694. cmRC_t _cmScModGetCrossParam( cmScModulator* p, cmScModEntry_t* ep, cmScModParam_t* pp, const cmChar_t* label, double* valRef )
  2695. {
  2696. cmRC_t rc;
  2697. if((rc = _cmScModGetParam(p, pp, valRef )) != cmOkRC )
  2698. rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Invalid %s parameter for cross variable:%s",label,cmSymTblLabel(p->stH,ep->varPtr->varSymId) );
  2699. return rc;
  2700. }
  2701. cmRC_t _cmScModExecCross( cmScModulator* p, cmScModEntry_t* ep )
  2702. {
  2703. cmRC_t rc = cmOkRC;
  2704. double x = 0.0;
  2705. double y0 = 0.0, y1 = 0.0;
  2706. if((rc = _cmScModGetCrossParam(p, ep, &ep->arg, "src var", &x )) != cmOkRC )
  2707. return rc;
  2708. if((rc = _cmScModGetCrossParam(p, ep, &ep->min, "dst min", &y0 )) != cmOkRC )
  2709. return rc;
  2710. if((rc = _cmScModGetCrossParam(p, ep, &ep->max, "dst max", &y1 )) != cmOkRC )
  2711. return rc;
  2712. //printf("%s x:%f y0:%f y1:%f\n",__FUNCTION__,x,y0,y1);
  2713. ep->varPtr->value = y0 + x * (y1-y0);
  2714. return rc;
  2715. }
  2716. // Type specific variable activation -
  2717. cmRC_t _cmScModActivate(cmScModulator* p, cmScModEntry_t* ep )
  2718. {
  2719. cmRC_t rc = cmOkRC;
  2720. cmScModVar_t* vp = ep->varPtr;
  2721. // optionally update the min/max/rate values in the target var
  2722. if( ep->min.pid != kInvalidModPId )
  2723. if((rc = _cmScModGetParam(p,&ep->min,&vp->min)) != cmOkRC )
  2724. goto errLabel;
  2725. if( ep->max.pid != kInvalidModPId )
  2726. if((rc = _cmScModGetParam(p,&ep->max,&vp->max)) != cmOkRC )
  2727. goto errLabel;
  2728. if( ep->rate.pid != kInvalidModPId )
  2729. if((rc = _cmScModGetParam(p,&ep->rate,&vp->rate)) != cmOkRC )
  2730. goto errLabel;
  2731. switch( ep->typeId )
  2732. {
  2733. case kDeclModTId:
  2734. case kSetModTId:
  2735. break;
  2736. case kLineModTId:
  2737. vp->v0 = vp->value;
  2738. vp->phase = 0;
  2739. break;
  2740. case kSetLineModTId:
  2741. _cmScModGetParam(p,&ep->beg,&vp->value); // starting value
  2742. vp->v0 = vp->value; // set initial value
  2743. vp->phase = 0; // reset phase
  2744. break;
  2745. case kPostModTId:
  2746. p->postFl = vp->value;
  2747. break;
  2748. case kExecModTId:
  2749. rc = _cmScModActivateGroup(p,ep);
  2750. break;
  2751. case kInputModTId:
  2752. break;
  2753. case kCrossModTId:
  2754. break;
  2755. default:
  2756. { assert(0); }
  2757. }
  2758. errLabel:
  2759. return rc;
  2760. }
  2761. // Callback the application with a new variable value.
  2762. cmRC_t _cmScModExecSendValue( cmScModulator* p, cmScModVar_t* vp )
  2763. {
  2764. cmRC_t rc = cmOkRC;
  2765. bool sendFl = true;
  2766. double v = vp->value;
  2767. // scale the output value - this is equiv to scaling the LHS
  2768. if( cmIsFlag(vp->flags,kCalcModFl) && vp->min!=DBL_MAX && vp->max!=DBL_MAX )
  2769. v = vp->min + v * (vp->max - vp->min);
  2770. // if an output rate throttle is in effect ....
  2771. if( vp->rate!=DBL_MAX && vp->phase!=0 )
  2772. sendFl = remainder(vp->phase*p->samplesPerCycle, p->srate*vp->rate/1000 ) < p->samplesPerCycle;
  2773. if(sendFl)
  2774. p->cbFunc(p->cbArg,vp->varSymId,v,p->postFl);
  2775. return rc;
  2776. }
  2777. // Execute a variable.
  2778. // Return true if vp should be deactivated otherwise return false.
  2779. bool _cmScModExec( cmScModulator* p, cmScModVar_t* vp )
  2780. {
  2781. cmRC_t rc = cmOkRC;
  2782. bool fl = false;
  2783. bool sendFl = true;
  2784. switch( vp->entry->typeId )
  2785. {
  2786. case kDeclModTId:
  2787. sendFl = false;
  2788. fl = true;
  2789. break;
  2790. case kSetModTId:
  2791. {
  2792. // Get a new value for the variable *vp.
  2793. if((rc = _cmScModGetParam(p,&vp->entry->beg,&vp->value)) != cmOkRC )
  2794. goto errLabel;
  2795. vp->phase = 0; // force the value to be sent
  2796. fl = true;
  2797. }
  2798. break;
  2799. case kSetLineModTId:
  2800. case kLineModTId:
  2801. {
  2802. double v1=0, td=0;
  2803. // get the target value
  2804. if((rc = _cmScModGetParam(p,&vp->entry->end,&v1)) != cmOkRC)
  2805. goto errLabel;
  2806. // get the time duration
  2807. if((rc = _cmScModGetParam(p,&vp->entry->dur,&td)) != cmOkRC)
  2808. goto errLabel;
  2809. // update the value of the var *vp
  2810. double v = vp->v0 + (v1-vp->v0) * (vp->phase * p->samplesPerCycle) / (p->srate * td);
  2811. if((fl = (vp->value <= v1 && v >= v1) || (vp->value >= v1 && v <= v1 )) == true )
  2812. v = v1;
  2813. vp->value = v;
  2814. }
  2815. break;
  2816. case kPostModTId:
  2817. sendFl = false;
  2818. break;
  2819. case kExecModTId:
  2820. sendFl = false;
  2821. break;
  2822. case kInputModTId:
  2823. sendFl = false;
  2824. break;
  2825. case kCrossModTId:
  2826. _cmScModExecCross(p,vp->entry);
  2827. vp->phase = 0; // force the value to be sent
  2828. fl = true;
  2829. break;
  2830. default:
  2831. { assert(0); }
  2832. }
  2833. // notify the application that a new variable value has been generated
  2834. if(sendFl)
  2835. {
  2836. rc = _cmScModExecSendValue(p,vp);
  2837. // increment the phase - after send because send notices when phase is zero
  2838. vp->phase += 1;
  2839. }
  2840. errLabel:
  2841. if( rc != cmOkRC )
  2842. fl = true;
  2843. return fl;
  2844. }
  2845. // Execute the entries in xparray[] begining with entry xparray[idx] and continuing until:
  2846. // 1) cnt - idx entries have been executed
  2847. // 2) an entry is located whose scLocIdx != scLocIdx and also not -1
  2848. cmRC_t _cmScModActivateEntries( cmScModulator* p, cmScModEntry_t* earray, unsigned* idxRef, unsigned cnt, unsigned scLocIdx )
  2849. {
  2850. assert( idxRef != NULL );
  2851. cmRC_t trc;
  2852. cmRC_t rc = cmOkRC;
  2853. unsigned idx = *idxRef;
  2854. // trigger entries that have expired since the last call to this function
  2855. for(; idx<cnt && (earray[idx].scLocIdx==-1 || earray[idx].scLocIdx<=scLocIdx); ++idx)
  2856. {
  2857. cmScModEntry_t* ep = earray + idx;
  2858. // if the variable assoc'd with this entry is not on the active list ...
  2859. if( cmIsFlag(ep->varPtr->flags,kActiveModFl) == false )
  2860. {
  2861. // ... then append it to the end of the active list ...
  2862. ep->varPtr->flags |= kActiveModFl;
  2863. if( p->elist == NULL )
  2864. p->elist = ep->varPtr;
  2865. else
  2866. {
  2867. p->elist->alink = ep->varPtr;
  2868. p->elist = ep->varPtr;
  2869. }
  2870. p->elist->alink = NULL;
  2871. if( p->alist == NULL )
  2872. p->alist = ep->varPtr;
  2873. }
  2874. // do type specific activation
  2875. if((trc = _cmScModActivate(p,ep)) != cmOkRC )
  2876. rc = trc;
  2877. ep->varPtr->entry = ep;
  2878. }
  2879. *idxRef = idx;
  2880. return rc;
  2881. }
  2882. cmRC_t cmScModulatorExec( cmScModulator* p, unsigned scLocIdx )
  2883. {
  2884. cmRC_t rc = cmOkRC;
  2885. rc = _cmScModActivateEntries(p, p->xlist->earray, &p->nei, p->xlist->en, scLocIdx );
  2886. // Update the active variables
  2887. cmScModVar_t* pp = NULL;
  2888. cmScModVar_t* vp = p->alist;
  2889. for(; vp!=NULL; vp=vp->alink)
  2890. {
  2891. if( _cmScModExec(p,vp) )
  2892. _cmScModUnlinkActive(p,vp,pp);
  2893. else
  2894. pp = vp;
  2895. }
  2896. return rc;
  2897. }
  2898. cmRC_t cmScModulatorDump( cmScModulator* p )
  2899. {
  2900. cmRC_t rc = cmOkRC;
  2901. printf("MOD:\n");
  2902. printf("nei:%i alist:%p outVarCnt:%i inVarCnt:%i\n",p->nei,p->alist,p->outVarCnt,p->inVarCnt);
  2903. printf("ENTRIES:\n");
  2904. cmScModEntryGroup_t* g = p->glist;
  2905. for(; g!=NULL; g=g->link)
  2906. {
  2907. printf("%s\n",cmSymTblLabel(p->stH,g->symId));
  2908. unsigned i;
  2909. for(i=0; i<g->en; ++i)
  2910. {
  2911. cmScModEntry_t* ep = g->earray + i;
  2912. printf("%3i ",i);
  2913. _cmScModDumpEntry(p,ep);
  2914. }
  2915. }
  2916. printf("VARIABLES\n");
  2917. cmScModVar_t* vp = p->vlist;
  2918. for(; vp!=NULL; vp=vp->vlink)
  2919. {
  2920. _cmScModDumpVar(p,vp);
  2921. printf("\n");
  2922. }
  2923. return rc;
  2924. }
  2925. //=======================================================================================================================
  2926. cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs )
  2927. {
  2928. cmRecdPlay* op = cmObjAlloc(cmRecdPlay,c,p);
  2929. if( cmRecdPlayInit(op,srate,fragCnt,chCnt,initFragSecs,maxLaSecs,curLaSecs) != cmOkRC )
  2930. cmRecdPlayFree(&op);
  2931. return op;
  2932. }
  2933. cmRC_t cmRecdPlayFree( cmRecdPlay** pp )
  2934. {
  2935. cmRC_t rc = cmOkRC;
  2936. if( pp==NULL || *pp==NULL )
  2937. return rc;
  2938. cmRecdPlay* p = *pp;
  2939. if((rc = cmRecdPlayFinal(p)) != cmOkRC )
  2940. return rc;
  2941. cmObjFree(pp);
  2942. return rc;
  2943. }
  2944. cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs )
  2945. {
  2946. cmRC_t rc;
  2947. unsigned i;
  2948. if( curLaSecs > maxLaSecs )
  2949. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial look-ahead time %f is greater than the maximum look-ahead time %f.",curLaSecs,maxLaSecs);
  2950. if((rc = cmRecdPlayFinal(p)) != cmOkRC )
  2951. return rc;
  2952. if( chCnt == 0 )
  2953. return cmOkRC;
  2954. p->frags = cmMemAllocZ(cmRecdPlayFrag,fragCnt);
  2955. p->fragCnt = fragCnt;
  2956. p->srate = srate;
  2957. p->chCnt = chCnt;
  2958. p->initFragSecs = initFragSecs;
  2959. p->maxLaSmpCnt = floor(maxLaSecs*srate);
  2960. p->curLaSmpCnt = floor(curLaSecs*srate);
  2961. p->laChs = cmMemAllocZ(cmSample_t*,chCnt);
  2962. p->laSmpIdx = 0;
  2963. for(i=0; i<chCnt; ++i)
  2964. p->laChs[i] = cmMemAllocZ(cmSample_t,p->maxLaSmpCnt);
  2965. return rc;
  2966. }
  2967. cmRC_t cmRecdPlayFinal( cmRecdPlay* p )
  2968. {
  2969. unsigned i,j;
  2970. // free the fragments
  2971. for(i=0; i<p->fragCnt; ++i)
  2972. {
  2973. for(j=0; j<p->chCnt; ++j)
  2974. cmMemFree(p->frags[i].chArray[j]);
  2975. cmMemFree(p->frags[i].chArray);
  2976. }
  2977. // free the look-ahead buffers
  2978. for(i=0; i<p->chCnt; ++i)
  2979. cmMemFree(p->laChs[i]);
  2980. cmMemPtrFree(&p->laChs);
  2981. cmMemPtrFree(&p->frags);
  2982. p->fragCnt = 0;
  2983. p->chCnt = 0;
  2984. p->rlist = NULL;
  2985. p->plist = NULL;
  2986. return cmOkRC;
  2987. }
  2988. cmRC_t cmRecdPlayRegisterFrag( cmRecdPlay* p, unsigned fragIdx, unsigned labelSymId )
  2989. {
  2990. assert( fragIdx < p->fragCnt );
  2991. unsigned i;
  2992. p->frags[ fragIdx ].labelSymId = labelSymId;
  2993. p->frags[ fragIdx ].chArray = cmMemResizeZ(cmSample_t*,p->frags[fragIdx].chArray,p->chCnt);
  2994. for(i=0; i<p->chCnt; ++i)
  2995. {
  2996. p->frags[ fragIdx ].allocCnt = floor(p->initFragSecs * p->srate);
  2997. p->frags[ fragIdx ].chArray[i] = cmMemResizeZ(cmSample_t,p->frags[ fragIdx ].chArray[i],p->frags[fragIdx].allocCnt);
  2998. }
  2999. return cmOkRC;
  3000. }
  3001. cmRC_t cmRecdPlaySetLaSecs( cmRecdPlay* p, double curLaSecs )
  3002. {
  3003. p->curLaSmpCnt = floor(curLaSecs*p->srate);
  3004. return cmOkRC;
  3005. }
  3006. cmRC_t cmRecdPlayRewind( cmRecdPlay* p )
  3007. {
  3008. unsigned i;
  3009. // zero the look-ahead buffers
  3010. p->laSmpIdx = 0;
  3011. for(i=0; i<p->chCnt; ++i)
  3012. cmVOS_Zero(p->laChs[i],p->maxLaSmpCnt);
  3013. // remove all the active players
  3014. while( p->plist != NULL )
  3015. cmRecdPlayEndPlay(p,p->plist->labelSymId);
  3016. // remove all the active recorders
  3017. while( p->rlist != NULL )
  3018. cmRecdPlayEndRecord(p,p->rlist->labelSymId);
  3019. // rewind all the fragments play posn.
  3020. for(i=0; i<p->fragCnt; ++i)
  3021. p->frags[i].playIdx = 0;
  3022. return cmOkRC;
  3023. }
  3024. cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId )
  3025. {
  3026. unsigned i;
  3027. for(i=0; i<p->fragCnt; ++i)
  3028. if( p->frags[i].labelSymId == labelSymId )
  3029. {
  3030. // if the frag is not already on the recd list
  3031. if( p->frags[i].rlink == NULL )
  3032. {
  3033. p->frags[i].recdIdx = 0;
  3034. p->frags[i].playIdx = 0;
  3035. p->frags[i].rlink = p->rlist;
  3036. p->rlist = p->frags + i;
  3037. // handle LA buf longer than frag buf.
  3038. int cpyCnt = cmMin(p->curLaSmpCnt,p->frags[i].allocCnt);
  3039. // go backwards in LA buf from newest sample to find init src offset
  3040. int srcOffs = p->laSmpIdx - cpyCnt;
  3041. // if the src is before the first sample in the LA buf then wrap to end of buf
  3042. if( srcOffs < 0 )
  3043. srcOffs += p->maxLaSmpCnt;
  3044. assert( 0 <= srcOffs && srcOffs < p->maxLaSmpCnt );
  3045. // cnt of samples to copy from LA buf (limited by end of LA buf)
  3046. int n0 = cmMin(cpyCnt,p->maxLaSmpCnt - srcOffs);
  3047. // if necessary wrap to begin of LA buf for remaining samples
  3048. int n1 = cpyCnt>n0 ? n1 = cpyCnt-n0 : 0;
  3049. int j;
  3050. assert(n0+n1 == cpyCnt );
  3051. for(j=0; j<p->chCnt; ++j)
  3052. cmVOS_Copy(p->frags[i].chArray[j],n0,p->laChs[j]+srcOffs);
  3053. if( n1 > 0 )
  3054. {
  3055. for(j=0; j<p->chCnt; ++j)
  3056. cmVOS_Copy(p->frags[i].chArray[j]+n0,n1,p->laChs[j]);
  3057. }
  3058. p->frags[i].recdIdx = cpyCnt;
  3059. p->frags[i].playIdx = 0;
  3060. }
  3061. return cmOkRC;
  3062. }
  3063. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin record'.",labelSymId);
  3064. }
  3065. cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId )
  3066. {
  3067. cmRecdPlayFrag* fp = p->rlist;
  3068. cmRecdPlayFrag* pp = NULL;
  3069. for(; fp != NULL; fp=fp->rlink )
  3070. {
  3071. if( fp->labelSymId == labelSymId )
  3072. {
  3073. if( pp == NULL )
  3074. p->rlist = fp->rlink;
  3075. else
  3076. pp->rlink = fp->rlink;
  3077. fp->rlink = NULL;
  3078. return cmOkRC;
  3079. }
  3080. pp = fp;
  3081. }
  3082. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end record'.",labelSymId);
  3083. }
  3084. cmRC_t cmRecdPlayInsertRecord(cmRecdPlay* p, unsigned labelSymId, const cmChar_t* wavFn )
  3085. {
  3086. cmRC_t rc = cmOkRC;
  3087. unsigned i;
  3088. for(i=0; i<p->fragCnt; ++i)
  3089. if( p->frags[i].labelSymId == labelSymId )
  3090. {
  3091. cmAudioFileH_t afH = cmNullAudioFileH;
  3092. cmAudioFileInfo_t afInfo;
  3093. cmRC_t afRC = kOkAfRC;
  3094. // open the audio file
  3095. if( cmAudioFileIsValid( afH = cmAudioFileNewOpen(wavFn, &afInfo, &afRC, p->obj.err.rpt )) == false )
  3096. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The audio file '%s' could not be opened'.",cmStringNullGuard(wavFn));
  3097. // ignore blank
  3098. if( afInfo.frameCnt == 0 )
  3099. return cmOkRC;
  3100. // allocate buffer space
  3101. unsigned j;
  3102. for(j=0; j<p->chCnt; ++j)
  3103. p->frags[i].chArray[j] = cmMemResize(cmSample_t,p->frags[i].chArray[j],afInfo.frameCnt);
  3104. p->frags[i].allocCnt = afInfo.frameCnt;
  3105. // read samples into the buffer space
  3106. unsigned chIdx = 0;
  3107. unsigned chCnt = cmMin(p->chCnt,afInfo.chCnt);
  3108. unsigned actFrmCnt = 0;
  3109. if( cmAudioFileReadSample(afH,afInfo.frameCnt,chIdx,chCnt,p->frags[i].chArray, &actFrmCnt) != kOkAfRC )
  3110. return cmCtxRtCondition(&p->obj, cmSubSysFailRC, "Read failed on the audio file '%s'.",cmStringNullGuard(wavFn));
  3111. p->frags[i].recdIdx = actFrmCnt;
  3112. return rc;
  3113. }
  3114. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin record'.",labelSymId);
  3115. }
  3116. cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId )
  3117. {
  3118. unsigned i;
  3119. for(i=0; i<p->fragCnt; ++i)
  3120. if( p->frags[i].labelSymId == labelSymId )
  3121. {
  3122. // if the frag is not already on the play list
  3123. if( p->frags[i].plink == NULL )
  3124. {
  3125. p->frags[i].playIdx = 0;
  3126. p->frags[i].fadeSmpIdx = 0;
  3127. p->frags[i].fadeDbPerSec = 0.0;
  3128. p->frags[i].plink = p->plist;
  3129. p->plist = p->frags + i;
  3130. }
  3131. return cmOkRC;
  3132. }
  3133. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin play'.",labelSymId);
  3134. }
  3135. cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId )
  3136. {
  3137. cmRecdPlayFrag* fp = p->plist;
  3138. cmRecdPlayFrag* pp = NULL;
  3139. for(; fp != NULL; fp=fp->plink )
  3140. {
  3141. if( fp->labelSymId == labelSymId )
  3142. {
  3143. if( pp == NULL )
  3144. p->plist = fp->plink;
  3145. else
  3146. pp->plink = fp->plink;
  3147. fp->plink = NULL;
  3148. return cmOkRC;
  3149. }
  3150. pp = fp;
  3151. }
  3152. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end play'.",labelSymId);
  3153. }
  3154. cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec )
  3155. {
  3156. cmRecdPlayFrag* fp = p->plist;
  3157. for(; fp != NULL; fp=fp->plink )
  3158. if( fp->labelSymId == labelSymId )
  3159. {
  3160. fp->fadeDbPerSec = -fabs(fadeDbPerSec);
  3161. return cmOkRC;
  3162. }
  3163. return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'fade begin'.",labelSymId);
  3164. }
  3165. cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt )
  3166. {
  3167. unsigned i;
  3168. chCnt = cmMin(chCnt, p->chCnt);
  3169. //-------------------------------------------------------------------
  3170. // copy incoming audio into the look-ahead buffers
  3171. //
  3172. // if the number of incoming samples is longer than the look-head buffer
  3173. // then copy exactly maxLaSmpCnt samples from the end of the incoming sample
  3174. // buffer to the look-ahead buffer.
  3175. unsigned srcOffs = 0;
  3176. unsigned srcSmpCnt = smpCnt;
  3177. if( srcSmpCnt > p->maxLaSmpCnt )
  3178. {
  3179. // advance incoming sample buffer so that there are maxLaSmpCnt samples remaining
  3180. srcOffs = srcSmpCnt-p->maxLaSmpCnt;
  3181. srcSmpCnt = p->maxLaSmpCnt; // decrease the total samples to copy
  3182. }
  3183. // count of samples from cur posn to end of the LA buffer.
  3184. unsigned n0 = cmMin(srcSmpCnt, p->maxLaSmpCnt - p->laSmpIdx );
  3185. // count of samples past the end of the LA buffer to be wrapped into begin of buffer
  3186. unsigned n1 = srcSmpCnt>n0 ? srcSmpCnt-n0 : 0;
  3187. assert(n0+n1 == srcSmpCnt);
  3188. // copy first block to end of LA buffer
  3189. for(i=0; i<chCnt; ++i)
  3190. if( iChs[i] == NULL )
  3191. cmVOS_Zero(p->laChs[i]+p->laSmpIdx,n0);
  3192. else
  3193. cmVOS_Copy(p->laChs[i]+p->laSmpIdx,n0,iChs[i] + srcOffs);
  3194. p->laSmpIdx += n0;
  3195. if( n1!=0)
  3196. {
  3197. // copy second block to begin of LA buffer
  3198. for(i=0; i<chCnt; ++i)
  3199. if( iChs[i] == NULL )
  3200. cmVOS_Zero(p->laChs[i],n1);
  3201. else
  3202. cmVOS_Copy(p->laChs[i],n1,iChs[i] + srcOffs + n0);
  3203. p->laSmpIdx = n1;
  3204. }
  3205. //-------------------------------------------------------------------
  3206. // copy incoming audio into the active record buffers
  3207. //
  3208. cmRecdPlayFrag* fp = p->rlist;
  3209. for(; fp!=NULL; fp=fp->rlink)
  3210. {
  3211. assert( fp->recdIdx <= fp->allocCnt);
  3212. unsigned n = cmMin(fp->allocCnt - fp->recdIdx,smpCnt);
  3213. unsigned i;
  3214. for(i=0; i<p->chCnt; ++i)
  3215. if( iChs[i] == NULL )
  3216. cmVOS_Zero(fp->chArray[i] + fp->recdIdx, n );
  3217. else
  3218. cmVOS_Copy(fp->chArray[i] + fp->recdIdx, n, iChs[i] );
  3219. fp->recdIdx += n;
  3220. }
  3221. //-------------------------------------------------------------------
  3222. // copy outgoing audio out of the active play buffers
  3223. //
  3224. fp = p->plist;
  3225. for(; fp!=NULL; fp=fp->rlink)
  3226. {
  3227. assert( fp->playIdx <= fp->recdIdx);
  3228. double gain = pow(10.0,((fp->fadeSmpIdx / p->srate) * fp->fadeDbPerSec)/20.0);
  3229. unsigned n = cmMin(fp->recdIdx - fp->playIdx,smpCnt);
  3230. unsigned i;
  3231. for(i=0; i<p->chCnt; ++i)
  3232. if( oChs[i] != NULL )
  3233. cmVOS_MultVVS(oChs[i],n,fp->chArray[i] + fp->playIdx,gain);
  3234. fp->playIdx += n;
  3235. // if a fade rate has been set then advance the fade phase
  3236. if(fp->fadeDbPerSec!=0.0)
  3237. fp->fadeSmpIdx += smpCnt;
  3238. }
  3239. return cmOkRC;
  3240. }