XmlWriter.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /* ----------------------------------------------------------------- */
  2. /* The HMM-Based Singing Voice Synthesis System "Sinsy" */
  3. /* developed by Sinsy Working Group */
  4. /* http://sinsy.sourceforge.net/ */
  5. /* ----------------------------------------------------------------- */
  6. /* */
  7. /* Copyright (c) 2009-2015 Nagoya Institute of Technology */
  8. /* Department of Computer Science */
  9. /* */
  10. /* All rights reserved. */
  11. /* */
  12. /* Redistribution and use in source and binary forms, with or */
  13. /* without modification, are permitted provided that the following */
  14. /* conditions are met: */
  15. /* */
  16. /* - Redistributions of source code must retain the above copyright */
  17. /* notice, this list of conditions and the following disclaimer. */
  18. /* - Redistributions in binary form must reproduce the above */
  19. /* copyright notice, this list of conditions and the following */
  20. /* disclaimer in the documentation and/or other materials provided */
  21. /* with the distribution. */
  22. /* - Neither the name of the Sinsy working group nor the names of */
  23. /* its contributors may be used to endorse or promote products */
  24. /* derived from this software without specific prior written */
  25. /* permission. */
  26. /* */
  27. /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */
  28. /* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */
  29. /* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
  30. /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
  31. /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */
  32. /* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */
  33. /* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
  34. /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
  35. /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
  36. /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
  37. /* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY */
  38. /* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
  39. /* POSSIBILITY OF SUCH DAMAGE. */
  40. /* ----------------------------------------------------------------- */
  41. #include <algorithm>
  42. #include <string>
  43. #include <sstream>
  44. #include <iostream>
  45. #include <exception>
  46. #include <stdexcept>
  47. #include <iomanip>
  48. #include <stack>
  49. #include "XmlWriter.h"
  50. #include "util_log.h"
  51. #include "Note.h"
  52. #include "Dynamics.h"
  53. #include "Key.h"
  54. #include "Syllabic.h"
  55. #include "ScorePosition.h"
  56. #include "WritableStrStream.h"
  57. #include "xml_tags.h"
  58. #include "util_converter.h"
  59. #include "util_score.h"
  60. #include "Converter.h"
  61. namespace sinsy
  62. {
  63. const XmlWriter::Clef XmlWriter::CLEF_DEFAULT = 0;
  64. const XmlWriter::Clef XmlWriter::CLEF_G = 1;
  65. const XmlWriter::Clef XmlWriter::CLEF_F = 2;
  66. const XmlWriter::Clef XmlWriter::CLEF_C = 3;
  67. namespace
  68. {
  69. const char FLAT = 'b';
  70. const std::string DEFAULT_CLEF = "G";
  71. const std::string DEFAULT_LINE = "0";
  72. /*!
  73. convert type T to string
  74. */
  75. template <class T>
  76. std::string toStr(const T& value)
  77. {
  78. std::ostringstream oss;
  79. oss << value;
  80. return oss.str();
  81. }
  82. std::string clefToStr(XmlWriter::Clef clef)
  83. {
  84. if (XmlWriter::CLEF_DEFAULT == clef) {
  85. throw std::runtime_error("clefToStr() clef is default");
  86. }
  87. if (XmlWriter::CLEF_G == clef) {
  88. return "G";
  89. }
  90. if (XmlWriter::CLEF_F == clef) {
  91. return "F";
  92. }
  93. if (XmlWriter::CLEF_C == clef) {
  94. return "C";
  95. }
  96. throw std::runtime_error("clefToStr() clef is invalid");
  97. }
  98. /*!
  99. get child data of target tag
  100. */
  101. XmlData* getChildData(XmlData& parent, const std::string& tag)
  102. {
  103. XmlData* ret(NULL);
  104. XmlData::Children::iterator itr(parent.childBegin());
  105. const XmlData::Children::iterator itrEnd(parent.childEnd());
  106. for (; itrEnd != itr; ++itr) {
  107. if ((*itr)->getTag() == tag) {
  108. ret = *itr;
  109. break;
  110. }
  111. }
  112. if (NULL == ret) {
  113. ret = new XmlData(tag);
  114. parent.addChild(ret);
  115. }
  116. return ret;
  117. }
  118. /*!
  119. add clef tag to head of score
  120. */
  121. void addClefToHead(XmlData& top, XmlWriter::Clef clefType)
  122. {
  123. if (XmlWriter::CLEF_DEFAULT == clefType) {
  124. return;
  125. }
  126. XmlData* part(getChildData(top, TAG_PART));
  127. XmlData* measure(getChildData(*part, TAG_MEASURE));
  128. XmlData* attributes(getChildData(*measure, TAG_ATTRIBUTES));
  129. XmlData* clef(getChildData(*attributes, TAG_CLEF));
  130. XmlData* sign(getChildData(*clef, TAG_SIGN));
  131. XmlData* line(getChildData(*clef, TAG_LINE));
  132. sign->setData(clefToStr(clefType));
  133. line->setData(DEFAULT_LINE);
  134. }
  135. /*!
  136. change clef
  137. @return if failed return false
  138. */
  139. void changeClef(XmlData& data, std::stack<std::string>& tagStack, XmlWriter::Clef clef)
  140. {
  141. if (!tagStack.empty()) {
  142. const std::string tag(tagStack.top());
  143. XmlData::Children::iterator itr(data.childBegin());
  144. const XmlData::Children::iterator itrEnd(data.childEnd());
  145. for (; itrEnd != itr; ++itr) {
  146. if (tag == (*itr)->getTag()) {
  147. tagStack.pop();
  148. changeClef(**itr, tagStack, clef);
  149. tagStack.push(tag);
  150. }
  151. }
  152. } else {
  153. XmlData::Children::iterator itr(data.childBegin());
  154. const XmlData::Children::iterator itrEnd(data.childEnd());
  155. for (; itrEnd != itr; ++itr) {
  156. if (TAG_SIGN == (*itr)->getTag()) {
  157. (*itr)->setData(clefToStr(clef));
  158. } else if (TAG_LINE == (*itr)->getTag()) {
  159. (*itr)->setData(DEFAULT_LINE);
  160. }
  161. }
  162. }
  163. }
  164. void changeClefTag(XmlData& data, XmlWriter::Clef clef)
  165. {
  166. if (XmlWriter::CLEF_DEFAULT == clef) {
  167. return;
  168. }
  169. addClefToHead(data, clef);
  170. std::stack<std::string> tagStack;
  171. tagStack.push(TAG_CLEF);
  172. tagStack.push(TAG_ATTRIBUTES);
  173. tagStack.push(TAG_MEASURE);
  174. tagStack.push(TAG_PART);
  175. changeClef(data, tagStack, clef);
  176. }
  177. }; // namespace
  178. /*!
  179. constructor
  180. */
  181. XmlWriter::XmlWriter() :
  182. xmlData(NULL), part(NULL), lastMeasure(NULL), lastMeasureNumber(0), duration(0), clef(CLEF_DEFAULT)
  183. {
  184. initXmlData();
  185. }
  186. /*!
  187. destructor
  188. */
  189. XmlWriter::~XmlWriter()
  190. {
  191. delete xmlData;
  192. }
  193. /*!
  194. clear
  195. */
  196. void XmlWriter::clear()
  197. {
  198. delete xmlData;
  199. initXmlData();
  200. }
  201. /*!
  202. get xml data
  203. */
  204. const XmlData* XmlWriter::getXmlData() const
  205. {
  206. return xmlData;
  207. }
  208. /*!
  209. set encoding
  210. */
  211. void XmlWriter::setEncoding(const std::string& enc)
  212. {
  213. encoding = enc;
  214. }
  215. /*!
  216. change tempo
  217. */
  218. void XmlWriter::changeTempo(double tempo)
  219. {
  220. std::ostringstream oss;
  221. oss << std::fixed << std::setprecision(13) << tempo << std::resetiosflags(std::ios_base::floatfield) << std::setprecision(6);
  222. const std::string tempoStr(oss.str());
  223. {
  224. XmlData* sound = new XmlData(TAG_SOUND);
  225. sound->addAttribute("tempo", tempoStr);
  226. addXmlData(sound);
  227. }
  228. {
  229. // for finale
  230. XmlData* directionTag = new XmlData(TAG_DIRECTION);
  231. XmlData* directionTypeTag = new XmlData(TAG_DIRECTION_TYPE);
  232. XmlData* soundTag = new XmlData(TAG_SOUND);
  233. soundTag->addAttribute("tempo", tempoStr);
  234. XmlData* metronomeTag = new XmlData(TAG_METRONOME);
  235. XmlData* beatUnitTag = new XmlData(TAG_BEAT_UNIT, "quarter");
  236. XmlData* perMinuteTag = new XmlData(TAG_PER_MINUTE, tempoStr);
  237. metronomeTag->addChild(beatUnitTag);
  238. metronomeTag->addChild(perMinuteTag);
  239. directionTypeTag->addChild(metronomeTag);
  240. directionTag->addChild(directionTypeTag);
  241. directionTag->addChild(soundTag);
  242. addXmlData(directionTag);
  243. }
  244. }
  245. /*!
  246. change beat
  247. */
  248. void XmlWriter::changeBeat(const Beat& beat)
  249. {
  250. XmlData* attributes = new XmlData(TAG_ATTRIBUTES);
  251. XmlData* time = new XmlData(TAG_TIME);
  252. attributes->addChild(time);
  253. {
  254. std::ostringstream oss;
  255. oss << beat.getBeats();
  256. XmlData* beats = new XmlData(TAG_BEATS, oss.str());
  257. time->addChild(beats);
  258. }
  259. {
  260. std::ostringstream oss;
  261. oss << beat.getBeatType();
  262. XmlData* beatType = new XmlData(TAG_BEAT_TYPE, oss.str());
  263. time->addChild(beatType);
  264. }
  265. addXmlData(attributes);
  266. // adjust position in this measure
  267. this->duration = duration * beat.getBeats() * lastBeat.getBeatType() / (beat.getBeatType() * lastBeat.getBeats());
  268. lastBeat = beat;
  269. }
  270. /*!
  271. change dynamics
  272. */
  273. void XmlWriter::changeDynamics(const Dynamics& dynamics)
  274. {
  275. XmlData* direction = new XmlData(TAG_DIRECTION);
  276. XmlData* directionType = new XmlData(TAG_DIRECTION_TYPE);
  277. direction->addChild(directionType);
  278. XmlData* dynamics_ = new XmlData(TAG_DYNAMICS);
  279. directionType->addChild(dynamics_);
  280. {
  281. std::ostringstream oss;
  282. oss << dynamics.getTagStr();
  283. XmlData* d = new XmlData(oss.str());
  284. dynamics_->addChild(d);
  285. }
  286. addXmlData(direction);
  287. }
  288. /*!
  289. change key
  290. */
  291. void XmlWriter::changeKey(const Key& key)
  292. {
  293. XmlData* attributes = new XmlData(TAG_ATTRIBUTES);
  294. XmlData* k = new XmlData(TAG_KEY);
  295. attributes->addChild(k);
  296. {
  297. XmlData* f = new XmlData(TAG_FIFTHS, toStr(key.getOrigFifths()));
  298. k->addChild(f);
  299. std::ostringstream oss;
  300. oss << key.getMode();
  301. XmlData* m = new XmlData(TAG_MODE, oss.str());
  302. k->addChild(m);
  303. }
  304. addXmlData(attributes);
  305. lastKey = key;
  306. }
  307. /*!
  308. start crescendo
  309. */
  310. void XmlWriter::startCrescendo()
  311. {
  312. setWedgeTag("crescendo");
  313. }
  314. /*!
  315. start diminuendo
  316. */
  317. void XmlWriter::startDiminuendo()
  318. {
  319. setWedgeTag("diminuendo");
  320. }
  321. /*!
  322. stop crescendo
  323. */
  324. void XmlWriter::stopCrescendo()
  325. {
  326. setWedgeTag("stop");
  327. }
  328. /*!
  329. stop diminuendo
  330. */
  331. void XmlWriter::stopDiminuendo()
  332. {
  333. setWedgeTag("stop");
  334. }
  335. /*!
  336. add note
  337. */
  338. void XmlWriter::addNote(const Note& note)
  339. {
  340. const size_t measureDur = getMeasureDuration(lastBeat);
  341. size_t dur = note.getDuration();
  342. bool first = true;
  343. while (0 < dur) {
  344. Note n(note);
  345. size_t d = dur;
  346. if (measureDur < (this->duration + dur)) { // note duration is over this measure
  347. d = measureDur - this->duration;
  348. }
  349. if (0 < d) { // fail safe
  350. dur -= d;
  351. this->duration += d;
  352. bool last = (0 == dur);
  353. if (first && last) { // single
  354. // do nothing
  355. } else if (first) {
  356. n.setTieStart(true);
  357. n.setTieStop(false);
  358. n.setSlurStart(false);
  359. if(note.getSyllabic() == Syllabic::SINGLE)
  360. n.setSyllabic(Syllabic::BEGIN);
  361. else if(note.getSyllabic() == Syllabic::END)
  362. n.setSyllabic(Syllabic::MIDDLE);
  363. } else if (last) {
  364. n.setLyric("");
  365. n.setTieStart(false);
  366. n.setTieStop(true);
  367. n.setSlurStop(false);
  368. if(note.getSyllabic() == Syllabic::SINGLE)
  369. n.setSyllabic(Syllabic::END);
  370. else if(note.getSyllabic() == Syllabic::BEGIN)
  371. n.setSyllabic(Syllabic::MIDDLE);
  372. } else {
  373. n.setLyric("");
  374. n.setTieStart(false);
  375. n.setTieStop(false);
  376. n.setSlurStart(false);
  377. n.setSlurStop(false);
  378. if(note.getSyllabic() != Syllabic::MIDDLE)
  379. n.setSyllabic(Syllabic::MIDDLE);
  380. }
  381. if((lastSyllabic == Syllabic::BEGIN || lastSyllabic == Syllabic::MIDDLE) && n.getSyllabic() == Syllabic::SINGLE) {
  382. n.setSyllabic(Syllabic::MIDDLE);
  383. }
  384. lastSyllabic = n.getSyllabic();
  385. n.setDuration(d);
  386. setNoteTag(n); // set tags
  387. first = false;
  388. }
  389. if (measureDur == this->duration) { // measure is full of notes
  390. fixMeasure();
  391. }
  392. }
  393. }
  394. /*!
  395. @internal
  396. set note tag
  397. */
  398. void XmlWriter::setNoteTag(const Note& note)
  399. {
  400. XmlData* noteTag = new XmlData(TAG_NOTE);
  401. XmlData* notationsTag = NULL;
  402. XmlData* articulationsTag = NULL;
  403. XmlData* technicalTag = NULL;
  404. if (note.isRest()) {
  405. noteTag->addChild(new XmlData(TAG_REST)); // rest
  406. } else {
  407. // pitch
  408. XmlData* pitchTag = new XmlData(TAG_PITCH);
  409. Pitch pitch(note.getPitch());
  410. std::string stepStr(pitch.getStepStr());
  411. size_t len = stepStr.length();
  412. int alter = 0;
  413. int octave = pitch.getOctave();
  414. if ((1 < len) && (FLAT == stepStr[len - 1])) { // flat
  415. ++pitch;
  416. alter = -1;
  417. stepStr = pitch.getStepStr();
  418. }
  419. if (0 <= lastKey.getOrigFifths()) {
  420. if (- 1 == alter) {
  421. pitch -= 2;
  422. alter = 1;
  423. stepStr = pitch.getStepStr();
  424. }
  425. }
  426. pitchTag->addChild(new XmlData(TAG_STEP, stepStr)); // step
  427. if (0 != alter) {
  428. pitchTag->addChild(new XmlData(TAG_ALTER, toStr(alter))); // alter
  429. }
  430. pitchTag->addChild(new XmlData(TAG_OCTAVE, toStr(octave))); // octave
  431. noteTag->addChild(pitchTag);
  432. }
  433. noteTag->addChild(new XmlData(TAG_DURATION, toStr(note.getDuration()))); // duration
  434. if (!note.isRest()) {
  435. // tie
  436. std::string type;
  437. if (note.isTieStart()) {
  438. type = "start";
  439. } else if (note.isTieStop()) {
  440. type = "stop";
  441. }
  442. if (!type.empty()) {
  443. XmlData* tieTag = new XmlData(TAG_TIE);
  444. tieTag->addAttribute("type", type);
  445. noteTag->addChild(tieTag);
  446. if (NULL == notationsTag) {
  447. notationsTag = new XmlData(TAG_NOTATIONS);
  448. noteTag->addChild(notationsTag);
  449. }
  450. XmlData* tiedTag = new XmlData(TAG_TIED);
  451. tiedTag->addAttribute("type", type);
  452. notationsTag->addChild(tiedTag);
  453. }
  454. }
  455. {
  456. // slur
  457. std::string type;
  458. if (note.isSlurStart()) {
  459. type = "start";
  460. } else if (note.isSlurStop()) {
  461. type = "stop";
  462. }
  463. if (!type.empty()) {
  464. if (NULL == notationsTag) {
  465. notationsTag = new XmlData(TAG_NOTATIONS);
  466. noteTag->addChild(notationsTag);
  467. }
  468. XmlData* slurTag = new XmlData(TAG_SLUR);
  469. slurTag->addAttribute("type", type);
  470. notationsTag->addChild(slurTag);
  471. }
  472. }
  473. // breath
  474. if (note.hasBreathMark()) {
  475. if (NULL == notationsTag) {
  476. notationsTag = new XmlData(TAG_NOTATIONS);
  477. noteTag->addChild(notationsTag);
  478. }
  479. if (NULL == technicalTag) {
  480. technicalTag = new XmlData(TAG_TECHNICAL);
  481. notationsTag->addChild(technicalTag);
  482. }
  483. XmlData* upBowTag = new XmlData(TAG_UP_BOW);
  484. technicalTag->addChild(upBowTag);
  485. }
  486. // accent
  487. if (note.hasAccent()) {
  488. if (NULL == notationsTag) {
  489. notationsTag = new XmlData(TAG_NOTATIONS);
  490. noteTag->addChild(notationsTag);
  491. }
  492. if (NULL == articulationsTag) {
  493. articulationsTag = new XmlData(TAG_ARTICULATIONS);
  494. notationsTag->addChild(articulationsTag);
  495. }
  496. XmlData* accentTag = new XmlData(TAG_ACCENT);
  497. articulationsTag->addChild(accentTag);
  498. }
  499. // staccato
  500. if (note.hasStaccato()) {
  501. if (NULL == notationsTag) {
  502. notationsTag = new XmlData(TAG_NOTATIONS);
  503. noteTag->addChild(notationsTag);
  504. }
  505. if (NULL == articulationsTag) {
  506. articulationsTag = new XmlData(TAG_ARTICULATIONS);
  507. notationsTag->addChild(articulationsTag);
  508. }
  509. XmlData* staccatoTag = new XmlData(TAG_STACCATO);
  510. articulationsTag->addChild(staccatoTag);
  511. }
  512. if (!note.isRest()) {
  513. // lyric
  514. const std::string& lyric(note.getLyric());
  515. XmlData* lyricTag = new XmlData(TAG_LYRIC);
  516. lyricTag->addChild(new XmlData(TAG_SYLLABIC, toStr(note.getSyllabic()))); // syllabic
  517. lyricTag->addChild(new XmlData(TAG_TEXT, lyric)); // text
  518. noteTag->addChild(lyricTag);
  519. }
  520. addXmlData(noteTag);
  521. }
  522. /*!
  523. @internal
  524. set wedge tag
  525. @param type type of wedge ("crescendo" or "diminuendo" or "stop")
  526. */
  527. void XmlWriter::setWedgeTag(const std::string& type)
  528. {
  529. XmlData* direction = new XmlData(TAG_DIRECTION);
  530. XmlData* directionType = new XmlData(TAG_DIRECTION_TYPE);
  531. direction->addChild(directionType);
  532. XmlData* wedge = new XmlData(TAG_WEDGE);
  533. directionType->addChild(wedge);
  534. wedge->addAttribute("type", type);
  535. addXmlData(direction);
  536. }
  537. /*!
  538. @internal
  539. set tags of head measure
  540. */
  541. void XmlWriter::setHeadMeasureTag()
  542. {
  543. XmlData* attributes = new XmlData(TAG_ATTRIBUTES);
  544. // divisions
  545. attributes->addChild(new XmlData(TAG_DIVISIONS, toStr(BASE_DIVISIONS)));
  546. addXmlData(attributes);
  547. }
  548. /*!
  549. @internal
  550. initialize xml data
  551. */
  552. void XmlWriter::initXmlData()
  553. {
  554. XmlData* scorePart = new XmlData("score-part");
  555. scorePart->addAttribute("id", "P1");
  556. scorePart->addChild(new XmlData("part-name", "MusicXML Part"));
  557. XmlData* partList = new XmlData("part-list");
  558. partList->addChild(scorePart);
  559. part = new XmlData(TAG_PART);
  560. part->addAttribute("id", "P1");
  561. xmlData = new XmlData(TAG_SCORE_PARTWISE);
  562. xmlData->addAttribute("version", "2.0");
  563. xmlData->addChild(partList);
  564. xmlData->addChild(part);
  565. lastBeat = Beat();
  566. lastMeasure = NULL;
  567. lastMeasureNumber = 0;
  568. lastSyllabic = Syllabic::SINGLE;
  569. duration = 0;
  570. // donot initialize clef
  571. }
  572. /*!
  573. @internal
  574. fix measure
  575. */
  576. void XmlWriter::fixMeasure()
  577. {
  578. this->lastMeasure = NULL;
  579. this->duration = 0;
  580. }
  581. /*!
  582. @internal
  583. get last measure
  584. @return last measure xml data
  585. */
  586. XmlData* XmlWriter::getLastMeasure()
  587. {
  588. if (NULL == lastMeasure) {
  589. lastMeasure = new XmlData(TAG_MEASURE);
  590. if (0 == lastMeasureNumber) { // set divisions tag to the first measure
  591. setHeadMeasureTag();
  592. }
  593. ++lastMeasureNumber;
  594. lastMeasure->addAttribute("number", toStr(lastMeasureNumber));
  595. part->addChild(lastMeasure);
  596. }
  597. return lastMeasure;
  598. }
  599. /*!
  600. @internal
  601. add xml data
  602. */
  603. void XmlWriter::addXmlData(XmlData* data)
  604. {
  605. XmlData* measure = getLastMeasure();
  606. measure->addChild(data);
  607. }
  608. /*!
  609. set clef
  610. */
  611. void XmlWriter::setClef(Clef c)
  612. {
  613. if ((CLEF_DEFAULT != c) && (CLEF_G != c) && (CLEF_F != c) && (CLEF_C != c)) {
  614. throw std::runtime_error("Invalid clef");
  615. }
  616. clef = c;
  617. }
  618. /*!
  619. write xml to stream
  620. @param stream output stream
  621. @return if success, true
  622. */
  623. bool XmlWriter::writeXml(WritableStrStream& stream) const
  624. {
  625. if (NULL == xmlData) {
  626. ERR_MSG("Cannot write Xml file (data is not set)");
  627. return false;
  628. }
  629. // change clef tag
  630. if (CLEF_DEFAULT != clef) {
  631. changeClefTag(*xmlData, clef);
  632. }
  633. stream << "<\?xml version=\"1.0\" encoding=\"" << encoding << "\"\?>\n";
  634. stream << "<!DOCTYPE score-partwise PUBLIC \"-//Recordare//DTD MusicXML 2.0 Partwise//EN\"\n";
  635. stream << " \"http://www.musicxml.org/dtds/partwise.dtd\">\n";
  636. stream << *xmlData;
  637. return true;
  638. }
  639. }; // namespace sinsy