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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. } cmSp_t;
  54. cmSpRC_t _cmJsonReadDynArray( cmJsonH_t jsH, unsigned** dynArray, unsigned* dynCnt )
  55. {
  56. cmJsonNode_t* np;
  57. int i;
  58. if( cmJsonPathToArray(jsH, NULL, NULL, "dynRef", &np ) != kOkJsRC )
  59. return kJsonFailSpRC;
  60. *dynCnt = cmJsonChildCount(np);
  61. *dynArray = cmMemAllocZ(unsigned,*dynCnt);
  62. for(i=0; i<*dynCnt; ++i)
  63. if( cmJsonUIntValue( cmJsonArrayElement(np,i), (*dynArray)+i ) != kOkJsRC )
  64. return kJsonFailSpRC;
  65. return kOkSpRC;
  66. }
  67. cmSpRC_t _cmScoreProcInit( cmCtx_t* ctx, cmSp_t* p, const cmChar_t* rsrcFn )
  68. {
  69. cmSpRC_t rc = kOkSpRC;
  70. const cmChar_t* scFn = NULL;
  71. const cmChar_t* tlFn = NULL;
  72. p->srate = 96000;
  73. cmErrSetup(&p->err,&ctx->rpt,"ScoreProc");
  74. // open the resource file
  75. if( cmJsonInitializeFromFile( &p->jsH, rsrcFn, ctx ) != kOkJsRC )
  76. {
  77. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to load the main resource file:%s.",cmStringNullGuard(rsrcFn));
  78. goto errLabel;
  79. }
  80. // get the time line fn
  81. if( cmJsonPathToString( p->jsH, NULL, NULL, "timeLineFn", &tlFn ) != kOkJsRC )
  82. {
  83. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to locate the time line file name in the main resource file:%s",cmStringNullGuard(rsrcFn));
  84. goto errLabel;
  85. }
  86. // get the score file name
  87. if( cmJsonPathToString( p->jsH, NULL, NULL, "scoreFn", &scFn ) != kOkJsRC )
  88. {
  89. rc = cmErrMsg(&p->err,kJsonFailSpRC,"Unable to locate the score file name in the main resource file:%s",cmStringNullGuard(rsrcFn));
  90. goto errLabel;
  91. }
  92. // read the dynamics reference array
  93. if((rc = _cmJsonReadDynArray( p->jsH, &p->dynArray, &p->dynCnt )) != kOkSpRC )
  94. {
  95. rc = cmErrMsg(&p->err,rc,"Unable to read dynamics reference array resource from the main resource file:%s",cmStringNullGuard(rsrcFn));
  96. goto errLabel;
  97. }
  98. // load the score file
  99. if( cmScoreInitialize(ctx, &p->scH, scFn, p->srate, NULL, 0, NULL, NULL, cmSymTblNullHandle ) != kOkScRC )
  100. {
  101. rc = cmErrMsg(&p->err,kScoreFailSpRC,"Score load failed for score file:%s.",cmStringNullGuard(scFn));
  102. goto errLabel;
  103. }
  104. // load the time-line file
  105. if( cmTimeLineInitializeFromFile(ctx, &p->tlH, NULL, NULL, tlFn ) != kOkTlRC )
  106. {
  107. rc = cmErrMsg(&p->err,kTimeLineFailSpRC,"Time line load failed for time line file:%s.",cmStringNullGuard(tlFn));
  108. goto errLabel;
  109. }
  110. p->ctx = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
  111. errLabel:
  112. return rc;
  113. }
  114. cmSpRC_t _cmScoreProcFinal( cmSp_t* p )
  115. {
  116. cmSpRC_t rc = kOkSpRC;
  117. cmCtxFree(&p->ctx);
  118. if( cmScoreFinalize(&p->scH) != kOkScRC )
  119. cmErrMsg(&p->err,kScoreFailSpRC,"Score finalize failed.");
  120. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  121. cmErrMsg(&p->err,kTimeLineFailSpRC,"Time line finalize failed.");
  122. if( cmJsonFinalize(&p->jsH) != kOkJsRC )
  123. cmErrMsg(&p->err,kJsonFailSpRC,"JSON finalize failed.");
  124. cmMemFree(p->dynArray);
  125. return rc;
  126. }
  127. cmSpRC_t _cmScWriteMeasFile( cmCtx_t* ctx, cmSp_t* sp, const cmChar_t* outFn )
  128. {
  129. cmFileH_t fH = cmFileNullHandle;
  130. cmSpRC_t rc = kOkSpRC;
  131. unsigned i;
  132. if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
  133. {
  134. rc = cmErrMsg(&sp->err,kFileFailSpRC,"Unable to create the output file '%s'.",cmStringNullGuard(outFn));
  135. goto errLabel;
  136. }
  137. cmFilePrintf(fH,"{\n meas : \n[\n[\"seq\" \"mark\" \"typeId\" \"typeLabel\" \"loc\" \"evt\" \"sec\" \"val\" \"cost\" ]\n");
  138. _cmScMeas_t* mp = sp->list_beg;
  139. for(; mp!=NULL; mp=mp->link)
  140. {
  141. const cmChar_t* typeLabel = NULL;
  142. switch(mp->setPtr->varId)
  143. {
  144. case kEvenVarScId: typeLabel="even"; break;
  145. case kDynVarScId: typeLabel="dyn"; break;
  146. case kTempoVarScId:typeLabel="tempo";break;
  147. default:
  148. { assert(0); }
  149. }
  150. for(i=0; i<mp->setPtr->sectCnt; ++i)
  151. {
  152. cmFilePrintf(fH,"[ %i \"%s\" %i \"%s\" %i %i \"%s\" %f %f ]\n",
  153. mp->markPtr->obj.seqId,
  154. cmStringNullGuard(mp->markPtr->obj.name),
  155. mp->setPtr->varId,
  156. typeLabel,
  157. mp->setPtr->sectArray[i]->locPtr->index,
  158. mp->setPtr->sectArray[i]->begEvtIndex,
  159. cmStringNullGuard(mp->setPtr->sectArray[i]->label),
  160. mp->value,
  161. mp->cost );
  162. }
  163. }
  164. cmFilePrintf(fH,"\n]\n}\n");
  165. errLabel:
  166. if( cmFileClose(&fH) != kOkFileRC )
  167. cmErrMsg(&sp->err,kFileFailSpRC,"The output file close failed on '%s'.",cmStringNullGuard(outFn));
  168. return rc;
  169. }
  170. void _cmScMatchCb( cmScMatcher* p, void* arg, cmScMatcherResult_t* rp )
  171. {
  172. cmSp_t* sp = (cmSp_t*)arg;
  173. cmScMeas* sm = sp->meas;
  174. if( cmScMeasExec(sm, rp->mni, rp->locIdx, rp->scEvtIdx, rp->flags, rp->smpIdx, rp->pitch, rp->vel ) == cmOkRC )
  175. {
  176. unsigned i;
  177. for(i=sm->vsi; i<sm->nsi; ++i)
  178. // ignore set's which did not produce a valid value
  179. if(sm->set[i].value != DBL_MAX )
  180. {
  181. _cmScMeas_t* r = cmMemAllocZ(_cmScMeas_t,1);
  182. r->markPtr = sp->curMarkPtr;
  183. r->setPtr = sm->set[i].sp;
  184. r->value = sm->set[i].value;
  185. r->cost = sm->set[i].match_cost;
  186. if( sp->list_beg == NULL )
  187. {
  188. sp->list_beg = r;
  189. sp->list_end = r;
  190. }
  191. else
  192. {
  193. sp->list_end->link = r;
  194. sp->list_end = r;
  195. }
  196. }
  197. }
  198. }
  199. cmSpRC_t _cmScoreGenAllMeasurements(cmCtx_t* ctx, cmSp_t* sp, const cmChar_t* outFn)
  200. {
  201. cmSpRC_t rc = kOkSpRC;
  202. unsigned midiN = 7;
  203. unsigned scWndN = 10;
  204. unsigned seqN = cmTimeLineSeqCount(sp->tlH);
  205. double srate = cmTimeLineSampleRate(sp->tlH);
  206. unsigned seqId;
  207. assert( sp->srate == srate);
  208. // allocate the performance eval. object
  209. sp->meas = cmScMeasAlloc( sp->ctx, NULL, sp->scH, sp->srate, sp->dynArray, sp->dynCnt );
  210. assert( sp->meas != NULL );
  211. // allocate the score matcher
  212. sp->match = cmScMatcherAlloc(sp->ctx,NULL,sp->srate,sp->scH,scWndN,midiN,_cmScMatchCb,sp);
  213. assert(sp->match != NULL );
  214. // for each time line sequence
  215. for(seqId=0; seqId<seqN; ++seqId)
  216. {
  217. cmTlObj_t* o0p = NULL;
  218. // for each 'marker' in this time line sequence
  219. while( (o0p = cmTimeLineNextTypeObj(sp->tlH, o0p, seqId, kMarkerTlId)) != NULL )
  220. {
  221. // get the 'marker' recd
  222. cmTlMarker_t* markPtr = cmTimeLineMarkerObjPtr(sp->tlH,o0p);
  223. assert( markPtr != NULL );
  224. // if the marker does not have a valid start bar location
  225. if( markPtr->bar == 0 )
  226. continue;
  227. // set the marker ptr (which is used in _cmScMatchCb())
  228. sp->curMarkPtr = markPtr;
  229. // get the end-of-marker time as a sample index
  230. unsigned markEndSmpIdx = markPtr->obj.seqSmpIdx + markPtr->obj.durSmpCnt;
  231. // get the score event associated with the marker's bar number.
  232. const cmScoreEvt_t* evtPtr = cmScoreBarEvt(sp->scH,markPtr->bar);
  233. assert( evtPtr != NULL );
  234. // get the score location associated with the markers bar score event
  235. const cmScoreLoc_t* locPtr = cmScoreEvtLoc(sp->scH,evtPtr);
  236. assert( locPtr != NULL );
  237. cmRptPrintf(&ctx->rpt,"Processing loc:%i seq:%i %s %s\n",locPtr->index,seqId,cmStringNullGuard(markPtr->obj.name),cmStringNullGuard(markPtr->text));
  238. // reset the performance evaluation object
  239. if( cmScMeasReset(sp->meas) != cmOkRC )
  240. {
  241. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score performance evaluation object failed on reset.");
  242. continue;
  243. }
  244. // reset the score matcher to begin searching at the bar location
  245. if( cmScMatcherReset(sp->match, locPtr->index ) != cmOkRC )
  246. {
  247. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher reset failed on location: %i.",locPtr->index);
  248. continue;
  249. }
  250. cmTlObj_t* o1p = o0p;
  251. // as long as more MIDI events are available get the next MIDI msg
  252. while( (rc == kOkSpRC) && (o1p = cmTimeLineNextTypeObj(sp->tlH, o1p, seqId, kMidiEvtTlId )) != NULL )
  253. {
  254. cmTlMidiEvt_t* mep = cmTimeLineMidiEvtObjPtr(sp->tlH,o1p);
  255. assert(mep != NULL );
  256. // if the msg falls after the end of the marker then we are done
  257. if( mep->obj.seqSmpIdx != cmInvalidIdx && mep->obj.seqSmpIdx > markEndSmpIdx )
  258. break;
  259. // if the time line MIDI msg a note-on
  260. if( mep->msg->status == kNoteOnMdId )
  261. {
  262. cmRC_t cmRC = cmScMatcherExec(sp->match, mep->obj.seqSmpIdx, mep->msg->status, mep->msg->u.chMsgPtr->d0, mep->msg->u.chMsgPtr->d1, NULL );
  263. switch( cmRC )
  264. {
  265. case cmOkRC: // continue processing MIDI events
  266. break;
  267. case cmEofRC: // end of the score was encountered
  268. break;
  269. case cmInvalidArgRC: // p->eli was not set correctly
  270. rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed due to an invalid argument.");
  271. goto errLabel;
  272. break;
  273. case cmSubSysFailRC: // scan resync failed
  274. rc = cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher failed on resync.");
  275. cmScMatcherPrint(sp->match);
  276. //goto errLabel;
  277. break;
  278. default:
  279. { assert(0); }
  280. }
  281. }
  282. }
  283. rc = kOkSpRC;
  284. }
  285. }
  286. errLabel:
  287. if((rc = _cmScWriteMeasFile(ctx, sp, outFn )) != kOkSpRC )
  288. cmErrMsg(&sp->err,kFileFailSpRC,"The measurement output did not complete without errors.");
  289. _cmScMeas_t* mp = sp->list_beg;
  290. while(mp!=NULL)
  291. {
  292. _cmScMeas_t* np = mp->link;
  293. cmMemFree(mp);
  294. mp = np;
  295. }
  296. if( cmScMatcherFree(&sp->match) != cmOkRC )
  297. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The score matcher release failed.");
  298. if( cmScMeasFree(&sp->meas) != cmOkRC )
  299. cmErrMsg(&sp->err,kScoreMatchFailSpRC,"The performance evaluation object failed.");
  300. return rc;
  301. }
  302. unsigned cmScoreProc(cmCtx_t* ctx)
  303. {
  304. cmSpRC_t rc = kOkSpRC;
  305. const cmChar_t* rsrcFn = "/home/kevin/.kc/time_line.js";
  306. const cmChar_t* outFn = "/home/kevin/src/cmkc/src/kc/data/meas0.js";
  307. cmSp_t sp;
  308. memset(&sp,0,sizeof(sp));
  309. cmRptPrintf(&ctx->rpt,"Score Proc Start\n");
  310. if((rc = _cmScoreProcInit(ctx,&sp,rsrcFn)) != kOkSpRC )
  311. goto errLabel;
  312. _cmScoreGenAllMeasurements(ctx,&sp,outFn);
  313. //cmScorePrint(sp.scH,&ctx->rpt);
  314. //cmScorePrintLoc(sp.scH);
  315. errLabel:
  316. _cmScoreProcFinal(&sp);
  317. cmRptPrintf(&ctx->rpt,"Score Proc End\n");
  318. return rc;
  319. }