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

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