libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmScore.c 40KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  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 "cmMidi.h"
  10. #include "cmLex.h"
  11. #include "cmCsv.h"
  12. #include "cmMidiFile.h"
  13. #include "cmAudioFile.h"
  14. #include "cmTimeLine.h"
  15. #include "cmScore.h"
  16. #include "cmVectOpsTemplateMain.h"
  17. cmScH_t cmScNullHandle = cmSTATIC_NULL_HANDLE;
  18. enum
  19. {
  20. kLabelCharCnt = 7,
  21. kInvalidDynScId = 0,
  22. };
  23. enum
  24. {
  25. kMidiFileIdColScIdx= 0,
  26. kTypeLabelColScIdx = 3,
  27. kDSecsColScIdx = 4,
  28. kSecsColScIdx = 5,
  29. kPitchColScIdx = 11,
  30. kBarColScIdx = 13,
  31. kSkipColScIdx = 14,
  32. kEvenColScIdx = 15,
  33. kTempoColScIdx = 16,
  34. kDynColScIdx = 17,
  35. kSectionColScIdx = 18,
  36. kRemarkColScIdx = 19
  37. };
  38. typedef struct
  39. {
  40. unsigned id;
  41. cmChar_t label[ kLabelCharCnt + 1 ];
  42. } cmScEvtRef_t;
  43. typedef struct cmScSect_str
  44. {
  45. const cmChar_t* label;
  46. unsigned startIdx;
  47. struct cmScSect_str* link;
  48. } cmScSect_t;
  49. typedef struct cmScSetEle_str
  50. {
  51. cmChar_t* label;
  52. unsigned eleIdx;
  53. struct cmScSetEle_str* link;
  54. } cmScSetEle_t;
  55. typedef struct cmScSet_str
  56. {
  57. unsigned typeFl; // type of this set
  58. cmScSetEle_t* eles; // indexes of set elements
  59. cmScSetEle_t* sects; // application section labels
  60. bool inFl; // true if currently accepting elements
  61. struct cmScSet_str* link; //
  62. } cmScSet_t;
  63. typedef struct cmScPerf_str
  64. {
  65. cmScoreSet_t* set;
  66. struct cmScPerf_str* link;
  67. } cmScPerf_t;
  68. typedef struct
  69. {
  70. cmErr_t err;
  71. cmCsvH_t cH;
  72. cmScCb_t cbFunc;
  73. void* cbArg;
  74. cmChar_t* fn;
  75. cmScoreEvt_t* array;
  76. unsigned cnt;
  77. cmScoreLoc_t* loc;
  78. unsigned locCnt;
  79. cmScoreSection_t* sect;
  80. unsigned sectCnt;
  81. unsigned sciPitchLexTId; // sci pitch and section id lexer token id's
  82. unsigned sectionLexTId;
  83. cmScSect_t* sectList; // lists used during parsing
  84. cmScSet_t* setList;
  85. cmScoreSet_t* sets;
  86. unsigned setCnt;
  87. cmScPerf_t perf;
  88. } cmSc_t;
  89. cmScEvtRef_t _cmScEvtRefArray[] =
  90. {
  91. { kTimeSigEvtScId, "tsg" },
  92. { kKeySigEvtScId, "ksg" },
  93. { kTempoEvtScId, "tmp" },
  94. { kTrackEvtScId, "trk" },
  95. { kTextEvtScId, "txt" },
  96. { kEOTrackEvtScId, "eot" },
  97. { kCopyEvtScId, "cpy"},
  98. { kBlankEvtScId, "blk"},
  99. { kBarEvtScId, "bar"},
  100. { kPgmEvtScId, "pgm" },
  101. { kCtlEvtScId, "ctl" },
  102. { kNonEvtScId, "non" },
  103. { kInvalidEvtScId, "***" }
  104. };
  105. cmScEvtRef_t _cmScDynRefArray[] =
  106. {
  107. { 1, "pppp" },
  108. { 2, "ppp" },
  109. { 3, "pp" },
  110. { 4, "p" },
  111. { 5, "mp" },
  112. { 6, "m" },
  113. { 7, "mf" },
  114. { 8, "f" },
  115. { 9, "ff" },
  116. { 10, "fff" },
  117. { 11, "ffff"},
  118. { kInvalidDynScId, "***" },
  119. };
  120. cmSc_t* _cmScHandleToPtr( cmScH_t h )
  121. {
  122. cmSc_t* p = (cmSc_t*)h.h;
  123. assert( p != NULL );
  124. return p;
  125. }
  126. unsigned _cmScEvtTypeLabelToId( const cmChar_t* label )
  127. {
  128. cmScEvtRef_t* r = _cmScEvtRefArray;
  129. for(; r->id != kInvalidEvtScId; ++r )
  130. if( strcmp(label,r->label) == 0 )
  131. return r->id;
  132. return kInvalidEvtScId;
  133. }
  134. const cmChar_t* cmScEvtTypeIdToLabel( unsigned id )
  135. {
  136. cmScEvtRef_t* r = _cmScEvtRefArray;
  137. for(; r->id != kInvalidEvtScId; ++r )
  138. if( r->id == id )
  139. return r->label;
  140. return NULL;
  141. }
  142. unsigned _cmScDynLabelToId( const cmChar_t* label )
  143. {
  144. cmScEvtRef_t* r = _cmScDynRefArray;
  145. for(; r->id != kInvalidEvtScId; ++r )
  146. if( strncmp(label,r->label,strlen(r->label)) == 0 )
  147. return r->id;
  148. return kInvalidDynScId;
  149. }
  150. const cmChar_t* cmScDynIdToLabel( unsigned id )
  151. {
  152. cmScEvtRef_t* r = _cmScDynRefArray;
  153. for(; r->id != kInvalidDynScId; ++r )
  154. if( r->id == id )
  155. return r->label;
  156. return NULL;
  157. }
  158. unsigned _cmScLexSciPitchMatcher( const cmChar_t* cp, unsigned cn )
  159. {
  160. if( cp==NULL || cn < 2 )
  161. return 0;
  162. // first char must be "A-G"
  163. if( strspn(cp,"ABCDEFG") != 1 )
  164. return 0;
  165. unsigned i = 1;
  166. // next char could be accidental
  167. if( cp[i] == '#' || cp[i] == 'b' )
  168. ++i; // i==2
  169. // the 2nd or 3rd char must be a digit
  170. if( i>=cn || isdigit(cp[i]) == false )
  171. return 0;
  172. ++i; // i==2 or i==3
  173. // the 3rd or 4th char must be a digit or EOS
  174. if( i>=cn || isdigit(cp[i]) == false )
  175. return i;
  176. ++i;
  177. return i;
  178. }
  179. unsigned _cmScLexSectionIdMatcher( const cmChar_t* cp, unsigned cn )
  180. {
  181. if( cp==NULL || cn < 2 )
  182. return 0;
  183. // first char must be a number
  184. if( !isdigit(cp[0]) )
  185. return 0;
  186. // if 2nd char is a char then terminate
  187. if( 'a'<=cp[1] && cp[1]<='z' )
  188. return 2;
  189. // if 2nd char is digit and 3rd char is char then terminate
  190. if( isdigit(cp[1]) && cn>2 && 'a'<=cp[2] && cp[2]<='z' )
  191. return 3;
  192. return 0;
  193. }
  194. void _cmScFreeSetList( cmScSet_t* setList )
  195. {
  196. cmScSet_t* tp = setList;
  197. cmScSet_t* ntp = NULL;
  198. while(tp!=NULL)
  199. {
  200. ntp = tp->link;
  201. cmScSetEle_t* ep = tp->eles;
  202. while( ep != NULL )
  203. {
  204. cmScSetEle_t* nep = ep->link;
  205. cmMemFree(ep);
  206. ep = nep;
  207. }
  208. ep = tp->sects;
  209. while( ep != NULL )
  210. {
  211. cmScSetEle_t* nep = ep->link;
  212. cmMemFree(ep->label);
  213. cmMemFree(ep);
  214. ep = nep;
  215. }
  216. cmMemFree(tp);
  217. tp = ntp;
  218. }
  219. }
  220. cmScRC_t _cmScFinalize( cmSc_t* p )
  221. {
  222. cmScRC_t rc = kOkScRC;
  223. unsigned i;
  224. if( cmCsvFinalize(&p->cH) != kOkCsvRC )
  225. return rc;
  226. if( p->sets != NULL )
  227. {
  228. for(i=0; i<p->setCnt; ++i)
  229. {
  230. cmMemFree(p->sets[i].eleArray);
  231. cmMemFree(p->sets[i].sectArray);
  232. }
  233. cmMemFree(p->sets);
  234. }
  235. _cmScFreeSetList(p->setList);
  236. if( p->loc != NULL )
  237. {
  238. for(i=0; i<p->locCnt; ++i)
  239. cmMemFree(p->loc[i].evtArray);
  240. cmMemFree(p->loc);
  241. }
  242. cmMemFree(p->sect);
  243. cmMemFree(p->fn);
  244. cmMemFree(p->array);
  245. cmMemFree(p);
  246. return rc;
  247. }
  248. cmScRC_t _cmScParseBar( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int* barNumb )
  249. {
  250. if((*barNumb = cmCsvCellInt(p->cH,rowIdx,kBarColScIdx)) == INT_MAX )
  251. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to parse the bar number.");
  252. s->type = kBarEvtScId;
  253. s->secs = 0;
  254. s->barNumb = *barNumb;
  255. s->csvRowNumb = rowIdx + 1;
  256. return kOkScRC;
  257. }
  258. cmScSet_t* _cmScNewSet( cmSc_t* p, unsigned typeFl )
  259. {
  260. // create a new set record
  261. cmScSet_t* nsp = cmMemAllocZ(cmScSet_t,1);
  262. nsp->inFl = true;
  263. nsp->typeFl = typeFl;
  264. if( p->setList == NULL )
  265. p->setList = nsp;
  266. else
  267. {
  268. // go to the end of the the set list
  269. cmScSet_t* sp = p->setList;
  270. assert(sp!=NULL);
  271. while( sp->link != NULL )
  272. sp = sp->link;
  273. sp->link = nsp;
  274. }
  275. return nsp;
  276. }
  277. cmScSet_t* _cmScFindSet( cmSc_t* p, unsigned typeFl )
  278. {
  279. // locate the set currently accepting ele's for this type
  280. cmScSet_t* sp = p->setList;
  281. for(; sp != NULL; sp=sp->link )
  282. if( sp->typeFl == typeFl && sp->inFl )
  283. break;
  284. return sp;
  285. }
  286. void _cmScSetDone(cmSc_t* p, unsigned typeFl)
  287. {
  288. cmScSet_t* sp = _cmScFindSet(p,typeFl);
  289. assert( sp != NULL );
  290. sp->inFl = false;
  291. }
  292. // This function is called during parsing to
  293. // insert a set element or set section into a cmScSet_t
  294. // element or section linked list. Either the scoreIdx
  295. // or the label is valid but not both.
  296. cmScSet_t* _cmScInsertSetEle(cmSc_t* p, unsigned scoreIdx, unsigned typeFl, const cmChar_t* label, unsigned labelCharCnt)
  297. {
  298. assert( scoreIdx!=cmInvalidId || (scoreIdx==cmInvalidIdx && label!=NULL && labelCharCnt>0));
  299. cmScSet_t* sp = _cmScFindSet(p,typeFl);
  300. if( sp == NULL )
  301. sp = _cmScNewSet(p,typeFl);
  302. // allocate a new set element record
  303. cmScSetEle_t* nep = cmMemAllocZ(cmScSetEle_t,1);
  304. cmScSetEle_t** list = NULL;
  305. nep->eleIdx = scoreIdx;
  306. if( label == NULL )
  307. {
  308. // all elements must be of the same type
  309. assert( sp->typeFl == typeFl );
  310. sp->typeFl = typeFl;
  311. list = &sp->eles;
  312. }
  313. else
  314. {
  315. nep->label = cmMemAllocStrN(label,labelCharCnt);
  316. list = &sp->sects;
  317. }
  318. // *list refers to sp->sects or sp->ele's depending on the type of ele
  319. if( *list == NULL )
  320. *list = nep;
  321. else
  322. {
  323. // got to the last element in the set
  324. cmScSetEle_t* ep = *list;
  325. while( ep->link != NULL )
  326. ep = ep->link;
  327. // append the new element to the end of the list
  328. ep->link = nep;
  329. }
  330. return sp;
  331. }
  332. // Extract the next attribute section identifier.
  333. const cmChar_t* _cmScParseOneSetSection( cmSc_t* p, unsigned typeFl, const cmChar_t* c0p )
  334. {
  335. // advance white space
  336. while( *c0p && (isspace(*c0p) || *c0p==',') )
  337. ++c0p;
  338. if( *c0p==0 )
  339. return c0p;
  340. // c0p now points to a section id or an asterisk
  341. const cmChar_t* c1p = c0p;
  342. // advance past section id
  343. while( *c1p && (!isspace(*c1p) && (isdigit(*c1p) || isalpha(*c1p))))
  344. ++c1p;
  345. // if c0p pointed to an asterisk then c1p is still equal to c0p
  346. if( c1p > c0p )
  347. _cmScInsertSetEle(p,cmInvalidIdx,typeFl,c0p,c1p-c0p);
  348. return c1p;
  349. }
  350. // Parse an attribute string to extract the section
  351. // identifiers which may follow the attribute token (e,t,mf,ff,...)
  352. cmScRC_t _cmScParseAttr(cmSc_t* p, unsigned scoreIdx, const cmChar_t* text, unsigned typeFl)
  353. {
  354. const cmChar_t* cp = text;
  355. // insert a set element - all attribute's produce one element record
  356. _cmScInsertSetEle(p,scoreIdx,typeFl,NULL,0);
  357. // advance past the attribute type marking (e,t,(p,mf,f,fff,etc)) in search
  358. // of section identifiers
  359. while( *cp && !isspace(*cp) )
  360. ++cp;
  361. if( *cp )
  362. {
  363. // search for the first section identifier
  364. if((cp =_cmScParseOneSetSection(p,typeFl,cp)) != NULL )
  365. {
  366. bool asteriskFl = false;
  367. // search for the second section identifier
  368. if((cp = _cmScParseOneSetSection(p,typeFl,cp)) != NULL && *cp!=0 )
  369. asteriskFl = *cp == '*';
  370. _cmScSetDone(p,typeFl);
  371. // if the attr just parsed ended with an asterisk then it is both
  372. // the last element of the previous set and the first ele of the
  373. // next set
  374. if( asteriskFl )
  375. {
  376. // if the attr just parsed had a section id then it was the last
  377. // element in the set - create a new set record to hold the next set
  378. _cmScNewSet(p,typeFl);
  379. _cmScInsertSetEle(p,scoreIdx,typeFl,NULL,0);
  380. }
  381. }
  382. }
  383. return kOkScRC;
  384. }
  385. void _cmScPrintSets( const cmChar_t* label, cmScSet_t* setList )
  386. {
  387. printf("%s\n",label);
  388. const cmScSet_t* sp = setList;
  389. for(; sp != NULL; sp=sp->link )
  390. {
  391. const cmScSetEle_t* ep = sp->eles;
  392. for(; ep!=NULL; ep=ep->link)
  393. printf("%i ",ep->eleIdx);
  394. printf(" : ");
  395. for(ep=sp->sects; ep!=NULL; ep=ep->link)
  396. printf("%s ",cmStringNullGuard(ep->label));
  397. printf("\n");
  398. }
  399. }
  400. cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned scoreIdx, int barNumb, unsigned barNoteIdx )
  401. {
  402. cmScRC_t rc = kOkScRC;
  403. unsigned flags = 0;
  404. unsigned dynVal = kInvalidDynScId;
  405. const cmChar_t* sciPitch;
  406. cmMidiByte_t midiPitch;
  407. const cmChar_t* attr;
  408. double secs;
  409. double durSecs;
  410. const cmCsvCell_t* cell;
  411. s += scoreIdx;
  412. // verify the scientific pitch cell was formatted correcly
  413. if((cell = cmCsvCellPtr(p->cH,rowIdx,kPitchColScIdx)) == NULL || cell->lexTId != p->sciPitchLexTId )
  414. return cmErrMsg(&p->err,kSyntaxErrScRC,"Pitch column format error.");
  415. if((sciPitch = cmCsvCellText(p->cH,rowIdx,kPitchColScIdx)) == NULL )
  416. return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
  417. if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch)
  418. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
  419. // it is possible that note delta-secs field is empty - so default to 0
  420. if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
  421. flags += kInvalidScFl;
  422. // skip attribute
  423. if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
  424. flags += kSkipScFl;
  425. // evenness attribute
  426. if((attr = cmCsvCellText(p->cH,rowIdx,kEvenColScIdx)) != NULL && *attr == 'e' )
  427. {
  428. flags += kEvenScFl;
  429. _cmScParseAttr(p,scoreIdx,attr,kEvenScFl);
  430. }
  431. // tempo attribute
  432. if((attr = cmCsvCellText(p->cH,rowIdx,kTempoColScIdx)) != NULL && *attr == 't' )
  433. {
  434. flags += kTempoScFl;
  435. _cmScParseAttr(p,scoreIdx,attr,kTempoScFl);
  436. }
  437. // dynamics attribute
  438. if((attr = cmCsvCellText(p->cH,rowIdx,kDynColScIdx)) != NULL )
  439. {
  440. if((dynVal = _cmScDynLabelToId(attr)) == kInvalidDynScId )
  441. return cmErrMsg(&p->err,kSyntaxErrScRC,"Unknown dynamic label '%s'.",cmStringNullGuard(attr));
  442. flags += kDynScFl;
  443. _cmScParseAttr(p,scoreIdx,attr,kDynScFl);
  444. }
  445. // Returns DBL_MAX on error.
  446. if((durSecs = cmCsvCellDouble(p->cH, rowIdx, kDSecsColScIdx )) == DBL_MAX)
  447. durSecs = 0.25;
  448. s->type = kNonEvtScId;
  449. s->secs = secs;
  450. s->pitch = midiPitch;
  451. s->flags = flags;
  452. s->dynVal = dynVal;
  453. s->barNumb = barNumb;
  454. s->barNoteIdx = barNoteIdx;
  455. s->durSecs = durSecs;
  456. s->csvRowNumb = rowIdx+1;
  457. return rc;
  458. }
  459. cmScRC_t _cmScParseSectionColumn( cmSc_t* p, unsigned rowIdx, unsigned evtIdx, cmScSect_t* sectList )
  460. {
  461. const cmCsvCell_t* cell;
  462. cmScSect_t* sect;
  463. const cmChar_t* label;
  464. // most rows don't have section labels
  465. if( (cell = cmCsvCellPtr( p->cH,rowIdx,kSectionColScIdx)) == NULL
  466. || (label = cmCsvCellText(p->cH,rowIdx,kSectionColScIdx)) == NULL)
  467. return kOkScRC;
  468. // verify the section id type
  469. if( cell->lexTId != p->sectionLexTId && cell->lexTId != kIntLexTId )
  470. return cmErrMsg(&p->err,kSyntaxErrScRC,"'section' column format error.");
  471. sect = cmMemAllocZ(cmScSect_t,1);
  472. sect->label = label;
  473. sect->startIdx = evtIdx;
  474. //printf("section:%s\n",label);
  475. cmScSect_t* sp = sectList;
  476. assert( sp != NULL );
  477. while( sp->link != NULL )
  478. sp = sp->link;
  479. sp->link = sect;
  480. return kOkScRC;
  481. }
  482. cmScoreSection_t* _cmScLabelToSection( cmSc_t* p, const cmChar_t* label )
  483. {
  484. int i;
  485. for(i=0; i<p->sectCnt; ++i)
  486. if( strcmp(p->sect[i].label,label) == 0 )
  487. return p->sect + i;
  488. return NULL;
  489. }
  490. // Calculate the total number of all types of sets and
  491. // then convert each of the cmScSet_t linked list's to
  492. // a single linear cmScoreSet_t list (p->sets[]).
  493. cmScRC_t _cmScProcSets( cmSc_t* p )
  494. {
  495. cmScRC_t rc = kOkScRC;
  496. // calculate the count of all sets
  497. unsigned i;
  498. unsigned n = 0;
  499. cmScSet_t* sp = p->setList;
  500. for(n=0; sp!=NULL; sp=sp->link)
  501. if( sp->eles != NULL )
  502. ++n;
  503. // allocate the linear set array
  504. p->sets = cmMemAllocZ(cmScoreSet_t,n);
  505. p->setCnt = n;
  506. // fill in the linear set array
  507. sp = p->setList;
  508. for(i=0; sp!=NULL; sp=sp->link)
  509. if( sp->eles != NULL )
  510. {
  511. unsigned j;
  512. unsigned en;
  513. unsigned rowNumb = 0;
  514. assert( i<n );
  515. // get the count of elements assoc'd with this set
  516. cmScSetEle_t* ep = sp->eles;
  517. for(en=0; ep!=NULL; ep=ep->link)
  518. ++en;
  519. assert( en > 0 );
  520. // allocate the element array
  521. p->sets[i].eleCnt = en;
  522. p->sets[i].eleArray = cmMemAllocZ(cmScoreEvt_t*,en);
  523. // fill in the element array
  524. ep = sp->eles;
  525. for(j=0; ep!=NULL; ep=ep->link,++j)
  526. {
  527. assert(ep->eleIdx != cmInvalidIdx && ep->eleIdx<p->cnt);
  528. p->sets[i].eleArray[j] = p->array + ep->eleIdx;
  529. assert( cmIsFlag( p->sets[i].eleArray[j]->flags, sp->typeFl) );
  530. rowNumb = p->array[ep->eleIdx].csvRowNumb;
  531. }
  532. // get the count of sections assoc'd with this set
  533. ep = sp->sects;
  534. for(en=0; ep!=NULL; ep=ep->link)
  535. ++en;
  536. // allocate the section array
  537. p->sets[i].typeFl = sp->typeFl;
  538. p->sets[i].sectCnt = en;
  539. p->sets[i].sectArray = cmMemAllocZ(cmScoreSection_t*,en);
  540. // fill in the section array
  541. ep = sp->sects;
  542. for(j=0; ep!=NULL; ep=ep->link,++j)
  543. {
  544. assert(ep->label != NULL);
  545. if((p->sets[i].sectArray[j] = _cmScLabelToSection(p, ep->label )) == NULL )
  546. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The section labelled '%s' could not be found for the set which includes row number %i.",ep->label,rowNumb);
  547. }
  548. ++i;
  549. }
  550. assert(i==n);
  551. // assign each set to the location which contains it's last element.
  552. // (this is earliest point in the score location where all the
  553. // performance information contained in the set may be valid)
  554. for(i=0; i<p->setCnt; ++i)
  555. {
  556. assert( p->sets[i].eleCnt >= 1 );
  557. // get a ptr to the last element for the ith set
  558. const cmScoreEvt_t* ep = p->sets[i].eleArray[ p->sets[i].eleCnt-1 ];
  559. unsigned j,k;
  560. // find the location which contains the last element
  561. for(j=0; j<p->locCnt; ++j)
  562. {
  563. for(k=0; k<p->loc[j].evtCnt; ++k)
  564. if( p->loc[j].evtArray[k] == ep )
  565. break;
  566. if(k<p->loc[j].evtCnt)
  567. break;
  568. }
  569. assert( j<p->locCnt );
  570. // assign the ith set to the location which contains it's last element
  571. p->sets[i].link = p->loc[j].setList;
  572. p->loc[j].setList = p->sets + i;
  573. }
  574. return rc;
  575. }
  576. cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList )
  577. {
  578. cmScRC_t rc = kOkScRC;
  579. unsigned i;
  580. // count the sections
  581. cmScSect_t* sp = sectList;
  582. p->sectCnt = 0;
  583. for(; sp!=NULL; sp=sp->link)
  584. if( sp->label != NULL )
  585. ++p->sectCnt;
  586. // alloc a section array
  587. p->sect = cmMemAllocZ(cmScoreSection_t,p->sectCnt);
  588. // fill the section array
  589. sp = sectList;
  590. for(i=0; sp!=NULL; sp=sp->link)
  591. if( sp->label != NULL )
  592. {
  593. p->sect[i].label = sp->label;
  594. p->sect[i].begIndex = sp->startIdx;
  595. ++i;
  596. }
  597. // assign the begSectPtr to each section
  598. for(i=0; i<p->sectCnt; ++i)
  599. {
  600. assert( p->sect[i].begIndex < p->cnt );
  601. unsigned j,k;
  602. const cmScoreEvt_t* ep = p->array + p->sect[i].begIndex;
  603. for(j=0; j<p->locCnt; ++j)
  604. {
  605. for(k=0; k<p->loc[j].evtCnt; ++k)
  606. if( p->loc[j].evtArray[k] == ep )
  607. {
  608. p->loc[j].begSectPtr = p->sect + i;
  609. p->sect[i].locPtr = p->loc + j;
  610. break;
  611. }
  612. if( k<p->loc[j].evtCnt)
  613. break;
  614. }
  615. }
  616. // release the section linked list
  617. sp = sectList;
  618. cmScSect_t* np = NULL;
  619. while(sp!=NULL)
  620. {
  621. np = sp->link;
  622. cmMemFree(sp);
  623. sp = np;
  624. }
  625. _cmScPrintSets("Sets",p->setList );
  626. //_cmScPrintSets("even",p->evenSetList);
  627. //_cmScPrintSets("dyn",p->evenSetList);
  628. //_cmScPrintSets("tempo",p->evenSetList);
  629. _cmScProcSets(p);
  630. return rc;
  631. }
  632. cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
  633. {
  634. cmScRC_t rc = kOkScRC;
  635. unsigned barNoteIdx = 0;
  636. int barEvtIdx = cmInvalidIdx;
  637. int barNumb = 0;
  638. double secs;
  639. double cur_secs = 0;
  640. p->sectList = cmMemAllocZ(cmScSect_t,1); // section zero
  641. //_cmScNewSet(p); // preallocate the first set
  642. // initialize the CSV file parser
  643. if( cmCsvInitialize(&p->cH, ctx ) != kOkCsvRC )
  644. {
  645. rc = cmErrMsg(&p->err,kCsvFailScRC,"Score file initialization failed.");
  646. goto errLabel;
  647. }
  648. // register custom lex token matchers for sci-pitch and section id's
  649. if( cmCsvLexRegisterMatcher(p->cH, p->sciPitchLexTId = cmCsvLexNextAvailId(p->cH)+0, _cmScLexSciPitchMatcher ) != kOkCsvRC
  650. ||cmCsvLexRegisterMatcher(p->cH, p->sectionLexTId = cmCsvLexNextAvailId(p->cH)+1, _cmScLexSectionIdMatcher) != kOkCsvRC )
  651. {
  652. rc = cmErrMsg(&p->err,kCsvFailScRC,"CSV token matcher registration failed.");
  653. goto errLabel;
  654. }
  655. // parse the CSV file
  656. if( cmCsvParseFile(p->cH, fn, 0 ) != kOkCsvRC )
  657. {
  658. rc = cmErrMsg(&p->err,kCsvFailScRC,"CSV file parsing failed on the file '%s'.",cmStringNullGuard(fn));
  659. goto errLabel;
  660. }
  661. // allocate the score event array
  662. p->cnt = cmCsvRowCount(p->cH);
  663. p->array = cmMemAllocZ(cmScoreEvt_t,p->cnt);
  664. unsigned i,j;
  665. // skip labels line - start on line 1
  666. for(i=1,j=0; i<p->cnt && rc==kOkScRC; ++i)
  667. {
  668. // get the row 'type' label
  669. const char* typeLabel;
  670. if((typeLabel = cmCsvCellText(p->cH,i,kTypeLabelColScIdx)) == NULL )
  671. {
  672. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"No type label.");
  673. break;
  674. }
  675. // convert the row 'type' label to an id
  676. unsigned tid;
  677. if((tid = _cmScEvtTypeLabelToId(typeLabel)) == kInvalidEvtScId)
  678. {
  679. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"Unknown type '%s'.",cmStringNullGuard(typeLabel));
  680. break;
  681. }
  682. secs = DBL_MAX;
  683. switch(tid)
  684. {
  685. case kBarEvtScId: // parse bar lines
  686. if((rc = _cmScParseBar(p,i,p->array+j,&barNumb)) == kOkScRC )
  687. {
  688. barNoteIdx = 0;
  689. barEvtIdx = j;
  690. p->array[j].index = j;
  691. ++j;
  692. }
  693. break;
  694. case kNonEvtScId: // parse note-on events
  695. if((rc = _cmScParseNoteOn(p, i, p->array, j, barNumb, barNoteIdx )) == kOkScRC )
  696. {
  697. secs = p->array[j].secs;
  698. if( p->array[j].secs == DBL_MAX )
  699. p->array[j].secs = cur_secs;
  700. if( cmIsFlag(p->array[j].flags,kSkipScFl) == false )
  701. {
  702. p->array[j].index = j;
  703. ++j;
  704. }
  705. ++barNoteIdx;
  706. }
  707. break;
  708. default:
  709. // Returns DBL_MAX on error.
  710. secs = cmCsvCellDouble(p->cH, i, kSecsColScIdx );
  711. break;
  712. }
  713. if( secs != DBL_MAX )
  714. cur_secs = secs;
  715. // form the section list
  716. if( j > 0 )
  717. if((rc = _cmScParseSectionColumn(p,i,j-1,p->sectList)) != kOkScRC )
  718. break;
  719. // the bar lines don't have times so set the time of the bar line to the
  720. // time of the first event in the bar.
  721. if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
  722. {
  723. assert( p->array[ barEvtIdx ].type == kBarEvtScId );
  724. p->array[ barEvtIdx ].secs = secs;
  725. // handle the case where the previous bar had no events
  726. // BUG BUG BUG this is a hack which will fail if the first bar does not have events.
  727. if( barEvtIdx>=1 && p->array[ barEvtIdx-1].type == kBarEvtScId )
  728. p->array[ barEvtIdx-1].secs = secs;
  729. barEvtIdx = cmInvalidIdx;
  730. }
  731. }
  732. if( rc == kSyntaxErrScRC )
  733. {
  734. cmErrMsg(&p->err,rc,"Syntax error on line %i in '%s'.",i+1,cmStringNullGuard(fn));
  735. goto errLabel;
  736. }
  737. p->cnt = j;
  738. errLabel:
  739. return rc;
  740. }
  741. // This function does not currently work because there is no
  742. // guarantee that all the time values (secs field) have been filled in
  743. /// with valid times and that all event records have a valid 'type' id.
  744. cmScRC_t _cmScoreInitLocArray( cmSc_t* p )
  745. {
  746. cmScRC_t rc = kOkScRC;
  747. double maxDSecs = 0; // max time between events that are considered simultaneous
  748. unsigned barNumb = 0;
  749. int i,j,k;
  750. if( p->cnt==0)
  751. return rc;
  752. p->locCnt = 1;
  753. // count the number of unique time locations in the score
  754. p->locCnt = 1;
  755. for(i=1; i<p->cnt; ++i )
  756. {
  757. if( p->array[i].secs < p->array[i-1].secs )
  758. rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The time associated with the score entry on line %i is less than the previous line.",p->array[i].csvRowNumb);
  759. if( (p->array[i].secs - p->array[i-1].secs) > maxDSecs )
  760. ++p->locCnt;
  761. }
  762. if( rc != kOkScRC )
  763. return rc;
  764. // allocate the loc. array
  765. p->loc = cmMemAllocZ(cmScoreLoc_t,p->locCnt);
  766. // fill in the location array
  767. for(i=0,k=0; i<p->cnt; ++k)
  768. {
  769. j = i+1;
  770. // get the count of events at this location
  771. while( j<p->cnt && p->array[j].secs - p->array[j-1].secs <= maxDSecs )
  772. ++j;
  773. assert(k<p->locCnt);
  774. p->loc[k].evtCnt = j-i;
  775. p->loc[k].evtArray = cmMemAllocZ(cmScoreEvt_t*,p->loc[k].evtCnt);
  776. // fill in the location record event pointers
  777. for(j=0; j<p->loc[k].evtCnt; ++j)
  778. {
  779. p->loc[k].evtArray[j] = p->array + (i + j);
  780. if( p->array[i+j].type == kBarEvtScId )
  781. barNumb = p->array[i+j].barNumb;
  782. }
  783. // fill in the location record
  784. p->loc[k].secs = p->array[i].secs;
  785. p->loc[k].barNumb = barNumb;
  786. i += p->loc[k].evtCnt;
  787. }
  788. assert( p->locCnt == k );
  789. return rc;
  790. }
  791. cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg )
  792. {
  793. cmScRC_t rc = kOkScRC;
  794. if((rc = cmScoreFinalize(hp)) != kOkScRC )
  795. return rc;
  796. cmSc_t* p = cmMemAllocZ(cmSc_t,1);
  797. cmErrSetup(&p->err,&ctx->rpt,"Score");
  798. if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC )
  799. goto errLabel;
  800. // See note at function
  801. if((rc = _cmScoreInitLocArray(p)) != kOkScRC )
  802. goto errLabel;
  803. if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC )
  804. goto errLabel;
  805. p->cbFunc = cbFunc;
  806. p->cbArg = cbArg;
  807. p->fn = cmMemAllocStr(fn);
  808. hp->h = p;
  809. cmScoreClearPerfInfo(*hp);
  810. //cmScorePrintLoc(*hp);
  811. errLabel:
  812. if( rc != kOkScRC )
  813. _cmScFinalize(p);
  814. return rc;
  815. }
  816. cmScRC_t cmScoreFinalize( cmScH_t* hp )
  817. {
  818. cmScRC_t rc = kOkScRC;
  819. if( hp == NULL || cmScoreIsValid(*hp) == false )
  820. return kOkScRC;
  821. cmSc_t* p = _cmScHandleToPtr(*hp);
  822. if((rc = _cmScFinalize(p)) != kOkScRC )
  823. return rc;
  824. hp->h = NULL;
  825. return rc;
  826. }
  827. const cmChar_t* cmScoreFileName( cmScH_t h )
  828. {
  829. cmSc_t* p = _cmScHandleToPtr(h);
  830. return p->fn;
  831. }
  832. bool cmScoreIsValid( cmScH_t h )
  833. { return h.h != NULL; }
  834. unsigned cmScoreEvtCount( cmScH_t h )
  835. {
  836. cmSc_t* p = _cmScHandleToPtr(h);
  837. return p->cnt;
  838. }
  839. cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx )
  840. {
  841. cmSc_t* p = _cmScHandleToPtr(h);
  842. if( idx >= p->cnt )
  843. {
  844. cmErrMsg(&p->err,kInvalidIdxScRC,"%i is an invalid index for %i records.",idx,p->cnt);
  845. return NULL;
  846. }
  847. return p->array + idx;
  848. }
  849. unsigned cmScoreLocCount( cmScH_t h )
  850. {
  851. cmSc_t* p = _cmScHandleToPtr(h);
  852. return p->locCnt;
  853. }
  854. cmScoreLoc_t* cmScoreLoc( cmScH_t h, unsigned idx )
  855. {
  856. cmSc_t* p = _cmScHandleToPtr(h);
  857. if( idx >= p->locCnt )
  858. {
  859. cmErrMsg(&p->err,kInvalidIdxScRC,"%i is an invalid index for %i location records.",idx,p->locCnt);
  860. return NULL;
  861. }
  862. return p->loc + idx;
  863. }
  864. char _cmScFlagsToChar( unsigned flags )
  865. {
  866. switch(flags)
  867. {
  868. case kEvenScFl: return 'e';
  869. case kDynScFl: return 'd';
  870. case kTempoScFl:return 't';
  871. default:
  872. { assert(0); }
  873. }
  874. return ' ';
  875. }
  876. const char* _cmScFlagsToStr( unsigned flags, char* buf, int bufCharCnt )
  877. {
  878. unsigned i=0;
  879. if( cmIsFlag(flags,kEvenScFl) )
  880. {
  881. assert(i<bufCharCnt);
  882. buf[i] = 'e';
  883. ++i;
  884. }
  885. if( cmIsFlag(flags,kDynScFl) )
  886. {
  887. assert(i<bufCharCnt);
  888. buf[i] = 'd';
  889. ++i;
  890. }
  891. if( cmIsFlag(flags,kTempoScFl ))
  892. {
  893. assert(i<bufCharCnt);
  894. buf[i] = 't';
  895. ++i;
  896. }
  897. assert(i<bufCharCnt);
  898. buf[i] = 0;
  899. return buf;
  900. }
  901. void cmScorePrintLoc( cmScH_t h )
  902. {
  903. unsigned i = 0;
  904. cmSc_t* p = _cmScHandleToPtr(h);
  905. unsigned colCnt = 10;
  906. int bufCharCnt = 4;
  907. char buf[ bufCharCnt ];
  908. const char* emptyStr = " ";
  909. for(i=0; i<p->locCnt; i+=colCnt )
  910. {
  911. unsigned c,j,k;
  912. printf("index: ");
  913. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  914. printf("%7i ",j);
  915. printf("\n");
  916. printf("sectn: ");
  917. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  918. if( p->loc[j].begSectPtr==NULL )
  919. printf("%s",emptyStr);
  920. else
  921. printf("%7s ",p->loc[j].begSectPtr->label);
  922. printf("\n");
  923. unsigned n=0;
  924. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  925. if( p->loc[j].evtCnt > n )
  926. n = p->loc[j].evtCnt;
  927. for(k=0; k<n; ++k)
  928. {
  929. printf("sco%2i: ",k);
  930. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  931. if( k >= p->loc[j].evtCnt )
  932. printf("%s",emptyStr);
  933. else
  934. {
  935. switch(p->loc[j].evtArray[k]->type)
  936. {
  937. case kBarEvtScId:
  938. printf(" |%3i ",p->loc[j].evtArray[k]->barNumb);
  939. break;
  940. case kNonEvtScId:
  941. {
  942. int bn=16;
  943. char b[bn];
  944. strcpy(b,cmMidiToSciPitch(p->loc[j].evtArray[k]->pitch,NULL,0));
  945. strcat(b,_cmScFlagsToStr( p->loc[j].evtArray[k]->flags,buf,bufCharCnt));
  946. assert(strlen(b)<bn);
  947. printf("%7s ",b);
  948. break;
  949. }
  950. }
  951. }
  952. printf("\n");
  953. }
  954. n=0;
  955. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  956. {
  957. unsigned m = 0;
  958. const cmScoreSet_t* sp = p->loc[j].setList;
  959. for(; sp!=NULL; sp=sp->link)
  960. m += sp->sectCnt;
  961. if( m>n)
  962. n = m;
  963. }
  964. for(k=0; k<n; ++k)
  965. {
  966. printf("trig%1i: ",k);
  967. for(c=0,j=i; j<p->locCnt && c<colCnt; ++c,++j)
  968. {
  969. unsigned y = 0;
  970. bool fl = true;
  971. const cmScoreSet_t* sp = p->loc[j].setList;
  972. for(; sp!=NULL && fl; sp=sp->link)
  973. {
  974. unsigned z;
  975. for(z=0; z<sp->sectCnt; ++y,++z)
  976. if( y == k )
  977. {
  978. printf(" %3s%c ",sp->sectArray[z]->label,_cmScFlagsToChar(sp->typeFl) );
  979. fl = false;
  980. break;
  981. }
  982. }
  983. if( fl )
  984. printf("%s",emptyStr);
  985. }
  986. printf("\n");
  987. }
  988. printf("\n");
  989. }
  990. }
  991. cmScRC_t cmScoreSeqNotify( cmScH_t h )
  992. {
  993. cmScRC_t rc = kOkScRC;
  994. cmSc_t* p = _cmScHandleToPtr(h);
  995. cmScMsg_t m;
  996. unsigned i;
  997. if( p->cbFunc != NULL )
  998. {
  999. memset(&m.evt,0,sizeof(m.evt));
  1000. m.typeId = kBeginMsgScId;
  1001. p->cbFunc(p->cbArg,&m,sizeof(m));
  1002. m.typeId = kEventMsgScId;
  1003. for(i=0; i<p->cnt; ++i)
  1004. {
  1005. m.evt = p->array[i];
  1006. p->cbFunc(p->cbArg,&m,sizeof(m));
  1007. }
  1008. memset(&m.evt,0,sizeof(m.evt));
  1009. m.typeId = kEndMsgScId;
  1010. p->cbFunc(p->cbArg,&m,sizeof(m));
  1011. }
  1012. return rc;
  1013. }
  1014. void cmScoreClearPerfInfo( cmScH_t h )
  1015. {
  1016. cmSc_t* p = _cmScHandleToPtr(h);
  1017. unsigned i;
  1018. for(i=0; i<p->cnt; ++i)
  1019. {
  1020. p->array[i].perfSmpIdx = cmInvalidIdx;
  1021. p->array[i].perfVel = 0;
  1022. }
  1023. }
  1024. bool _cmScIsSetPerfDone( cmScoreSet_t* sp )
  1025. {
  1026. unsigned i = 0;
  1027. for(i=0; i<sp->eleCnt; ++i)
  1028. if( sp->eleArray[i]->perfSmpIdx == cmInvalidIdx )
  1029. return false;
  1030. return true;
  1031. }
  1032. void cmScoreSetPerfEvent( cmScH_t h, unsigned locIdx, unsigned smpIdx, unsigned pitch, unsigned vel )
  1033. {
  1034. cmSc_t* p = _cmScHandleToPtr(h);
  1035. assert(locIdx < p->locCnt );
  1036. cmScoreLoc_t* lp = p->loc + locIdx;
  1037. unsigned i;
  1038. for(i=0; i<lp->evtCnt; ++i)
  1039. {
  1040. cmScoreEvt_t* ep = lp->evtArray[i];
  1041. if( ep->type == kNonEvtScId && ep->pitch == pitch )
  1042. {
  1043. assert( ep->perfSmpIdx == cmInvalidIdx );
  1044. ep->perfSmpIdx = smpIdx;
  1045. ep->perfVel = vel;
  1046. break;
  1047. }
  1048. }
  1049. }
  1050. cmScRC_t cmScoreDecode( const void* msg, unsigned msgByteCnt, cmScMsg_t* m)
  1051. {
  1052. cmScMsg_t* mp = (cmScMsg_t*)msg;
  1053. *m = *mp;
  1054. return kOkScRC;
  1055. }
  1056. void cmScorePrint( cmScH_t h, cmRpt_t* rpt )
  1057. {
  1058. cmSc_t* p = _cmScHandleToPtr(h);
  1059. unsigned i;
  1060. for(i=0; i<20 /*p->cnt*/; ++i)
  1061. {
  1062. cmScoreEvt_t* r = p->array + i;
  1063. switch(r->type)
  1064. {
  1065. case kNonEvtScId:
  1066. cmRptPrintf(rpt,"%5i %3i %3i %s 0x%2x %c%c%c %s\n",
  1067. i,
  1068. r->barNumb,
  1069. r->barNoteIdx,
  1070. cmScEvtTypeIdToLabel(r->type),
  1071. r->pitch,
  1072. cmIsFlag(r->flags,kEvenScFl) ? 'e' : ' ',
  1073. cmIsFlag(r->flags,kTempoScFl) ? 't' : ' ',
  1074. cmIsFlag(r->flags,kDynScFl) ? 'd' : ' ',
  1075. cmIsFlag(r->flags,kDynScFl) ? cmScDynIdToLabel(r->dynVal) : "");
  1076. break;
  1077. default:
  1078. break;
  1079. }
  1080. }
  1081. }
  1082. /*
  1083. // Each time line note-on object is decorated (via cmTlObj_t.userDataPtr) with a
  1084. // cmScSyncState_t record.
  1085. typedef struct
  1086. {
  1087. unsigned cnt; // count of candidate sync locations
  1088. double dist; // edit distance to the closest sync location
  1089. unsigned scEvtIdx; // score record this note-on is assigned to
  1090. } cmScSyncState_t;
  1091. void _cmScSyncTimeLineAllocFree( cmTlH_t tlH, bool allocFl )
  1092. {
  1093. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  1094. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId))
  1095. if( mep->msg->status == kNoteOnMdId )
  1096. {
  1097. if( allocFl )
  1098. mep->obj.userDataPtr = cmMemAllocZ(cmScSyncState_t,1);
  1099. else
  1100. cmMemPtrFree(&mep->obj.userDataPtr);
  1101. }
  1102. }
  1103. void _cmScPrintSyncState( cmSc_t* p, cmTlH_t tlH )
  1104. {
  1105. unsigned i = 0;
  1106. double sr = cmTimeLineSampleRate(tlH);
  1107. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  1108. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId))
  1109. if( mep->msg->status == kNoteOnMdId )
  1110. {
  1111. cmScSyncState_t* ssp = (cmScSyncState_t*)mep->obj.userDataPtr;
  1112. cmRptPrintf(p->err.rpt,"%5.3f pit:0x%2x (%3i) bar:%3i bni:%3i cnt:%3i dst:%1.6f ref:%s\n",
  1113. (mep->obj.ref->begSmpIdx - mep->obj.begSmpIdx) / (sr*60),
  1114. mep->msg->u.chMsgPtr->d0,
  1115. mep->msg->u.chMsgPtr->d0,
  1116. ssp->cnt ? p->array[ ssp->scEvtIdx ].barNumb : 0,
  1117. ssp->cnt ? p->array[ ssp->scEvtIdx ].barNoteIdx : 0,
  1118. ssp->cnt,
  1119. ssp->dist,
  1120. cmStringNullGuard(mep->obj.ref->name));
  1121. ++i;
  1122. if( i>=300)
  1123. break;
  1124. }
  1125. }
  1126. double _cmScWndEditDist( cmSc_t* p, unsigned* mtx, const unsigned* tlWnd, cmScSyncState_t* tlObjWnd[], unsigned wndCnt )
  1127. {
  1128. unsigned scWnd[ wndCnt ];
  1129. unsigned scIdxWnd[ wndCnt ];
  1130. unsigned i;
  1131. unsigned wn = 0;
  1132. double minDist = DBL_MAX;
  1133. // for each note-on score event
  1134. for(i=0; i<p->cnt; ++i)
  1135. if( p->array[i].type == kNonEvtScId )
  1136. {
  1137. // shift the score event window to the the left
  1138. memmove(scWnd, scWnd+1, (wndCnt-1)*sizeof(scWnd[0]));
  1139. memmove(scIdxWnd,scIdxWnd+1,(wndCnt-1)*sizeof(scIdxWnd[0]));
  1140. // insert new score event data on right
  1141. scWnd[wndCnt-1] = p->array[i].pitch;
  1142. scIdxWnd[wndCnt-1] = i;
  1143. ++wn;
  1144. // if the window is full
  1145. if(wn >= wndCnt )
  1146. {
  1147. // score the edit distance between the time line window and the edit window
  1148. double dist = cmVOU_LevEditDist(wndCnt,mtx,scWnd,wndCnt,tlWnd,wndCnt,wndCnt);
  1149. if( dist < minDist )
  1150. minDist = dist;
  1151. // update the match information in the time line window
  1152. unsigned j;
  1153. for(j=0; j<wndCnt; ++j)
  1154. {
  1155. // if the pitch matches and the score is less than the previous score
  1156. if( scWnd[j] == tlWnd[j] && (tlObjWnd[j]->cnt == 0 || dist < tlObjWnd[j]->dist) )
  1157. {
  1158. tlObjWnd[j]->cnt += 1;
  1159. tlObjWnd[j]->dist = dist;
  1160. tlObjWnd[j]->scEvtIdx = scIdxWnd[j];
  1161. }
  1162. }
  1163. }
  1164. }
  1165. return minDist;
  1166. }
  1167. cmScRC_t cmScoreSyncTimeLine( cmScH_t scH, cmTlH_t tlH, unsigned edWndCnt, cmReal_t maxSecs )
  1168. {
  1169. cmSc_t* p = _cmScHandleToPtr(scH);
  1170. unsigned* edWndMtx = cmVOU_LevEditDistAllocMtx(edWndCnt);
  1171. unsigned maxMicroSecs = floor(maxSecs*1000000);
  1172. unsigned edWndData[ edWndCnt ];
  1173. cmScSyncState_t* edWndObj[ edWndCnt ];
  1174. // alloc a sync state record for each MIDI note-on in the time line
  1175. _cmScSyncTimeLineAllocFree(tlH, true );
  1176. // get the first time line object
  1177. cmTlObj_t* rfp = cmTimeLineNextTypeObj(tlH,NULL,cmInvalidId,kMidiFileTlId);
  1178. // interate through the time line in search of MIDI file objects
  1179. for(; rfp != NULL; rfp = cmTimeLineNextTypeObj(tlH,rfp,cmInvalidId,kMidiFileTlId))
  1180. {
  1181. cmTlMidiFile_t* mfp = cmTimeLineMidiFileObjPtr(tlH,rfp);
  1182. unsigned curEdWndCnt = 0;
  1183. double prog = 0.1;
  1184. unsigned progIdx = 0;
  1185. cmRptPrintf(p->err.rpt,"MIDI File:%s\n", cmMidiFileName( mfp->h ));
  1186. // get first midi event object
  1187. cmTlMidiEvt_t* mep = cmTlNextMidiEvtObjPtr(tlH,NULL,cmInvalidId);
  1188. // iterate through the time line in search of MIDI note-on events with belong to mfp
  1189. for(; mep != NULL; mep = cmTlNextMidiEvtObjPtr(tlH,&mep->obj,cmInvalidId) )
  1190. {
  1191. if( mep->obj.ref == rfp && mep->msg->status == kNoteOnMdId )
  1192. {
  1193. // If this notes inter-onset time is greater than maxMicroSecs
  1194. // then dispose of the current window and begin refilling it again.
  1195. if( mep->msg->dtick > maxMicroSecs )
  1196. curEdWndCnt = 0;
  1197. // shift window one slot to left
  1198. unsigned i;
  1199. for(i=0; i<edWndCnt-1; ++i)
  1200. {
  1201. edWndData[i] = edWndData[i+1];
  1202. edWndObj[i] = edWndObj[i+1];
  1203. }
  1204. // fill window on right
  1205. edWndData[edWndCnt-1] = mep->msg->u.chMsgPtr->d0; // d0=pitch
  1206. edWndObj[ edWndCnt-1] = (cmScSyncState_t*)mep->obj.userDataPtr;
  1207. ++curEdWndCnt;
  1208. // if a complete window exists then update the time-line / score match state
  1209. if( curEdWndCnt >= edWndCnt )
  1210. _cmScWndEditDist( p, edWndMtx, edWndData, edWndObj, edWndCnt );
  1211. // print the progress
  1212. ++progIdx;
  1213. if( progIdx >= prog * mfp->noteOnCnt )
  1214. {
  1215. cmRptPrintf(p->err.rpt,"%i ",(unsigned)round(prog*10));
  1216. prog += 0.1;
  1217. }
  1218. }
  1219. }
  1220. cmRptPrintf(p->err.rpt,"\n");
  1221. }
  1222. _cmScPrintSyncState(p,tlH );
  1223. // free sync state records
  1224. _cmScSyncTimeLineAllocFree(tlH,false);
  1225. cmMemFree(edWndMtx);
  1226. return kOkScRC;
  1227. }
  1228. cmScRC_t cmScoreSyncTimeLineTest( cmCtx_t* ctx, const cmChar_t* timeLineJsFn, const cmChar_t* scoreCsvFn )
  1229. {
  1230. cmScRC_t rc = kOkScRC;
  1231. cmTlH_t tlH = cmTimeLineNullHandle;
  1232. cmScH_t scH = cmScNullHandle;
  1233. unsigned edWndCnt = 7;
  1234. cmReal_t maxSecs = 2.0;
  1235. if((rc = cmTimeLineInitialize(ctx,&tlH,NULL,NULL)) != kOkTlRC )
  1236. return cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line initialization failed.");;
  1237. if((rc = cmTimeLineReadJson(tlH,timeLineJsFn)) != kOkTlRC )
  1238. {
  1239. rc = cmErrMsg(&ctx->err,kTimeLineFailScRC,"Time line parse failed.");;
  1240. goto errLabel;
  1241. }
  1242. //cmTimeLinePrint(tlH,&ctx->rpt);
  1243. if(1)
  1244. {
  1245. if((rc = cmScoreInitialize(ctx,&scH,scoreCsvFn,NULL,NULL)) != kOkScRC )
  1246. goto errLabel;
  1247. rc = cmScoreSyncTimeLine(scH, tlH, edWndCnt, maxSecs );
  1248. }
  1249. //cmScorePrint(scH, ctx->err.rpt );
  1250. errLabel:
  1251. cmScoreFinalize(&scH);
  1252. cmTimeLineFinalize(&tlH);
  1253. return rc;
  1254. }
  1255. */
  1256. void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
  1257. {
  1258. cmScH_t h = cmScNullHandle;
  1259. if( cmScoreInitialize(ctx,&h,fn,NULL,NULL) != kOkScRC )
  1260. return;
  1261. cmScorePrint(h,&ctx->rpt);
  1262. cmScoreFinalize(&h);
  1263. }
  1264. // 1. Fix absolute message time which was incorrect on original score file.
  1265. // 2.
  1266. void cmScoreFix( cmCtx_t* ctx )
  1267. {
  1268. const cmChar_t* mfn = "/home/kevin/src/cmgv/src/gv/data/ImaginaryThemes.mid";
  1269. const cmChar_t* crfn = "/home/kevin/src/cmgv/src/gv/data/mod0a.txt";
  1270. const cmChar_t* cwfn = "/home/kevin/src/cmgv/src/gv/data/mod1.csv";
  1271. cmMidiFileH_t mfH = cmMidiFileNullHandle;
  1272. cmCsvH_t csvH = cmCsvNullHandle;
  1273. const cmMidiTrackMsg_t** msg = NULL;
  1274. double secs = 0.0;
  1275. int ci,mi,crn,mn;
  1276. bool errFl = true;
  1277. unsigned handCnt = 0;
  1278. unsigned midiMissCnt = 0;
  1279. if( cmCsvInitialize(&csvH,ctx) != kOkCsvRC )
  1280. goto errLabel;
  1281. if( cmCsvLexRegisterMatcher(csvH, cmCsvLexNextAvailId(csvH), _cmScLexSciPitchMatcher ) != kOkCsvRC )
  1282. goto errLabel;
  1283. if( cmCsvParseFile(csvH, crfn, 0 ) != kOkCsvRC )
  1284. goto errLabel;
  1285. if( cmMidiFileOpen(mfn,&mfH,ctx) != kOkMfRC )
  1286. goto errLabel;
  1287. cmMidiFileTickToMicros(mfH);
  1288. cmMidiFileCalcNoteDurations(mfH);
  1289. mn = cmMidiFileMsgCount(mfH);
  1290. msg = cmMidiFileMsgArray(mfH);
  1291. crn = cmCsvRowCount(csvH);
  1292. // for each row in the score file
  1293. for(ci=1,mi=0; ci<crn && cmCsvLastRC(csvH)==kOkCsvRC; ++ci)
  1294. {
  1295. unsigned id;
  1296. // zero the duration column
  1297. if( cmCsvCellPtr(csvH, ci, kDSecsColScIdx ) != NULL )
  1298. cmCsvSetCellUInt( csvH, ci, kDSecsColScIdx, 0 );
  1299. // get the MIDI file event id for this row
  1300. if((id = cmCsvCellUInt(csvH,ci,kMidiFileIdColScIdx)) == UINT_MAX)
  1301. {
  1302. // this is a hand-entered event - so it has no event id
  1303. ++handCnt;
  1304. }
  1305. else
  1306. {
  1307. for(; mi<mn; ++mi)
  1308. {
  1309. const cmMidiTrackMsg_t* m = msg[mi];
  1310. assert( mi+1 <= id );
  1311. secs += m->dtick/1000000.0;
  1312. if( mi+1 != id )
  1313. {
  1314. if( m->status == kNoteOnMdId && m->u.chMsgPtr->d1>0 )
  1315. {
  1316. // this MIDI note-on does not have a corresponding score event
  1317. ++midiMissCnt;
  1318. }
  1319. }
  1320. else
  1321. {
  1322. cmCsvSetCellDouble( csvH, ci, kSecsColScIdx, secs );
  1323. ++mi;
  1324. if( m->status == kNoteOnMdId )
  1325. cmCsvSetCellDouble( csvH, ci, kDSecsColScIdx, m->u.chMsgPtr->durTicks/1000000.0 );
  1326. break;
  1327. }
  1328. }
  1329. if( mi==mn)
  1330. printf("done on row:%i\n",ci);
  1331. }
  1332. }
  1333. if( cmCsvLastRC(csvH) != kOkCsvRC )
  1334. goto errLabel;
  1335. if( cmCsvWrite(csvH,cwfn) != kOkCsvRC )
  1336. goto errLabel;
  1337. errFl = false;
  1338. errLabel:
  1339. if( errFl )
  1340. printf("Score fix failed.\n");
  1341. else
  1342. printf("Score fix done! hand:%i miss:%i\n",handCnt,midiMissCnt);
  1343. cmMidiFileClose(&mfH);
  1344. cmCsvFinalize(&csvH);
  1345. }