libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmXScore.c 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmLinkedHeap.h"
  10. #include "cmXml.h"
  11. #include "cmText.h"
  12. #include "cmXScore.h"
  13. cmXsH_t cmXsNullHandle = cmSTATIC_NULL_HANDLE;
  14. typedef struct cmXsNote_str
  15. {
  16. } cmXsNote_t;
  17. typedef struct cmXsVoice_str
  18. {
  19. unsigned id; // Voice id
  20. cmXsNote_t* noteL; // List of notes in this voice
  21. struct cmXsVoice_str* link; // Link to other voices in this measure
  22. } cmXsVoice_t;
  23. typedef struct cmXsMeas_str
  24. {
  25. unsigned number; // Measure number
  26. unsigned divisions;
  27. unsigned beats;
  28. unsigned beat_type;
  29. cmXsVoice_t* voiceL; // List of voices in this measure
  30. struct cmXsMeas_str* link; // Link to other measures in this part.
  31. } cmXsMeas_t;
  32. typedef struct cmXsPart_str
  33. {
  34. const cmChar_t* idStr; // Id of this part
  35. cmXsMeas_t* measL; // List of measures in this part.
  36. struct cmXsPart_str* link; // Link to other parts in this score
  37. } cmXsPart_t;
  38. typedef struct
  39. {
  40. cmErr_t err;
  41. cmXmlH_t xmlH;
  42. cmLHeapH_t lhH;
  43. cmXsPart_t* partL;
  44. } cmXScore_t;
  45. cmXScore_t* _cmXScoreHandleToPtr( cmXsH_t h )
  46. {
  47. cmXScore_t* p = (cmXScore_t*)h.h;
  48. assert( p != NULL );
  49. return p;
  50. }
  51. cmXsRC_t _cmXScoreFinalize( cmXScore_t* p )
  52. {
  53. cmXsRC_t rc = kOkXsRC;
  54. // release the XML file
  55. if( cmXmlIsValid(p->xmlH) )
  56. cmXmlFree( &p->xmlH );
  57. // release the local linked heap memory
  58. if( cmLHeapIsValid(p->lhH) )
  59. cmLHeapDestroy(&p->lhH);
  60. cmMemFree(p);
  61. return rc;
  62. }
  63. cmXsRC_t _cmXScoreMissingNode( cmXScore_t* p, const cmChar_t* label, const cmXmlAttr_t* attr )
  64. {
  65. if( attr == NULL )
  66. return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML node '%s'.",label);
  67. return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML node '%s' - Attribute:%s=%s",label,attr->label,attr->value);
  68. }
  69. cmXsRC_t _cmXScoreMissingAttribute( cmXScore_t* p, const cmXmlNode_t* np, const cmChar_t* attrLabel )
  70. {
  71. return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML attribute '%s' from node '%s'.",attrLabel,np->label);
  72. }
  73. cmXsRC_t _cmXScoreParsePartList( cmXScore_t* p )
  74. {
  75. cmXsRC_t rc = kOkXsRC;
  76. cmXsPart_t* lastPartPtr = NULL;
  77. const cmXmlNode_t* xnp;
  78. // find the 'part-list'
  79. if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part-list", NULL, 0)) == NULL )
  80. return _cmXScoreMissingNode(p,"part-list",NULL);
  81. const cmXmlNode_t* cnp = xnp->children;
  82. // for each child of the 'part-list'
  83. for(; cnp!=NULL; cnp=cnp->sibling)
  84. if( cmTextCmp( cnp->label, "score-part" ) == 0 )
  85. {
  86. const cmXmlAttr_t* a;
  87. // find the 'score-part' id
  88. if((a = cmXmlFindAttrib(cnp,"id")) == NULL )
  89. return _cmXScoreMissingAttribute(p,cnp,"id");
  90. // allocate a new part record
  91. cmXsPart_t* pp = cmLhAllocZ(p->lhH,cmXsPart_t,1);
  92. pp->idStr = a->value; // set the part id
  93. // link the new part record to the end of the part list
  94. if(lastPartPtr == NULL)
  95. p->partL = pp;
  96. else
  97. lastPartPtr->link = pp;
  98. lastPartPtr = pp;
  99. }
  100. return rc;
  101. }
  102. cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t* mnp )
  103. {
  104. cmXsRC_t rc = kOkXsRC;
  105. cmXsMeas_t* meas = cmLhAllocZ(p->lhH,cmXsMeas_t,1);
  106. const cmXmlNode_t* np;
  107. // get measure number
  108. if( cmXmlAttrUInt(mnp,"number", &meas->number) != kOkXmlRC )
  109. return _cmXScoreMissingAttribute(p,mnp,"number");
  110. if( pp->measL == NULL )
  111. pp->measL = meas;
  112. else
  113. {
  114. cmXsMeas_t* m = pp->measL;
  115. while( m->link != NULL )
  116. m = m->link;
  117. m->link = meas;
  118. }
  119. // get measure attributes node
  120. if((np = cmXmlSearch(mnp,"attributes",NULL,0)) == NULL)
  121. return rc; // (this measure does not have any attributes)
  122. cmXmlNodeUInt(np,&meas->divisions,"divisions",NULL);
  123. cmXmlNodeUInt(np,&meas->beats,"time","beats",NULL);
  124. cmXmlNodeUInt(np,&meas->beat_type,"time","beat-type",NULL);
  125. return rc;
  126. }
  127. cmXsRC_t _cmXScoreParsePart( cmXScore_t* p, cmXsPart_t* pp )
  128. {
  129. cmXsRC_t rc = kOkXsRC;
  130. const cmXmlNode_t* xnp;
  131. cmXmlAttr_t partAttr = { "id", pp->idStr };
  132. // find the 'part'
  133. if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part", &partAttr, 1)) == NULL )
  134. return _cmXScoreMissingNode(p,"part",&partAttr);
  135. // for each child of this part - find each measure
  136. const cmXmlNode_t* cnp = xnp->children;
  137. for(; cnp!=NULL; cnp=cnp->sibling)
  138. if( cmTextCmp(cnp->label,"measure") == 0 )
  139. if((rc = _cmXScoreParseMeasure(p,pp,cnp)) != kOkXsRC )
  140. return rc;
  141. return rc;
  142. }
  143. cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
  144. {
  145. cmXsRC_t rc = kOkXsRC;
  146. if((rc = cmXScoreFinalize(hp)) != kOkXsRC )
  147. return rc;
  148. cmXScore_t* p = cmMemAllocZ(cmXScore_t,1);
  149. cmErrSetup(&p->err,&ctx->rpt,"XScore");
  150. // create a local linked heap
  151. if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false )
  152. return cmErrMsg(&p->err,kLHeapFailXsRC,"Lheap create failed.");
  153. // open the music xml file
  154. if( cmXmlAlloc(ctx, &p->xmlH, xmlFn) != kOkXmlRC )
  155. {
  156. rc = cmErrMsg(&p->err,kXmlFailXsRC,"Unable to open the MusicXML file '%s'.",cmStringNullGuard(xmlFn));
  157. goto errLabel;
  158. }
  159. // parse the part-list
  160. if((rc = _cmXScoreParsePartList( p )) != kOkXsRC )
  161. goto errLabel;
  162. cmXsPart_t* pp = p->partL;
  163. for(; pp!=NULL; pp=pp->link)
  164. if((rc = _cmXScoreParsePart(p,pp)) != kOkXsRC )
  165. goto errLabel;
  166. errLabel:
  167. if( rc != kOkXsRC )
  168. _cmXScoreFinalize(p);
  169. else
  170. hp->h = p;
  171. return rc;
  172. }
  173. cmXsRC_t cmXScoreFinalize( cmXsH_t* hp )
  174. {
  175. cmXsRC_t rc = kOkXsRC;
  176. if( hp == NULL || cmXScoreIsValid(*hp)==false )
  177. return kOkXsRC;
  178. cmXScore_t* p = _cmXScoreHandleToPtr(*hp);
  179. if((rc = _cmXScoreFinalize(p)) != kOkXsRC )
  180. return rc;
  181. hp->h = NULL;
  182. return rc;
  183. }
  184. bool cmXScoreIsValid( cmXsH_t h )
  185. { return h.h != NULL; }
  186. void cmXScoreReport( cmXsH_t h, cmRpt_t* rpt )
  187. {
  188. cmXScore_t* p = _cmXScoreHandleToPtr(h);
  189. cmXsPart_t* pp = p->partL;
  190. for(; pp!=NULL; pp=pp->link)
  191. {
  192. cmRptPrintf(rpt,"Part:%s\n",pp->idStr);
  193. const cmXsMeas_t* meas = pp->measL;
  194. for(; meas!=NULL; meas=meas->link)
  195. cmRptPrintf(rpt," %i : div:%i beat:%i beat-type:%i\n",meas->number,meas->divisions,meas->beats,meas->beat_type);
  196. }
  197. }
  198. cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
  199. {
  200. cmXsRC_t rc;
  201. cmXsH_t h = cmXsNullHandle;
  202. if((rc = cmXScoreInitialize( ctx, &h, fn)) != kOkXsRC )
  203. return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
  204. cmXScoreReport(h,&ctx->rpt);
  205. return cmXScoreFinalize(&h);
  206. }