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.

cmScore.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmMidi.h"
  10. #include "cmLex.h"
  11. #include "cmCsv.h"
  12. #include "cmMidiFile.h"
  13. #include "cmAudioFile.h"
  14. #include "cmTimeLine.h"
  15. #include "cmScore.h"
  16. /*
  17. #include "cmComplexTypes.h"
  18. #include "cmLinkedHeap.h"
  19. #include "cmSymTbl.h"
  20. #include "cmProcObj.h"
  21. #include "cmProc.h"
  22. #include "cmProcTemplate.h"
  23. */
  24. #include "cmVectOpsTemplateMain.h"
  25. cmScH_t cmScNullHandle = cmSTATIC_NULL_HANDLE;
  26. enum
  27. {
  28. kLabelCharCnt = 7,
  29. kInvalidDynScId = 0,
  30. };
  31. enum
  32. {
  33. kTypeLabelColScIdx = 3,
  34. kDSecsColScIdx = 5,
  35. kPitchColScIdx = 11,
  36. kBarColScIdx = 13,
  37. kSkipColScIdx = 14,
  38. kEvenColScIdx = 15,
  39. kTempoColScIdx = 16,
  40. kDynColScIdx = 17
  41. };
  42. typedef struct
  43. {
  44. unsigned id;
  45. cmChar_t label[ kLabelCharCnt + 1 ];
  46. } cmScEvtRef_t;
  47. typedef struct
  48. {
  49. cmErr_t err;
  50. cmScoreEvt_t* array;
  51. unsigned cnt;
  52. cmCsvH_t cH;
  53. } cmSc_t;
  54. cmScEvtRef_t _cmScEvtRefArray[] =
  55. {
  56. { kTimeSigEvtScId, "tsg" },
  57. { kKeySigEvtScId, "ksg" },
  58. { kTempoEvtScId, "tmp" },
  59. { kTrackEvtScId, "trk" },
  60. { kTextEvtScId, "txt" },
  61. { kEOTrackEvtScId, "eot" },
  62. { kCopyEvtScId, "cpy"},
  63. { kBlankEvtScId, "blk"},
  64. { kBarEvtScId, "bar"},
  65. { kPgmEvtScId, "pgm" },
  66. { kCtlEvtScId, "ctl" },
  67. { kNonEvtScId, "non" },
  68. { kInvalidEvtScId, "***" }
  69. };
  70. cmScEvtRef_t _cmScDynRefArray[] =
  71. {
  72. { 1, "pppp" },
  73. { 2, "ppp" },
  74. { 3, "pp" },
  75. { 4, "p" },
  76. { 5, "mp" },
  77. { 6, "m" },
  78. { 7, "mf" },
  79. { 8, "f" },
  80. { 9, "ff" },
  81. { 10, "fff" },
  82. { 11, "ffff"},
  83. { kInvalidDynScId, "***" },
  84. };
  85. cmSc_t* _cmScHandleToPtr( cmScH_t h )
  86. {
  87. cmSc_t* p = (cmSc_t*)h.h;
  88. assert( p != NULL );
  89. return p;
  90. }
  91. unsigned _cmScEvtTypeLabelToId( const cmChar_t* label )
  92. {
  93. cmScEvtRef_t* r = _cmScEvtRefArray;
  94. for(; r->id != kInvalidEvtScId; ++r )
  95. if( strcmp(label,r->label) == 0 )
  96. return r->id;
  97. return kInvalidEvtScId;
  98. }
  99. const cmChar_t* _cmScEvtTypeIdToLabel( unsigned id )
  100. {
  101. cmScEvtRef_t* r = _cmScEvtRefArray;
  102. for(; r->id != kInvalidEvtScId; ++r )
  103. if( r->id == id )
  104. return r->label;
  105. return NULL;
  106. }
  107. unsigned _cmScDynLabelToId( const cmChar_t* label )
  108. {
  109. cmScEvtRef_t* r = _cmScDynRefArray;
  110. for(; r->id != kInvalidEvtScId; ++r )
  111. if( strcmp(label,r->label) == 0 )
  112. return r->id;
  113. return kInvalidDynScId;
  114. }
  115. const cmChar_t* _cmScDynIdToLabel( unsigned id )
  116. {
  117. cmScEvtRef_t* r = _cmScDynRefArray;
  118. for(; r->id != kInvalidDynScId; ++r )
  119. if( r->id == id )
  120. return r->label;
  121. return NULL;
  122. }
  123. unsigned _cmScLexSciPitchMatcher( const cmChar_t* cp, unsigned cn )
  124. {
  125. // first char must be "A-G"
  126. if( strspn(cp,"ABCDEFG") != 1 )
  127. return 0;
  128. unsigned i = 1;
  129. // next char could be accidental
  130. if( cp[i] == '#' || cp[i] == 'b' )
  131. ++i; // i==2
  132. // the 2nd or 3rd char must be a digit
  133. if( isdigit(cp[i]) == false )
  134. return 0;
  135. ++i; // i==2 or i==3
  136. // the 3rd or 4th char must be a digit or EOS
  137. if( isdigit(cp[i]) == false )
  138. return i;
  139. ++i;
  140. return i;
  141. }
  142. cmScRC_t _cmScFinalize( cmSc_t* p )
  143. {
  144. cmScRC_t rc = kOkScRC;
  145. if( cmCsvFinalize(&p->cH) != kOkCsvRC )
  146. return rc;
  147. cmMemFree(p->array);
  148. cmMemFree(p);
  149. return rc;
  150. }
  151. cmScRC_t _cmScParseBar( cmSc_t* p, unsigned rowIdx, int* barNumb )
  152. {
  153. if((*barNumb = cmCsvCellInt(p->cH,rowIdx,kBarColScIdx)) == INT_MAX )
  154. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to parse the bar number.");
  155. return kOkScRC;
  156. }
  157. cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int barNumb, unsigned barNoteIdx )
  158. {
  159. cmScRC_t rc = kOkScRC;
  160. unsigned flags = 0;
  161. unsigned dynVal = kInvalidDynScId;
  162. const cmChar_t* sciPitch;
  163. cmMidiByte_t midiPitch;
  164. const cmChar_t* attr;
  165. double dsecs;
  166. if((sciPitch = cmCsvCellText(p->cH,rowIdx,kPitchColScIdx)) == NULL )
  167. return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
  168. if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch)
  169. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
  170. // it is possible that note delta-secs field is empty - so default to 0
  171. if((dsecs = cmCsvCellDouble(p->cH, rowIdx, kDSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
  172. dsecs = 0;
  173. if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
  174. flags += kSkipScFl;
  175. if((attr = cmCsvCellText(p->cH,rowIdx,kEvenColScIdx)) != NULL && *attr == 'e' )
  176. flags += kEvenScFl;
  177. if((attr = cmCsvCellText(p->cH,rowIdx,kTempoColScIdx)) != NULL && *attr == 't' )
  178. flags += kTempoScFl;
  179. if((attr = cmCsvCellText(p->cH,rowIdx,kDynColScIdx)) != NULL )
  180. {
  181. if((dynVal = _cmScDynLabelToId(attr)) == kInvalidDynScId )
  182. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unknown dynamic label '%s'.",cmStringNullGuard(attr));
  183. flags += kDynScFl;
  184. }
  185. s->type = kNonEvtScId;
  186. s->pitch = midiPitch;
  187. s->flags = flags;
  188. s->dynVal = dynVal;
  189. s->barNumb = barNumb;
  190. s->barNoteIdx = barNoteIdx;
  191. return rc;
  192. }
  193. cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
  194. {
  195. cmScRC_t rc = kOkScRC;
  196. unsigned barNoteIdx;
  197. int barNumb;
  198. if( cmCsvInitialize(&p->cH, ctx ) != kOkCsvRC )
  199. {
  200. rc = cmErrMsg(&p->err,kCsvFailScRC,"Score file initialization failed.");
  201. goto errLabel;
  202. }
  203. if( cmCsvLexRegisterMatcher(p->cH, cmCsvLexNextAvailId(p->cH), _cmScLexSciPitchMatcher ) != kOkCsvRC )
  204. {
  205. rc = cmErrMsg(&p->err,kCsvFailScRC,"CSV token matcher registration failed.");
  206. goto errLabel;
  207. }
  208. if( cmCsvParseFile(p->cH, fn, 0 ) != kOkCsvRC )
  209. {
  210. rc = cmErrMsg(&p->err,kCsvFailScRC,"CSV file parsing failed on the file '%s'.",cmStringNullGuard(fn));
  211. goto errLabel;
  212. }
  213. p->cnt = cmCsvRowCount(p->cH);
  214. p->array = cmMemAllocZ(cmScoreEvt_t,p->cnt);
  215. unsigned i,j;
  216. // skip labels line - start on line 1
  217. for(i=1,j=0; i<p->cnt && rc==kOkScRC; ++i)
  218. {
  219. // get the row 'type' label
  220. const char* typeLabel;
  221. if((typeLabel = cmCsvCellText(p->cH,i,kTypeLabelColScIdx)) == NULL )
  222. {
  223. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"No type label.");
  224. break;
  225. }
  226. // convert the row 'type' label to an id
  227. unsigned tid;
  228. if((tid = _cmScEvtTypeLabelToId(typeLabel)) == kInvalidEvtScId)
  229. {
  230. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"Unknown type '%s'.",cmStringNullGuard(typeLabel));
  231. break;
  232. }
  233. switch(tid)
  234. {
  235. case kBarEvtScId:
  236. // parse bar lines
  237. if((rc = _cmScParseBar(p,i,&barNumb)) == kOkScRC )
  238. barNoteIdx = 0;
  239. break;
  240. case kNonEvtScId:
  241. // parse note-on events
  242. if((rc = _cmScParseNoteOn(p, i, p->array + j, barNumb, barNoteIdx )) == kOkScRC )
  243. {
  244. if( cmIsFlag(p->array[j].flags,kSkipScFl) == false )
  245. ++j;
  246. ++barNoteIdx;
  247. }
  248. break;
  249. default:
  250. break;
  251. }
  252. }
  253. if( rc == kSyntaxErrScRC )
  254. {
  255. cmErrMsg(&p->err,rc,"Syntax error on line %i in '%s'.",i+1,cmStringNullGuard(fn));
  256. goto errLabel;
  257. }
  258. p->cnt = i;
  259. errLabel:
  260. return rc;
  261. }
  262. cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn )
  263. {
  264. cmScRC_t rc = kOkScRC;
  265. if((rc = cmScoreFinalize(hp)) != kOkScRC )
  266. return rc;
  267. cmSc_t* p = cmMemAllocZ(cmSc_t,1);
  268. cmErrSetup(&p->err,&ctx->rpt,"Score");
  269. if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC )
  270. goto errLabel;
  271. hp->h = p;
  272. errLabel:
  273. if( rc != kOkScRC )
  274. _cmScFinalize(p);
  275. return rc;
  276. }
  277. cmScRC_t cmScoreFinalize( cmScH_t* hp )
  278. {
  279. cmScRC_t rc = kOkScRC;
  280. if( hp == NULL || cmScoreIsValid(*hp) == false )
  281. return kOkScRC;
  282. cmSc_t* p = _cmScHandleToPtr(*hp);
  283. if((rc = _cmScFinalize(p)) != kOkScRC )
  284. return rc;
  285. hp->h = NULL;
  286. return rc;
  287. }
  288. bool cmScoreIsValid( cmScH_t h )
  289. { return h.h != NULL; }
  290. unsigned cmScoreEvtCount( cmScH_t h )
  291. {
  292. cmSc_t* p = _cmScHandleToPtr(h);
  293. return p->cnt;
  294. }
  295. cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx )
  296. {
  297. cmSc_t* p = _cmScHandleToPtr(h);
  298. if( idx >= p->cnt )
  299. {
  300. cmErrMsg(&p->err,kInvalidIdxScRC,"%i is an invalid index for %i records.",idx,p->cnt);
  301. return NULL;
  302. }
  303. return p->array + idx;
  304. }
  305. void cmScorePrint( cmScH_t h, cmRpt_t* rpt )
  306. {
  307. cmSc_t* p = _cmScHandleToPtr(h);
  308. unsigned i;
  309. for(i=0; i<20 /*p->cnt*/; ++i)
  310. {
  311. cmScoreEvt_t* r = p->array + i;
  312. switch(r->type)
  313. {
  314. case kNonEvtScId:
  315. cmRptPrintf(rpt,"%5i %3i %3i %s 0x%2x %c%c%c %s\n",
  316. i,
  317. r->barNumb,
  318. r->barNoteIdx,
  319. _cmScEvtTypeIdToLabel(r->type),
  320. r->pitch,
  321. cmIsFlag(r->flags,kEvenScFl) ? 'e' : ' ',
  322. cmIsFlag(r->flags,kTempoScFl) ? 't' : ' ',
  323. cmIsFlag(r->flags,kDynScFl) ? 'd' : ' ',
  324. cmIsFlag(r->flags,kDynScFl) ? _cmScDynIdToLabel(r->dynVal) : "");
  325. break;
  326. default:
  327. break;
  328. }
  329. }
  330. }
  331. // Each time line note-on object is decorated (via cmTlObj_t.userDataPtr) with a
  332. // cmScSyncState_t record.
  333. typedef struct
  334. {
  335. unsigned cnt; // count of candidate sync locations
  336. double dist; // edit distance to the closest sync location
  337. unsigned scEvtIdx; // score record this note-on is assigned to
  338. } cmScSyncState_t;
  339. void _cmScSyncTimeLineAllocFree( cmTlH_t tlH, bool allocFl )
  340. {
  341. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  342. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId))
  343. if( mep->msg->status == kNoteOnMdId )
  344. {
  345. if( allocFl )
  346. mep->obj.userDataPtr = cmMemAllocZ(cmScSyncState_t,1);
  347. else
  348. cmMemPtrFree(&mep->obj.userDataPtr);
  349. }
  350. }
  351. void _cmScPrintSyncState( cmSc_t* p, cmTlH_t tlH )
  352. {
  353. unsigned i = 0;
  354. double sr = cmTimeLineSampleRate(tlH);
  355. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  356. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId))
  357. if( mep->msg->status == kNoteOnMdId )
  358. {
  359. cmScSyncState_t* ssp = (cmScSyncState_t*)mep->obj.userDataPtr;
  360. cmRptPrintf(p->err.rpt,"%5.3f pit:0x%2x (%3i) bar:%3i bni:%3i cnt:%3i dst:%1.6f ref:%s\n",
  361. (mep->obj.ref->begSmpIdx - mep->obj.begSmpIdx) / (sr*60),
  362. mep->msg->u.chMsgPtr->d0,
  363. mep->msg->u.chMsgPtr->d0,
  364. ssp->cnt ? p->array[ ssp->scEvtIdx ].barNumb : 0,
  365. ssp->cnt ? p->array[ ssp->scEvtIdx ].barNoteIdx : 0,
  366. ssp->cnt,
  367. ssp->dist,
  368. cmStringNullGuard(mep->obj.ref->name));
  369. ++i;
  370. if( i>=300)
  371. break;
  372. }
  373. }
  374. double _cmScWndEditDist( cmSc_t* p, unsigned* mtx, const unsigned* tlWnd, cmScSyncState_t* tlObjWnd[], unsigned wndCnt )
  375. {
  376. unsigned scWnd[ wndCnt ];
  377. unsigned scIdxWnd[ wndCnt ];
  378. unsigned i;
  379. unsigned wn = 0;
  380. double minDist = DBL_MAX;
  381. // for each note-on score event
  382. for(i=0; i<p->cnt; ++i)
  383. if( p->array[i].type == kNonEvtScId )
  384. {
  385. // shift the score event window to the the left
  386. memmove(scWnd, scWnd+1, (wndCnt-1)*sizeof(scWnd[0]));
  387. memmove(scIdxWnd,scIdxWnd+1,(wndCnt-1)*sizeof(scIdxWnd[0]));
  388. // insert new score event data on right
  389. scWnd[wndCnt-1] = p->array[i].pitch;
  390. scIdxWnd[wndCnt-1] = i;
  391. ++wn;
  392. // if the window is full
  393. if(wn >= wndCnt )
  394. {
  395. // score the edit distance between the time line window and the edit window
  396. double dist = cmVOU_LevEditDist(wndCnt,mtx,scWnd,wndCnt,tlWnd,wndCnt,wndCnt);
  397. if( dist < minDist )
  398. minDist = dist;
  399. // update the match information in the time line window
  400. unsigned j;
  401. for(j=0; j<wndCnt; ++j)
  402. {
  403. // if the pitch matches and the score is less than the previous score
  404. if( scWnd[j] == tlWnd[j] && (tlObjWnd[j]->cnt == 0 || dist < tlObjWnd[j]->dist) )
  405. {
  406. tlObjWnd[j]->cnt += 1;
  407. tlObjWnd[j]->dist = dist;
  408. tlObjWnd[j]->scEvtIdx = scIdxWnd[j];
  409. }
  410. }
  411. }
  412. }
  413. return minDist;
  414. }
  415. cmScRC_t cmScoreSyncTimeLine( cmScH_t scH, cmTlH_t tlH, unsigned edWndCnt, cmReal_t maxSecs )
  416. {
  417. cmSc_t* p = _cmScHandleToPtr(scH);
  418. unsigned* edWndMtx = cmVOU_LevEditDistAllocMtx(edWndCnt);
  419. unsigned maxMicroSecs = floor(maxSecs*1000000);
  420. unsigned edWndData[ edWndCnt ];
  421. cmScSyncState_t* edWndObj[ edWndCnt ];
  422. // alloc a sync state record for each MIDI note-on in the time line
  423. _cmScSyncTimeLineAllocFree(tlH, true );
  424. // get the first time line object
  425. cmTlObj_t* rfp = cmTimeLineNextTypeObj(tlH,NULL,cmInvalidId,kMidiFileTlId);
  426. // interate through the time line in search of MIDI file objects
  427. for(; rfp != NULL; rfp = cmTimeLineNextTypeObj(tlH,rfp,cmInvalidId,kMidiFileTlId))
  428. {
  429. cmTlMidiFile_t* mfp = cmTimeLineMidiFileObjPtr(tlH,rfp);
  430. unsigned curEdWndCnt = 0;
  431. double prog = 0.1;
  432. unsigned progIdx = 0;
  433. cmRptPrintf(p->err.rpt,"MIDI File:%s\n", cmMidiFileName( mfp->h ));
  434. // get first midi event object
  435. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  436. // iterate through the time line in search of MIDI note-on events with belong to mfp
  437. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId) )
  438. {
  439. if( mep->obj.ref == rfp && mep->msg->status == kNoteOnMdId )
  440. {
  441. // If this notes inter-onset time is greater than maxMicroSecs
  442. // then dispose of the current window and begin refilling it again.
  443. if( mep->msg->dtick > maxMicroSecs )
  444. curEdWndCnt = 0;
  445. // shift window one slot to left
  446. unsigned i;
  447. for(i=0; i<edWndCnt-1; ++i)
  448. {
  449. edWndData[i] = edWndData[i+1];
  450. edWndObj[i] = edWndObj[i+1];
  451. }
  452. // fill window on right
  453. edWndData[edWndCnt-1] = mep->msg->u.chMsgPtr->d0; // d0=pitch
  454. edWndObj[ edWndCnt-1] = (cmScSyncState_t*)mep->obj.userDataPtr;
  455. ++curEdWndCnt;
  456. // if a complete window exists then update the time-line / score match state
  457. if( curEdWndCnt >= edWndCnt )
  458. _cmScWndEditDist( p, edWndMtx, edWndData, edWndObj, edWndCnt );
  459. // print the progress
  460. ++progIdx;
  461. if( progIdx >= prog * mfp->noteOnCnt )
  462. {
  463. cmRptPrintf(p->err.rpt,"%i ",(unsigned)round(prog*10));
  464. prog += 0.1;
  465. }
  466. }
  467. }
  468. cmRptPrintf(p->err.rpt,"\n");
  469. }
  470. _cmScPrintSyncState(p,tlH );
  471. // free sync state records
  472. _cmScSyncTimeLineAllocFree(tlH,false);
  473. cmMemFree(edWndMtx);
  474. return kOkScRC;
  475. }
  476. cmScRC_t cmScoreSyncTimeLineTest( cmCtx_t* ctx, const cmChar_t* timeLineJsFn, const cmChar_t* scoreCsvFn )
  477. {
  478. cmScRC_t rc = kOkScRC;
  479. cmTlH_t tlH = cmTimeLineNullHandle;
  480. cmScH_t scH = cmScNullHandle;
  481. unsigned edWndCnt = 7;
  482. cmReal_t maxSecs = 2.0;
  483. if((rc = cmTimeLineInitialize(ctx,&tlH,NULL,NULL)) != kOkTlRC )
  484. return cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line initialization failed.");;
  485. if((rc = cmTimeLineReadJson(tlH,timeLineJsFn)) != kOkTlRC )
  486. {
  487. rc = cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line parse failed.");;
  488. goto errLabel;
  489. }
  490. //cmTimeLinePrint(tlH,&ctx->rpt);
  491. if(1)
  492. {
  493. if((rc = cmScoreInitialize(ctx,&scH,scoreCsvFn)) != kOkScRC )
  494. goto errLabel;
  495. rc = cmScoreSyncTimeLine(scH, tlH, edWndCnt, maxSecs );
  496. }
  497. //cmScorePrint(scH, ctx->err.rpt );
  498. errLabel:
  499. cmScoreFinalize(&scH);
  500. cmTimeLineFinalize(&tlH);
  501. return rc;
  502. }
  503. void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
  504. {
  505. cmScH_t h = cmScNullHandle;
  506. if( cmScoreInitialize(ctx,&h,fn) != kOkScRC )
  507. return;
  508. cmScorePrint(h,&ctx->rpt);
  509. cmScoreFinalize(&h);
  510. }