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.

cmTakeSeqBldr.c 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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 "cmLinkedHeap.h"
  10. #include "cmJson.h"
  11. #include "cmTime.h"
  12. #include "cmMidi.h"
  13. #include "cmMidiFile.h"
  14. #include "cmAudioFile.h"
  15. #include "cmTimeLine.h"
  16. #include "cmSymTbl.h"
  17. #include "cmScore.h"
  18. #include "cmTakeSeqBldr.h"
  19. // Score track record: Map a score event to a MIDI event.
  20. typedef struct cmScTrkMidiTsb_str
  21. {
  22. unsigned mni; // MIDI note index as an offset from the take marker
  23. unsigned muid; // MIDI file msg unique id
  24. unsigned scEvtIdx; // score event index this note/pedal is assoc'd with or -1 if it did not match
  25. unsigned flags; // flags from cmScMatcherResult_t
  26. } cmScTrkMidiTsb_t;
  27. // Score Tracking info. from a single take (time-line marker)
  28. typedef struct cmScTrkTakeTsb_str
  29. {
  30. unsigned tlMarkerUid; // marker time line uid assoc'd with this take
  31. cmScTrkMidiTsb_t* midiV; // midiV[midiN] score to midi file map recd. array.
  32. unsigned midiN; // count of records in midiV[]
  33. unsigned minMuid; // min MIDI muid in midiV[]
  34. unsigned maxMuid; // max MIDI muid in midiV[]
  35. bool failFl;
  36. } cmScTrkTakeTsb_t;
  37. enum
  38. {
  39. kNoteTsbFl = 0x01,
  40. kPedalTsbFl = 0x02,
  41. kEnableTsbFl = 0x04
  42. };
  43. //
  44. typedef struct cmMidiTsb_str
  45. {
  46. unsigned srcId; // marker uid or -1 if this event was manually inserted
  47. unsigned scEvtIdx; // score event assocd with this midi event
  48. unsigned flags; // note | pedal | enable
  49. struct cmMidiTsb_str* ref; // previous MIDI event in time
  50. unsigned offsetSmp; // time offset from *ref
  51. unsigned durSmp; // duration of this MIDI event
  52. unsigned d0; // d0 MIDI channel msg data.
  53. unsigned d1; // d1 MIDI channel msg data
  54. struct cmMidiTsb_str* link; // pointer to next MIDI event in list
  55. } cmMidiTsb_t;
  56. // This record contains all the score events and and score synchronized MIDI events
  57. // associated with a given take. Each call to cmTakeSeqBldrLoadTake() creates
  58. // one of these records.
  59. typedef struct cmTakeTsb_str
  60. {
  61. unsigned tlMarkerUid; // time-line marker uid associated with this take
  62. cmMidiTsb_t* midi; // midi events contained by this take
  63. struct cmTakeTsb_str* link;
  64. } cmTakeTsb_t;
  65. typedef struct
  66. {
  67. cmCtx_t ctx; // application context
  68. cmErr_t err; // internal error object
  69. cmJsonH_t jsH; // JSON tree used to hold score tracker info.
  70. const cmChar_t* tlFn; // time line filename
  71. const cmChar_t* scFn; // score file name
  72. const cmChar_t* tlPrefixPath; // path to time line audio and MIDI files
  73. cmTlH_t tlH; // time-line handle
  74. cmScH_t scH; // score handle
  75. cmScTrkTakeTsb_t* scTrkTakeV; // score tracker scTrkTakeV[ scTrkTakeN ]
  76. unsigned scTrkTakeN;
  77. cmTakeTsb_t* takes; // list of loaded takes
  78. cmTakeTsb_t* manual; // list of manually inserted MIDI events
  79. cmTakeTsb_t* out; // render list
  80. } cmTsb_t;
  81. cmTakeSeqBldrH_t cmTakeSeqBldrNullHandle = cmSTATIC_NULL_HANDLE;
  82. cmTsb_t* _cmTsbHandleToPtr( cmTakeSeqBldrH_t h )
  83. {
  84. cmTsb_t* p = (cmTsb_t*)h.h;
  85. return p;
  86. }
  87. cmTsbRC_t _cmTsbScoreTrkFree( cmTsb_t* p )
  88. {
  89. cmTsbRC_t rc = kOkTsbRC;
  90. unsigned i;
  91. if( cmJsonFinalize(&p->jsH) != kOkJsRC )
  92. {
  93. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON object finalize failed.");
  94. goto errLabel;
  95. }
  96. if( p->scTrkTakeV != NULL )
  97. {
  98. for(i=0; i<p->scTrkTakeN; ++i)
  99. cmMemPtrFree(&p->scTrkTakeV[i].midiV);
  100. cmMemPtrFree(&p->scTrkTakeV);
  101. }
  102. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  103. rc = cmErrMsg(&p->err,kTimeLineFailTsbRC,"Time line object finalize failed.");
  104. if( cmScoreFinalize(&p->scH) != kOkScRC )
  105. rc = cmErrMsg(&p->err,kScoreFailTsbRC,"Score finalize failed.");
  106. errLabel:
  107. return rc;
  108. }
  109. // Free a take record. Note that the record must be unlinked
  110. // unlinked from p->takes (See _cmTakeTsbUnlink().) prior to calling this function.
  111. void _cmTsbTakeFree( cmTsb_t* p, cmTakeTsb_t** tp )
  112. {
  113. if( tp == NULL || *tp==NULL )
  114. return;
  115. cmMidiTsb_t* m = (*tp)->midi;
  116. while( m != NULL )
  117. {
  118. cmMidiTsb_t* nm = m->link;
  119. cmMemFree(m);
  120. m = nm;
  121. }
  122. cmMemPtrFree(tp);
  123. }
  124. // Unlink a 'take' record from p->takes.
  125. cmTakeTsb_t* _cmTsbTakeUnlink( cmTsb_t* p, cmTakeTsb_t* t )
  126. {
  127. cmTakeTsb_t* t0 = NULL;
  128. cmTakeTsb_t* t1 = p->takes;
  129. while( t1 != NULL )
  130. {
  131. if( t1 == t )
  132. {
  133. if( t0 == NULL )
  134. p->takes = t->link;
  135. else
  136. t0->link = t1->link;
  137. return t;
  138. }
  139. }
  140. return NULL;
  141. }
  142. cmTsbRC_t _cmTsbFree( cmTsb_t* p )
  143. {
  144. cmTsbRC_t rc = kOkTsbRC;
  145. if((rc = _cmTsbScoreTrkFree(p)) != kOkTsbRC )
  146. goto errLabel;
  147. cmTakeTsb_t* t = p->takes;
  148. while( t != NULL )
  149. {
  150. cmTakeTsb_t* nt = t->link;
  151. _cmTsbTakeFree(p,&t);
  152. t = nt;
  153. }
  154. _cmTsbTakeFree(p,&p->out);
  155. cmMemFree(p);
  156. errLabel:
  157. return rc;
  158. }
  159. cmScTrkTakeTsb_t* _cmTsbMarkerIdToScTrkTake( cmTsb_t* p, unsigned markerUid )
  160. {
  161. unsigned i;
  162. for(i=0; p->scTrkTakeN; ++i)
  163. if( p->scTrkTakeV[i].tlMarkerUid == markerUid )
  164. return p->scTrkTakeV + i;
  165. return NULL;
  166. }
  167. cmScTrkMidiTsb_t* _cmTsbMuidToScTrkMidi( cmScTrkTakeTsb_t* t, unsigned muid )
  168. {
  169. unsigned i;
  170. for(i=0; i<t->midiN; ++i)
  171. if( t->midiV[i].muid == muid )
  172. return t->midiV + i;
  173. return NULL;
  174. }
  175. cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
  176. {
  177. cmTsbRC_t rc = kOkTsbRC;
  178. cmJsonNode_t* tkArrObj = NULL;
  179. cmJsRC_t jsRC = kOkJsRC;
  180. const cmChar_t* errMsg = NULL;
  181. unsigned i;
  182. // initialize the TSB json object
  183. if(( rc = cmJsonInitializeFromFile(&p->jsH,scoreTrkFn,&p->ctx)) != kOkJsRC )
  184. {
  185. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"The Take Sequence Builder JSON file object could not be initialized from '%s'.",cmStringNullGuard(scoreTrkFn));
  186. goto errLabel;
  187. }
  188. // parse the header
  189. if((jsRC = cmJsonMemberValues( cmJsonRoot(p->jsH), &errMsg,
  190. "timeLineFn", kStringTId, &p->tlFn,
  191. "scoreFn", kStringTId, &p->scFn,
  192. "tlPrefixPath", kStringTId, &p->tlPrefixPath,
  193. "takeArray", kArrayTId | kOptArgJsFl, &tkArrObj,
  194. NULL )) != kOkJsRC )
  195. {
  196. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  197. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed missing required field:'%s'",errMsg);
  198. else
  199. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed.");
  200. goto errLabel;
  201. }
  202. // count of take records
  203. p->scTrkTakeN = cmJsonChildCount(tkArrObj);
  204. // array of take records
  205. p->scTrkTakeV = cmMemAllocZ(cmScTrkTakeTsb_t,p->scTrkTakeN);
  206. // for each take record
  207. for(i=0; i<p->scTrkTakeN; ++i)
  208. {
  209. cmJsonNode_t* takeObj = NULL;
  210. cmJsonNode_t* noteArrObj = NULL;
  211. cmScTrkTakeTsb_t* t = p->scTrkTakeV + i;
  212. unsigned j;
  213. // get a pointer to the take record JSON object
  214. if((takeObj = cmJsonArrayElement(tkArrObj,i)) == NULL )
  215. {
  216. rc = cmErrMsg(&p->err,kParseFailTsbRC,"Take record header at index %i access failed.",i);
  217. goto errLabel;
  218. }
  219. // parse the take record
  220. if((jsRC = cmJsonMemberValues( takeObj, &errMsg,
  221. "markerUid",kIntTId, &t->tlMarkerUid,
  222. "failFl", kIntTId, &t->failFl,
  223. "array", kArrayTId, &noteArrObj,
  224. NULL)) != kOkJsRC )
  225. {
  226. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  227. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed missing required field:'%s'",errMsg);
  228. else
  229. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed.");
  230. goto errLabel;
  231. }
  232. // get the count of note records
  233. t->midiN = cmJsonChildCount(noteArrObj);
  234. // allocate a note record array for this take
  235. t->midiV = cmMemAllocZ(cmScTrkMidiTsb_t, t->midiN);
  236. t->minMuid = INT_MAX;
  237. t->maxMuid = 0;
  238. // for each note record
  239. for(j=0; j<t->midiN; ++j)
  240. {
  241. cmJsonNode_t* noteObj = NULL;
  242. // get the note record JSON object
  243. if((noteObj = cmJsonArrayElement(noteArrObj,j)) == NULL )
  244. {
  245. rc = cmErrMsg(&p->err,kParseFailTsbRC,"Access failed for note record at index %i at take index %i.",j,i);
  246. goto errLabel;
  247. }
  248. // parse the note record
  249. if((jsRC = cmJsonMemberValues( noteObj, &errMsg,
  250. "mni", kIntTId, &t->midiV[j].mni,
  251. "muid", kIntTId, &t->midiV[j].muid,
  252. "scEvtIdx", kIntTId, &t->midiV[j].scEvtIdx,
  253. "flags", kIntTId, &t->midiV[j].flags,
  254. NULL)) != kOkJsRC )
  255. {
  256. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  257. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed missing required field:'%s'",errMsg);
  258. else
  259. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed.");
  260. goto errLabel;
  261. }
  262. if( t->midiV[j].muid < t->minMuid )
  263. t->minMuid = t->midiV[j].muid;
  264. if( t->midiV[j].muid > t->maxMuid )
  265. t->maxMuid = t->midiV[j].muid;
  266. }
  267. }
  268. errLabel:
  269. if( rc != kOkTsbRC )
  270. rc = _cmTsbScoreTrkFree(p);
  271. return rc;
  272. }
  273. cmTsbRC_t _cmTakeSeqBldrRender( cmTsb_t* p )
  274. {
  275. cmTsbRC_t rc = kOkTsbRC;
  276. _cmTsbTakeFree(p,&p->out);
  277. // get the min/max scEvtIdx among all takes
  278. cmTakeTsb_t* t = p->takes;
  279. cmMidiTsb_t* m = NULL;
  280. unsigned minScEvtIdx = INT_MAX;
  281. unsigned maxScEvtIdx = 0;
  282. unsigned i;
  283. for(; t!=NULL; t=t->link)
  284. {
  285. for(m=t->midi; m!=NULL; m=m->link)
  286. {
  287. if( m->scEvtIdx < minScEvtIdx )
  288. minScEvtIdx = m->scEvtIdx;
  289. if( m->scEvtIdx > maxScEvtIdx )
  290. maxScEvtIdx = m->scEvtIdx;
  291. }
  292. }
  293. p->out = cmMemAllocZ(cmTakeTsb_t,1);
  294. // allocate one event for each score postion to render
  295. cmMidiTsb_t* m0 = NULL;
  296. for(i=0; i<maxScEvtIdx-minScEvtIdx+1; ++i)
  297. {
  298. m = cmMemAllocZ(cmMidiTsb_t,1);
  299. m->srcId = cmInvalidId;
  300. m->scEvtIdx = minScEvtIdx + i;
  301. m->ref = m0;
  302. m0 = m;
  303. if( p->out->midi == NULL )
  304. p->out->midi = m;
  305. }
  306. // fill the event list from the selected takes
  307. for(t=p->takes; t!=NULL; t=t->link)
  308. {
  309. }
  310. if( rc != kOkTsbRC )
  311. _cmTsbTakeFree(p,&p->out);
  312. return rc;
  313. }
  314. cmTsbRC_t cmTakeSeqBldrAlloc( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp )
  315. {
  316. cmTsbRC_t rc;
  317. if((rc = cmTakeSeqBldrFree(hp)) != kOkTsbRC )
  318. return kOkTsbRC;
  319. cmTsb_t* p = cmMemAllocZ(cmTsb_t,1);
  320. cmErrSetup(&p->err,&ctx->rpt,"TakeSeqBldr");
  321. p->ctx = *ctx;
  322. hp->h = p;
  323. return rc;
  324. }
  325. cmTsbRC_t cmTakeSeqBldrAllocFn( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp, const cmChar_t* scoreTrkFn )
  326. {
  327. cmTsbRC_t rc;
  328. if((rc = cmTakeSeqBldrAlloc(ctx,hp)) != kOkTsbRC )
  329. return rc;
  330. if((rc = cmTakeSeqBldrInitialize(*hp,scoreTrkFn)) != kOkTsbRC )
  331. return rc;
  332. return rc;
  333. }
  334. cmTsbRC_t cmTakeSeqBldrFree( cmTakeSeqBldrH_t* hp )
  335. {
  336. cmRC_t rc = kOkTsbRC;
  337. if( hp == NULL || cmTakeSeqBldrIsValid(*hp)==false )
  338. return kOkTsbRC;
  339. cmTsb_t* p = _cmTsbHandleToPtr(*hp);
  340. if((rc = _cmTsbFree(p)) != kOkTsbRC )
  341. return rc;
  342. hp->h = NULL;
  343. return rc;
  344. }
  345. bool cmTakeSeqBldrIsValid( cmTakeSeqBldrH_t h )
  346. { return h.h != NULL; }
  347. cmTsbRC_t cmTakeSeqBldrInitialize( cmTakeSeqBldrH_t h, const cmChar_t* scoreTrkFn )
  348. {
  349. cmTsbRC_t rc = kOkTsbRC;
  350. cmTsb_t* p = _cmTsbHandleToPtr(h);
  351. if(( rc = _cmTsbLoadScoreTrkFile( p, scoreTrkFn )) != kOkTsbRC )
  352. return rc;
  353. if( cmTimeLineInitializeFromFile(&p->ctx, &p->tlH, NULL, NULL, p->tlFn, p->tlPrefixPath ) != kOkTlRC )
  354. {
  355. rc = cmErrMsg(&p->err,kTimeLineFailTsbRC,"The time-line file '%s' could not be loaded.",p->tlFn);
  356. goto errLabel;
  357. }
  358. if( cmScoreInitialize(&p->ctx, &p->scH, p->scFn, 0, NULL, 0, NULL, NULL, cmSymTblNullHandle ) != kOkScRC )
  359. {
  360. rc = cmErrMsg(&p->err,kScoreFailTsbRC,"The score file '%s' could not be loaded.",p->scFn);
  361. goto errLabel;
  362. }
  363. errLabel:
  364. if( rc != kOkTsbRC )
  365. _cmTsbScoreTrkFree(p);
  366. return rc;
  367. }
  368. cmTakeTsb_t* _cmTsbMarkerUidToTake( cmTsb_t* p, unsigned tlMarkerUid )
  369. {
  370. cmTakeTsb_t* t = p->takes;
  371. for(; t != NULL; t=t->link)
  372. if( t->tlMarkerUid == tlMarkerUid )
  373. return t;
  374. return NULL;
  375. }
  376. cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool overwriteFL )
  377. {
  378. cmTsbRC_t rc = kOkTsbRC;
  379. cmTsb_t* p = _cmTsbHandleToPtr(h);
  380. cmTlMarker_t* mark = NULL;
  381. cmTlMidiFile_t* mf = NULL;
  382. cmMidiFileH_t mfH = cmMidiFileNullHandle;
  383. cmScTrkTakeTsb_t* stt = NULL;
  384. // verify that the requested take has not already been loaded
  385. if( _cmTsbMarkerUidToTake( p, tlMarkUid ) != NULL )
  386. {
  387. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i has already been loaded.",tlMarkUid );
  388. goto errLabel;
  389. }
  390. // find the score tracked take for the requested marker
  391. if((stt = _cmTsbMarkerIdToScTrkTake(p,tlMarkUid )) == NULL )
  392. {
  393. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The score tracked take indicated by marker id %i could not be found.", tlMarkUid );
  394. goto errLabel;
  395. }
  396. // get a pointer to the time-line marker object
  397. if((mark = cmTlMarkerObjPtr( p->tlH, cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkUid))) == NULL )
  398. {
  399. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker uid '%i' is not valid.",tlMarkUid);
  400. goto errLabel;
  401. }
  402. // get the name of the MIDI file which contains the marker
  403. if((mf = cmTimeLineMidiFileAtTime( p->tlH, mark->obj.seqId, mark->obj.seqSmpIdx )) == NULL )
  404. {
  405. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker '%i' does not intersect with a MIDI file.",tlMarkUid);
  406. goto errLabel;
  407. }
  408. // open the MIDI file
  409. if( cmMidiFileOpen( cmMidiFileName(mf->h), &mfH, &p->ctx ) != kOkMfRC )
  410. {
  411. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The MIDI file '%s' could not be opened.", cmStringNullGuard(cmMidiFileName(mf->h)));
  412. goto errLabel;
  413. }
  414. // convert the dtick field to absolute sample indexes
  415. cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), true );
  416. // calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
  417. cmMidiFileCalcNoteDurations( mfH );
  418. unsigned i = 0;
  419. unsigned n = cmMidiFileMsgCount(mfH);
  420. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(mfH);
  421. // allocate and link a new take render record
  422. cmTakeTsb_t* t = cmMemAllocZ(cmTakeTsb_t,1);
  423. t->tlMarkerUid = tlMarkUid;
  424. t->link = p->takes;
  425. p->takes = t;
  426. cmMidiTsb_t* m0 = NULL;
  427. const cmMidiTrackMsg_t* mf0 = NULL;
  428. // for each MIDI message in the file
  429. for(i=0; i<n; ++i)
  430. {
  431. const cmMidiTrackMsg_t* mf1 = a[i];
  432. // we are only interested in rendering notes and control msgs
  433. switch( mf1->status )
  434. {
  435. case kNoteOnMdId:
  436. case kNoteOffMdId:
  437. case kCtlMdId:
  438. break;
  439. default:
  440. continue;
  441. }
  442. // if this MIDI message is inside the tracked region of the take
  443. if( stt->minMuid > mf1->uid || mf1->uid > stt->maxMuid )
  444. continue;
  445. // get a pointer to the tracking map
  446. cmScTrkMidiTsb_t* stm = _cmTsbMuidToScTrkMidi(stt, mf1->uid );
  447. // create a MIDI render event
  448. cmMidiTsb_t* m1 = cmMemAllocZ(cmMidiTsb_t,1);
  449. m1->srcId = tlMarkUid;
  450. m1->scEvtIdx = stm != NULL ? stm->scEvtIdx : cmInvalidIdx;
  451. m1->flags = stm != NULL ? stm->flags : 0;
  452. m1->ref = m0;
  453. m1->offsetSmp = mf0 == NULL ? 0 : mf1->dtick - mf0->dtick;
  454. m1->durSmp = mf1->u.chMsgPtr->durTicks;
  455. m1->d0 = mf1->u.chMsgPtr->d0;
  456. m1->d1 = mf1->u.chMsgPtr->d1;
  457. m1->link = NULL;
  458. if( m0 != NULL )
  459. m0->link = m1;
  460. if( t->midi == NULL )
  461. t->midi = m1;
  462. m0 = m1;
  463. mf0 = mf1;
  464. }
  465. errLabel:
  466. if( cmMidiFileClose(&mfH) != kOkMfRC )
  467. rc = cmErrMsg(&p->err,kMidiFileFailTsbRC,"MIDI file close failed.");
  468. return rc;
  469. }
  470. cmTsbRC_t cmTakeSeqBldrUnloadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid )
  471. {
  472. cmTsbRC_t rc = kOkTsbRC;
  473. cmTsb_t* p = _cmTsbHandleToPtr(h);
  474. cmTakeTsb_t* t;
  475. if((t = _cmTsbMarkerUidToTake(p, tlMarkUid )) == NULL )
  476. return cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i could not be found.",tlMarkUid);
  477. t = _cmTsbTakeUnlink(p,t);
  478. assert( t != NULL );
  479. _cmTsbTakeFree(p,&t);
  480. return rc;
  481. }
  482. cmTsbRC_t cmTakeSeqBldrInsertScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId )
  483. {
  484. cmTsbRC_t rc = kOkTsbRC;
  485. return rc;
  486. }
  487. cmTsbRC_t cmTakeSeqBldrRemoveScoreNotes( cmTakeSeqBldrH_t h, unsigned begScEvtIdx, unsigned endScEvtId )
  488. {
  489. cmTsbRC_t rc = kOkTsbRC;
  490. return rc;
  491. }
  492. cmTsbRC_t cmTakeSeqBldrSelectEnable( cmTakeSeqBldrH_t h, unsigned flags, unsigned id, bool selectFl )
  493. {
  494. cmTsbRC_t rc = kOkTsbRC;
  495. return rc;
  496. }
  497. cmTsbRC_t cmTakeSeqBldrEnableNote( cmTakeSeqBldrH_t h, unsigned ssqId, bool enableFl )
  498. {
  499. cmTsbRC_t rc = kOkTsbRC;
  500. return rc;
  501. }
  502. cmTsbRC_t cmTakeSeqBldrMoveNote( cmTakeSeqBldrH_t h, unsigned ssqId, int deltaSmpIdx )
  503. {
  504. cmTsbRC_t rc = kOkTsbRC;
  505. return rc;
  506. }
  507. cmTsbRC_t cmTakeSeqBldrWriteMidiFile( cmTakeSeqBldrH_t h, const char* fn )
  508. {
  509. cmTsbRC_t rc = kOkTsbRC;
  510. return rc;
  511. }
  512. cmTsbRC_t cmTakeSeqBldrTest( cmCtx_t* ctx )
  513. {
  514. const cmChar_t* scoreTrkFn = "/home/kevin/src/cmkc/src/kc/data/takeSeqBldr0.js";
  515. cmTakeSeqBldrH_t tsbH = cmTakeSeqBldrNullHandle;
  516. cmTsbRC_t tsbRC = kOkTsbRC;
  517. unsigned markerIdV[] = { 2200, 2207 };
  518. unsigned markerN = sizeof(markerIdV)/sizeof(markerIdV[0]);
  519. unsigned i;
  520. if((tsbRC = cmTakeSeqBldrAllocFn(ctx, &tsbH, scoreTrkFn )) != kOkTsbRC )
  521. return cmErrMsg(&ctx->err,tsbRC,"TSB Allocate and parse '%s' failed.",scoreTrkFn);
  522. cmRptPrintf(&ctx->rpt, "TakeSeqBldr Allocation Completed.");
  523. for(i=0; i<markerN; ++i)
  524. {
  525. if((tsbRC = cmTakeSeqBldrLoadTake(tsbH,markerIdV[i],false)) != kOkTsbRC )
  526. cmErrMsg(&ctx->err,tsbRC,"TSB load take failed.");
  527. cmRptPrintf(&ctx->rpt, "TakeSeqBldr Load Take %i Completed.",markerIdV[i]);
  528. }
  529. if((tsbRC = cmTakeSeqBldrFree(&tsbH)) != kOkTsbRC )
  530. return cmErrMsg(&ctx->err,tsbRC,"TSB Free failed.");
  531. return tsbRC;
  532. }