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

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