libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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. }