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

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( &p->ctx, &mfH, cmMidiFileName(mf->h) ) != 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. }