libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmTakeSeqBldr.c 42KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620
  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 "cmFile.h"
  18. #include "cmScore.h"
  19. #include "cmTakeSeqBldr.h"
  20. // Score track record: Map a score event to a MIDI event.
  21. typedef struct cmScTrkMidiTsb_str
  22. {
  23. unsigned mni; // MIDI note index as an offset from the take marker
  24. unsigned muid; // MIDI file msg unique id
  25. unsigned scEvtIdx; // score event index this note/pedal is assoc'd with or -1 if it did not match
  26. unsigned flags; // flags from cmScMatcherResult_t
  27. } cmScTrkMidiTsb_t;
  28. // Score Tracking info. from a single take (time-line marker)
  29. typedef struct cmScTrkTakeTsb_str
  30. {
  31. unsigned tlMarkerUid; // marker time line uid assoc'd with this take
  32. cmScTrkMidiTsb_t* midiV; // midiV[midiN] score to midi file map recd. array.
  33. unsigned midiN; // count of records in midiV[]
  34. unsigned minMuid; // min MIDI muid in midiV[]
  35. unsigned maxMuid; // max MIDI muid in midiV[]
  36. unsigned minScEvtIdx; // min scEvtIdx in midiV[]
  37. unsigned maxScEvtIdx; // max scEvtIdx in midiV[]
  38. bool failFl;
  39. } cmScTrkTakeTsb_t;
  40. //
  41. typedef struct cmMidiTsb_str
  42. {
  43. unsigned rid; // unique id among all object in this take
  44. unsigned srcId; // marker uid or -1 if this event was manually inserted
  45. unsigned scEvtIdx; // score event assocd with this midi event
  46. unsigned flags; // copy of cmScTrkMidiTsb_t.flags or 0 if not assoc'd with a score event
  47. struct cmMidiTsb_str* ref; // previous MIDI event in time
  48. unsigned offsetSmp; // time offset from *ref
  49. unsigned durSmp; // duration of this MIDI event
  50. unsigned status; // MIDI status value
  51. unsigned d0; // d0 MIDI channel msg data byte 0.
  52. unsigned d1; // d1 MIDI channel msg data byte 1.
  53. struct cmMidiTsb_str* link; // pointer to next MIDI event in list
  54. } cmMidiTsb_t;
  55. // This record contains all the score events and and score synchronized MIDI events
  56. // associated with a given take. Each call to cmTakeSeqBldrLoadTake() creates
  57. // one of these records.
  58. typedef struct cmTakeTsb_str
  59. {
  60. unsigned tlMarkerUid; // time-line marker uid associated with this take
  61. cmScTrkTakeTsb_t* stt; // score tracking info
  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 file info scTrkTakeV[ scTrkTakeN ]
  76. unsigned scTrkTakeN; // (one record per take)
  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. cmMidiTsb_t* evt; // next event to play from the render list
  81. unsigned absPlaySmp; // absolute sample index of the clock
  82. unsigned absEvtSmp; // absolute sample index of the next event to play
  83. unsigned nextRid;
  84. cmMidiTsb_t* rend;
  85. } cmTsb_t;
  86. cmTakeSeqBldrH_t cmTakeSeqBldrNullHandle = cmSTATIC_NULL_HANDLE;
  87. cmTsb_t* _cmTsbHandleToPtr( cmTakeSeqBldrH_t h )
  88. {
  89. cmTsb_t* p = (cmTsb_t*)h.h;
  90. return p;
  91. }
  92. //-------------------------------------------------------------------------------------------------------------------------
  93. typedef struct cmOrderTsb_str
  94. {
  95. cmTakeTsb_t* t;
  96. unsigned minScEvtIdx; // take begin
  97. unsigned maxScEvtIdx; // take end
  98. unsigned begScEvtIdx; // render begin (render beg/end is always contained
  99. unsigned endScEvtIdx; // render end withing min/maxScEvtIdx)
  100. struct cmOrderTsb_str* link;
  101. } cmOrderTsb_t;
  102. // Notes:
  103. // 1) begScEvtIdx - endScEvtIdx is always contained within minScEvtIdx-maxScEvtIdx.
  104. // 2) If begScEvtIdx == cmInvalidIdx then the take was entirely contained inside the
  105. // previous take and is therefore skipped over.
  106. // Free a linked list of cmOrderTsb_t records
  107. void _cmTakeSeqBldrFreeOrder( cmOrderTsb_t* o )
  108. {
  109. while(o!=NULL)
  110. {
  111. cmOrderTsb_t* o0 = o->link;
  112. cmMemFree(o);
  113. o = o0;
  114. }
  115. }
  116. // Create a linked list of cmOrderTsb_t records from the p->takes list.
  117. cmOrderTsb_t* _cmTakeSeqBldrAllocOrder( cmTsb_t* p )
  118. {
  119. cmOrderTsb_t* o = NULL;
  120. cmOrderTsb_t* o0 = NULL;
  121. cmTakeTsb_t* t = p->takes;
  122. // create a list of order records - one per take
  123. for(; t!=NULL; t=t->link)
  124. if( t->stt != NULL )
  125. {
  126. cmOrderTsb_t* o1 = cmMemAllocZ(cmOrderTsb_t,1);
  127. o1->t = t;
  128. o1->minScEvtIdx = t->stt->minScEvtIdx;
  129. o1->maxScEvtIdx = t->stt->maxScEvtIdx;
  130. o1->begScEvtIdx = o1->minScEvtIdx;
  131. o1->endScEvtIdx = o1->maxScEvtIdx;
  132. if( o0 == NULL )
  133. o = o1;
  134. else
  135. o0->link = o1;
  136. o0 = o1;
  137. }
  138. return o;
  139. }
  140. // Sort a list of cmOrderTsb_t records on minScEvtIdx.
  141. cmOrderTsb_t* _cmTakeSeqBldrSortOrder( cmOrderTsb_t* o )
  142. {
  143. cmOrderTsb_t* beg = NULL;
  144. cmOrderTsb_t* end = NULL;
  145. cmOrderTsb_t* m = NULL;
  146. // while elements remain on the unordered list
  147. while( o != NULL )
  148. {
  149. cmOrderTsb_t* c0 = NULL;
  150. cmOrderTsb_t* c1 = o->link;
  151. m = o;
  152. // set m to point to the recd with the min minScEvtIdx
  153. for(; c1!=NULL; c1=c1->link )
  154. if( c1->minScEvtIdx < m->minScEvtIdx )
  155. m = c1;
  156. // for each recd on the unordered list
  157. for(c1=o; c1!=NULL; c1=c1->link)
  158. {
  159. // if this is the min record
  160. if( c1==m )
  161. {
  162. // remove the min recd from this list
  163. if( c0 == NULL )
  164. o = c1->link;
  165. else
  166. c0->link = c1->link;
  167. c1->link = NULL;
  168. break;
  169. }
  170. c0 = c1;
  171. }
  172. // c1 now points to the min record
  173. assert(c1==m);
  174. if( end == NULL )
  175. beg = end = m;
  176. else
  177. {
  178. end->link = m;
  179. end = m;
  180. }
  181. }
  182. return beg;
  183. }
  184. // Set the begScEvtIdx and endScEvtIdx fields to settle conflicts
  185. // between overlapping takes.
  186. void _cmTakeSeqBldrSetBegEndOrder( cmOrderTsb_t* o )
  187. {
  188. if( o == NULL )
  189. return;
  190. // Earlier takes have priority over later takes so the first
  191. // take has highest priority and therefore it's beg=min and end=max.
  192. o->begScEvtIdx = o->minScEvtIdx;
  193. o->endScEvtIdx = o->maxScEvtIdx;
  194. cmOrderTsb_t* o0 = o;
  195. cmOrderTsb_t* o1 = o->link;
  196. while( o1!=NULL)
  197. {
  198. bool skipFl = false;
  199. // if this take begins after the previous take
  200. if( o1->minScEvtIdx > o0->endScEvtIdx )
  201. {
  202. o1->begScEvtIdx = o1->minScEvtIdx;
  203. o1->endScEvtIdx = o1->maxScEvtIdx;
  204. }
  205. else
  206. {
  207. // if this take is entirely contained in the previous take
  208. // then this take is skipped.
  209. if( o0->endScEvtIdx > o1->maxScEvtIdx )
  210. {
  211. o1->begScEvtIdx = cmInvalidIdx;
  212. o1->endScEvtIdx = cmInvalidIdx;
  213. skipFl = true;
  214. }
  215. else // this take overlaps with the previous take
  216. {
  217. o1->begScEvtIdx = o0->endScEvtIdx + 1;
  218. o1->endScEvtIdx = o1->maxScEvtIdx;
  219. }
  220. }
  221. if( skipFl )
  222. {
  223. // the current take is being skipped so do not change o0
  224. o1 = o1->link;
  225. }
  226. else
  227. {
  228. // advance to the next take
  229. o0 = o1;
  230. o1 = o0->link;
  231. }
  232. }
  233. }
  234. void _cmTakeSeqBldrPrintOrder( cmOrderTsb_t* o )
  235. {
  236. int i;
  237. for(i=0; o!=NULL; o=o->link,++i)
  238. printf("%i : %p min:%i max:%i beg:%i end:%i\n",i, o->t, o->minScEvtIdx, o->maxScEvtIdx, o->begScEvtIdx, o->endScEvtIdx);
  239. printf("\n");
  240. }
  241. //-------------------------------------------------------------------------------------------------------------------------
  242. typedef struct
  243. {
  244. cmScoreEvt_t* sep;
  245. unsigned absSmp;
  246. } cmTsbTempo_t;
  247. void _cmTsbTempoPrint( cmTsbTempo_t* r, unsigned rN )
  248. {
  249. unsigned i;
  250. for(i=0; i<rN; ++i)
  251. printf("%s %i\n",cmScEvtTypeIdToLabel(r[i].sep->type),r[i].absSmp);
  252. printf("\n");
  253. }
  254. cmTsbTempo_t* _cmTsbTempoFind( cmTsbTempo_t* r, unsigned rN, unsigned scEvtIdx )
  255. {
  256. unsigned i;
  257. for(i=0; i<rN; ++i)
  258. if( r[i].sep->index == scEvtIdx )
  259. return r + i;
  260. return NULL;
  261. }
  262. // Starting at r[ri] calc the tempo for the next two bars.
  263. unsigned _cmTsbTempoCalc( cmTsbTempo_t* r, unsigned rN, unsigned ri, double srate )
  264. {
  265. unsigned durBarCnt = 2;
  266. unsigned barIdx = 0;
  267. double beats = 0;
  268. unsigned abs0Smp = -1;
  269. unsigned abs1Smp = -1;
  270. for(; ri<rN; ++ri)
  271. {
  272. // if this is a note event
  273. if( r[ri].sep->type == kNonEvtScId )
  274. {
  275. beats += r[ri].sep->frac;
  276. if( abs0Smp == -1 )
  277. abs0Smp = r[ri].absSmp;
  278. if( r[ri].absSmp != -1 )
  279. abs1Smp = r[ri].absSmp;
  280. }
  281. // if this is a bar event
  282. if( r[ri].sep->type == kBarEvtScId )
  283. {
  284. barIdx += 1;
  285. if( barIdx == durBarCnt )
  286. break;
  287. }
  288. }
  289. double durSmp = abs1Smp - abs0Smp;
  290. if( durSmp == 0 )
  291. return 0;
  292. return (unsigned)round(beats / (durSmp / (srate * 60.0)));
  293. }
  294. cmTsbRC_t _cmTsbCalcTempo( cmTsb_t* p, cmTakeTsb_t* t, unsigned* begBpSRef, unsigned* endBpSRef )
  295. {
  296. unsigned i,j;
  297. assert( begBpSRef != NULL && endBpSRef != NULL );
  298. *begBpSRef = 0;
  299. *endBpSRef = 0;
  300. if( t->stt == NULL )
  301. return cmErrMsg(&p->err,kMissingScTrkTsbRC,"The tempo of takes without score-tracking results cannot be calculated.");
  302. if( t->midi == NULL )
  303. return cmErrMsg(&p->err,kInvalidArgTsbRC,"The tempo of a take without MIDI events cannot be estimated.");
  304. // allocate an array to with one record per score event in the take
  305. unsigned rN = t->stt->maxScEvtIdx - t->stt->minScEvtIdx + 1;
  306. cmTsbTempo_t r[ rN ];
  307. // assign a score event pointer to each record
  308. for(i=0; i<rN; ++i)
  309. {
  310. r[i].sep = cmScoreEvt(p->scH,t->stt->minScEvtIdx + i);
  311. assert( r[i].sep != NULL );
  312. r[i].absSmp = -1;
  313. }
  314. // use MIDI events with score information to assign absolute
  315. // time information to as many score events as possible.
  316. unsigned absSmp = 0;
  317. cmMidiTsb_t* m = t->midi;
  318. while( m!=NULL )
  319. {
  320. cmTsbTempo_t* r0 = NULL;
  321. if( m->scEvtIdx != cmInvalidIdx && (r0 = _cmTsbTempoFind(r,rN,m->scEvtIdx)) != NULL )
  322. {
  323. assert( r0->sep->type == kNonEvtScId );
  324. r0->absSmp = absSmp;
  325. }
  326. m = m->link;
  327. if( m != NULL )
  328. absSmp += m->offsetSmp;
  329. }
  330. unsigned barCnt = 0;
  331. // assign an absolute time to each bar recd
  332. for(i=0; i<rN; ++i)
  333. if( r[i].sep->type == kBarEvtScId )
  334. {
  335. barCnt += 1; // count the number of bars found
  336. // search ahead from the bar to the next note
  337. unsigned j;
  338. for(j=i; j<rN; ++j)
  339. if( r[j].sep->type == kNonEvtScId )
  340. {
  341. r[i].absSmp = r[j].absSmp; // the bar time is the same as the next
  342. break;
  343. }
  344. }
  345. //_cmTsbTempoPrint(r,rN);
  346. unsigned tempoV[ barCnt ];
  347. for(i=0,j=0; i<rN && j<barCnt; ++i)
  348. {
  349. tempoV[j++] = _cmTsbTempoCalc(r, rN, i, cmTimeLineSampleRate(p->tlH) );
  350. for(; i<rN; ++i)
  351. if( r[i].sep->type == kBarEvtScId )
  352. break;
  353. }
  354. if( j > 0 )
  355. {
  356. *begBpSRef = tempoV[0];
  357. *endBpSRef = tempoV[j-1];
  358. }
  359. printf("Bars:%i ",barCnt);
  360. for(i=0; i<j; ++i)
  361. printf("%i ",tempoV[i]);
  362. printf("\n");
  363. return kOkTsbRC;
  364. }
  365. //-------------------------------------------------------------------------------------------------------------------------
  366. void _cmTsbPrintMidi( cmTakeTsb_t* t )
  367. {
  368. if( t==NULL )
  369. return;
  370. cmMidiTsb_t* m = t->midi;
  371. for(; m!=NULL; m=m->link)
  372. printf("mark:%4i sei:%4i fl:0x%x offs:%8i dur:%8i\n", m->srcId, m->scEvtIdx,m->flags,m->offsetSmp,m->durSmp);
  373. printf("\n");
  374. }
  375. void _cmTsbTakePrint( cmTakeTsb_t* t )
  376. {
  377. for(; t!=NULL; t=t->link)
  378. {
  379. printf("Take:%i %p\n", t->tlMarkerUid, t->stt);
  380. _cmTsbPrintMidi(t);
  381. }
  382. }
  383. cmTsbRC_t _cmTsbScoreTrkFree( cmTsb_t* p )
  384. {
  385. cmTsbRC_t rc = kOkTsbRC;
  386. unsigned i;
  387. if( cmJsonFinalize(&p->jsH) != kOkJsRC )
  388. {
  389. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON object finalize failed.");
  390. goto errLabel;
  391. }
  392. if( p->scTrkTakeV != NULL )
  393. {
  394. for(i=0; i<p->scTrkTakeN; ++i)
  395. cmMemPtrFree(&p->scTrkTakeV[i].midiV);
  396. cmMemPtrFree(&p->scTrkTakeV);
  397. }
  398. if( cmTimeLineFinalize(&p->tlH) != kOkTlRC )
  399. rc = cmErrMsg(&p->err,kTimeLineFailTsbRC,"Time line object finalize failed.");
  400. if( cmScoreFinalize(&p->scH) != kOkScRC )
  401. rc = cmErrMsg(&p->err,kScoreFailTsbRC,"Score finalize failed.");
  402. errLabel:
  403. return rc;
  404. }
  405. // Free a take record. Note that the record must be unlinked
  406. // from p->takes (See _cmTakeTsbUnlink().) prior to calling this function.
  407. void _cmTsbTakeFree( cmTsb_t* p, cmTakeTsb_t** tp )
  408. {
  409. if( tp==NULL || *tp==NULL )
  410. return;
  411. cmMidiTsb_t* m = (*tp)->midi;
  412. while( m != NULL )
  413. {
  414. cmMidiTsb_t* nm = m->link;
  415. cmMemFree(m);
  416. m = nm;
  417. }
  418. cmMemPtrFree(tp);
  419. }
  420. void _cmTsbRendTakeFree( cmTsb_t* p, cmTakeTsb_t** t )
  421. {
  422. _cmTsbTakeFree(p,t);
  423. p->evt = NULL;
  424. p->absPlaySmp = 0;
  425. p->absEvtSmp = 0;
  426. p->nextRid = 0;
  427. p->rend = NULL;
  428. }
  429. // Unlink a 'take' record from p->takes.
  430. cmTakeTsb_t* _cmTsbTakeUnlink( cmTsb_t* p, cmTakeTsb_t* t )
  431. {
  432. cmTakeTsb_t* t0 = NULL;
  433. cmTakeTsb_t* t1 = p->takes;
  434. while( t1 != NULL )
  435. {
  436. if( t1 == t )
  437. {
  438. if( t0 == NULL )
  439. p->takes = t->link;
  440. else
  441. t0->link = t->link;
  442. return t;
  443. }
  444. }
  445. return NULL;
  446. }
  447. cmTsbRC_t _cmTsbFree( cmTsb_t* p )
  448. {
  449. cmTsbRC_t rc = kOkTsbRC;
  450. if((rc = _cmTsbScoreTrkFree(p)) != kOkTsbRC )
  451. goto errLabel;
  452. //_cmTsbTakePrint(p->takes);
  453. //_cmTsbTakePrint(p->out);
  454. cmTakeTsb_t* t = p->takes;
  455. while( t != NULL )
  456. {
  457. cmTakeTsb_t* nt = t->link;
  458. _cmTsbTakeFree(p,&t);
  459. t = nt;
  460. }
  461. _cmTsbRendTakeFree(p,&p->out);
  462. cmMemFree(p);
  463. errLabel:
  464. return rc;
  465. }
  466. cmScTrkTakeTsb_t* _cmTsbMarkerIdToScTrkTake( cmTsb_t* p, unsigned markerUid )
  467. {
  468. unsigned i;
  469. for(i=0; p->scTrkTakeN; ++i)
  470. if( p->scTrkTakeV[i].tlMarkerUid == markerUid )
  471. return p->scTrkTakeV + i;
  472. return NULL;
  473. }
  474. cmScTrkMidiTsb_t* _cmTsbMuidToScTrkMidi( cmScTrkTakeTsb_t* t, unsigned muid )
  475. {
  476. unsigned i;
  477. for(i=0; i<t->midiN; ++i)
  478. if( t->midiV[i].muid == muid )
  479. return t->midiV + i;
  480. return NULL;
  481. }
  482. cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
  483. {
  484. cmTsbRC_t rc = kOkTsbRC;
  485. cmJsonNode_t* tkArrObj = NULL;
  486. cmJsRC_t jsRC = kOkJsRC;
  487. const cmChar_t* errMsg = NULL;
  488. unsigned i;
  489. // initialize the TSB json object
  490. if(( rc = cmJsonInitializeFromFile(&p->jsH,scoreTrkFn,&p->ctx)) != kOkJsRC )
  491. {
  492. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"The Take Sequence Builder JSON file object could not be initialized from '%s'.",cmStringNullGuard(scoreTrkFn));
  493. goto errLabel;
  494. }
  495. // parse the header
  496. if((jsRC = cmJsonMemberValues( cmJsonRoot(p->jsH), &errMsg,
  497. "timeLineFn", kStringTId, &p->tlFn,
  498. "scoreFn", kStringTId, &p->scFn,
  499. "tlPrefixPath", kStringTId, &p->tlPrefixPath,
  500. "takeArray", kArrayTId | kOptArgJsFl, &tkArrObj,
  501. NULL )) != kOkJsRC )
  502. {
  503. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  504. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed missing required field:'%s'",errMsg);
  505. else
  506. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file header parse failed.");
  507. goto errLabel;
  508. }
  509. // count of take records
  510. p->scTrkTakeN = cmJsonChildCount(tkArrObj);
  511. // array of take records
  512. p->scTrkTakeV = cmMemAllocZ(cmScTrkTakeTsb_t,p->scTrkTakeN);
  513. // for each take record
  514. for(i=0; i<p->scTrkTakeN; ++i)
  515. {
  516. cmJsonNode_t* takeObj = NULL;
  517. cmJsonNode_t* noteArrObj = NULL;
  518. cmScTrkTakeTsb_t* t = p->scTrkTakeV + i;
  519. unsigned j;
  520. // get a pointer to the take record JSON object
  521. if((takeObj = cmJsonArrayElement(tkArrObj,i)) == NULL )
  522. {
  523. rc = cmErrMsg(&p->err,kParseFailTsbRC,"Take record header at index %i access failed.",i);
  524. goto errLabel;
  525. }
  526. // parse the take record
  527. if((jsRC = cmJsonMemberValues( takeObj, &errMsg,
  528. "markerUid",kIntTId, &t->tlMarkerUid,
  529. "failFl", kIntTId, &t->failFl,
  530. "array", kArrayTId, &noteArrObj,
  531. NULL)) != kOkJsRC )
  532. {
  533. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  534. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed missing required field:'%s'",errMsg);
  535. else
  536. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file take record parse failed.");
  537. goto errLabel;
  538. }
  539. // get the count of note records
  540. t->midiN = cmJsonChildCount(noteArrObj);
  541. // allocate a note record array for this take
  542. t->midiV = cmMemAllocZ(cmScTrkMidiTsb_t, t->midiN);
  543. t->minMuid = INT_MAX;
  544. t->maxMuid = 0;
  545. t->minScEvtIdx = INT_MAX;
  546. t->maxScEvtIdx = 0;
  547. // for each note record
  548. for(j=0; j<t->midiN; ++j)
  549. {
  550. cmJsonNode_t* noteObj = NULL;
  551. // get the note record JSON object
  552. if((noteObj = cmJsonArrayElement(noteArrObj,j)) == NULL )
  553. {
  554. rc = cmErrMsg(&p->err,kParseFailTsbRC,"Access failed for note record at index %i at take index %i.",j,i);
  555. goto errLabel;
  556. }
  557. // parse the note record
  558. if((jsRC = cmJsonMemberValues( noteObj, &errMsg,
  559. "mni", kIntTId, &t->midiV[j].mni,
  560. "muid", kIntTId, &t->midiV[j].muid,
  561. "scEvtIdx", kIntTId, &t->midiV[j].scEvtIdx,
  562. "flags", kIntTId, &t->midiV[j].flags,
  563. NULL)) != kOkJsRC )
  564. {
  565. if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
  566. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed missing required field:'%s'",errMsg);
  567. else
  568. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file note record parse failed.");
  569. goto errLabel;
  570. }
  571. if( t->midiV[j].muid < t->minMuid )
  572. t->minMuid = t->midiV[j].muid;
  573. if( t->midiV[j].muid > t->maxMuid )
  574. t->maxMuid = t->midiV[j].muid;
  575. unsigned scEvtIdx = t->midiV[j].scEvtIdx;
  576. if( scEvtIdx!=0 && scEvtIdx!=cmInvalidIdx && scEvtIdx < t->minScEvtIdx )
  577. t->minScEvtIdx = scEvtIdx;
  578. if( scEvtIdx!=0 && scEvtIdx!=cmInvalidIdx && scEvtIdx > t->maxScEvtIdx )
  579. t->maxScEvtIdx = t->midiV[j].scEvtIdx;
  580. }
  581. }
  582. errLabel:
  583. if( rc != kOkTsbRC )
  584. rc = _cmTsbScoreTrkFree(p);
  585. return rc;
  586. }
  587. cmTsbRC_t _cmTakeSeqBldrRender( cmTsb_t* p )
  588. {
  589. cmTsbRC_t rc = kOkTsbRC;
  590. unsigned takeCnt = 0;
  591. unsigned midiCnt = 0;
  592. // delete the previous output rendering
  593. _cmTsbRendTakeFree(p,&p->out);
  594. // allocate a take order list
  595. cmOrderTsb_t* o = _cmTakeSeqBldrAllocOrder( p );
  596. // sort the list by minScEvtIdx
  597. o = _cmTakeSeqBldrSortOrder(o);
  598. // assign beg/endScEvtIdx values to each take
  599. _cmTakeSeqBldrSetBegEndOrder(o);
  600. //_cmTakeSeqBldrPrintOrder(o);
  601. // if the render take has not yet been allocated
  602. p->out = cmMemAllocZ(cmTakeTsb_t,1);
  603. p->out->tlMarkerUid = cmInvalidId;
  604. p->nextRid = 0;
  605. cmMidiTsb_t* m0 = NULL;
  606. cmOrderTsb_t* t = o;
  607. for(; t!=NULL; t=t->link)
  608. {
  609. // skip takes whose begScEvtIdx is not valid
  610. if( t->begScEvtIdx == cmInvalidIdx )
  611. continue;
  612. takeCnt += 1;
  613. //_cmTsbPrintMidi(t->t);
  614. // advance to the MIDI event assoc'd with t->begScEvtIdx
  615. cmMidiTsb_t* m = t->t->midi;
  616. for(; m!=NULL; m=m->link)
  617. if( m->scEvtIdx >= t->begScEvtIdx )
  618. break;
  619. // copy the MIDI events from the take into the render list
  620. for(; m!=NULL; m=m->link)
  621. {
  622. midiCnt += 1;
  623. // allocate a MIDI record to hold this render event
  624. cmMidiTsb_t* m1 = cmMemAllocZ(cmMidiTsb_t,1);
  625. // copy in the MIDI record
  626. *m1 = *m;
  627. //memcpy(m1,m,sizeof(cmMidiTsb_t));
  628. m1->link= NULL; // NULLify the copied link
  629. m1->ref = m0; // set prev. link
  630. m1->rid = p->nextRid++; // set the unique id
  631. // if this is not the first MIDI event ...
  632. if( m0 != NULL )
  633. m0->link = m1; // then set next link on the previous record
  634. else //
  635. { // otherwise
  636. p->out->midi = m1; // 1) set the render take event list
  637. m1->offsetSmp = 0; // 2) the first event always starts at time zero.
  638. p->evt = m1; // 3) set the first event to play
  639. p->absPlaySmp = 0; // 4) set the current play clock to 0
  640. p->absEvtSmp = 0; // 5) set the current next play event time to 0
  641. }
  642. m0 = m1;
  643. // if this is the last event in this take
  644. if( m0->scEvtIdx == t->endScEvtIdx )
  645. break;
  646. }
  647. }
  648. // free the take order list
  649. _cmTakeSeqBldrFreeOrder(o);
  650. printf("rendered takes:%i events:%i\n",takeCnt,midiCnt);
  651. //_cmTsbPrintMidi(p->out);
  652. return rc;
  653. }
  654. cmTsbRC_t cmTakeSeqBldrAlloc( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp )
  655. {
  656. cmTsbRC_t rc;
  657. if((rc = cmTakeSeqBldrFree(hp)) != kOkTsbRC )
  658. return kOkTsbRC;
  659. cmTsb_t* p = cmMemAllocZ(cmTsb_t,1);
  660. cmErrSetup(&p->err,&ctx->rpt,"TakeSeqBldr");
  661. p->ctx = *ctx;
  662. hp->h = p;
  663. return rc;
  664. }
  665. cmTsbRC_t cmTakeSeqBldrAllocFn( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp, const cmChar_t* scoreTrkFn )
  666. {
  667. cmTsbRC_t rc;
  668. if((rc = cmTakeSeqBldrAlloc(ctx,hp)) != kOkTsbRC )
  669. return rc;
  670. if((rc = cmTakeSeqBldrInitialize(*hp,scoreTrkFn)) != kOkTsbRC )
  671. return rc;
  672. return rc;
  673. }
  674. cmTsbRC_t cmTakeSeqBldrFree( cmTakeSeqBldrH_t* hp )
  675. {
  676. cmRC_t rc = kOkTsbRC;
  677. if( hp == NULL || cmTakeSeqBldrIsValid(*hp)==false )
  678. return kOkTsbRC;
  679. cmTsb_t* p = _cmTsbHandleToPtr(*hp);
  680. if((rc = _cmTsbFree(p)) != kOkTsbRC )
  681. return rc;
  682. hp->h = NULL;
  683. return rc;
  684. }
  685. bool cmTakeSeqBldrIsValid( cmTakeSeqBldrH_t h )
  686. { return h.h != NULL; }
  687. cmTsbRC_t cmTakeSeqBldrInitialize( cmTakeSeqBldrH_t h, const cmChar_t* scoreTrkFn )
  688. {
  689. cmTsbRC_t rc = kOkTsbRC;
  690. cmTsb_t* p = _cmTsbHandleToPtr(h);
  691. if(( rc = _cmTsbLoadScoreTrkFile( p, scoreTrkFn )) != kOkTsbRC )
  692. return rc;
  693. if( cmTimeLineInitializeFromFile(&p->ctx, &p->tlH, NULL, NULL, p->tlFn, p->tlPrefixPath ) != kOkTlRC )
  694. {
  695. rc = cmErrMsg(&p->err,kTimeLineFailTsbRC,"The time-line file '%s' could not be loaded.",p->tlFn);
  696. goto errLabel;
  697. }
  698. if( cmScoreInitialize(&p->ctx, &p->scH, p->scFn, 0, NULL, 0, NULL, NULL, cmSymTblNullHandle ) != kOkScRC )
  699. {
  700. rc = cmErrMsg(&p->err,kScoreFailTsbRC,"The score file '%s' could not be loaded.",p->scFn);
  701. goto errLabel;
  702. }
  703. errLabel:
  704. if( rc != kOkTsbRC )
  705. _cmTsbScoreTrkFree(p);
  706. return rc;
  707. }
  708. cmTakeTsb_t* _cmTsbMarkerUidToTake( cmTsb_t* p, unsigned tlMarkerUid )
  709. {
  710. cmTakeTsb_t* t = p->takes;
  711. for(; t != NULL; t=t->link)
  712. if( t->tlMarkerUid == tlMarkerUid )
  713. return t;
  714. return NULL;
  715. }
  716. cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool overwriteFL )
  717. {
  718. cmTsbRC_t rc = kOkTsbRC;
  719. cmTsb_t* p = _cmTsbHandleToPtr(h);
  720. cmTlMarker_t* mark = NULL;
  721. cmTlMidiFile_t* mf = NULL;
  722. cmMidiFileH_t mfH = cmMidiFileNullHandle;
  723. cmScTrkTakeTsb_t* stt = NULL;
  724. // verify that the requested take has not already been loaded
  725. if( _cmTsbMarkerUidToTake( p, tlMarkUid ) != NULL )
  726. {
  727. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i has already been loaded.",tlMarkUid );
  728. goto errLabel;
  729. }
  730. // find the score tracked take for the requested marker
  731. if((stt = _cmTsbMarkerIdToScTrkTake(p,tlMarkUid )) == NULL )
  732. {
  733. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The score tracked take indicated by marker id %i could not be found.", tlMarkUid );
  734. goto errLabel;
  735. }
  736. // get a pointer to the time-line marker object
  737. if((mark = cmTlMarkerObjPtr( p->tlH, cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkUid))) == NULL )
  738. {
  739. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker uid '%i' is not valid.",tlMarkUid);
  740. goto errLabel;
  741. }
  742. // get the name of the MIDI file which contains the marker
  743. if((mf = cmTimeLineMidiFileAtTime( p->tlH, mark->obj.seqId, mark->obj.seqSmpIdx )) == NULL )
  744. {
  745. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker '%i' does not intersect with a MIDI file.",tlMarkUid);
  746. goto errLabel;
  747. }
  748. // open the MIDI file
  749. if( cmMidiFileOpen( &p->ctx, &mfH, cmMidiFileName(mf->h) ) != kOkMfRC )
  750. {
  751. rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The MIDI file '%s' could not be opened.", cmStringNullGuard(cmMidiFileName(mf->h)));
  752. goto errLabel;
  753. }
  754. // convert the dtick field to delta samples
  755. //cmMidiFileTickToSamples( mfH, cmTimeLineSampleRate(p->tlH), false );
  756. // calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
  757. cmMidiFileCalcNoteDurations( mfH );
  758. unsigned i = 0;
  759. unsigned n = cmMidiFileMsgCount(mfH);
  760. const cmMidiTrackMsg_t** a = cmMidiFileMsgArray(mfH);
  761. double srate = cmTimeLineSampleRate(p->tlH);
  762. // allocate and link a new take render record
  763. cmTakeTsb_t* t = cmMemAllocZ(cmTakeTsb_t,1);
  764. t->tlMarkerUid = tlMarkUid;
  765. t->stt = stt;
  766. t->link = p->takes;
  767. p->takes = t;
  768. unsigned rid = 0;
  769. cmMidiTsb_t* m0 = NULL;
  770. const cmMidiTrackMsg_t* mf0 = NULL;
  771. // for each MIDI message in the file
  772. for(i=0; i<n; ++i)
  773. {
  774. const cmMidiTrackMsg_t* mf1 = a[i];
  775. // we are only interested in rendering notes and control msgs
  776. switch( mf1->status )
  777. {
  778. case kNoteOnMdId:
  779. case kNoteOffMdId:
  780. case kCtlMdId:
  781. break;
  782. default:
  783. continue;
  784. }
  785. // if this MIDI message is inside the tracked region of the take
  786. if( stt->minMuid > mf1->uid || mf1->uid > stt->maxMuid )
  787. continue;
  788. // get a pointer to the tracking map for the given MIDI file event.
  789. // (Note that since control messages are not tracked so this function may return NULL.)
  790. cmScTrkMidiTsb_t* stm = _cmTsbMuidToScTrkMidi(stt, mf1->uid );
  791. // create a MIDI render event
  792. cmMidiTsb_t* m1 = cmMemAllocZ(cmMidiTsb_t,1);
  793. m1->rid = rid++;
  794. m1->srcId = tlMarkUid;
  795. m1->scEvtIdx = stm != NULL ? stm->scEvtIdx : cmInvalidIdx;
  796. m1->flags = stm != NULL ? stm->flags : 0;
  797. m1->ref = m0;
  798. m1->offsetSmp = mf0 == NULL ? 0 : round(mf1->amicro * srate / 1000000.0);
  799. m1->durSmp = mf1->u.chMsgPtr->durMicros * srate / 1000000.0;
  800. m1->d0 = mf1->u.chMsgPtr->d0;
  801. m1->d1 = mf1->u.chMsgPtr->d1;
  802. m1->status = mf1->status;
  803. m1->link = NULL;
  804. //printf("0x%x %f %f\n",m1->status,m1->offsetSmp/96000.0,m1->durSmp/96000.0);
  805. if( m0 != NULL )
  806. m0->link = m1;
  807. if( t->midi == NULL )
  808. t->midi = m1;
  809. m0 = m1;
  810. mf0 = mf1;
  811. }
  812. //unsigned begBpS, endBpS;
  813. //_cmTsbCalcTempo(p, t, &begBpS, &endBpS );
  814. // render the new output sequence
  815. if((rc = _cmTakeSeqBldrRender(p)) != kOkTsbRC)
  816. cmErrMsg(&p->err,rc,"Take sequence builder rendering failed.");
  817. errLabel:
  818. if( cmMidiFileClose(&mfH) != kOkMfRC )
  819. rc = cmErrMsg(&p->err,kMidiFileFailTsbRC,"MIDI file close failed.");
  820. return rc;
  821. }
  822. cmTsbRC_t cmTakeSeqBldrUnloadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid )
  823. {
  824. cmTsbRC_t rc = kOkTsbRC;
  825. cmTsb_t* p = _cmTsbHandleToPtr(h);
  826. cmTakeTsb_t* t;
  827. if((t = _cmTsbMarkerUidToTake(p, tlMarkUid )) == NULL )
  828. return cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i could not be found.",tlMarkUid);
  829. t = _cmTsbTakeUnlink(p,t);
  830. assert( t != NULL );
  831. _cmTsbTakeFree(p,&t);
  832. // render the new output sequence
  833. if((rc = _cmTakeSeqBldrRender(p)) != kOkTsbRC)
  834. cmErrMsg(&p->err,rc,"Take sequence builder rendering failed.");
  835. return rc;
  836. }
  837. double cmTakeSeqBldrSampleRate( cmTakeSeqBldrH_t h )
  838. {
  839. cmTsb_t* p = _cmTsbHandleToPtr(h);
  840. if( cmTimeLineIsValid( p->tlH ) )
  841. return cmTimeLineSampleRate(p->tlH );
  842. return 0;
  843. }
  844. cmScH_t cmTakeSeqBldrScoreHandle( cmTakeSeqBldrH_t h )
  845. {
  846. cmTsb_t* p = _cmTsbHandleToPtr(h);
  847. return p->scH;
  848. }
  849. unsigned cmTakeSeqBldrScTrkTakeCount( cmTakeSeqBldrH_t h )
  850. {
  851. cmTsb_t* p = _cmTsbHandleToPtr(h);
  852. return p->scTrkTakeN;
  853. }
  854. cmTsbRC_t cmTakeSeqBldrScTrkTake( cmTakeSeqBldrH_t h, unsigned idx, cmTksbScTrkTake_t* ref )
  855. {
  856. cmTsb_t* p = _cmTsbHandleToPtr(h);
  857. assert( idx < p->scTrkTakeN );
  858. ref->minScEvtIdx = p->scTrkTakeV[ idx ].minScEvtIdx;
  859. ref->maxScEvtIdx = p->scTrkTakeV[ idx ].maxScEvtIdx;
  860. ref->tlMarkerUid = p->scTrkTakeV[idx].tlMarkerUid;
  861. return kOkTsbRC;
  862. }
  863. const cmChar_t* cmTakeSeqBldrScTrkTakeText( cmTakeSeqBldrH_t h, unsigned tlMarkerUid )
  864. {
  865. cmTsb_t* p = _cmTsbHandleToPtr(h);
  866. cmTlObj_t* tlObj = NULL;
  867. cmTlMarker_t* tlMark = NULL;
  868. if((tlObj = cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkerUid )) == NULL )
  869. {
  870. cmErrMsg(&p->err,kTimeLineFailTsbRC,"Unable to locate the time line record for score-track-take uid: %i.",tlMarkerUid);
  871. return NULL;
  872. }
  873. if((tlMark = cmTimeLineMarkerObjPtr( p->tlH, tlObj)) == NULL )
  874. {
  875. cmErrMsg(&p->err,kTimeLineFailTsbRC,"Unable to cast a time line marker object for score-track-take %i.",tlMarkerUid);
  876. return NULL;
  877. }
  878. return tlMark->text;
  879. }
  880. cmTsbRC_t cmTakeSeqBldrPlaySeekLoc( cmTakeSeqBldrH_t h, unsigned scLocIdx )
  881. {
  882. cmTsb_t* p = _cmTsbHandleToPtr(h);
  883. if( p->out == NULL )
  884. return cmErrMsg(&p->err,kRenderSeqEmptyTsbRC,"Seek faied. The render sequence is empty.");
  885. if( scLocIdx == cmInvalidIdx )
  886. p->evt = p->out->midi;
  887. else
  888. {
  889. cmScoreLoc_t* loc;
  890. if(( loc = cmScoreLoc(p->scH, scLocIdx )) == NULL )
  891. return cmErrMsg(&p->err,kInvalidArgTsbRC,"Seek failed. The requested score location (%i) could not be found.",scLocIdx);
  892. if( loc->evtCnt == 0 || loc->evtArray[0]==NULL )
  893. return cmErrMsg(&p->err,kInvalidArgTsbRC,"Seek failed. The requested score location (%i) has no associated event.",scLocIdx);
  894. unsigned scEvtIdx = loc->evtArray[0]->index;
  895. cmMidiTsb_t* m = p->out->midi;
  896. for(; m!=NULL; m=m->link)
  897. if( m->scEvtIdx >= scEvtIdx )
  898. {
  899. p->evt = m;
  900. break;
  901. }
  902. if( m == NULL )
  903. return cmErrMsg(&p->err,kInvalidArgTsbRC,"Seek failed. The requested score event index (%i) is out of range.",scEvtIdx );
  904. }
  905. return kOkTsbRC;
  906. }
  907. cmTsbRC_t cmTakeSeqBldrPlayExec( cmTakeSeqBldrH_t h, unsigned deltaSmp, cmTakeSeqBldrPlayFunc_t cbFunc, void* cbArg )
  908. {
  909. cmTsb_t* p = _cmTsbHandleToPtr(h);
  910. if( p->evt == NULL )
  911. return kOkTsbRC;
  912. // advance the play clock
  913. p->absPlaySmp += deltaSmp;
  914. // if the next event time has elapsed
  915. while( p->evt != NULL && p->absEvtSmp <= p->absPlaySmp )
  916. {
  917. // make the event callback
  918. cmTksbEvent_t e;
  919. e.smpIdx = p->absEvtSmp;
  920. e.status = p->evt->status;
  921. e.d0 = p->evt->d0;
  922. e.d1 = p->evt->d1;
  923. cbFunc(cbArg,&e);
  924. do
  925. {
  926. // advance the current play event
  927. p->evt = p->evt->link;
  928. // the last event was not encountered and the events offset time is legal
  929. if( p->evt != NULL && p->evt->offsetSmp != cmInvalidIdx )
  930. {
  931. // advance the event absolute time
  932. p->absEvtSmp += p->evt->offsetSmp;
  933. break;
  934. }
  935. }while( p->evt != NULL );
  936. }
  937. return kOkTsbRC;
  938. }
  939. void cmTakeSeqBldrRendReset( cmTakeSeqBldrH_t h )
  940. {
  941. cmTsb_t* p = _cmTsbHandleToPtr(h);
  942. if( p->out == NULL )
  943. return;
  944. p->rend = p->out->midi;
  945. }
  946. void _cmTakeSeqBldrMidiToRend( cmTksbRend_t* r, const cmMidiTsb_t* m )
  947. {
  948. r->rid = m->rid;
  949. r->srcId = m->srcId;
  950. r->scEvtIdx = m->scEvtIdx;
  951. r->flags = m->flags;
  952. r->offsetSmp = m->offsetSmp;
  953. r->durSmp = m->durSmp;
  954. r->evt.smpIdx = 0;
  955. r->evt.status = m->status;
  956. r->evt.d0 = m->d0;
  957. r->evt.d1 = m->d1;
  958. }
  959. cmMidiTsb_t* _cmTakeSeqBldrRidToMidi( cmTsb_t* p, unsigned rid )
  960. {
  961. cmMidiTsb_t* m;
  962. if( p->out == NULL )
  963. return NULL;
  964. for(m=p->out->midi; m!=NULL; m=m->link)
  965. if( m->rid == rid )
  966. return m;
  967. return NULL;
  968. }
  969. bool cmTakeSeqBldrRendNext(cmTakeSeqBldrH_t h, cmTksbRend_t* r)
  970. {
  971. cmTsb_t* p = _cmTsbHandleToPtr(h);
  972. cmMidiTsb_t* m = p->rend;
  973. if( m == NULL )
  974. return false;
  975. p->rend = p->rend->link;
  976. _cmTakeSeqBldrMidiToRend(r,m);
  977. return true;
  978. }
  979. cmTsbRC_t cmTakeSeqBldrRendInfo( cmTakeSeqBldrH_t h, unsigned rid, cmTksbRend_t* r )
  980. {
  981. cmTsb_t* p = _cmTsbHandleToPtr(h);
  982. cmMidiTsb_t* m;
  983. if((m = _cmTakeSeqBldrRidToMidi(p, rid )) == NULL )
  984. return cmErrMsg(&p->err,kInvalidArgTsbRC,"Unable to locate the MIDI render record associated with rid:%i.",rid);
  985. _cmTakeSeqBldrMidiToRend(r,m);
  986. return kOkTsbRC;
  987. }
  988. cmTsbRC_t cmTakeSeqBldrRendDelete( cmTakeSeqBldrH_t h, unsigned rid )
  989. {
  990. cmTsb_t* p = _cmTsbHandleToPtr(h);
  991. if( p->out == NULL || p->out->midi == NULL )
  992. return kOkTsbRC;
  993. cmMidiTsb_t* m1 = p->out->midi;
  994. for(; m1!=NULL; m1=m1->link)
  995. if( m1->rid == rid )
  996. {
  997. // if there is no recd before m1
  998. if( m1->ref == NULL )
  999. {
  1000. p->out->midi = m1->link;
  1001. // if there is a record after m1
  1002. if( p->out->midi != NULL )
  1003. {
  1004. p->out->midi->ref = NULL;
  1005. p->out->midi->offsetSmp = 0; // the first record never has a time offset
  1006. }
  1007. }
  1008. else // there is a record before m1
  1009. {
  1010. m1->ref->link = m1->link;
  1011. // if there is a record after m1
  1012. if( m1->link != NULL )
  1013. {
  1014. m1->link->ref = m1->ref;
  1015. m1->link->offsetSmp += m1->offsetSmp; // absorb m1's offset time into the next revent
  1016. }
  1017. }
  1018. cmMemFree(m1);
  1019. break;
  1020. }
  1021. _cmTsbTakePrint(p->out);
  1022. return kOkTsbRC;
  1023. }
  1024. cmTsbRC_t cmTakeSeqBldrRendInsert( cmTakeSeqBldrH_t h, const cmTksbEvent_t* e, unsigned durSmp, unsigned* ridRef)
  1025. {
  1026. cmTsb_t* p = _cmTsbHandleToPtr(h);
  1027. if( ridRef != NULL )
  1028. *ridRef = cmInvalidId;
  1029. cmMidiTsb_t* nm = cmMemAllocZ(cmMidiTsb_t,1);
  1030. nm->rid = p->nextRid++;
  1031. nm->srcId = cmInvalidId;
  1032. nm->scEvtIdx = cmInvalidId;
  1033. nm->flags = 0;
  1034. nm->durSmp = durSmp;
  1035. nm->status = e->status;
  1036. nm->d0 = e->d0;
  1037. nm->d1 = e->d1;
  1038. if( p->out == NULL )
  1039. {
  1040. p->out = cmMemAllocZ(cmTakeTsb_t,1);
  1041. p->out->tlMarkerUid = cmInvalidId;
  1042. }
  1043. if( p->out->midi == NULL )
  1044. {
  1045. p->out->midi = nm;
  1046. goto doneLabel;
  1047. }
  1048. cmMidiTsb_t* m0 = NULL;
  1049. cmMidiTsb_t* m1 = p->out->midi;
  1050. unsigned absSmpIdx = m1==NULL ? 0 : m1->offsetSmp;
  1051. for(; m1!=NULL; m1=m1->link)
  1052. {
  1053. // absSmpIdx is the absolute time of m1
  1054. // if m1 is the recd just after the new record
  1055. if( absSmpIdx > e->smpIdx )
  1056. {
  1057. // the record prior to the new record is m0
  1058. nm->ref = m0;
  1059. // the reocrd after the new record is m1
  1060. nm->link = m1;
  1061. // the new record is before m1
  1062. m1->ref = nm;
  1063. // if the new record is first on the list
  1064. if( m0 == NULL )
  1065. {
  1066. p->out->midi = nm;
  1067. // TODO: without giving more information there is no way
  1068. // to give the old first event an offset relative to the new
  1069. // first event - so the both events will be scheduled at
  1070. // time zero.
  1071. nm->offsetSmp = 0;
  1072. }
  1073. else // the new record is between m0 and m1
  1074. {
  1075. m0->link = nm;
  1076. // offset from new record to m1
  1077. unsigned dsi = absSmpIdx - e->smpIdx;
  1078. // m1's time offset is being reduced
  1079. assert( m1->offsetSmp >= dsi );
  1080. // the offset to the new record from m0
  1081. nm->offsetSmp = m1->offsetSmp - dsi;
  1082. m1->offsetSmp = dsi;
  1083. }
  1084. break;
  1085. }
  1086. // if m1 is not the last element on the list
  1087. if( m1->link != NULL )
  1088. absSmpIdx += m1->link->offsetSmp;
  1089. else
  1090. {
  1091. // insert the new event at the end of the list
  1092. nm->ref = m1;
  1093. nm->link = NULL;
  1094. m1->link = nm;
  1095. assert( e->smpIdx > absSmpIdx );
  1096. nm->offsetSmp = e->smpIdx - absSmpIdx;
  1097. break;
  1098. }
  1099. m0 = m1;
  1100. }
  1101. doneLabel:
  1102. if( ridRef != NULL )
  1103. *ridRef = nm->rid;
  1104. //_cmTsbTakePrint(p->out);
  1105. return kOkTsbRC;
  1106. }
  1107. cmTsbRC_t cmTakeSeqBldrWrite( cmTakeSeqBldrH_t h, const cmChar_t* fn )
  1108. {
  1109. cmTsbRC_t rc = kOkTsbRC;
  1110. cmJsonH_t jsH = cmJsonNullHandle;
  1111. cmJsonNode_t* arr;
  1112. cmMidiTsb_t* m;
  1113. cmTsb_t* p = _cmTsbHandleToPtr(h);
  1114. if( p->out == NULL )
  1115. return rc;
  1116. // allocate a JSON tree
  1117. if( cmJsonInitialize(&jsH,&p->ctx) != kOkJsRC )
  1118. {
  1119. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON write tree allocate failed.");
  1120. goto errLabel;
  1121. }
  1122. // insert the root object
  1123. if( cmJsonCreateObject(jsH, NULL ) != kOkJsRC )
  1124. {
  1125. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON root object allocate failed.");
  1126. goto errLabel;
  1127. }
  1128. // create the header record
  1129. if( cmJsonInsertPairs(jsH, cmJsonRoot(jsH),
  1130. "tlMarkerUid", kIntTId, p->out->tlMarkerUid,
  1131. "tlFileName", kStringTId, cmTimeLineFileName(p->tlH),
  1132. NULL) != kOkJsRC )
  1133. {
  1134. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON header record create failed.");
  1135. goto errLabel;
  1136. }
  1137. // create the MIDI event array
  1138. if((arr = cmJsonInsertPairArray(jsH, cmJsonRoot(jsH), "midi")) == NULL )
  1139. {
  1140. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"Create the MIDI event array.");
  1141. goto errLabel;
  1142. }
  1143. // fill the MIDI array
  1144. for(m=p->out->midi; m!=NULL; m=m->link)
  1145. {
  1146. if( cmJsonCreateFilledObject(jsH, arr,
  1147. "rid", kIntTId, m->rid,
  1148. "srcId", kIntTId, m->srcId,
  1149. "scEvtIdx", kIntTId, m->scEvtIdx,
  1150. "flags", kIntTId, m->flags,
  1151. "offsetSmp", kIntTId, m->offsetSmp,
  1152. "durSmp", kIntTId, m->durSmp,
  1153. "status", kIntTId, m->status,
  1154. "d0", kIntTId, m->d0,
  1155. "d1", kIntTId, m->d1,
  1156. NULL) == NULL )
  1157. {
  1158. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON MIDI record create failed.");
  1159. goto errLabel;
  1160. }
  1161. }
  1162. // write the tree
  1163. if( cmJsonWrite( jsH, cmJsonRoot(jsH), fn ) != kOkJsRC )
  1164. {
  1165. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON write to '%s' failed.",cmStringNullGuard(fn));
  1166. }
  1167. errLabel:
  1168. if( cmJsonFinalize(&jsH) != kOkJsRC )
  1169. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON tree finalize failed.");
  1170. return rc;
  1171. }
  1172. cmTsbRC_t cmTakeSeqBldrRead( cmTakeSeqBldrH_t h, const cmChar_t* fn )
  1173. {
  1174. cmTsbRC_t rc = kOkTsbRC;
  1175. cmTsb_t* p = _cmTsbHandleToPtr(h);
  1176. cmJsonH_t jsH = cmJsonNullHandle;
  1177. const cmChar_t* jsErrLabel = NULL;
  1178. cmTakeTsb_t* t = NULL;
  1179. cmMidiTsb_t* m0 = NULL;
  1180. cmJsonNode_t* arr = NULL;
  1181. cmJsRC_t jsRC;
  1182. if( cmJsonInitializeFromFile( &jsH, fn, &p->ctx ) != kOkJsRC )
  1183. {
  1184. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"Unable to parse the JSON file '%s'.",cmStringNullGuard(fn));
  1185. goto errLabel;
  1186. }
  1187. t = cmMemAllocZ(cmTakeTsb_t,1);
  1188. if((jsRC = cmJsonMemberValues( cmJsonRoot(jsH), &jsErrLabel,
  1189. "tlMarkerUid", kIntTId, &t->tlMarkerUid,
  1190. "midi", kArrayTId, &arr,
  1191. NULL)) != kOkJsRC )
  1192. {
  1193. if( jsRC == kNodeNotFoundJsRC && jsErrLabel != NULL )
  1194. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file MIDI render header failed missing required field:'%s'",cmStringNullGuard(jsErrLabel));
  1195. else
  1196. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file MIDI render header parse failed.");
  1197. goto errLabel;
  1198. }
  1199. unsigned n = cmJsonChildCount(arr);
  1200. unsigned i;
  1201. for(i=0; i<n; ++i)
  1202. {
  1203. const cmJsonNode_t* e = cmJsonArrayElementC(arr, i );
  1204. cmMidiTsb_t* m = cmMemAllocZ(cmMidiTsb_t,1);
  1205. if((jsRC = cmJsonMemberValues( e, &jsErrLabel,
  1206. "rid", kIntTId, &m->rid,
  1207. "srcId", kIntTId, &m->srcId,
  1208. "scEvtIdx", kIntTId, &m->scEvtIdx,
  1209. "flags", kIntTId, &m->flags,
  1210. "offsetSmp", kIntTId, &m->offsetSmp,
  1211. "durSmp", kIntTId, &m->durSmp,
  1212. "status", kIntTId, &m->status,
  1213. "d0", kIntTId, &m->d0,
  1214. "d1", kIntTId, &m->d1,
  1215. NULL)) != kOkJsRC )
  1216. {
  1217. if( jsRC == kNodeNotFoundJsRC && jsErrLabel != NULL )
  1218. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file MIDI render element failed missing required field:'%s' on index:%i",cmStringNullGuard(jsErrLabel),i);
  1219. else
  1220. rc = cmErrMsg(&p->err,kParseFailTsbRC,"JSON file MIDI render element parse failed on index: %i.", i);
  1221. goto errLabel;
  1222. }
  1223. m->ref = m0;
  1224. if( m0 == NULL )
  1225. t->midi = m;
  1226. else
  1227. m0->link = m;
  1228. }
  1229. errLabel:
  1230. if( cmJsonFinalize(&jsH) != kOkJsRC )
  1231. rc = cmErrMsg(&p->err,kJsonFailTsbRC,"JSON finalize failed.");
  1232. if( rc != kOkTsbRC )
  1233. _cmTsbTakeFree(p,&t);
  1234. else
  1235. {
  1236. _cmTsbRendTakeFree(p,&p->out);
  1237. p->out = t;
  1238. }
  1239. return rc;
  1240. }
  1241. cmTsbRC_t cmTakeSeqBldrTest( cmCtx_t* ctx )
  1242. {
  1243. const cmChar_t* scoreTrkFn = "/home/kevin/src/cmkc/src/kc/data/takeSeqBldr0.js";
  1244. cmTakeSeqBldrH_t tsbH = cmTakeSeqBldrNullHandle;
  1245. cmTsbRC_t tsbRC = kOkTsbRC;
  1246. unsigned markerIdV[] = { 2200, 2207 };
  1247. unsigned markerN = sizeof(markerIdV)/sizeof(markerIdV[0]);
  1248. unsigned i;
  1249. if((tsbRC = cmTakeSeqBldrAllocFn(ctx, &tsbH, scoreTrkFn )) != kOkTsbRC )
  1250. return cmErrMsg(&ctx->err,tsbRC,"TSB Allocate and parse '%s' failed.",scoreTrkFn);
  1251. cmRptPrintf(&ctx->rpt, "TakeSeqBldr Allocation Completed.");
  1252. for(i=0; i<markerN; ++i)
  1253. {
  1254. if((tsbRC = cmTakeSeqBldrLoadTake(tsbH,markerIdV[i],false)) != kOkTsbRC )
  1255. cmErrMsg(&ctx->err,tsbRC,"TSB load take failed.");
  1256. cmRptPrintf(&ctx->rpt, "TakeSeqBldr Load Take %i Completed.",markerIdV[i]);
  1257. }
  1258. if((tsbRC = cmTakeSeqBldrFree(&tsbH)) != kOkTsbRC )
  1259. return cmErrMsg(&ctx->err,tsbRC,"TSB Free failed.");
  1260. return tsbRC;
  1261. }