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.

cmScoreProc.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. #include "cmGlobal.h"
  2. #include "cmFloatTypes.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 "cmSymTbl.h"
  10. #include "cmJson.h"
  11. #include "cmFile.h"
  12. #include "cmTime.h"
  13. #include "cmMidi.h"
  14. #include "cmMidiFile.h"
  15. #include "cmAudioFile.h"
  16. #include "cmScore.h"
  17. #include "cmTimeLine.h"
  18. #include "cmScoreProc.h"
  19. #include "cmProcObj.h"
  20. #include "cmProc4.h"
  21. enum
  22. {
  23. kOkSpRC,
  24. kJsonFailSpRC,
  25. kScoreFailSpRC,
  26. kTimeLineFailSpRC,
  27. kScoreMatchFailSpRC,
  28. kFileFailSpRC,
  29. };
  30. typedef struct _cmScMeas_t
  31. {
  32. cmTlMarker_t* markPtr; // time-line marker in which this 'set' exists
  33. cmScoreSet_t* setPtr; // score set on which this measurment is based
  34. double value; // the value of the measurement
  35. double cost; // the quality of the perf->score match
  36. struct _cmScMeas_t* link;
  37. } _cmScMeas_t;
  38. typedef struct
  39. {
  40. cmErr_t err; // score proc object error state
  41. cmCtx* ctx; // application context
  42. cmScH_t scH; // score object
  43. const cmChar_t* tlFn; // time-line filename
  44. cmTlH_t tlH; // time-line object
  45. cmJsonH_t jsH; //
  46. unsigned* dynArray; // dynArray[dynCnt] dynamics reference array
  47. unsigned dynCnt; //
  48. double srate; //
  49. cmScMeas* meas; // performance analyzer
  50. cmScMatcher* match; // score follower
  51. cmTlMarker_t* curMarkPtr;
  52. _cmScMeas_t* list_beg;
  53. _cmScMeas_t* list_end;
  54. _cmScMeas_t* slist_beg;
  55. } cmSp_t;
  56. // read the dynamics reference array from the time-line project file.
  57. cmSpRC_t _cmJsonReadDynArray( cmJsonH_t jsH, unsigned** dynArray, unsigned* dynCnt )
  58. {
  59. cmJsonNode_t* np;
  60. int i;
  61. if( cmJsonPathToArray(jsH, NULL, NULL, "dynRef", &np ) != kOkJsRC )
  62. return kJsonFailSpRC;
  63. *dynCnt = cmJsonChildCount(np);
  64. *dynArray = cmMemAllocZ(unsigned,*dynCnt);
  65. for(i=0; i<*dynCnt; ++i)
  66. if( cmJsonUIntValue( cmJsonArrayElement(np,i), (*dynArray)+i ) != kOkJsRC )
  67. return kJsonFailSpRC;
  68. return kOkSpRC;
  69. }
  70. cmSpRC_t _cmScoreProcInit( cmCtx_t* ctx, cmSp_t* p, const cmChar_t* rsrcFn )
  71. {
  72. cmSpRC_t rc = kOkSpRC;
  73. const cmChar_t* scFn = NULL;
  74. const cmChar_t* tlFn = NULL;
  75. const cmChar_t* tlPrefixPath = NULL;
  76. p->srate = 96000;
  77. cmErrSetup(&p->err,&ctx->rpt,"ScoreProc");
  78. // open the resource file
  79. if( cmJsonInitializeFromFile( &p->jsH, rsrcFn, ctx ) != kOkJsRC )
  80. {
  81. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to load the main resource file:%s.",cmStringNullGuard(rsrcFn));
  82. goto errLabel;
  83. }
  84. // get the time line fn
  85. if( cmJsonPathToString( p->jsH, NULL, NULL, "timeLineFn", &tlFn ) != kOkJsRC )
  86. {
  87. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to locate the time line file name in the main resource file:%s",cmStringNullGuard(rsrcFn));
  88. goto errLabel;
  89. }
  90. // get the score file name
  91. if( cmJsonPathToString( p->jsH, NULL, NULL, "scoreFn", &scFn ) != kOkJsRC )
  92. {
  93. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to locate the score file name in the main resource file:%s",cmStringNullGuard(rsrcFn));
  94. goto errLabel;
  95. }
  96. // get the time line data file prefix path
  97. if( cmJsonPathToString( p->jsH, NULL, NULL, "tlPrefixPath", &tlPrefixPath ) != kOkJsRC )
  98. {
  99. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to locate the time line data file prefix path in the main resource file:%s",cmStringNullGuard(rsrcFn));
  100. goto errLabel;
  101. }
  102. // read the dynamics reference array
  103. if((rc = _cmJsonReadDynArray( p->jsH, &p->dynArray, &p->dynCnt )) != kOkSpRC )
  104. {
  105. rc = cmErrMsg(&p->err,rc,"Unable to read dynamics reference array resource from the main resource file:%s",cmStringNullGuard(rsrcFn));
  106. goto errLabel;
  107. }
  108. // load the score file
  109. if( cmScoreInitialize(ctx, &p->scH, scFn, p->srate, NULL, 0, NULL, NULL, cmSymTblNullHandle ) != kOkScRC )
  110. {
  111. rc = cmErrMsg(&p->err,kScoreFailSpRC,"Score load failed for score file:%s.",cmStringNullGuard(scFn));
  112. goto errLabel;
  113. }
  114. // load the time-line file
  115. if( cmTimeLineInitializeFromFile(ctx, &p->tlH, NULL, NULL, tlFn, tlPrefixPath ) != kOkTlRC )
  116. {
  117. rc = cmErrMsg(&p->err,kTimeLineFailSpRC,"Time line load failed for time line file:%s.",cmStringNullGuard(tlFn));
  118. goto errLabel;
  119. }
  120. p->ctx = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
  121. errLabel:
  122. return rc;
  123. }
  124. cmSpRC_t _cmScoreProcFinal( cmSp_t* p )
  125. {
  126. cmSpRC_t rc = kOkSpRC;
  127. cmCtxFree(&p->ctx);
  128. if( cmScoreFinalize(&p->scH) != kOkScRC )
  129. cmErrMsg(&p->err,kScoreFailSpRC,"Score finalize failed.");
  130. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  131. cmErrMsg(&p->err,kTimeLineFailSpRC,"Time line finalize failed.");
  132. if( cmJsonFinalize(&p->jsH) != kOkJsRC )
  133. cmErrMsg(&p->err,kJsonFailSpRC,"JSON finalize failed.");
  134. cmMemFree(p->dynArray);
  135. return rc;
  136. }
  137. unsigned _cmScMeasSectCount( cmSp_t* sp )
  138. {
  139. const _cmScMeas_t* mp = sp->list_beg;
  140. unsigned n = 0;
  141. for(; mp != NULL; mp=mp->link)
  142. n += mp->setPtr->sectCnt;
  143. return n;
  144. }
  145. typedef struct
  146. {
  147. unsigned srcSeqId;
  148. const cmChar_t* srcMarkNameStr;
  149. unsigned srcTypeId;
  150. const cmChar_t* srcTypeLabelStr;
  151. unsigned dstScLocIdx;
  152. unsigned dstEvtIdx;
  153. const cmChar_t* dstSectLabelStr;
  154. double value;
  155. double cost;
  156. } _cmScMeasSect_t;
  157. int _cmScMeasSectCompare( const void* p0, const void* p1 )
  158. {
  159. _cmScMeasSect_t* m0 = (_cmScMeasSect_t*)p0;
  160. _cmScMeasSect_t* m1 = (_cmScMeasSect_t*)p1;
  161. return (int)m0->dstScLocIdx - (int)m1->dstScLocIdx;
  162. }
  163. cmSpRC_t _cmScWriteMeasFile( cmCtx_t* ctx, cmSp_t* sp, const cmChar_t* outFn )
  164. {
  165. cmFileH_t fH = cmFileNullHandle;
  166. cmSpRC_t rc = kOkSpRC;
  167. unsigned i,j,k;
  168. _cmScMeas_t* mp = sp->list_beg;
  169. unsigned scnt = _cmScMeasSectCount(sp);
  170. _cmScMeasSect_t sarray[ scnt ];
  171. for(i=0,k=0; k<scnt && mp!=NULL; ++i,mp=mp->link)
  172. {
  173. const cmChar_t* typeLabel = NULL;
  174. switch(mp->setPtr->varId)
  175. {
  176. case kEvenVarScId: typeLabel="even"; break;
  177. case kDynVarScId: typeLabel="dyn"; break;
  178. case kTempoVarScId:typeLabel="tempo";break;
  179. default:
  180. { assert(0); }
  181. }
  182. for(j=0; j<mp->setPtr->sectCnt; ++j,++k)
  183. {
  184. _cmScMeasSect_t* r = sarray + k;
  185. r->srcSeqId = mp->markPtr->obj.seqId,
  186. r->srcMarkNameStr = cmStringNullGuard(mp->markPtr->obj.name),
  187. r->srcTypeId = mp->setPtr->varId,
  188. r->srcTypeLabelStr = typeLabel,
  189. r->dstScLocIdx = mp->setPtr->sectArray[j]->locPtr->index,
  190. r->dstEvtIdx = mp->setPtr->sectArray[j]->begEvtIndex,
  191. r->dstSectLabelStr = cmStringNullGuard(mp->setPtr->sectArray[j]->label),
  192. r->value = mp->value,
  193. r->cost = mp->cost;
  194. }
  195. }
  196. assert(mp==NULL && k==scnt);
  197. qsort(sarray,scnt,sizeof(sarray[0]),_cmScMeasSectCompare);
  198. if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
  199. {
  200. rc = cmErrMsg(&sp->err,kFileFailSpRC,"Unable to create the output file '%s'.",cmStringNullGuard(outFn));
  201. goto errLabel;
  202. }
  203. cmFilePrintf(fH,"{\n meas : \n[\n[ \"sec\" \"typeLabel\" \"val\" \"cost\" \"loc\" \"evt\" \"seq\" \"mark\" \"typeId\" ]\n");
  204. for(i=0; i<scnt; ++i)
  205. {
  206. _cmScMeasSect_t* r = sarray + i;
  207. cmFilePrintf(fH,"[ \"%s\" \"%s\" %f %f %i %i %i \"%s\" %i ]\n",
  208. r->dstSectLabelStr,
  209. r->srcTypeLabelStr,
  210. r->value,
  211. r->cost,
  212. r->dstScLocIdx,
  213. r->dstEvtIdx,
  214. r->srcSeqId,
  215. r->srcMarkNameStr,
  216. r->srcTypeId
  217. );
  218. }
  219. /*
  220. mp = sp->list_beg;
  221. for(; mp!=NULL; mp=mp->link)
  222. {
  223. for(i=0; i<mp->setPtr->sectCnt; ++i)
  224. {
  225. cmFilePrintf(fH,"[ %i \"%s\" %i \"%s\" %i %i \"%s\" %f %f ]\n",
  226. mp->markPtr->obj.seqId,
  227. cmStringNullGuard(mp->markPtr->obj.name),
  228. mp->setPtr->varId,
  229. typeLabel,
  230. mp->setPtr->sectArray[i]->locPtr->index,
  231. mp->setPtr->sectArray[i]->begEvtIndex,
  232. cmStringNullGuard(mp->setPtr->sectArray[i]->label),
  233. mp->value,
  234. mp->cost );
  235. }
  236. }
  237. */
  238. cmFilePrintf(fH,"\n]\n}\n");
  239. errLabel:
  240. if( cmFileClose(&fH) != kOkFileRC )
  241. cmErrMsg(&sp->err,kFileFailSpRC,"The output file close failed on '%s'.",cmStringNullGuard(outFn));
  242. return rc;
  243. }
  244. void _cmScMatchCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
  245. {
  246. cmSp_t* sp = (cmSp_t*)arg;
  247. cmScMeas* sm = sp->meas;
  248. if( cmScMeasExec(sm, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel ) == cmOkRC )
  249. {
  250. unsigned i;
  251. for(i=sm->vsi; i<sm->nsi; ++i)
  252. // ignore set's which did not produce a valid value
  253. if(sm->set[i].value != DBL_MAX )
  254. {
  255. _cmScMeas_t* r = cmMemAllocZ(_cmScMeas_t,1);
  256. r->markPtr = sp->curMarkPtr;
  257. r->setPtr = sm->set[i].sp;
  258. r->value = sm->set[i].value;
  259. r->cost = sm->set[i].match_cost;
  260. if( sp->list_beg == NULL )
  261. {
  262. sp->list_beg = r;
  263. sp->list_end = r;
  264. }
  265. else
  266. {
  267. sp->list_end->link = r;
  268. sp->list_end = r;
  269. }
  270. }
  271. }
  272. }
  273. cmSpRC_t _cmScoreGenAllMeasurements(cmCtx_t* ctx, cmSp_t* sp, const cmChar_t* outFn)
  274. {
  275. cmSpRC_t rc = kOkSpRC;
  276. unsigned midiN = 7;
  277. unsigned scWndN = 10;
  278. unsigned seqN = cmTimeLineSeqCount(sp->tlH);
  279. double srate = cmTimeLineSampleRate(sp->tlH);
  280. unsigned seqId;
  281. assert( sp->srate == srate);
  282. // allocate the performance eval. object
  283. sp->meas = cmScMeasAlloc( sp->ctx, NULL, sp->scH, sp->srate, sp->dynArray, sp->dynCnt );
  284. assert( sp->meas != NULL );
  285. // allocate the score matcher
  286. sp->match = cmScMatcherAlloc(sp->ctx,NULL,sp->srate,sp->scH,scWndN,midiN,_cmScMatchCb,sp);
  287. assert(sp->match != NULL );
  288. // for each time line sequence
  289. for(seqId=0; seqId<seqN; ++seqId)
  290. {
  291. cmTlObj_t* o0p = NULL;
  292. // for each 'marker' in this time line sequence
  293. while( (o0p = cmTimeLineNextTypeObj(sp->tlH, o0p, seqId, kMarkerTlId)) != NULL )
  294. {
  295. // get the 'marker' recd
  296. cmTlMarker_t* markPtr = cmTimeLineMarkerObjPtr(sp->tlH,o0p);
  297. assert( markPtr != NULL );
  298. // if the marker does not have a valid start bar location
  299. if( markPtr->bar == 0 )
  300. continue;
  301. // set the marker ptr (which is used in _cmScMatchCb())
  302. sp->curMarkPtr = markPtr;
  303. // get the end-of-marker time as a sample index
  304. unsigned markEndSmpIdx = markPtr->obj.seqSmpIdx + markPtr->obj.durSmpCnt;
  305. // get the score event associated with the marker's bar number.
  306. const cmScoreEvt_t* evtPtr = cmScoreBarEvt(sp->scH,markPtr->bar);
  307. assert( evtPtr != NULL );
  308. // get the score location associated with the markers bar score event
  309. const cmScoreLoc_t* locPtr = cmScoreEvtLoc(sp->scH,evtPtr);
  310. assert( locPtr != NULL );
  311. cmRptPrintf(&ctx->rpt,"Processing loc:%i seq:%i %s %s\n",locPtr->index,seqId,cmStringNullGuard(markPtr->obj.name),cmStringNullGuard(markPtr->text));
  312. // reset the performance evaluation object
  313. if( cmScMeasReset(sp->meas) != cmOkRC )
  314. {
  315. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score performance evaluation object failed on reset.");
  316. continue;
  317. }
  318. // reset the score matcher to begin searching at the bar location
  319. if( cmScMatcherReset(sp->match, locPtr->index ) != cmOkRC )
  320. {
  321. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher reset failed on location: %i.",locPtr->index);
  322. continue;
  323. }
  324. cmTlObj_t* o1p = o0p;
  325. // as long as more MIDI events are available get the next MIDI msg
  326. while( (rc == kOkSpRC) && (o1p = cmTimeLineNextTypeObj(sp->tlH, o1p, seqId, kMidiEvtTlId )) != NULL )
  327. {
  328. cmTlMidiEvt_t* mep = cmTimeLineMidiEvtObjPtr(sp->tlH,o1p);
  329. assert(mep != NULL );
  330. // if the msg falls after the end of the marker then we are done
  331. if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > markEndSmpIdx )
  332. break;
  333. // if the time line MIDI msg a note-on
  334. if( mep->msg->status == kNoteOnMdId )
  335. {
  336. cmRC_t cmRC = cmScMatcherExec(sp->match, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
  337. switch( cmRC )
  338. {
  339. case cmOkRC: // continue processing MIDI events
  340. break;
  341. case cmEofRC: // end of the score was encountered
  342. break;
  343. case cmInvalidArgRC: // p->eli was not set correctly
  344. rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed due to an invalid argument.");
  345. goto errLabel;
  346. break;
  347. case cmSubSysFailRC: // scan resync failed
  348. rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed on resync.");
  349. cmScMatcherPrint(sp->match);
  350. //goto errLabel;
  351. break;
  352. default:
  353. { assert(0); }
  354. }
  355. }
  356. }
  357. rc = kOkSpRC;
  358. }
  359. }
  360. errLabel:
  361. if((rc = _cmScWriteMeasFile(ctx, sp, outFn )) != kOkSpRC )
  362. cmErrMsg(&sp->err,kFileFailSpRC,"The measurement output did not complete without errors.");
  363. _cmScMeas_t* mp = sp->list_beg;
  364. while(mp!=NULL)
  365. {
  366. _cmScMeas_t* np = mp->link;
  367. cmMemFree(mp);
  368. mp = np;
  369. }
  370. if( cmScMatcherFree(&sp->match) != cmOkRC )
  371. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher release failed.");
  372. if( cmScMeasFree(&sp->meas) != cmOkRC )
  373. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The performance evaluation object failed.");
  374. return rc;
  375. }
  376. //==================================================================================================
  377. unsigned cmScoreProc(cmCtx_t* ctx)
  378. {
  379. cmSpRC_t rc = kOkSpRC;
  380. const cmChar_t* rsrcFn = "/home/kevin/.kc/time_line.js";
  381. const cmChar_t* outFn = "/home/kevin/src/cmkc/src/kc/data/meas0.js";
  382. cmSp_t sp;
  383. memset(&sp,0,sizeof(sp));
  384. cmRptPrintf(&ctx->rpt,"Score Proc Start\n");
  385. if((rc = _cmScoreProcInit(ctx,&sp,rsrcFn)) != kOkSpRC )
  386. goto errLabel;
  387. _cmScoreGenAllMeasurements(ctx,&sp,outFn);
  388. //cmScorePrint(sp.scH,&ctx->rpt);
  389. //cmScorePrintLoc(sp.scH);
  390. errLabel:
  391. _cmScoreProcFinal(&sp);
  392. cmRptPrintf(&ctx->rpt,"Score Proc End\n");
  393. return rc;
  394. }