libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmScoreProc.c 14KB

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