2016-09-13 09:39:50 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2016 Werner Schweer and others
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENSE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "xml.h"
|
|
|
|
#include "score.h"
|
2016-09-20 11:12:44 +02:00
|
|
|
#include "staff.h"
|
|
|
|
#include "revisions.h"
|
|
|
|
#include "part.h"
|
|
|
|
#include "page.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "sym.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "arpeggio.h"
|
2016-09-20 11:12:44 +02:00
|
|
|
#include "audio.h"
|
|
|
|
#include "sig.h"
|
|
|
|
#include "barline.h"
|
2016-09-21 15:22:51 +02:00
|
|
|
#include "measure.h"
|
|
|
|
#include "ambitus.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "bend.h"
|
|
|
|
#include "chordline.h"
|
|
|
|
#include "hook.h"
|
2016-09-21 15:22:51 +02:00
|
|
|
#include "tuplet.h"
|
|
|
|
#include "systemdivider.h"
|
|
|
|
#include "spacer.h"
|
|
|
|
#include "keysig.h"
|
|
|
|
#include "stafftext.h"
|
|
|
|
#include "dynamic.h"
|
2016-10-20 10:13:12 +02:00
|
|
|
#include "drumset.h"
|
2016-09-21 15:22:51 +02:00
|
|
|
#include "timesig.h"
|
|
|
|
#include "slur.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "tie.h"
|
2016-09-21 15:22:51 +02:00
|
|
|
#include "chord.h"
|
|
|
|
#include "rest.h"
|
|
|
|
#include "breath.h"
|
|
|
|
#include "repeat.h"
|
2016-09-22 12:02:27 +02:00
|
|
|
#include "utils.h"
|
2016-10-06 12:21:28 +02:00
|
|
|
#include "read206.h"
|
2016-12-12 12:15:53 +01:00
|
|
|
#include "excerpt.h"
|
2017-01-05 11:23:47 +01:00
|
|
|
#include "articulation.h"
|
2017-02-09 11:57:10 +01:00
|
|
|
#include "volta.h"
|
|
|
|
#include "pedal.h"
|
2017-02-13 19:26:43 +01:00
|
|
|
#include "hairpin.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "glissando.h"
|
2017-03-08 14:18:34 +01:00
|
|
|
#include "ottava.h"
|
2017-03-13 10:24:49 +01:00
|
|
|
#include "trill.h"
|
2017-05-23 16:52:04 +02:00
|
|
|
#include "rehearsalmark.h"
|
2017-11-20 14:46:46 +01:00
|
|
|
#include "box.h"
|
|
|
|
#include "textframe.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "textline.h"
|
|
|
|
#include "fingering.h"
|
2018-01-16 13:38:17 +01:00
|
|
|
#include "fermata.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "image.h"
|
2018-05-08 10:51:24 +02:00
|
|
|
#include "stem.h"
|
2018-08-27 22:57:15 +02:00
|
|
|
#include "stemslash.h"
|
|
|
|
#include "undo.h"
|
2018-06-19 13:39:20 +02:00
|
|
|
#include "lyrics.h"
|
2018-06-27 09:04:11 +02:00
|
|
|
#include "tempotext.h"
|
2018-10-24 10:40:03 +02:00
|
|
|
#include "measurenumber.h"
|
2018-11-02 18:38:07 +01:00
|
|
|
#include "marker.h"
|
2016-09-20 11:12:44 +02:00
|
|
|
|
|
|
|
#ifdef OMR
|
|
|
|
#include "omr/omr.h"
|
|
|
|
#include "omr/omrpage.h"
|
|
|
|
#endif
|
|
|
|
|
2016-09-13 09:39:50 +02:00
|
|
|
|
|
|
|
namespace Ms {
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
static void readText206(XmlReader& e, TextBase* t, Element* be);
|
|
|
|
|
2016-09-22 10:03:59 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// StyleVal206
|
2018-10-30 12:18:11 +01:00
|
|
|
// this is a list of default style values which are
|
|
|
|
// different in 3.x
|
|
|
|
//
|
|
|
|
// TODO: remove style values which are equal
|
2016-09-22 10:03:59 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
struct StyleVal2 {
|
2018-03-27 15:36:00 +02:00
|
|
|
Sid idx;
|
2016-09-22 10:03:59 +02:00
|
|
|
QVariant val;
|
|
|
|
};
|
|
|
|
static const StyleVal2 style206[] = {
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::staffUpperBorder, Spatium(7.0) },
|
|
|
|
{ Sid::staffLowerBorder, Spatium(7.0) },
|
|
|
|
{ Sid::staffDistance, Spatium(6.5) },
|
|
|
|
{ Sid::akkoladeDistance, Spatium(6.5) },
|
|
|
|
{ Sid::minSystemDistance, Spatium(8.5) },
|
|
|
|
{ Sid::maxSystemDistance, Spatium(15.0) },
|
|
|
|
|
|
|
|
{ Sid::lyricsMinBottomDistance, Spatium(4.0) },
|
|
|
|
{ Sid::lyricsLineHeight, QVariant(1.0) },
|
|
|
|
{ Sid::figuredBassFontFamily, QVariant(QString("MScoreBC")) },
|
|
|
|
{ Sid::figuredBassFontSize, QVariant(8.0) },
|
|
|
|
{ Sid::figuredBassYOffset, QVariant(6.0) },
|
|
|
|
{ Sid::figuredBassLineHeight, QVariant(1.0) },
|
|
|
|
{ Sid::figuredBassAlignment, QVariant(0) },
|
|
|
|
{ Sid::figuredBassStyle, QVariant(0) },
|
|
|
|
{ Sid::systemFrameDistance, Spatium(7.0) },
|
|
|
|
{ Sid::frameSystemDistance, Spatium(7.0) },
|
|
|
|
{ Sid::minMeasureWidth, Spatium(5.0) },
|
|
|
|
{ Sid::barWidth, Spatium(0.16) }, // 0.1875
|
|
|
|
{ Sid::doubleBarWidth, Spatium(0.16) },
|
|
|
|
{ Sid::endBarWidth, Spatium(0.5) }, // 0.5
|
|
|
|
{ Sid::doubleBarDistance, Spatium(0.46) }, // 0.3 + doubleBarWidth
|
|
|
|
{ Sid::endBarDistance, Spatium(0.65) }, // 0.3
|
|
|
|
{ Sid::repeatBarTips, QVariant(false) },
|
|
|
|
{ Sid::startBarlineSingle, QVariant(false) },
|
|
|
|
{ Sid::startBarlineMultiple, QVariant(true) },
|
|
|
|
{ Sid::bracketWidth, Spatium(0.45) },
|
|
|
|
{ Sid::bracketDistance, Spatium(0.1) },
|
|
|
|
{ Sid::akkoladeWidth, Spatium(1.6) },
|
|
|
|
{ Sid::akkoladeBarDistance, Spatium(.4) },
|
|
|
|
{ Sid::clefLeftMargin, Spatium(0.64) },
|
|
|
|
{ Sid::keysigLeftMargin, Spatium(0.5) },
|
|
|
|
{ Sid::timesigLeftMargin, Spatium(0.5) },
|
|
|
|
{ Sid::clefKeyRightMargin, Spatium(1.75) },
|
|
|
|
{ Sid::clefBarlineDistance, Spatium(0.5) },
|
|
|
|
{ Sid::stemWidth, Spatium(0.13) }, // 0.09375
|
|
|
|
{ Sid::shortenStem, QVariant(true) },
|
|
|
|
{ Sid::shortStemProgression, Spatium(0.25) },
|
|
|
|
{ Sid::shortestStem, Spatium(2.25) },
|
|
|
|
{ Sid::beginRepeatLeftMargin, Spatium(1.0) },
|
|
|
|
{ Sid::minNoteDistance, Spatium(0.25) }, // 0.4
|
|
|
|
{ Sid::barNoteDistance, Spatium(1.2) },
|
|
|
|
{ Sid::barAccidentalDistance, Spatium(.3) },
|
|
|
|
{ Sid::multiMeasureRestMargin, Spatium(1.2) },
|
|
|
|
{ Sid::noteBarDistance, Spatium(1.0) },
|
|
|
|
{ Sid::measureSpacing, QVariant(1.2) },
|
|
|
|
{ Sid::staffLineWidth, Spatium(0.08) }, // 0.09375
|
|
|
|
{ Sid::ledgerLineWidth, Spatium(0.16) }, // 0.1875
|
|
|
|
{ Sid::ledgerLineLength, Spatium(.6) }, // notehead width + this value
|
|
|
|
{ Sid::accidentalDistance, Spatium(0.22) },
|
|
|
|
{ Sid::accidentalNoteDistance, Spatium(0.22) },
|
|
|
|
{ Sid::beamWidth, Spatium(0.5) }, // was 0.48
|
|
|
|
{ Sid::beamDistance, QVariant(0.5) }, // 0.25sp
|
|
|
|
{ Sid::beamMinLen, QVariant(1.32) }, // 1.316178 exactly notehead width
|
|
|
|
{ Sid::beamNoSlope, QVariant(false) },
|
|
|
|
{ Sid::dotMag, QVariant(1.0) },
|
|
|
|
{ Sid::dotNoteDistance, QVariant(0.35) },
|
|
|
|
{ Sid::dotRestDistance, QVariant(0.25) },
|
|
|
|
{ Sid::dotDotDistance, QVariant(0.5) },
|
|
|
|
{ Sid::propertyDistanceHead, QVariant(1.0) },
|
|
|
|
{ Sid::propertyDistanceStem, QVariant(1.8) },
|
|
|
|
{ Sid::propertyDistance, QVariant(1.0) },
|
|
|
|
{ Sid::articulationMag, QVariant(1.0) },
|
|
|
|
{ Sid::lastSystemFillLimit, QVariant(0.3) },
|
2018-10-18 11:53:01 +02:00
|
|
|
{ Sid::hairpinPosBelow, QPointF(0.0, 3.5) },
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::hairpinHeight, QVariant(1.2) },
|
|
|
|
{ Sid::hairpinContHeight, QVariant(0.5) },
|
|
|
|
{ Sid::hairpinLineWidth, QVariant(0.13) },
|
2018-10-18 11:53:01 +02:00
|
|
|
{ Sid::pedalPosBelow, QPointF(0.0, 4) },
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::pedalLineWidth, QVariant(.15) },
|
|
|
|
{ Sid::pedalLineStyle, QVariant(int(Qt::SolidLine)) },
|
2018-10-18 11:53:01 +02:00
|
|
|
{ Sid::trillPosAbove, QPointF(0.0, -1) },
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::harmonyFretDist, QVariant(0.5) },
|
|
|
|
{ Sid::minHarmonyDistance, QVariant(0.5) },
|
|
|
|
{ Sid::maxHarmonyBarDistance, QVariant(3.0) },
|
|
|
|
{ Sid::capoPosition, QVariant(0) },
|
|
|
|
{ Sid::fretNumMag, QVariant(2.0) },
|
|
|
|
{ Sid::fretNumPos, QVariant(0) },
|
|
|
|
{ Sid::fretY, QVariant(2.0) },
|
|
|
|
{ Sid::showPageNumber, QVariant(true) },
|
|
|
|
{ Sid::showPageNumberOne, QVariant(false) },
|
|
|
|
{ Sid::pageNumberOddEven, QVariant(true) },
|
|
|
|
{ Sid::showMeasureNumber, QVariant(true) },
|
|
|
|
{ Sid::showMeasureNumberOne, QVariant(false) },
|
|
|
|
{ Sid::measureNumberInterval, QVariant(5) },
|
|
|
|
{ Sid::measureNumberSystem, QVariant(true) },
|
|
|
|
{ Sid::measureNumberAllStaffs, QVariant(false) },
|
|
|
|
{ Sid::smallNoteMag, QVariant(.7) },
|
|
|
|
{ Sid::graceNoteMag, QVariant(0.7) },
|
|
|
|
{ Sid::smallStaffMag, QVariant(0.7) },
|
|
|
|
{ Sid::smallClefMag, QVariant(0.8) },
|
|
|
|
{ Sid::genClef, QVariant(true) },
|
|
|
|
{ Sid::genKeysig, QVariant(true) },
|
|
|
|
{ Sid::genCourtesyTimesig, QVariant(true) },
|
|
|
|
{ Sid::genCourtesyKeysig, QVariant(true) },
|
|
|
|
{ Sid::genCourtesyClef, QVariant(true) },
|
|
|
|
{ Sid::swingRatio, QVariant(60) },
|
|
|
|
{ Sid::swingUnit, QVariant(QString("")) },
|
|
|
|
{ Sid::useStandardNoteNames, QVariant(true) },
|
|
|
|
{ Sid::useGermanNoteNames, QVariant(false) },
|
|
|
|
{ Sid::useFullGermanNoteNames, QVariant(false) },
|
|
|
|
{ Sid::useSolfeggioNoteNames, QVariant(false) },
|
|
|
|
{ Sid::useFrenchNoteNames, QVariant(false) },
|
|
|
|
{ Sid::automaticCapitalization, QVariant(true) },
|
|
|
|
{ Sid::lowerCaseMinorChords, QVariant(false) },
|
|
|
|
{ Sid::lowerCaseBassNotes, QVariant(false) },
|
|
|
|
{ Sid::allCapsNoteNames, QVariant(false) },
|
|
|
|
{ Sid::chordStyle, QVariant(QString("std")) },
|
|
|
|
{ Sid::chordsXmlFile, QVariant(false) },
|
|
|
|
{ Sid::chordDescriptionFile, QVariant(QString("chords_std.xml")) },
|
|
|
|
{ Sid::concertPitch, QVariant(false) },
|
|
|
|
{ Sid::createMultiMeasureRests, QVariant(false) },
|
|
|
|
{ Sid::minEmptyMeasures, QVariant(2) },
|
|
|
|
{ Sid::minMMRestWidth, Spatium(4) },
|
|
|
|
{ Sid::hideEmptyStaves, QVariant(false) },
|
|
|
|
{ Sid::dontHideStavesInFirstSystem, QVariant(true) },
|
|
|
|
{ Sid::hideInstrumentNameIfOneInstrument, QVariant(true) },
|
|
|
|
{ Sid::gateTime, QVariant(100) },
|
|
|
|
{ Sid::tenutoGateTime, QVariant(100) },
|
|
|
|
{ Sid::staccatoGateTime, QVariant(50) },
|
|
|
|
{ Sid::slurGateTime, QVariant(100) },
|
|
|
|
{ Sid::ArpeggioNoteDistance, QVariant(.5) },
|
|
|
|
{ Sid::ArpeggioLineWidth, QVariant(.18) },
|
|
|
|
{ Sid::ArpeggioHookLen, QVariant(.8) },
|
|
|
|
{ Sid::SlurEndWidth, QVariant(.07) },
|
|
|
|
{ Sid::SlurMidWidth, QVariant(.15) },
|
|
|
|
{ Sid::SlurDottedWidth, QVariant(.1) },
|
|
|
|
{ Sid::MinTieLength, QVariant(1.0) },
|
|
|
|
{ Sid::SectionPause, QVariant(qreal(3.0)) },
|
|
|
|
{ Sid::MusicalSymbolFont, QVariant(QString("Emmentaler")) },
|
|
|
|
{ Sid::MusicalTextFont, QVariant(QString("MScore Text")) },
|
|
|
|
{ Sid::showHeader, QVariant(false) },
|
|
|
|
{ Sid::headerFirstPage, QVariant(false) },
|
|
|
|
{ Sid::headerOddEven, QVariant(true) },
|
|
|
|
{ Sid::evenHeaderL, QVariant(QString()) },
|
|
|
|
{ Sid::evenHeaderC, QVariant(QString()) },
|
|
|
|
{ Sid::evenHeaderR, QVariant(QString()) },
|
|
|
|
{ Sid::oddHeaderL, QVariant(QString()) },
|
|
|
|
{ Sid::oddHeaderC, QVariant(QString()) },
|
|
|
|
{ Sid::oddHeaderR, QVariant(QString()) },
|
|
|
|
{ Sid::showFooter, QVariant(true) },
|
|
|
|
{ Sid::footerFirstPage, QVariant(true) },
|
|
|
|
{ Sid::footerOddEven, QVariant(true) },
|
|
|
|
{ Sid::evenFooterL, QVariant(QString("$p")) },
|
|
|
|
{ Sid::evenFooterC, QVariant(QString("$:copyright:")) },
|
|
|
|
{ Sid::evenFooterR, QVariant(QString()) },
|
|
|
|
{ Sid::oddFooterL, QVariant(QString()) },
|
|
|
|
{ Sid::oddFooterC, QVariant(QString("$:copyright:")) },
|
|
|
|
{ Sid::oddFooterR, QVariant(QString("$p")) },
|
2018-10-18 11:53:01 +02:00
|
|
|
{ Sid::voltaPosAbove, QPointF(0.0, -3.0) },
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::voltaHook, QVariant(1.9) },
|
|
|
|
{ Sid::voltaLineWidth, QVariant(.1) },
|
|
|
|
{ Sid::voltaLineStyle, QVariant(int(Qt::SolidLine)) },
|
2018-10-18 11:53:01 +02:00
|
|
|
{ Sid::ottavaPosAbove, QPointF(0.0, -3.0) },
|
2018-07-11 12:23:32 +02:00
|
|
|
{ Sid::ottavaHookAbove, QVariant(1.9) },
|
|
|
|
{ Sid::ottavaHookBelow, QVariant(-1.9) },
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::ottavaLineWidth, QVariant(.1) },
|
|
|
|
{ Sid::ottavaLineStyle, QVariant(int(Qt::DashLine)) },
|
|
|
|
{ Sid::ottavaNumbersOnly, true },
|
|
|
|
{ Sid::tabClef, QVariant(int(ClefType::TAB)) },
|
|
|
|
{ Sid::tremoloWidth, QVariant(1.2) }, // tremolo stroke width: notehead width
|
|
|
|
{ Sid::tremoloBoxHeight, QVariant(0.65) },
|
|
|
|
{ Sid::tremoloStrokeWidth, QVariant(0.5) }, // was 0.35
|
|
|
|
{ Sid::tremoloDistance, QVariant(0.8) },
|
|
|
|
// TODO { Sid::tremoloBeamLengthMultiplier, QVariant(0.62) },
|
|
|
|
// TODO { Sid::tremoloMaxBeamLength, QVariant(12.0) },
|
|
|
|
{ Sid::linearStretch, QVariant(qreal(1.5)) },
|
|
|
|
{ Sid::crossMeasureValues, QVariant(false) },
|
|
|
|
{ Sid::keySigNaturals, QVariant(int(KeySigNatural::NONE)) },
|
2018-03-28 17:49:08 +02:00
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
{ Sid::tupletMaxSlope, QVariant(qreal(0.5)) },
|
|
|
|
{ Sid::tupletOufOfStaff, QVariant(true) },
|
|
|
|
{ Sid::tupletVHeadDistance, QVariant(.5) },
|
|
|
|
{ Sid::tupletVStemDistance, QVariant(.25) },
|
|
|
|
{ Sid::tupletStemLeftDistance, QVariant(.5) },
|
|
|
|
{ Sid::tupletStemRightDistance, QVariant(.5) },
|
|
|
|
{ Sid::tupletNoteLeftDistance, QVariant(0.0) },
|
|
|
|
{ Sid::tupletNoteRightDistance, QVariant(0.0) },
|
|
|
|
|
|
|
|
{ Sid::barreLineWidth, QVariant(1.0) },
|
|
|
|
{ Sid::fretMag, QVariant(1.0) },
|
|
|
|
{ Sid::scaleBarlines, QVariant(true) },
|
|
|
|
{ Sid::barGraceDistance, QVariant(.6) },
|
|
|
|
{ Sid::rehearsalMarkFrameRound, QVariant(20) },
|
2018-11-26 21:09:20 +01:00
|
|
|
{ Sid::dynamicsFontStyle, int(FontStyle::Normal) },
|
2018-10-30 12:18:11 +01:00
|
|
|
|
|
|
|
// { Sid::staffTextFontFace, "FreeSerif" },
|
|
|
|
// { Sid::staffTextFontSize, 10.0 },
|
|
|
|
// { Sid::staffTextFontBold, false },
|
|
|
|
// { Sid::staffTextFontItalic, false },
|
|
|
|
// { Sid::staffTextFontUnderline, false },
|
|
|
|
{ Sid::staffTextAlign, QVariant::fromValue(Align::LEFT | Align::TOP) }, // different from 3.x
|
|
|
|
// { Sid::staffTextOffsetType, int(OffsetType::SPATIUM) },
|
|
|
|
// { Sid::staffTextPlacement, int(Placement::ABOVE) },
|
|
|
|
// { Sid::staffTextPosAbove, QPointF(.0, -2.0) },
|
|
|
|
// { Sid::staffTextMinDistance, Spatium(0.5) },
|
|
|
|
// { Sid::staffTextFrameType, int(FrameType::NO_FRAME) },
|
|
|
|
// { Sid::staffTextFramePadding, 0.2 },
|
|
|
|
// { Sid::staffTextFrameWidth, 0.1 },
|
|
|
|
// { Sid::staffTextFrameRound, 0 },
|
|
|
|
// { Sid::staffTextFrameFgColor, QColor(0, 0, 0, 255) },
|
|
|
|
// { Sid::staffTextFrameBgColor, QColor(255, 255, 255, 0) },
|
2018-11-02 18:38:07 +01:00
|
|
|
{ Sid::defaultFrameRound, QVariant(25) },
|
|
|
|
{ Sid::defaultFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::defaultFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::titleFrameRound, QVariant(25) },
|
|
|
|
{ Sid::titleFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::titleFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::subTitleFrameRound, QVariant(25) },
|
|
|
|
{ Sid::subTitleFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::subTitleFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::composerFrameRound, QVariant(25) },
|
|
|
|
{ Sid::composerFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::composerFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::lyricistFrameRound, QVariant(25) },
|
|
|
|
{ Sid::lyricistFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::lyricistFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::fingeringFrameRound, QVariant(25) },
|
|
|
|
{ Sid::fingeringFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::fingeringFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::lhGuitarFingeringFrameRound, QVariant(25) },
|
|
|
|
{ Sid::lhGuitarFingeringFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::lhGuitarFingeringFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::rhGuitarFingeringFrameRound, QVariant(25) },
|
|
|
|
{ Sid::rhGuitarFingeringFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::rhGuitarFingeringFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::partInstrumentFrameRound, QVariant(25) },
|
|
|
|
{ Sid::partInstrumentFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::partInstrumentFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::tempoFrameRound, QVariant(0) },
|
|
|
|
{ Sid::tempoFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::tempoFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::tempoFrameRound, QVariant(25) },
|
|
|
|
{ Sid::tempoFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::tempoFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::systemTextFrameRound, QVariant(25) },
|
|
|
|
{ Sid::systemTextFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::systemTextFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::staffTextFrameRound, QVariant(25) },
|
|
|
|
{ Sid::staffTextFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::staffTextFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::rehearsalMarkFrameRound, QVariant(20) },
|
|
|
|
{ Sid::rehearsalMarkFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::rehearsalMarkFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::repeatLeftFrameRound, QVariant(25) },
|
|
|
|
{ Sid::repeatLeftFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::repeatLeftFramePadding, Spatium(0.5) },
|
|
|
|
|
|
|
|
{ Sid::repeatRightFrameRound, QVariant(25) },
|
|
|
|
{ Sid::repeatRightFrameWidth, Spatium(0.2) },
|
|
|
|
{ Sid::repeatRightFramePadding, Spatium(0.5) },
|
2016-09-22 10:03:59 +02:00
|
|
|
};
|
|
|
|
|
2017-01-25 15:54:46 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// setPageFormat
|
|
|
|
// set Style from PageFormat
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void setPageFormat(MStyle* style, const PageFormat& pf)
|
|
|
|
{
|
2018-03-27 15:36:00 +02:00
|
|
|
style->set(Sid::pageWidth, pf.size().width());
|
|
|
|
style->set(Sid::pageHeight, pf.size().height());
|
|
|
|
style->set(Sid::pagePrintableWidth, pf.printableWidth());
|
|
|
|
style->set(Sid::pageEvenLeftMargin, pf.evenLeftMargin());
|
|
|
|
style->set(Sid::pageOddLeftMargin, pf.oddLeftMargin());
|
|
|
|
style->set(Sid::pageEvenTopMargin, pf.evenTopMargin());
|
|
|
|
style->set(Sid::pageEvenBottomMargin, pf.evenBottomMargin());
|
|
|
|
style->set(Sid::pageOddTopMargin, pf.oddTopMargin());
|
|
|
|
style->set(Sid::pageOddBottomMargin, pf.oddBottomMargin());
|
|
|
|
style->set(Sid::pageTwosided, pf.twosided());
|
2017-01-25 15:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// initPageFormat
|
|
|
|
// initialize PageFormat from Style
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void initPageFormat(MStyle* style, PageFormat* pf)
|
|
|
|
{
|
|
|
|
QSizeF sz;
|
2018-03-27 15:36:00 +02:00
|
|
|
sz.setWidth(style->value(Sid::pageWidth).toReal());
|
|
|
|
sz.setHeight(style->value(Sid::pageHeight).toReal());
|
2017-01-25 15:54:46 +01:00
|
|
|
pf->setSize(sz);
|
2018-03-27 15:36:00 +02:00
|
|
|
pf->setPrintableWidth(style->value(Sid::pagePrintableWidth).toReal());
|
|
|
|
pf->setEvenLeftMargin(style->value(Sid::pageEvenLeftMargin).toReal());
|
|
|
|
pf->setOddLeftMargin(style->value(Sid::pageOddLeftMargin).toReal());
|
|
|
|
pf->setEvenTopMargin(style->value(Sid::pageEvenTopMargin).toReal());
|
|
|
|
pf->setEvenBottomMargin(style->value(Sid::pageEvenBottomMargin).toReal());
|
|
|
|
pf->setOddTopMargin(style->value(Sid::pageOddTopMargin).toReal());
|
|
|
|
pf->setOddBottomMargin(style->value(Sid::pageOddBottomMargin).toReal());
|
|
|
|
pf->setTwosided(style->value(Sid::pageTwosided).toBool());
|
2017-01-25 15:54:46 +01:00
|
|
|
}
|
|
|
|
|
2017-03-21 16:21:36 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readPageFormat
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void readPageFormat(MStyle* style, XmlReader& e)
|
|
|
|
{
|
|
|
|
PageFormat pf;
|
|
|
|
initPageFormat(style, &pf);
|
|
|
|
pf.read(e);
|
|
|
|
setPageFormat(style, pf);
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:54:46 +01:00
|
|
|
//---------------------------------------------------------
|
2018-10-30 12:18:11 +01:00
|
|
|
// readTextStyle206
|
2017-01-25 15:54:46 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-10-13 12:12:11 +02:00
|
|
|
void readTextStyle206(MStyle* style, XmlReader& e)
|
2017-01-25 15:54:46 +01:00
|
|
|
{
|
|
|
|
QString family = "FreeSerif";
|
|
|
|
double size = 10;
|
2018-10-29 10:13:39 +01:00
|
|
|
bool sizeIsSpatiumDependent = false;
|
2018-11-26 21:09:20 +01:00
|
|
|
FontStyle fontStyle = FontStyle::Normal;
|
2017-01-25 15:54:46 +01:00
|
|
|
Align align = Align::LEFT;
|
2018-08-01 11:46:07 +02:00
|
|
|
QPointF offset;
|
|
|
|
OffsetType offsetType = OffsetType::SPATIUM;
|
|
|
|
|
2018-07-26 13:14:06 +02:00
|
|
|
FrameType frameType = FrameType::NO_FRAME;
|
2017-01-25 15:54:46 +01:00
|
|
|
Spatium paddingWidth(0.0);
|
2018-08-01 11:46:07 +02:00
|
|
|
Spatium frameWidth(0.0);
|
2017-01-25 15:54:46 +01:00
|
|
|
QColor foregroundColor = QColor(0, 0, 0, 255);
|
|
|
|
QColor backgroundColor = QColor(255, 255, 255, 0);
|
2018-08-01 11:46:07 +02:00
|
|
|
|
2018-06-11 14:16:16 +02:00
|
|
|
Placement placement = Placement::ABOVE;
|
2018-06-27 09:04:11 +02:00
|
|
|
bool placementValid = false;
|
2018-08-01 11:46:07 +02:00
|
|
|
|
|
|
|
QString name = e.attribute("name");
|
|
|
|
QColor frameColor = QColor(0, 0, 0, 255);
|
|
|
|
|
|
|
|
bool systemFlag = false;
|
2018-06-27 09:04:11 +02:00
|
|
|
qreal lineWidth = -1.0;
|
2017-01-25 15:54:46 +01:00
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "name")
|
|
|
|
name = e.readElementText();
|
|
|
|
else if (tag == "family")
|
|
|
|
family = e.readElementText();
|
|
|
|
else if (tag == "size")
|
|
|
|
size = e.readDouble();
|
2018-11-26 21:09:20 +01:00
|
|
|
else if (tag == "bold") {
|
|
|
|
if (e.readInt())
|
|
|
|
fontStyle = fontStyle + FontStyle::Bold;
|
|
|
|
}
|
|
|
|
else if (tag == "italic") {
|
|
|
|
if (e.readInt())
|
|
|
|
fontStyle = fontStyle + FontStyle::Italic;
|
|
|
|
}
|
|
|
|
else if (tag == "underline") {
|
|
|
|
if (e.readInt())
|
|
|
|
fontStyle = fontStyle + FontStyle::Underline;
|
|
|
|
}
|
2017-01-25 15:54:46 +01:00
|
|
|
else if (tag == "align")
|
|
|
|
align = Align(e.readInt());
|
|
|
|
else if (tag == "anchor") // obsolete
|
|
|
|
e.skipCurrentElement();
|
|
|
|
|
|
|
|
else if (tag == "halign") {
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
if (val == "center")
|
|
|
|
align = align | Align::HCENTER;
|
|
|
|
else if (val == "right")
|
|
|
|
align = align | Align::RIGHT;
|
|
|
|
else if (val == "left")
|
|
|
|
;
|
|
|
|
else
|
|
|
|
qDebug("Text::readProperties: unknown alignment: <%s>", qPrintable(val));
|
|
|
|
}
|
|
|
|
else if (tag == "valign") {
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
if (val == "center")
|
|
|
|
align = align | Align::VCENTER;
|
|
|
|
else if (val == "bottom")
|
|
|
|
align = align | Align::BOTTOM;
|
|
|
|
else if (val == "baseline")
|
|
|
|
align = align | Align::BASELINE;
|
|
|
|
else if (val == "top")
|
|
|
|
;
|
|
|
|
else
|
|
|
|
qDebug("Text::readProperties: unknown alignment: <%s>", qPrintable(val));
|
|
|
|
}
|
|
|
|
else if (tag == "xoffset") {
|
|
|
|
qreal xo = e.readDouble();
|
|
|
|
if (offsetType == OffsetType::ABS)
|
|
|
|
xo /= INCH;
|
|
|
|
offset.setX(xo);
|
|
|
|
}
|
|
|
|
else if (tag == "yoffset") {
|
|
|
|
qreal yo = e.readDouble();
|
|
|
|
if (offsetType == OffsetType::ABS)
|
|
|
|
yo /= INCH;
|
|
|
|
offset.setY(yo);
|
|
|
|
}
|
|
|
|
else if (tag == "rxoffset" || tag == "ryoffset") // obsolete
|
|
|
|
e.readDouble();
|
|
|
|
else if (tag == "offsetType") {
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
OffsetType ot = OffsetType::ABS;
|
|
|
|
if (val == "spatium" || val == "1")
|
|
|
|
ot = OffsetType::SPATIUM;
|
|
|
|
if (ot != offsetType) {
|
|
|
|
offsetType = ot;
|
|
|
|
if (ot == OffsetType::ABS)
|
|
|
|
offset /= INCH; // convert spatium -> inch
|
|
|
|
else
|
|
|
|
offset *= INCH; // convert inch -> spatium
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "sizeIsSpatiumDependent" || tag == "spatiumSizeDependent")
|
|
|
|
sizeIsSpatiumDependent = e.readInt();
|
|
|
|
else if (tag == "frameWidth") { // obsolete
|
2018-07-26 13:14:06 +02:00
|
|
|
frameType = FrameType::SQUARE;
|
2017-07-26 09:59:24 +02:00
|
|
|
/*frameWidthMM =*/ e.readDouble();
|
2017-01-25 15:54:46 +01:00
|
|
|
}
|
|
|
|
else if (tag == "frameWidthS") {
|
2018-07-26 13:14:06 +02:00
|
|
|
frameType = FrameType::SQUARE;
|
2017-01-25 15:54:46 +01:00
|
|
|
frameWidth = Spatium(e.readDouble());
|
|
|
|
}
|
|
|
|
else if (tag == "frame")
|
2018-07-26 13:14:06 +02:00
|
|
|
frameType = e.readInt() ? FrameType::SQUARE : FrameType::NO_FRAME;
|
2017-01-25 15:54:46 +01:00
|
|
|
else if (tag == "paddingWidth") // obsolete
|
2017-07-26 09:59:24 +02:00
|
|
|
/*paddingWidthMM =*/ e.readDouble();
|
2017-01-25 15:54:46 +01:00
|
|
|
else if (tag == "paddingWidthS")
|
|
|
|
paddingWidth = Spatium(e.readDouble());
|
|
|
|
else if (tag == "frameRound")
|
2018-07-26 13:14:06 +02:00
|
|
|
e.readInt();
|
2017-01-25 15:54:46 +01:00
|
|
|
else if (tag == "frameColor")
|
|
|
|
frameColor = e.readColor();
|
|
|
|
else if (tag == "foregroundColor")
|
|
|
|
foregroundColor = e.readColor();
|
|
|
|
else if (tag == "backgroundColor")
|
|
|
|
backgroundColor = e.readColor();
|
|
|
|
else if (tag == "circle")
|
2018-07-26 13:14:06 +02:00
|
|
|
frameType = e.readInt() ? FrameType::CIRCLE : FrameType::NO_FRAME;
|
2017-01-25 15:54:46 +01:00
|
|
|
else if (tag == "systemFlag")
|
|
|
|
systemFlag = e.readInt();
|
2018-06-11 14:16:16 +02:00
|
|
|
else if (tag == "placement") {
|
|
|
|
QString value(e.readElementText());
|
|
|
|
if (value == "above")
|
|
|
|
placement = Placement::ABOVE;
|
|
|
|
else if (value == "below")
|
|
|
|
placement = Placement::BELOW;
|
2018-06-27 09:04:11 +02:00
|
|
|
placementValid = true;
|
2018-06-11 14:16:16 +02:00
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
else if (tag == "lineWidth")
|
|
|
|
lineWidth = e.readDouble();
|
2017-01-25 15:54:46 +01:00
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (family == "MuseJazz")
|
|
|
|
family = "MuseJazz Text";
|
|
|
|
|
|
|
|
struct StyleTable {
|
|
|
|
const char* name;
|
2018-08-01 11:46:07 +02:00
|
|
|
Tid ss;
|
2017-01-25 15:54:46 +01:00
|
|
|
} styleTable[] = {
|
2018-08-01 11:46:07 +02:00
|
|
|
{ "", Tid::DEFAULT },
|
|
|
|
{ "Title", Tid::TITLE },
|
|
|
|
{ "Subtitle", Tid::SUBTITLE },
|
|
|
|
{ "Composer", Tid::COMPOSER },
|
|
|
|
{ "Lyricist", Tid::POET },
|
|
|
|
{ "Lyrics Odd Lines", Tid::LYRICS_ODD },
|
|
|
|
{ "Lyrics Even Lines", Tid::LYRICS_EVEN },
|
|
|
|
{ "Fingering", Tid::FINGERING },
|
|
|
|
{ "LH Guitar Fingering", Tid::LH_GUITAR_FINGERING },
|
|
|
|
{ "RH Guitar Fingering", Tid::RH_GUITAR_FINGERING },
|
|
|
|
{ "String Number", Tid::STRING_NUMBER },
|
|
|
|
{ "Instrument Name (Long)", Tid::INSTRUMENT_LONG },
|
|
|
|
{ "Instrument Name (Short)", Tid::INSTRUMENT_SHORT },
|
|
|
|
{ "Instrument Name (Part)", Tid::INSTRUMENT_EXCERPT },
|
|
|
|
{ "Dynamics", Tid::DYNAMICS },
|
|
|
|
{ "Technique", Tid::EXPRESSION },
|
|
|
|
{ "Tempo", Tid::TEMPO },
|
|
|
|
{ "Metronome", Tid::METRONOME },
|
|
|
|
{ "Measure Number", Tid::MEASURE_NUMBER },
|
|
|
|
{ "Translator", Tid::TRANSLATOR },
|
|
|
|
{ "Tuplet", Tid::TUPLET },
|
|
|
|
{ "System", Tid::SYSTEM },
|
|
|
|
{ "Staff", Tid::STAFF },
|
|
|
|
{ "Chord Symbol", Tid::HARMONY_A },
|
|
|
|
{ "Rehearsal Mark", Tid::REHEARSAL_MARK },
|
|
|
|
{ "Repeat Text Left", Tid::REPEAT_LEFT },
|
|
|
|
{ "Repeat Text Right", Tid::REPEAT_RIGHT },
|
|
|
|
{ "Frame", Tid::FRAME },
|
|
|
|
{ "Text Line", Tid::TEXTLINE },
|
|
|
|
{ "Glissando", Tid::GLISSANDO },
|
|
|
|
{ "Ottava", Tid::OTTAVA },
|
|
|
|
{ "Pedal", Tid::PEDAL },
|
|
|
|
{ "Hairpin", Tid::HAIRPIN },
|
|
|
|
{ "Bend", Tid::BEND },
|
|
|
|
{ "Header", Tid::HEADER },
|
|
|
|
{ "Footer", Tid::FOOTER },
|
|
|
|
{ "Instrument Change", Tid::INSTRUMENT_CHANGE },
|
|
|
|
{ "Figured Bass", Tid::TEXT_STYLES }, // invalid
|
|
|
|
{ "Volta", Tid::VOLTA },
|
2017-01-25 15:54:46 +01:00
|
|
|
};
|
2018-08-01 11:46:07 +02:00
|
|
|
Tid ss = Tid::TEXT_STYLES;
|
2017-01-25 15:54:46 +01:00
|
|
|
for (const auto& i : styleTable) {
|
|
|
|
if (name == i.name) {
|
|
|
|
ss = i.ss;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-08-01 11:46:07 +02:00
|
|
|
if (ss == Tid::TEXT_STYLES) {
|
2018-06-11 14:16:16 +02:00
|
|
|
ss = e.addUserTextStyle(name);
|
2018-08-01 11:46:07 +02:00
|
|
|
if (ss == Tid::TEXT_STYLES) {
|
2018-06-11 14:16:16 +02:00
|
|
|
qDebug("unhandled substyle <%s>", qPrintable(name));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 11:46:07 +02:00
|
|
|
for (const auto& i : *textStyle(ss)) {
|
2018-06-11 14:16:16 +02:00
|
|
|
QVariant value;
|
|
|
|
if (i.sid == Sid::NOSTYLE)
|
|
|
|
break;
|
|
|
|
switch (i.pid) {
|
|
|
|
case Pid::SUB_STYLE:
|
|
|
|
value = int(ss);
|
|
|
|
break;
|
|
|
|
case Pid::BEGIN_FONT_FACE:
|
|
|
|
case Pid::CONTINUE_FONT_FACE:
|
|
|
|
case Pid::END_FONT_FACE:
|
|
|
|
case Pid::FONT_FACE:
|
|
|
|
value = family;
|
|
|
|
break;
|
|
|
|
case Pid::BEGIN_FONT_SIZE:
|
|
|
|
case Pid::CONTINUE_FONT_SIZE:
|
|
|
|
case Pid::END_FONT_SIZE:
|
|
|
|
case Pid::FONT_SIZE:
|
|
|
|
value = size;
|
|
|
|
break;
|
2018-11-26 21:09:20 +01:00
|
|
|
case Pid::BEGIN_FONT_STYLE:
|
|
|
|
case Pid::CONTINUE_FONT_STYLE:
|
|
|
|
case Pid::END_FONT_STYLE:
|
|
|
|
case Pid::FONT_STYLE:
|
|
|
|
value = int(fontStyle);
|
2018-06-11 14:16:16 +02:00
|
|
|
break;
|
2018-07-26 13:14:06 +02:00
|
|
|
case Pid::FRAME_TYPE:
|
|
|
|
value = int(frameType);
|
2018-06-11 14:16:16 +02:00
|
|
|
break;
|
|
|
|
case Pid::FRAME_WIDTH:
|
|
|
|
value = frameWidth;
|
|
|
|
break;
|
|
|
|
case Pid::FRAME_PADDING:
|
|
|
|
value = paddingWidth;
|
|
|
|
break;
|
|
|
|
case Pid::FRAME_FG_COLOR:
|
|
|
|
value = frameColor;
|
|
|
|
break;
|
|
|
|
case Pid::FRAME_BG_COLOR:
|
|
|
|
value = backgroundColor;
|
|
|
|
break;
|
2018-10-18 11:53:01 +02:00
|
|
|
case Pid::SIZE_SPATIUM_DEPENDENT:
|
2018-06-11 14:16:16 +02:00
|
|
|
value = sizeIsSpatiumDependent;
|
|
|
|
break;
|
|
|
|
case Pid::BEGIN_TEXT_ALIGN:
|
|
|
|
case Pid::CONTINUE_TEXT_ALIGN:
|
|
|
|
case Pid::END_TEXT_ALIGN:
|
|
|
|
case Pid::ALIGN:
|
|
|
|
value = QVariant::fromValue(align);
|
|
|
|
break;
|
2018-10-18 11:53:01 +02:00
|
|
|
#if 0 //TODO-offset
|
2018-06-11 14:16:16 +02:00
|
|
|
case Pid::OFFSET:
|
2018-06-27 09:04:11 +02:00
|
|
|
if (offsetValid) {
|
2018-08-01 11:46:07 +02:00
|
|
|
if (ss == Tid::TEMPO) {
|
2018-06-27 09:04:11 +02:00
|
|
|
style->set(Sid::tempoPosAbove, Spatium(offset.y()));
|
|
|
|
offset = QPointF();
|
|
|
|
}
|
2018-08-01 11:46:07 +02:00
|
|
|
else if (ss == Tid::STAFF) {
|
2018-06-27 09:04:11 +02:00
|
|
|
style->set(Sid::staffTextPosAbove, Spatium(offset.y()));
|
|
|
|
offset = QPointF();
|
|
|
|
}
|
2018-08-01 11:46:07 +02:00
|
|
|
else if (ss == Tid::REHEARSAL_MARK) {
|
2018-06-27 09:04:11 +02:00
|
|
|
style->set(Sid::rehearsalMarkPosAbove, Spatium(offset.y()));
|
|
|
|
offset = QPointF();
|
|
|
|
}
|
|
|
|
value = offset;
|
|
|
|
}
|
2018-06-11 14:16:16 +02:00
|
|
|
break;
|
|
|
|
case Pid::OFFSET_TYPE:
|
|
|
|
value = int(offsetType);
|
|
|
|
break;
|
2018-10-18 11:53:01 +02:00
|
|
|
#endif
|
2018-06-11 14:16:16 +02:00
|
|
|
case Pid::SYSTEM_FLAG:
|
|
|
|
value = systemFlag;
|
|
|
|
break;
|
|
|
|
case Pid::BEGIN_HOOK_HEIGHT:
|
|
|
|
case Pid::END_HOOK_HEIGHT:
|
|
|
|
value = QVariant();
|
|
|
|
break;
|
|
|
|
case Pid::PLACEMENT:
|
2018-06-27 09:04:11 +02:00
|
|
|
if (placementValid)
|
|
|
|
value = int(placement);
|
|
|
|
break;
|
|
|
|
case Pid::LINE_WIDTH:
|
|
|
|
if (lineWidth != -1.0)
|
|
|
|
value = lineWidth;
|
2018-06-11 14:16:16 +02:00
|
|
|
break;
|
|
|
|
default:
|
2018-06-27 09:04:11 +02:00
|
|
|
// qDebug("unhandled property <%s>%d", propertyName(i.pid), int (i.pid));
|
2018-03-28 10:43:28 +02:00
|
|
|
break;
|
2017-01-25 15:54:46 +01:00
|
|
|
}
|
2018-06-11 14:16:16 +02:00
|
|
|
if (value.isValid())
|
|
|
|
style->set(i.sid, value);
|
2018-06-27 09:04:11 +02:00
|
|
|
// else
|
|
|
|
// qDebug("invalid style value <%s> pid<%s>", MStyle::valueName(i.sid), propertyName(i.pid));
|
2017-01-25 15:54:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 12:02:27 +02:00
|
|
|
//---------------------------------------------------------
|
2018-08-27 22:57:15 +02:00
|
|
|
// readAccidental206
|
2016-09-22 12:02:27 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
void readAccidental206(Accidental* a, XmlReader& e)
|
2016-09-22 12:02:27 +02:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "bracket") {
|
|
|
|
int i = e.readInt();
|
|
|
|
if (i == 0 || i == 1)
|
2017-01-31 17:28:56 +01:00
|
|
|
a->setBracket(AccidentalBracket(i));
|
2016-09-22 12:02:27 +02:00
|
|
|
}
|
|
|
|
else if (tag == "subtype") {
|
2016-09-29 01:18:02 +02:00
|
|
|
QString text = e.readElementText();
|
|
|
|
const static std::map<QString, AccidentalType> accMap = {
|
2017-01-25 15:54:46 +01:00
|
|
|
{"none", AccidentalType::NONE},
|
|
|
|
{"sharp", AccidentalType::SHARP},
|
|
|
|
{"flat", AccidentalType::FLAT},
|
|
|
|
{"natural", AccidentalType::NATURAL},
|
|
|
|
{"double sharp", AccidentalType::SHARP2},
|
|
|
|
{"double flat", AccidentalType::FLAT2},
|
|
|
|
{"flat-slash", AccidentalType::FLAT_SLASH},
|
|
|
|
{"flat-slash2", AccidentalType::FLAT_SLASH2},
|
|
|
|
{"mirrored-flat2", AccidentalType::MIRRORED_FLAT2},
|
|
|
|
{"mirrored-flat", AccidentalType::MIRRORED_FLAT},
|
|
|
|
{"sharp-slash", AccidentalType::SHARP_SLASH},
|
|
|
|
{"sharp-slash2", AccidentalType::SHARP_SLASH2},
|
|
|
|
{"sharp-slash3", AccidentalType::SHARP_SLASH3},
|
|
|
|
{"sharp-slash4", AccidentalType::SHARP_SLASH4},
|
|
|
|
{"sharp arrow up", AccidentalType::SHARP_ARROW_UP},
|
|
|
|
{"sharp arrow down", AccidentalType::SHARP_ARROW_DOWN},
|
|
|
|
{"flat arrow up", AccidentalType::FLAT_ARROW_UP},
|
|
|
|
{"flat arrow down", AccidentalType::FLAT_ARROW_DOWN},
|
|
|
|
{"natural arrow up", AccidentalType::NATURAL_ARROW_UP},
|
|
|
|
{"natural arrow down", AccidentalType::NATURAL_ARROW_DOWN},
|
|
|
|
{"sori", AccidentalType::SORI},
|
|
|
|
{"koron", AccidentalType::KORON}
|
|
|
|
};
|
2016-09-29 01:18:02 +02:00
|
|
|
auto it = accMap.find(text);
|
|
|
|
if (it == accMap.end()) {
|
|
|
|
qDebug("invalid type %s", qPrintable(text));
|
|
|
|
a->setAccidentalType(AccidentalType::NONE);
|
2016-09-22 12:02:27 +02:00
|
|
|
}
|
|
|
|
else
|
2016-09-29 01:18:02 +02:00
|
|
|
a->setAccidentalType(it->second);
|
2016-09-22 12:02:27 +02:00
|
|
|
}
|
|
|
|
else if (tag == "role") {
|
|
|
|
AccidentalRole r = AccidentalRole(e.readInt());
|
|
|
|
if (r == AccidentalRole::AUTO || r == AccidentalRole::USER)
|
|
|
|
a->setRole(r);
|
|
|
|
}
|
|
|
|
else if (tag == "small")
|
|
|
|
a->setSmall(e.readInt());
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (a->Element::readProperties(e))
|
2016-09-22 12:02:27 +02:00
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-18 17:58:38 +02:00
|
|
|
static NoteHead::Group convertHeadGroup(int i)
|
|
|
|
{
|
|
|
|
NoteHead::Group val;
|
|
|
|
switch (i) {
|
|
|
|
case 1:
|
|
|
|
val = NoteHead::Group::HEAD_CROSS;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
val = NoteHead::Group::HEAD_DIAMOND;
|
|
|
|
break;
|
|
|
|
case 3:
|
2016-10-22 20:16:42 +02:00
|
|
|
val = NoteHead::Group::HEAD_TRIANGLE_DOWN;
|
2016-10-18 17:58:38 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
val = NoteHead::Group::HEAD_MI;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
val = NoteHead::Group::HEAD_SLASH;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
val = NoteHead::Group::HEAD_XCIRCLE;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
val = NoteHead::Group::HEAD_DO;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
val = NoteHead::Group::HEAD_RE;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
val = NoteHead::Group::HEAD_FA;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
val = NoteHead::Group::HEAD_LA;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
val = NoteHead::Group::HEAD_TI;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
val = NoteHead::Group::HEAD_SOL;
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
val = NoteHead::Group::HEAD_BREVIS_ALT;
|
|
|
|
break;
|
2017-12-19 15:41:37 +01:00
|
|
|
case 0:
|
2016-10-18 17:58:38 +02:00
|
|
|
default:
|
|
|
|
val = NoteHead::Group::HEAD_NORMAL;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NoteHead::Type convertHeadType(int i)
|
|
|
|
{
|
|
|
|
NoteHead::Type val;
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
|
|
val = NoteHead::Type::HEAD_WHOLE;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
val = NoteHead::Type::HEAD_HALF;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
val = NoteHead::Type::HEAD_QUARTER;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
val = NoteHead::Type::HEAD_BREVIS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
val = NoteHead::Type::HEAD_AUTO;;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2018-05-17 20:19:47 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ArticulationNames
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static struct ArticulationNames {
|
|
|
|
SymId id;
|
|
|
|
const char* name;
|
|
|
|
} articulationNames[] = {
|
|
|
|
{ SymId::fermataAbove, "fermata", },
|
|
|
|
{ SymId::fermataShortAbove, "shortfermata", },
|
|
|
|
{ SymId::fermataLongAbove, "longfermata", },
|
|
|
|
{ SymId::fermataVeryLongAbove, "verylongfermata", },
|
|
|
|
{ SymId::articAccentAbove, "sforzato", },
|
|
|
|
{ SymId::articStaccatoAbove, "staccato", },
|
|
|
|
{ SymId::articStaccatissimoAbove, "staccatissimo", },
|
|
|
|
{ SymId::articTenutoAbove, "tenuto", },
|
|
|
|
{ SymId::articTenutoStaccatoAbove, "portato", },
|
|
|
|
{ SymId::articMarcatoAbove, "marcato", },
|
|
|
|
{ SymId::guitarFadeIn, "fadein", },
|
|
|
|
{ SymId::guitarFadeOut, "fadeout", },
|
|
|
|
{ SymId::guitarVolumeSwell, "volumeswell", },
|
|
|
|
{ SymId::wiggleSawtooth, "wigglesawtooth", },
|
|
|
|
{ SymId::wiggleSawtoothWide, "wigglesawtoothwide", },
|
|
|
|
{ SymId::wiggleVibratoLargeFaster, "wigglevibratolargefaster", },
|
|
|
|
{ SymId::wiggleVibratoLargeSlowest, "wigglevibratolargeslowest", },
|
|
|
|
{ SymId::brassMuteOpen, "ouvert", },
|
|
|
|
{ SymId::brassMuteClosed, "plusstop", },
|
|
|
|
{ SymId::stringsUpBow, "upbow", },
|
|
|
|
{ SymId::stringsDownBow, "downbow", },
|
|
|
|
{ SymId::ornamentTurnInverted, "reverseturn", },
|
|
|
|
{ SymId::ornamentTurn, "turn", },
|
|
|
|
{ SymId::ornamentTrill, "trill", },
|
|
|
|
{ SymId::ornamentMordent, "prall", },
|
|
|
|
{ SymId::ornamentMordentInverted, "mordent", },
|
|
|
|
{ SymId::ornamentTremblement, "prallprall", },
|
|
|
|
{ SymId::ornamentPrallMordent, "prallmordent", },
|
|
|
|
{ SymId::ornamentUpPrall, "upprall", },
|
|
|
|
{ SymId::ornamentUpMordent, "upmordent", },
|
|
|
|
{ SymId::ornamentDownMordent, "downmordent", },
|
|
|
|
{ SymId::ornamentPrallDown, "pralldown", },
|
|
|
|
{ SymId::ornamentPrallUp, "prallup", },
|
|
|
|
{ SymId::ornamentLinePrall, "lineprall", },
|
|
|
|
{ SymId::ornamentPrecompSlide, "schleifer", },
|
|
|
|
{ SymId::pluckedSnapPizzicatoAbove, "snappizzicato", },
|
|
|
|
{ SymId::stringsThumbPosition, "thumb", },
|
|
|
|
{ SymId::luteFingeringRHThumb, "lutefingeringthumb", },
|
|
|
|
{ SymId::luteFingeringRHFirst, "lutefingering1st", },
|
|
|
|
{ SymId::luteFingeringRHSecond, "lutefingering2nd", },
|
|
|
|
{ SymId::luteFingeringRHThird, "lutefingering3rd", },
|
|
|
|
|
|
|
|
{ SymId::ornamentPrecompMordentUpperPrefix, "downprall" },
|
|
|
|
{ SymId::ornamentPrecompMordentUpperPrefix, "ornamentDownPrall" },
|
|
|
|
};
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// oldArticulationNames2SymId
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
SymId oldArticulationNames2SymId(const QString& s)
|
|
|
|
{
|
|
|
|
for (auto i : articulationNames) {
|
|
|
|
if (i.name == s)
|
|
|
|
return i.id;
|
|
|
|
}
|
|
|
|
return SymId::noSym;
|
|
|
|
}
|
|
|
|
|
2016-10-20 10:13:12 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readDrumset
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readDrumset(Drumset* ds, XmlReader& e)
|
|
|
|
{
|
|
|
|
int pitch = e.intAttribute("pitch", -1);
|
|
|
|
if (pitch < 0 || pitch > 127) {
|
|
|
|
qDebug("load drumset: invalid pitch %d", pitch);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "head")
|
|
|
|
ds->drum(pitch).notehead = convertHeadGroup(e.readInt());
|
2018-05-17 20:19:47 +02:00
|
|
|
else if (tag == "variants") {
|
|
|
|
while(e.readNextStartElement()) {
|
|
|
|
const QStringRef& tagv(e.name());
|
|
|
|
if (tagv == "variant") {
|
|
|
|
DrumInstrumentVariant div;
|
|
|
|
div.pitch = e.attribute("pitch").toInt();
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& taga(e.name());
|
|
|
|
if (taga == "articulation") {
|
|
|
|
QString oldArticulationName = e.readElementText();
|
|
|
|
SymId oldId = oldArticulationNames2SymId(oldArticulationName);
|
|
|
|
div.articulationName = Articulation::symId2ArticulationName(oldId);
|
|
|
|
}
|
|
|
|
else if (taga == "tremolo") {
|
|
|
|
div.tremolo = Tremolo::name2Type(e.readElementText());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ds->drum(pitch).addVariant(div);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-20 10:13:12 +02:00
|
|
|
else if (ds->readProperties(e, pitch))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readInstrument
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readInstrument(Instrument *i, Part* p, XmlReader& e)
|
|
|
|
{
|
|
|
|
int program = -1;
|
|
|
|
int bank = 0;
|
|
|
|
int volume = 100;
|
|
|
|
int pan = 60;
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
int chorus = 30;
|
|
|
|
int reverb = 30;
|
2016-10-20 10:13:12 +02:00
|
|
|
bool customDrumset = false;
|
|
|
|
i->clearChannels(); // remove default channel
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Drum") {
|
|
|
|
// if we see one of this tags, a custom drumset will
|
|
|
|
// be created
|
|
|
|
if (!i->drumset())
|
|
|
|
i->setDrumset(new Drumset(*smDrumset));
|
|
|
|
if (!customDrumset) {
|
|
|
|
i->drumset()->clear();
|
|
|
|
customDrumset = true;
|
|
|
|
}
|
|
|
|
readDrumset(i->drumset(), e);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (i->readProperties(e, p, &customDrumset))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (i->channel().empty()) { // for backward compatibility
|
|
|
|
Channel* a = new Channel;
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
a->setName(Channel::DEFAULT_NAME);
|
|
|
|
a->setProgram(program);
|
|
|
|
a->setBank(bank);
|
|
|
|
a->setVolume(volume);
|
|
|
|
a->setPan(pan);
|
|
|
|
a->setReverb(reverb);
|
|
|
|
a->setChorus(chorus);
|
2016-10-20 10:13:12 +02:00
|
|
|
i->appendChannel(a);
|
|
|
|
}
|
|
|
|
if (i->useDrumset()) {
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
if (i->channel()[0]->bank() == 0)
|
|
|
|
i->channel()[0]->setBank(128);
|
2016-10-20 10:13:12 +02:00
|
|
|
i->channel()[0]->updateInitList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-23 12:05:18 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readStaff(Staff* staff, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "type") { // obsolete
|
|
|
|
int staffTypeIdx = e.readInt();
|
|
|
|
qDebug("obsolete: Staff::read staffTypeIdx %d", staffTypeIdx);
|
|
|
|
}
|
|
|
|
else if (tag == "neverHide") {
|
|
|
|
bool v = e.readInt();
|
|
|
|
if (v)
|
|
|
|
staff->setHideWhenEmpty(Staff::HideMode::NEVER);
|
|
|
|
}
|
|
|
|
else if (tag == "barLineSpan") {
|
|
|
|
staff->setBarLineFrom(e.intAttribute("from", 0));
|
|
|
|
staff->setBarLineTo(e.intAttribute("to", 0));
|
|
|
|
int span = e.readInt();
|
2017-05-29 14:59:10 +02:00
|
|
|
staff->setBarLineSpan(span - 1);
|
2016-12-23 12:05:18 +01:00
|
|
|
}
|
|
|
|
else if (staff->readProperties(e))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readPart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-10-20 10:13:12 +02:00
|
|
|
static void readPart(Part* part, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Instrument") {
|
|
|
|
Instrument* i = part->instrument();
|
|
|
|
readInstrument(i, part, e);
|
|
|
|
Drumset* ds = i->drumset();
|
|
|
|
Staff* s = part->staff(0);
|
2016-12-23 12:05:18 +01:00
|
|
|
int lld = s ? qRound(s->lineDistance(0)) : 1;
|
2016-10-20 10:13:12 +02:00
|
|
|
if (ds && s && lld > 1) {
|
2018-08-17 15:06:15 +02:00
|
|
|
for (int j = 0; j < DRUM_INSTRUMENTS; ++j)
|
|
|
|
ds->drum(j).line /= lld;
|
2016-10-20 10:13:12 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-23 12:05:18 +01:00
|
|
|
else if (tag == "Staff") {
|
|
|
|
Staff* staff = new Staff(part->score());
|
|
|
|
staff->setPart(part);
|
|
|
|
part->score()->staves().push_back(staff);
|
|
|
|
part->staves()->push_back(staff);
|
|
|
|
readStaff(staff, e);
|
|
|
|
}
|
2016-10-20 10:13:12 +02:00
|
|
|
else if (part->readProperties(e))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-18 17:58:38 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readAmbitus
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readAmbitus(Ambitus* ambitus, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "head")
|
|
|
|
ambitus->setNoteHeadGroup(convertHeadGroup(e.readInt()));
|
|
|
|
else if (tag == "headType")
|
|
|
|
ambitus->setNoteHeadType(convertHeadType(e.readInt()));
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (ambitus->readProperties(e))
|
2016-10-18 17:58:38 +02:00
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 12:02:27 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readNote
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readNote(Note* note, XmlReader& e)
|
|
|
|
{
|
|
|
|
note->setTpc1(Tpc::TPC_INVALID);
|
|
|
|
note->setTpc2(Tpc::TPC_INVALID);
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Accidental") {
|
|
|
|
Accidental* a = new Accidental(note->score());
|
|
|
|
a->setTrack(note->track());
|
2018-08-27 22:57:15 +02:00
|
|
|
readAccidental206(a, e);
|
2016-09-22 12:02:27 +02:00
|
|
|
note->add(a);
|
|
|
|
}
|
2016-10-18 09:21:54 +02:00
|
|
|
else if (tag == "head") {
|
|
|
|
int i = e.readInt();
|
2016-10-18 17:58:38 +02:00
|
|
|
NoteHead::Group val = convertHeadGroup(i);
|
2016-10-18 09:21:54 +02:00
|
|
|
note->setHeadGroup(val);
|
|
|
|
}
|
|
|
|
else if (tag == "headType") {
|
|
|
|
int i = e.readInt();
|
2016-10-18 17:58:38 +02:00
|
|
|
NoteHead::Type val = convertHeadType(i);
|
2016-10-18 09:21:54 +02:00
|
|
|
note->setHeadType(val);
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (readNoteProperties206(note, e))
|
2016-09-22 12:02:27 +02:00
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
// ensure sane values:
|
|
|
|
note->setPitch(limit(note->pitch(), 0, 127));
|
|
|
|
|
|
|
|
if (!tpcIsValid(note->tpc1()) && !tpcIsValid(note->tpc2())) {
|
|
|
|
Key key = (note->staff() && note->chord()) ? note->staff()->key(note->chord()->tick()) : Key::C;
|
|
|
|
int tpc = pitch2tpc(note->pitch(), key, Prefer::NEAREST);
|
|
|
|
if (note->concertPitch())
|
|
|
|
note->setTpc1(tpc);
|
|
|
|
else
|
|
|
|
note->setTpc2(tpc);
|
|
|
|
}
|
|
|
|
if (!(tpcIsValid(note->tpc1()) && tpcIsValid(note->tpc2()))) {
|
|
|
|
int tick = note->chord() ? note->chord()->tick() : -1;
|
|
|
|
Interval v = note->staff() ? note->part()->instrument(tick)->transpose() : Interval();
|
|
|
|
if (tpcIsValid(note->tpc1())) {
|
|
|
|
v.flip();
|
|
|
|
if (v.isZero())
|
|
|
|
note->setTpc2(note->tpc1());
|
|
|
|
else
|
|
|
|
note->setTpc2(Ms::transposeTpc(note->tpc1(), v, true));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (v.isZero())
|
|
|
|
note->setTpc1(note->tpc2());
|
|
|
|
else
|
|
|
|
note->setTpc1(Ms::transposeTpc(note->tpc2(), v, true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check consistency of pitch, tpc1, tpc2, and transposition
|
2018-08-27 22:57:15 +02:00
|
|
|
// see note in InstrumentChange::read() about a known case of tpc corruption produced in 2.0.x
|
2016-09-22 12:02:27 +02:00
|
|
|
// but since there are other causes of tpc corruption (eg, https://musescore.org/en/node/74746)
|
|
|
|
// including perhaps some we don't know about yet,
|
|
|
|
// we will attempt to fix some problems here regardless of version
|
|
|
|
|
|
|
|
if (!e.pasteMode() && !MScore::testMode) {
|
|
|
|
int tpc1Pitch = (tpc2pitch(note->tpc1()) + 12) % 12;
|
|
|
|
int tpc2Pitch = (tpc2pitch(note->tpc2()) + 12) % 12;
|
|
|
|
int concertPitch = note->pitch() % 12;
|
|
|
|
if (tpc1Pitch != concertPitch) {
|
|
|
|
qDebug("bad tpc1 - concertPitch = %d, tpc1 = %d", concertPitch, tpc1Pitch);
|
|
|
|
note->setPitch(note->pitch() + tpc1Pitch - concertPitch);
|
|
|
|
}
|
|
|
|
Interval v = note->staff()->part()->instrument(e.tick())->transpose();
|
|
|
|
int transposedPitch = (note->pitch() - v.chromatic) % 12;
|
|
|
|
if (tpc2Pitch != transposedPitch) {
|
|
|
|
qDebug("bad tpc2 - transposedPitch = %d, tpc2 = %d", transposedPitch, tpc2Pitch);
|
|
|
|
// just in case the staff transposition info is not reliable here,
|
|
|
|
// do not attempt to correct tpc
|
|
|
|
// except for older scores where we know there are tpc problems
|
|
|
|
v.flip();
|
|
|
|
note->setTpc2(Ms::transposeTpc(note->tpc1(), v, true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readNoteProperties206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool readNoteProperties206(Note* note, XmlReader& e)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "pitch")
|
|
|
|
note->setPitch(e.readInt());
|
|
|
|
else if (tag == "tpc") {
|
|
|
|
const int tpc = e.readInt();
|
|
|
|
note->setTpc1(tpc);
|
|
|
|
note->setTpc2(tpc);
|
|
|
|
}
|
|
|
|
else if (tag == "track") // for performance
|
|
|
|
note->setTrack(e.readInt());
|
|
|
|
else if (tag == "Accidental") {
|
|
|
|
Accidental* a = new Accidental(note->score());
|
|
|
|
a->setTrack(note->track());
|
|
|
|
a->read(e);
|
|
|
|
note->add(a);
|
|
|
|
}
|
|
|
|
else if (tag == "Tie") {
|
|
|
|
Tie* tie = new Tie(note->score());
|
|
|
|
tie->setParent(note);
|
|
|
|
tie->setTrack(note->track());
|
|
|
|
readTie206(e, tie);
|
|
|
|
tie->setStartNote(note);
|
|
|
|
note->setTieFor(tie);
|
|
|
|
}
|
|
|
|
else if (tag == "tpc2")
|
|
|
|
note->setTpc2(e.readInt());
|
|
|
|
else if (tag == "small")
|
|
|
|
note->setSmall(e.readInt());
|
|
|
|
else if (tag == "mirror")
|
2018-10-26 10:41:07 +02:00
|
|
|
note->readProperty(e, Pid::MIRROR_HEAD);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tag == "dotPosition")
|
2018-10-26 10:41:07 +02:00
|
|
|
note->readProperty(e, Pid::DOT_POSITION);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tag == "fixed")
|
|
|
|
note->setFixed(e.readBool());
|
|
|
|
else if (tag == "fixedLine")
|
|
|
|
note->setFixedLine(e.readInt());
|
|
|
|
else if (tag == "head")
|
2018-10-26 10:41:07 +02:00
|
|
|
note->readProperty(e, Pid::HEAD_GROUP);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tag == "velocity")
|
|
|
|
note->setVeloOffset(e.readInt());
|
|
|
|
else if (tag == "play")
|
|
|
|
note->setPlay(e.readInt());
|
|
|
|
else if (tag == "tuning")
|
|
|
|
note->setTuning(e.readDouble());
|
|
|
|
else if (tag == "fret")
|
|
|
|
note->setFret(e.readInt());
|
|
|
|
else if (tag == "string")
|
|
|
|
note->setString(e.readInt());
|
|
|
|
else if (tag == "ghost")
|
|
|
|
note->setGhost(e.readInt());
|
|
|
|
else if (tag == "headType")
|
2018-10-26 10:41:07 +02:00
|
|
|
note->readProperty(e, Pid::HEAD_TYPE);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tag == "veloType")
|
2018-10-26 10:41:07 +02:00
|
|
|
note->readProperty(e, Pid::VELO_TYPE);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tag == "line")
|
|
|
|
note->setLine(e.readInt());
|
|
|
|
else if (tag == "Fingering") {
|
|
|
|
Fingering* f = new Fingering(note->score());
|
|
|
|
f->setTrack(note->track());
|
|
|
|
readText206(e, f, note);
|
|
|
|
note->add(f);
|
|
|
|
}
|
|
|
|
else if (tag == "Symbol") {
|
|
|
|
Symbol* s = new Symbol(note->score());
|
|
|
|
s->setTrack(note->track());
|
|
|
|
s->read(e);
|
|
|
|
note->add(s);
|
|
|
|
}
|
|
|
|
else if (tag == "Image") {
|
|
|
|
if (MScore::noImages)
|
|
|
|
e.skipCurrentElement();
|
|
|
|
else {
|
|
|
|
Image* image = new Image(note->score());
|
|
|
|
image->setTrack(note->track());
|
|
|
|
image->read(e);
|
|
|
|
note->add(image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "Bend") {
|
|
|
|
Bend* b = new Bend(note->score());
|
|
|
|
b->setTrack(note->track());
|
|
|
|
b->read(e);
|
|
|
|
note->add(b);
|
|
|
|
}
|
|
|
|
else if (tag == "NoteDot") {
|
|
|
|
NoteDot* dot = new NoteDot(note->score());
|
|
|
|
dot->read(e);
|
|
|
|
note->add(dot);
|
|
|
|
}
|
|
|
|
else if (tag == "Events") {
|
|
|
|
note->playEvents().clear(); // remove default event
|
|
|
|
while (e.readNextStartElement()) {
|
2018-09-25 15:55:08 +02:00
|
|
|
const QStringRef& etag(e.name());
|
|
|
|
if (etag == "Event") {
|
2018-08-27 22:57:15 +02:00
|
|
|
NoteEvent ne;
|
|
|
|
ne.read(e);
|
|
|
|
note->playEvents().append(ne);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (Chord* ch = note->chord())
|
|
|
|
ch->setPlayEventType(PlayEventType::User);
|
|
|
|
}
|
|
|
|
else if (tag == "endSpanner") {
|
|
|
|
int id = e.intAttribute("id");
|
|
|
|
Spanner* sp = e.findSpanner(id);
|
|
|
|
if (sp) {
|
|
|
|
sp->setEndElement(note);
|
|
|
|
if (sp->isTie())
|
|
|
|
note->setTieBack(toTie(sp));
|
|
|
|
else {
|
|
|
|
if (sp->isGlissando() && note->parent() && note->parent()->isChord())
|
|
|
|
toChord(note->parent())->setEndsGlissando(true);
|
|
|
|
note->addSpannerBack(sp);
|
|
|
|
}
|
|
|
|
e.removeSpanner(sp);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// End of a spanner whose start element will appear later;
|
|
|
|
// may happen for cross-staff spanner from a lower to a higher staff
|
|
|
|
// (for instance a glissando from bass to treble staff of piano).
|
|
|
|
// Create a place-holder spanner with end data
|
|
|
|
// (a TextLine is used only because both Spanner or SLine are abstract,
|
|
|
|
// the actual class does not matter, as long as it is derived from Spanner)
|
2018-09-25 15:55:08 +02:00
|
|
|
int id1 = e.intAttribute("id", -1);
|
2018-08-27 22:57:15 +02:00
|
|
|
Staff* staff = note->staff();
|
2018-09-25 15:55:08 +02:00
|
|
|
if (id1 != -1 &&
|
2018-08-27 22:57:15 +02:00
|
|
|
// DISABLE if pasting into a staff with linked staves
|
|
|
|
// because the glissando is not properly cloned into the linked staves
|
|
|
|
staff && (!e.pasteMode() || !staff->links() || staff->links()->empty())) {
|
|
|
|
Spanner* placeholder = new TextLine(note->score());
|
|
|
|
placeholder->setAnchor(Spanner::Anchor::NOTE);
|
|
|
|
placeholder->setEndElement(note);
|
|
|
|
placeholder->setTrack2(note->track());
|
|
|
|
placeholder->setTick(0);
|
|
|
|
placeholder->setTick2(e.tick());
|
2018-09-25 15:55:08 +02:00
|
|
|
e.addSpanner(id1, placeholder);
|
2018-08-27 22:57:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "TextLine"
|
|
|
|
|| tag == "Glissando") {
|
|
|
|
Spanner* sp = toSpanner(Element::name2Element(tag, note->score()));
|
|
|
|
// check this is not a lower-to-higher cross-staff spanner we already got
|
|
|
|
int id = e.intAttribute("id");
|
|
|
|
Spanner* placeholder = e.findSpanner(id);
|
|
|
|
if (placeholder && placeholder->endElement()) {
|
|
|
|
// if it is, fill end data from place-holder
|
|
|
|
sp->setAnchor(Spanner::Anchor::NOTE); // make sure we can set a Note as end element
|
|
|
|
sp->setEndElement(placeholder->endElement());
|
|
|
|
sp->setTrack2(placeholder->track2());
|
|
|
|
sp->setTick(e.tick()); // make sure tick2 will be correct
|
|
|
|
sp->setTick2(placeholder->tick2());
|
|
|
|
toNote(placeholder->endElement())->addSpannerBack(sp);
|
|
|
|
// remove no longer needed place-holder before reading the new spanner,
|
|
|
|
// as reading it also adds it to XML reader list of spanners,
|
|
|
|
// which would overwrite the place-holder
|
|
|
|
e.removeSpanner(placeholder);
|
|
|
|
delete placeholder;
|
|
|
|
}
|
|
|
|
sp->setTrack(note->track());
|
|
|
|
sp->read(e);
|
|
|
|
Staff* staff = note->staff();
|
|
|
|
// DISABLE pasting of glissandi into staves with other lionked staves
|
|
|
|
// because the glissando is not properly cloned into the linked staves
|
|
|
|
if (e.pasteMode() && staff && staff->links() && !staff->links()->empty()) {
|
|
|
|
e.removeSpanner(sp); // read() added the element to the XMLReader: remove it
|
|
|
|
delete sp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sp->setAnchor(Spanner::Anchor::NOTE);
|
|
|
|
sp->setStartElement(note);
|
|
|
|
sp->setTick(e.tick());
|
|
|
|
note->addSpannerFor(sp);
|
|
|
|
sp->setParent(note);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "offset")
|
|
|
|
note->Element::readProperties(e);
|
|
|
|
else if (note->Element::readProperties(e))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-05-23 16:52:04 +02:00
|
|
|
//---------------------------------------------------------
|
2018-10-30 12:18:11 +01:00
|
|
|
// readTextProperties206
|
2018-06-27 09:04:11 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool readTextProperties206(XmlReader& e, TextBase* t, Element* be)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "style") {
|
|
|
|
QString s = e.readElementText();
|
|
|
|
if (!be->isTuplet()) { // Hack
|
2018-08-01 11:46:07 +02:00
|
|
|
Tid ss;
|
2018-06-27 09:04:11 +02:00
|
|
|
ss = e.lookupUserTextStyle(s);
|
2018-08-01 11:46:07 +02:00
|
|
|
if (ss == Tid::TEXT_STYLES)
|
|
|
|
ss = textStyleFromName(s);
|
|
|
|
if (ss != Tid::TEXT_STYLES)
|
|
|
|
t->initTid(ss);
|
2018-06-27 09:04:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "foregroundColor") // same as "color" ?
|
|
|
|
e.skipCurrentElement();
|
|
|
|
else if (tag == "frame")
|
2018-07-26 13:14:06 +02:00
|
|
|
t->setFrameType(e.readBool() ? FrameType::SQUARE : FrameType::NO_FRAME);
|
2018-10-18 09:09:24 +02:00
|
|
|
else if (tag == "frameRound")
|
|
|
|
t->setFrameRound(e.readInt());
|
|
|
|
else if (tag == "circle") {
|
|
|
|
if (e.readBool())
|
|
|
|
t->setFrameType(FrameType::CIRCLE);
|
2018-11-02 18:38:07 +01:00
|
|
|
else {
|
|
|
|
if (t->circle())
|
|
|
|
t->setFrameType(FrameType::SQUARE);
|
|
|
|
}
|
2018-10-18 09:09:24 +02:00
|
|
|
}
|
|
|
|
else if (tag == "paddingWidthS")
|
|
|
|
t->setPaddingWidth(Spatium(e.readDouble()));
|
|
|
|
else if (tag == "frameWidthS")
|
|
|
|
t->setFrameWidth(Spatium(e.readDouble()));
|
|
|
|
else if (tag == "frameColor")
|
|
|
|
t->setFrameColor(e.readColor());
|
|
|
|
else if (tag == "backgroundColor")
|
|
|
|
t->setBgColor(e.readColor());
|
2018-06-27 09:04:11 +02:00
|
|
|
else if (tag == "halign") {
|
|
|
|
Align align = Align(int(t->align()) & int(~Align::HMASK));
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
if (val == "center")
|
|
|
|
align = align | Align::HCENTER;
|
|
|
|
else if (val == "right")
|
|
|
|
align = align | Align::RIGHT;
|
|
|
|
else if (val == "left")
|
|
|
|
;
|
|
|
|
else
|
|
|
|
qDebug("unknown alignment: <%s>", qPrintable(val));
|
|
|
|
t->setAlign(align);
|
|
|
|
}
|
|
|
|
else if (tag == "valign") {
|
|
|
|
Align align = Align(int(t->align()) & int(~Align::VMASK));
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
if (val == "center")
|
|
|
|
align = align | Align::VCENTER;
|
|
|
|
else if (val == "bottom")
|
|
|
|
align = align | Align::BOTTOM;
|
|
|
|
else if (val == "baseline")
|
|
|
|
align = align | Align::BASELINE;
|
|
|
|
else if (val == "top")
|
|
|
|
;
|
|
|
|
else
|
|
|
|
qDebug("unknown alignment: <%s>", qPrintable(val));
|
|
|
|
t->setAlign(align);
|
|
|
|
}
|
2018-10-30 12:18:11 +01:00
|
|
|
else if (tag == "pos") {
|
|
|
|
t->readProperty(e, Pid::OFFSET);
|
|
|
|
if ((char(t->align()) & char(Align::VMASK)) == char(Align::TOP))
|
|
|
|
t->ryoffset() += .5 * t->score()->spatium(); // HACK: bbox is different in 2.x
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!t->readProperties(e))
|
2018-06-27 09:04:11 +02:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readText206
|
2017-05-23 16:52:04 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-05-14 10:07:46 +02:00
|
|
|
static void readText206(XmlReader& e, TextBase* t, Element* be)
|
2018-06-27 09:04:11 +02:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (!readTextProperties206(e, t, be))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readTempoText(TempoText* t, XmlReader& e)
|
2017-05-23 16:52:04 +02:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
2018-06-27 09:04:11 +02:00
|
|
|
if (tag == "tempo")
|
|
|
|
t->setTempo(e.readDouble());
|
|
|
|
else if (tag == "followText")
|
|
|
|
t->setFollowText(e.readInt());
|
|
|
|
else if (!readTextProperties206(e, t, t))
|
2017-05-23 16:52:04 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
// check sanity
|
|
|
|
if (t->xmlText().isEmpty()) {
|
|
|
|
t->setXmlText(QString("<sym>metNoteQuarterUp</sym> = %1").arg(lrint(60 * t->tempo())));
|
|
|
|
t->setVisible(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
t->setXmlText(t->xmlText().replace("<sym>unicode", "<sym>met"));
|
2017-05-23 16:52:04 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 18:38:07 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readMarker
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readMarker(Marker* m, XmlReader& e)
|
|
|
|
{
|
|
|
|
Marker::Type mt = Marker::Type::SEGNO;
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "label") {
|
|
|
|
QString s(e.readElementText());
|
|
|
|
m->setLabel(s);
|
|
|
|
mt = m->markerType(s);
|
|
|
|
}
|
|
|
|
else if (!readTextProperties206(e, m, m))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
m->setMarkerType(mt);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readDynamic
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readDynamic(Dynamic* d, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag = e.name();
|
|
|
|
if (tag == "subtype")
|
|
|
|
d->setDynamicType(e.readElementText());
|
|
|
|
else if (tag == "velocity")
|
|
|
|
d->setVelocity(e.readInt());
|
|
|
|
else if (tag == "dynType")
|
|
|
|
d->setDynRange(Dynamic::Range(e.readInt()));
|
|
|
|
else if (!readTextProperties206(e, d, d))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 17:49:08 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readTuplet
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readTuplet(Tuplet* tuplet, XmlReader& e)
|
|
|
|
{
|
|
|
|
tuplet->setId(e.intAttribute("id", 0));
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Number") {
|
|
|
|
Text* _number = new Text(tuplet->score());
|
|
|
|
_number->setParent(tuplet);
|
2018-06-27 10:38:00 +02:00
|
|
|
_number->setComposition(true);
|
2018-03-28 17:49:08 +02:00
|
|
|
tuplet->setNumber(_number);
|
2018-06-27 10:38:00 +02:00
|
|
|
// _number reads property defaults from parent tuplet as "composition" is set:
|
2018-09-06 15:02:38 +02:00
|
|
|
tuplet->resetNumberProperty();
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, _number, tuplet);
|
2018-03-28 17:49:08 +02:00
|
|
|
_number->setVisible(tuplet->visible()); //?? override saved property
|
|
|
|
_number->setTrack(tuplet->track());
|
|
|
|
// move property flags from _number
|
2018-11-26 21:09:20 +01:00
|
|
|
for (auto p : { Pid::FONT_FACE, Pid::FONT_SIZE, Pid::FONT_STYLE, Pid::ALIGN })
|
2018-03-28 17:49:08 +02:00
|
|
|
tuplet->setPropertyFlags(p, _number->propertyFlags(p));
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!readTupletProperties206(e, tuplet))
|
2018-03-28 17:49:08 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
Fraction r = (tuplet->ratio() == 1) ? tuplet->ratio() : tuplet->ratio().reduced();
|
|
|
|
Fraction f(r.denominator(), tuplet->baseLen().fraction().denominator());
|
|
|
|
tuplet->setDuration(f.reduced());
|
|
|
|
}
|
|
|
|
|
2018-06-19 13:39:20 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readLyrics
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readLyrics(Lyrics* lyrics, XmlReader& e)
|
|
|
|
{
|
|
|
|
int iEndTick = 0; // used for backward compatibility
|
|
|
|
Text* _verseNumber = 0;
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "endTick") {
|
|
|
|
// store <endTick> tag value until a <ticks> tag has been read
|
|
|
|
// which positions this lyrics element in the score
|
|
|
|
iEndTick = e.readInt();
|
|
|
|
}
|
|
|
|
else if (tag == "Number") {
|
|
|
|
_verseNumber = new Text(lyrics->score());
|
2018-08-27 22:57:15 +02:00
|
|
|
readText206(e, _verseNumber, lyrics);
|
2018-06-19 13:39:20 +02:00
|
|
|
_verseNumber->setParent(lyrics);
|
|
|
|
}
|
2018-07-19 17:12:45 +02:00
|
|
|
else if (tag == "style")
|
|
|
|
e.readElementText(); // ignore style
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!lyrics->readProperties(e))
|
2018-06-19 13:39:20 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if any endTick, make it relative to current tick
|
|
|
|
if (iEndTick)
|
|
|
|
lyrics->setTicks(iEndTick - e.tick());
|
|
|
|
if (_verseNumber) {
|
|
|
|
// TODO: add text to main text
|
|
|
|
delete _verseNumber;
|
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
lyrics->setAutoplace(true);
|
|
|
|
lyrics->setOffset(QPointF());
|
2018-10-18 11:53:01 +02:00
|
|
|
//TODO-offset lyrics->setOffset(QPointF());
|
2018-06-19 13:39:20 +02:00
|
|
|
}
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readDurationProperties206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool readDurationProperties206(XmlReader& e, DurationElement* de)
|
|
|
|
{
|
|
|
|
if (e.name() == "Tuplet") {
|
|
|
|
int i = e.readInt();
|
|
|
|
Tuplet* t = e.findTuplet(i);
|
|
|
|
if (!t) {
|
|
|
|
qDebug("readDurationProperties206(): Tuplet id %d not found", i);
|
|
|
|
t = de->score()->searchTuplet(e, i);
|
|
|
|
if (t) {
|
|
|
|
qDebug(" ...found outside measure, input file corrupted?");
|
|
|
|
e.addTuplet(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (t) {
|
|
|
|
de->setTuplet(t);
|
|
|
|
if (!de->score()->undoStack()->active()) // HACK, also added in Undo::AddElement()
|
|
|
|
t->add(de);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (de->Element::readProperties(e))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readTupletProperties206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool readTupletProperties206(XmlReader& e, Tuplet* de)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (de->readStyledProperty(e, tag))
|
|
|
|
;
|
|
|
|
else if (tag == "normalNotes")
|
|
|
|
de->setProperty(Pid::NORMAL_NOTES, e.readInt());
|
|
|
|
else if (tag == "actualNotes")
|
|
|
|
de->setProperty(Pid::ACTUAL_NOTES, e.readInt());
|
|
|
|
else if (tag == "p1")
|
|
|
|
de->setProperty(Pid::P1, e.readPoint() * de->score()->spatium());
|
|
|
|
else if (tag == "p2")
|
|
|
|
de->setProperty(Pid::P2, e.readPoint() * de->score()->spatium());
|
|
|
|
else if (tag == "baseNote")
|
|
|
|
de->setBaseLen(TDuration(e.readElementText()));
|
|
|
|
else if (tag == "Number") {
|
|
|
|
Text* _number = new Text(de->score());
|
|
|
|
de->setNumber(_number);
|
|
|
|
_number->setComposition(true);
|
|
|
|
_number->setParent(de);
|
|
|
|
// _number->setSubStyleId(SubStyleId::TUPLET);
|
|
|
|
// initSubStyle(SubStyleId::TUPLET); // hack: initialize number
|
2018-11-26 21:09:20 +01:00
|
|
|
for (auto p : { Pid::FONT_FACE, Pid::FONT_SIZE, Pid::FONT_STYLE, Pid::ALIGN })
|
2018-08-27 22:57:15 +02:00
|
|
|
_number->resetProperty(p);
|
|
|
|
readText206(e, _number, de);
|
|
|
|
_number->setVisible(de->visible()); //?? override saved property
|
|
|
|
_number->setTrack(de->track());
|
|
|
|
// move property flags from _number
|
2018-11-26 21:09:20 +01:00
|
|
|
for (auto p : { Pid::FONT_FACE, Pid::FONT_SIZE, Pid::FONT_STYLE, Pid::ALIGN })
|
2018-08-27 22:57:15 +02:00
|
|
|
de->setPropertyFlags(p, _number->propertyFlags(p));
|
|
|
|
}
|
|
|
|
else if (!readDurationProperties206(e, de))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readChordRestProperties206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool readChordRestProperties206(XmlReader& e, ChordRest* ch)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "durationType") {
|
|
|
|
ch->setDurationType(e.readElementText());
|
|
|
|
if (ch->actualDurationType().type() != TDuration::DurationType::V_MEASURE) {
|
|
|
|
if (ch->score()->mscVersion() < 112 && (ch->type() == ElementType::REST) &&
|
|
|
|
// for backward compatibility, convert V_WHOLE rests to V_MEASURE
|
|
|
|
// if long enough to fill a measure.
|
|
|
|
// OTOH, freshly created (un-initialized) rests have numerator == 0 (< 4/4)
|
|
|
|
// (see Fraction() constructor in fraction.h; this happens for instance
|
|
|
|
// when pasting selection from clipboard): they should not be converted
|
|
|
|
ch->duration().numerator() != 0 &&
|
|
|
|
// rest durations are initialized to full measure duration when
|
|
|
|
// created upon reading the <Rest> tag (see Measure::read() )
|
|
|
|
// so a V_WHOLE rest in a measure of 4/4 or less => V_MEASURE
|
|
|
|
(ch->actualDurationType()==TDuration::DurationType::V_WHOLE && ch->duration() <= Fraction(4, 4)) ) {
|
|
|
|
// old pre 2.0 scores: convert
|
|
|
|
ch->setDurationType(TDuration::DurationType::V_MEASURE);
|
|
|
|
}
|
|
|
|
else // not from old score: set duration fraction from duration type
|
|
|
|
ch->setDuration(ch->actualDurationType().fraction());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (ch->score()->mscVersion() <= 114) {
|
|
|
|
SigEvent event = ch->score()->sigmap()->timesig(e.tick());
|
|
|
|
ch->setDuration(event.timesig());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "BeamMode") {
|
|
|
|
QString val(e.readElementText());
|
|
|
|
Beam::Mode bm = Beam::Mode::AUTO;
|
|
|
|
if (val == "auto")
|
|
|
|
bm = Beam::Mode::AUTO;
|
|
|
|
else if (val == "begin")
|
|
|
|
bm = Beam::Mode::BEGIN;
|
|
|
|
else if (val == "mid")
|
|
|
|
bm = Beam::Mode::MID;
|
|
|
|
else if (val == "end")
|
|
|
|
bm = Beam::Mode::END;
|
|
|
|
else if (val == "no")
|
|
|
|
bm = Beam::Mode::NONE;
|
|
|
|
else if (val == "begin32")
|
|
|
|
bm = Beam::Mode::BEGIN32;
|
|
|
|
else if (val == "begin64")
|
|
|
|
bm = Beam::Mode::BEGIN64;
|
|
|
|
else
|
|
|
|
bm = Beam::Mode(val.toInt());
|
|
|
|
ch->setBeamMode(bm);
|
|
|
|
}
|
|
|
|
else if (tag == "Articulation") {
|
2018-09-25 17:13:09 +02:00
|
|
|
Element* el = readArticulation(ch, e);
|
|
|
|
if (el->isFermata())
|
|
|
|
ch->segment()->add(el);
|
|
|
|
else
|
|
|
|
ch->add(el);
|
2018-08-27 22:57:15 +02:00
|
|
|
}
|
|
|
|
else if (tag == "leadingSpace" || tag == "trailingSpace") {
|
|
|
|
qDebug("ChordRest: %s obsolete", tag.toLocal8Bit().data());
|
|
|
|
e.skipCurrentElement();
|
|
|
|
}
|
|
|
|
else if (tag == "Beam") {
|
|
|
|
int id = e.readInt();
|
|
|
|
Beam* beam = e.findBeam(id);
|
|
|
|
if (beam)
|
|
|
|
beam->add(ch); // also calls ch->setBeam(beam)
|
|
|
|
else
|
|
|
|
qDebug("Beam id %d not found", id);
|
|
|
|
}
|
|
|
|
else if (tag == "small")
|
|
|
|
ch->setSmall(e.readInt());
|
|
|
|
else if (tag == "duration")
|
|
|
|
ch->setDuration(e.readFraction());
|
|
|
|
else if (tag == "ticklen") { // obsolete (version < 1.12)
|
|
|
|
int mticks = ch->score()->sigmap()->timesig(e.tick()).timesig().ticks();
|
|
|
|
int i = e.readInt();
|
|
|
|
if (i == 0)
|
|
|
|
i = mticks;
|
|
|
|
if ((ch->type() == ElementType::REST) && (mticks == i)) {
|
|
|
|
ch->setDurationType(TDuration::DurationType::V_MEASURE);
|
|
|
|
ch->setDuration(Fraction::fromTicks(i));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Fraction f = Fraction::fromTicks(i);
|
|
|
|
ch->setDuration(f);
|
|
|
|
ch->setDurationType(TDuration(f));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "dots")
|
|
|
|
ch->setDots(e.readInt());
|
|
|
|
else if (tag == "move")
|
|
|
|
ch->setStaffMove(e.readInt());
|
|
|
|
else if (tag == "Slur") {
|
|
|
|
int id = e.intAttribute("id");
|
|
|
|
if (id == 0)
|
|
|
|
id = e.intAttribute("number"); // obsolete
|
|
|
|
Spanner* spanner = e.findSpanner(id);
|
|
|
|
QString atype(e.attribute("type"));
|
|
|
|
|
|
|
|
if (!spanner) {
|
|
|
|
if (atype == "stop") {
|
|
|
|
SpannerValues sv;
|
|
|
|
sv.spannerId = id;
|
|
|
|
sv.track2 = ch->track();
|
|
|
|
sv.tick2 = e.tick();
|
|
|
|
e.addSpannerValues(sv);
|
|
|
|
}
|
|
|
|
else if (atype == "start")
|
|
|
|
qDebug("spanner: start without spanner");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (atype == "start") {
|
|
|
|
if (spanner->ticks() > 0 && spanner->tick() == -1) // stop has been read first
|
|
|
|
spanner->setTicks(spanner->ticks() - e.tick() - 1);
|
|
|
|
spanner->setTick(e.tick());
|
|
|
|
spanner->setTrack(ch->track());
|
|
|
|
if (spanner->type() == ElementType::SLUR)
|
|
|
|
spanner->setStartElement(ch);
|
|
|
|
if (e.pasteMode()) {
|
2018-09-25 15:55:34 +02:00
|
|
|
for (ScoreElement* el : spanner->linkList()) {
|
|
|
|
if (el == spanner)
|
2018-08-27 22:57:15 +02:00
|
|
|
continue;
|
2018-09-25 15:55:34 +02:00
|
|
|
Spanner* ls = static_cast<Spanner*>(el);
|
2018-08-27 22:57:15 +02:00
|
|
|
ls->setTick(spanner->tick());
|
|
|
|
for (ScoreElement* ee : ch->linkList()) {
|
|
|
|
ChordRest* cr = toChordRest(ee);
|
|
|
|
if (cr->score() == ee->score() && cr->staffIdx() == ls->staffIdx()) {
|
|
|
|
ls->setTrack(cr->track());
|
|
|
|
if (ls->type() == ElementType::SLUR)
|
|
|
|
ls->setStartElement(cr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (atype == "stop") {
|
|
|
|
spanner->setTick2(e.tick());
|
|
|
|
spanner->setTrack2(ch->track());
|
|
|
|
if (spanner->isSlur())
|
|
|
|
spanner->setEndElement(ch);
|
|
|
|
ChordRest* start = toChordRest(spanner->startElement());
|
|
|
|
if (start)
|
|
|
|
spanner->setTrack(start->track());
|
|
|
|
if (e.pasteMode()) {
|
2018-09-25 15:55:34 +02:00
|
|
|
for (ScoreElement* el : spanner->linkList()) {
|
|
|
|
if (el == spanner)
|
2018-08-27 22:57:15 +02:00
|
|
|
continue;
|
2018-09-25 15:55:34 +02:00
|
|
|
Spanner* ls = static_cast<Spanner*>(el);
|
2018-08-27 22:57:15 +02:00
|
|
|
ls->setTick2(spanner->tick2());
|
|
|
|
for (ScoreElement* ee : ch->linkList()) {
|
|
|
|
ChordRest* cr = toChordRest(ee);
|
|
|
|
if (cr->score() == ee->score() && cr->staffIdx() == ls->staffIdx()) {
|
|
|
|
ls->setTrack2(cr->track());
|
|
|
|
if (ls->type() == ElementType::SLUR)
|
|
|
|
ls->setEndElement(cr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2018-09-02 15:17:11 +02:00
|
|
|
qDebug("readChordRestProperties206(): unknown Slur type <%s>", qPrintable(atype));
|
2018-08-27 22:57:15 +02:00
|
|
|
}
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "Lyrics") {
|
|
|
|
Lyrics* l = new Lyrics(ch->score());
|
|
|
|
l->setTrack(e.track());
|
|
|
|
readLyrics(l, e);
|
|
|
|
ch->add(l);
|
|
|
|
}
|
|
|
|
else if (tag == "pos") {
|
|
|
|
QPointF pt = e.readPoint();
|
2018-10-18 11:53:01 +02:00
|
|
|
ch->setOffset(pt * ch->spatium());
|
2018-08-27 22:57:15 +02:00
|
|
|
}
|
|
|
|
else if (!readDurationProperties206(e, ch))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readChordProperties206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool readChordProperties206(XmlReader& e, Chord* ch)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "Note") {
|
|
|
|
Note* note = new Note(ch->score());
|
|
|
|
// the note needs to know the properties of the track it belongs to
|
|
|
|
note->setTrack(ch->track());
|
|
|
|
note->setChord(ch);
|
|
|
|
readNote(note, e);
|
|
|
|
ch->add(note);
|
|
|
|
}
|
|
|
|
else if (readChordRestProperties206(e, ch))
|
|
|
|
;
|
|
|
|
else if (tag == "Stem") {
|
|
|
|
Stem* s = new Stem(ch->score());
|
|
|
|
s->read(e);
|
|
|
|
ch->add(s);
|
|
|
|
}
|
|
|
|
else if (tag == "Hook") {
|
|
|
|
Hook* hook = new Hook(ch->score());
|
|
|
|
hook->read(e);
|
|
|
|
ch->add(hook);
|
|
|
|
}
|
|
|
|
else if (tag == "appoggiatura") {
|
|
|
|
ch->setNoteType(NoteType::APPOGGIATURA);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "acciaccatura") {
|
|
|
|
ch->setNoteType(NoteType::ACCIACCATURA);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace4") {
|
|
|
|
ch->setNoteType(NoteType::GRACE4);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace16") {
|
|
|
|
ch->setNoteType(NoteType::GRACE16);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace32") {
|
|
|
|
ch->setNoteType(NoteType::GRACE32);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace8after") {
|
|
|
|
ch->setNoteType(NoteType::GRACE8_AFTER);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace16after") {
|
|
|
|
ch->setNoteType(NoteType::GRACE16_AFTER);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "grace32after") {
|
|
|
|
ch->setNoteType(NoteType::GRACE32_AFTER);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "StemSlash") {
|
|
|
|
StemSlash* ss = new StemSlash(ch->score());
|
|
|
|
ss->read(e);
|
|
|
|
ch->add(ss);
|
|
|
|
}
|
|
|
|
else if (ch->readProperty(tag, e, Pid::STEM_DIRECTION))
|
|
|
|
;
|
|
|
|
else if (tag == "noStem")
|
|
|
|
ch->setNoStem(e.readInt());
|
|
|
|
else if (tag == "Arpeggio") {
|
|
|
|
Arpeggio* arpeggio = new Arpeggio(ch->score());
|
|
|
|
arpeggio->setTrack(ch->track());
|
|
|
|
arpeggio->read(e);
|
|
|
|
arpeggio->setParent(ch);
|
|
|
|
ch->add(arpeggio);
|
|
|
|
}
|
|
|
|
// old glissando format, chord-to-chord, attached to its final chord
|
|
|
|
else if (tag == "Glissando") {
|
|
|
|
// the measure we are reading is not inserted in the score yet
|
|
|
|
// as well as, possibly, the glissando intended initial chord;
|
|
|
|
// then we cannot fully link the glissando right now;
|
|
|
|
// temporarily attach the glissando to its final note as a back spanner;
|
|
|
|
// after the whole score is read, Score::connectTies() will look for
|
|
|
|
// the suitable initial note
|
|
|
|
Note* finalNote = ch->upNote();
|
|
|
|
Glissando* gliss = new Glissando(ch->score());
|
|
|
|
gliss->read(e);
|
|
|
|
gliss->setAnchor(Spanner::Anchor::NOTE);
|
|
|
|
gliss->setStartElement(nullptr);
|
|
|
|
gliss->setEndElement(nullptr);
|
|
|
|
// in TAB, use straight line with no text
|
|
|
|
if (ch->score()->staff(e.track() >> 2)->isTabStaff(ch->tick())) {
|
|
|
|
gliss->setGlissandoType(GlissandoType::STRAIGHT);
|
|
|
|
gliss->setShowText(false);
|
|
|
|
}
|
|
|
|
finalNote->addSpannerBack(gliss);
|
|
|
|
}
|
|
|
|
else if (tag == "Tremolo") {
|
|
|
|
Tremolo* tremolo = new Tremolo(ch->score());
|
|
|
|
tremolo->setTrack(ch->track());
|
|
|
|
tremolo->read(e);
|
|
|
|
tremolo->setParent(ch);
|
|
|
|
ch->setTremolo(tremolo);
|
|
|
|
}
|
|
|
|
else if (tag == "tickOffset") // obsolete
|
|
|
|
;
|
|
|
|
else if (tag == "ChordLine") {
|
|
|
|
ChordLine* cl = new ChordLine(ch->score());
|
|
|
|
cl->read(e);
|
|
|
|
ch->add(cl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-25 17:13:09 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// convertDoubleArticulations
|
|
|
|
// Replace double articulations with proper SMuFL
|
|
|
|
// symbols which were not available for use prior to 3.0
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-10-30 17:10:11 +01:00
|
|
|
static void convertDoubleArticulations(Chord* chord, XmlReader& e)
|
2018-09-25 17:13:09 +02:00
|
|
|
{
|
|
|
|
std::vector<Articulation*> pairableArticulations;
|
|
|
|
for (Articulation* a : chord->articulations()) {
|
|
|
|
if (a->isStaccato() || a->isTenuto()
|
|
|
|
|| a->isAccent() || a->isMarcato()) {
|
|
|
|
pairableArticulations.push_back(a);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (pairableArticulations.size() != 2)
|
|
|
|
// Do not replace triple articulation if this happens
|
|
|
|
return;
|
|
|
|
|
|
|
|
SymId newSymId = SymId::noSym;
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
if (newSymId != SymId::noSym)
|
|
|
|
break;
|
|
|
|
Articulation* ai = pairableArticulations[i];
|
|
|
|
Articulation* aj = pairableArticulations[(i == 0) ? 1 : 0];
|
|
|
|
if (ai->isStaccato()) {
|
|
|
|
if (aj->isAccent())
|
|
|
|
newSymId = SymId::articAccentStaccatoAbove;
|
|
|
|
else if (aj->isMarcato())
|
|
|
|
newSymId = SymId::articMarcatoStaccatoAbove;
|
|
|
|
else if (aj->isTenuto())
|
|
|
|
newSymId = SymId::articTenutoStaccatoAbove;
|
|
|
|
}
|
|
|
|
else if (ai->isTenuto()) {
|
|
|
|
if (aj->isAccent())
|
|
|
|
newSymId = SymId::articTenutoAccentAbove;
|
|
|
|
else if (aj->isMarcato())
|
|
|
|
newSymId = SymId::articMarcatoTenutoAbove;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newSymId != SymId::noSym) {
|
|
|
|
// We reuse old articulation and change symbol ID
|
|
|
|
// rather than constructing a new articulation
|
|
|
|
// in order to preserve its other properties.
|
|
|
|
Articulation* newArtic = pairableArticulations[0];
|
|
|
|
for (Articulation* a : pairableArticulations) {
|
|
|
|
chord->remove(a);
|
2018-10-30 17:10:11 +01:00
|
|
|
if (a != newArtic) {
|
|
|
|
if (LinkedElements* link = a->links())
|
|
|
|
e.linkIds().remove(link->lid());
|
2018-09-25 17:13:09 +02:00
|
|
|
delete a;
|
2018-10-30 17:10:11 +01:00
|
|
|
}
|
2018-09-25 17:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ArticulationAnchor anchor = newArtic->anchor();
|
|
|
|
newArtic->setSymId(newSymId);
|
|
|
|
newArtic->setAnchor(anchor);
|
|
|
|
chord->add(newArtic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-28 17:49:08 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readChord
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readChord(Chord* chord, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Note") {
|
|
|
|
Note* note = new Note(chord->score());
|
|
|
|
// the note needs to know the properties of the track it belongs to
|
|
|
|
note->setTrack(chord->track());
|
|
|
|
note->setChord(chord);
|
|
|
|
readNote(note, e);
|
|
|
|
chord->add(note);
|
|
|
|
}
|
2018-05-08 10:51:24 +02:00
|
|
|
else if (tag == "Stem") {
|
|
|
|
Stem* stem = new Stem(chord->score());
|
|
|
|
while (e.readNextStartElement()) {
|
2018-08-17 15:06:15 +02:00
|
|
|
const QStringRef& t(e.name());
|
|
|
|
if (t == "subtype") // obsolete
|
2018-05-08 10:51:24 +02:00
|
|
|
e.skipCurrentElement();
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!stem->readProperties(e))
|
2018-05-08 10:51:24 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
chord->add(stem);
|
|
|
|
}
|
2018-06-19 13:39:20 +02:00
|
|
|
else if (tag == "Lyrics") {
|
|
|
|
Lyrics* lyrics = new Lyrics(chord->score());
|
|
|
|
lyrics->setTrack(e.track());
|
|
|
|
readLyrics(lyrics, e);
|
|
|
|
chord->add(lyrics);
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (readChordProperties206(e, chord))
|
2018-03-28 17:49:08 +02:00
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
2018-10-30 17:10:11 +01:00
|
|
|
convertDoubleArticulations(chord, e);
|
2018-03-28 17:49:08 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 13:39:20 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readRest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readRest(Rest* rest, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
2018-09-25 17:13:09 +02:00
|
|
|
if (!readChordRestProperties206(e, rest))
|
2018-06-19 13:39:20 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-07 22:45:12 +02:00
|
|
|
//---------------------------------------------------------
|
2017-02-09 11:57:10 +01:00
|
|
|
// readTextLineProperties
|
2016-10-07 22:45:12 +02:00
|
|
|
//---------------------------------------------------------
|
2017-02-09 11:57:10 +01:00
|
|
|
|
|
|
|
static bool readTextLineProperties(XmlReader& e, TextLineBase* tl)
|
2016-10-07 22:45:12 +02:00
|
|
|
{
|
2017-02-09 11:57:10 +01:00
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "beginText") {
|
|
|
|
Text* text = new Text(tl->score());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, text, tl);
|
2017-02-09 11:57:10 +01:00
|
|
|
tl->setBeginText(text->xmlText());
|
|
|
|
delete text;
|
|
|
|
}
|
|
|
|
else if (tag == "continueText") {
|
|
|
|
Text* text = new Text(tl->score());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, text, tl);
|
2017-02-09 11:57:10 +01:00
|
|
|
tl->setContinueText(text->xmlText());
|
|
|
|
delete text;
|
|
|
|
}
|
|
|
|
else if (tag == "endText") {
|
|
|
|
Text* text = new Text(tl->score());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, text, tl);
|
2017-02-09 11:57:10 +01:00
|
|
|
tl->setEndText(text->xmlText());
|
|
|
|
delete text;
|
|
|
|
}
|
|
|
|
else if (tag == "beginHook")
|
|
|
|
tl->setBeginHookType(e.readBool() ? HookType::HOOK_90 : HookType::NONE);
|
|
|
|
else if (tag == "endHook")
|
|
|
|
tl->setEndHookType(e.readBool() ? HookType::HOOK_90 : HookType::NONE);
|
2017-10-20 12:43:36 +02:00
|
|
|
else if (tag == "beginHookType")
|
|
|
|
tl->setBeginHookType(e.readInt() == 0 ? HookType::HOOK_90 : HookType::HOOK_45);
|
|
|
|
else if (tag == "endHookType")
|
|
|
|
tl->setEndHookType(e.readInt() == 0 ? HookType::HOOK_90 : HookType::HOOK_45);
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (tl->readProperties(e))
|
2017-02-09 11:57:10 +01:00
|
|
|
return true;
|
|
|
|
return true;
|
2016-10-07 22:45:12 +02:00
|
|
|
}
|
2017-01-16 22:16:10 +01:00
|
|
|
|
2017-02-09 11:57:10 +01:00
|
|
|
//---------------------------------------------------------
|
2018-05-14 10:07:46 +02:00
|
|
|
// readVolta206
|
2017-02-09 11:57:10 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-05-14 10:07:46 +02:00
|
|
|
static void readVolta206(XmlReader& e, Volta* volta)
|
2017-02-09 11:57:10 +01:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "endings") {
|
|
|
|
QString s = e.readElementText();
|
|
|
|
QStringList sl = s.split(",", QString::SkipEmptyParts);
|
|
|
|
volta->endings().clear();
|
|
|
|
for (const QString& l : sl) {
|
|
|
|
int i = l.simplified().toInt();
|
|
|
|
volta->endings().append(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "lineWidth") {
|
2018-05-07 19:05:34 +02:00
|
|
|
volta->setLineWidth(e.readDouble() * volta->spatium());
|
2017-02-09 11:57:10 +01:00
|
|
|
// TODO lineWidthStyle = PropertyStyle::UNSTYLED;
|
|
|
|
}
|
|
|
|
else if (!readTextLineProperties(e, volta))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readPedal
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readPedal(XmlReader& e, Pedal* pedal)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (!readTextLineProperties(e, pedal))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readOttava
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readOttava(XmlReader& e, Ottava* ottava)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "subtype") {
|
|
|
|
QString s = e.readElementText();
|
|
|
|
bool ok;
|
|
|
|
int idx = s.toInt(&ok);
|
|
|
|
if (!ok) {
|
2017-03-08 14:18:34 +01:00
|
|
|
idx = 0; // OttavaType::OTTAVA_8VA;
|
2017-02-09 11:57:10 +01:00
|
|
|
int i = 0;
|
|
|
|
for (auto p : { "8va","8vb","15ma","15mb","22ma","22mb" } ) {
|
|
|
|
if (p == s) {
|
|
|
|
idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2017-03-08 14:18:34 +01:00
|
|
|
ottava->setOttavaType(OttavaType(idx));
|
2017-02-09 11:57:10 +01:00
|
|
|
}
|
|
|
|
else if (tag == "numbersOnly") {
|
|
|
|
ottava->setNumbersOnly(e.readBool());
|
|
|
|
//TODO numbersOnlyStyle = PropertyFlags::UNSTYLED;
|
|
|
|
}
|
|
|
|
else if (!readTextLineProperties(e, ottava))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-13 19:26:43 +01:00
|
|
|
//---------------------------------------------------------
|
2018-08-27 22:57:15 +02:00
|
|
|
// readHairpin206
|
2017-02-13 19:26:43 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
void readHairpin206(XmlReader& e, Hairpin* h)
|
2017-02-13 19:26:43 +01:00
|
|
|
{
|
2017-03-16 12:13:19 +01:00
|
|
|
bool useText = false;
|
2017-02-13 19:26:43 +01:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "subtype")
|
|
|
|
h->setHairpinType(HairpinType(e.readInt()));
|
|
|
|
else if (tag == "lineWidth") {
|
2018-05-07 19:05:34 +02:00
|
|
|
h->setLineWidth(e.readDouble() * h->spatium());
|
2017-02-13 19:26:43 +01:00
|
|
|
// lineWidthStyle = PropertyFlags::UNSTYLED;
|
|
|
|
}
|
|
|
|
else if (tag == "hairpinHeight") {
|
|
|
|
h->setHairpinHeight(Spatium(e.readDouble()));
|
|
|
|
// hairpinHeightStyle = PropertyFlags::UNSTYLED;
|
|
|
|
}
|
|
|
|
else if (tag == "hairpinContHeight") {
|
|
|
|
h->setHairpinContHeight(Spatium(e.readDouble()));
|
|
|
|
// hairpinContHeightStyle = PropertyFlags::UNSTYLED;
|
|
|
|
}
|
|
|
|
else if (tag == "hairpinCircledTip")
|
|
|
|
h->setHairpinCircledTip(e.readInt());
|
|
|
|
else if (tag == "veloChange")
|
|
|
|
h->setVeloChange(e.readInt());
|
|
|
|
else if (tag == "dynType")
|
|
|
|
h->setDynRange(Dynamic::Range(e.readInt()));
|
|
|
|
else if (tag == "useTextLine") { // < 206
|
|
|
|
e.readInt();
|
|
|
|
if (h->hairpinType() == HairpinType::CRESC_HAIRPIN)
|
|
|
|
h->setHairpinType(HairpinType::CRESC_LINE);
|
|
|
|
else if (h->hairpinType() == HairpinType::DECRESC_HAIRPIN)
|
|
|
|
h->setHairpinType(HairpinType::DECRESC_LINE);
|
2017-03-16 12:13:19 +01:00
|
|
|
useText = true;
|
2017-02-13 19:26:43 +01:00
|
|
|
}
|
|
|
|
else if (!readTextLineProperties(e, h))
|
|
|
|
e.unknown();
|
|
|
|
}
|
2017-03-16 12:13:19 +01:00
|
|
|
if (!useText) {
|
|
|
|
h->setBeginText("");
|
|
|
|
h->setContinueText("");
|
|
|
|
h->setEndText("");
|
|
|
|
}
|
2018-11-25 23:35:00 +01:00
|
|
|
h->eraseSpannerSegments();
|
2018-06-27 09:04:11 +02:00
|
|
|
#if 0
|
|
|
|
for (auto ss : h->spannerSegments()) {
|
2018-10-18 11:53:01 +02:00
|
|
|
ss->setOffset(QPointF());
|
2018-06-27 09:04:11 +02:00
|
|
|
ss->setUserOff2(QPointF());
|
|
|
|
}
|
|
|
|
#endif
|
2017-02-13 19:26:43 +01:00
|
|
|
}
|
|
|
|
|
2017-03-13 10:24:49 +01:00
|
|
|
//---------------------------------------------------------
|
2018-08-27 22:57:15 +02:00
|
|
|
// readTrill206
|
2017-03-13 10:24:49 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
void readTrill206(XmlReader& e, Trill* t)
|
2017-03-13 10:24:49 +01:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "subtype")
|
|
|
|
t->setTrillType(e.readElementText());
|
2017-10-27 14:03:40 +02:00
|
|
|
else if (tag == "Accidental") {
|
|
|
|
Accidental* _accidental = new Accidental(t->score());
|
2018-08-27 22:57:15 +02:00
|
|
|
readAccidental206(_accidental, e);
|
2017-10-27 14:03:40 +02:00
|
|
|
_accidental->setParent(t);
|
|
|
|
t->setAccidental(_accidental);
|
|
|
|
}
|
|
|
|
else if ( tag == "ornamentStyle")
|
2018-10-26 10:41:07 +02:00
|
|
|
t->readProperty(e, Pid::ORNAMENT_STYLE);
|
2017-10-27 14:03:40 +02:00
|
|
|
else if ( tag == "play")
|
|
|
|
t->setPlayArticulation(e.readBool());
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!t->SLine::readProperties(e))
|
2017-03-13 10:24:49 +01:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-09 11:57:10 +01:00
|
|
|
//---------------------------------------------------------
|
2018-05-14 10:07:46 +02:00
|
|
|
// readTextLine206
|
2017-02-09 11:57:10 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-05-14 10:07:46 +02:00
|
|
|
void readTextLine206(XmlReader& e, TextLineBase* tlb)
|
2017-02-09 11:57:10 +01:00
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (!readTextLineProperties(e, tlb))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
2016-10-07 22:45:12 +02:00
|
|
|
|
2018-01-16 13:38:17 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// setFermataPlacement
|
|
|
|
// set fermata placement from old ArticulationAnchor
|
|
|
|
// for backwards compatibility
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-01-22 16:50:52 +01:00
|
|
|
static void setFermataPlacement(Element* el, ArticulationAnchor anchor, Direction direction)
|
2018-01-16 13:38:17 +01:00
|
|
|
{
|
2018-01-22 16:50:52 +01:00
|
|
|
if (direction == Direction::UP)
|
|
|
|
el->setPlacement(Placement::ABOVE);
|
|
|
|
else if (direction == Direction::DOWN)
|
|
|
|
el->setPlacement(Placement::BELOW);
|
|
|
|
else {
|
|
|
|
switch (anchor) {
|
|
|
|
case ArticulationAnchor::TOP_STAFF:
|
|
|
|
case ArticulationAnchor::TOP_CHORD:
|
|
|
|
el->setPlacement(Placement::ABOVE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ArticulationAnchor::BOTTOM_STAFF:
|
|
|
|
case ArticulationAnchor::BOTTOM_CHORD:
|
|
|
|
el->setPlacement(Placement::BELOW);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ArticulationAnchor::CHORD:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2018-01-16 13:38:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-06 12:21:28 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readArticulation
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-01-16 13:38:17 +01:00
|
|
|
Element* readArticulation(ChordRest* cr, XmlReader& e)
|
2016-10-06 12:21:28 +02:00
|
|
|
{
|
2018-01-16 13:38:17 +01:00
|
|
|
Element* el = 0;
|
|
|
|
SymId sym = SymId::fermataAbove; // default -- backward compatibility (no type = ufermata in 1.2)
|
|
|
|
ArticulationAnchor anchor = ArticulationAnchor::TOP_STAFF;
|
|
|
|
Direction direction = Direction::AUTO;
|
|
|
|
|
2016-10-06 12:21:28 +02:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "subtype") {
|
|
|
|
QString s = e.readElementText();
|
|
|
|
if (s[0].isDigit()) {
|
|
|
|
int oldType = s.toInt();
|
2018-01-16 13:38:17 +01:00
|
|
|
sym = articulationNames[oldType].id;
|
2016-10-06 12:21:28 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-01-16 13:38:17 +01:00
|
|
|
sym = oldArticulationNames2SymId(s);
|
|
|
|
if (sym == SymId::noSym) {
|
2016-10-06 12:21:28 +02:00
|
|
|
struct {
|
|
|
|
const char* name;
|
|
|
|
bool up;
|
|
|
|
SymId id;
|
|
|
|
} al[] =
|
|
|
|
{
|
|
|
|
{ "fadein", true, SymId::guitarFadeIn },
|
|
|
|
{ "fadeout", true, SymId::guitarFadeOut },
|
|
|
|
{ "volumeswell", true, SymId::guitarVolumeSwell },
|
|
|
|
{ "wigglesawtooth", true, SymId::wiggleSawtooth },
|
|
|
|
{ "wigglesawtoothwide", true, SymId::wiggleSawtoothWide },
|
|
|
|
{ "wigglevibratolargefaster", true, SymId::wiggleVibratoLargeFaster },
|
|
|
|
{ "wigglevibratolargeslowest", true, SymId::wiggleVibratoLargeSlowest },
|
|
|
|
{ "umarcato", true, SymId::articMarcatoAbove },
|
|
|
|
{ "dmarcato", false, SymId::articMarcatoBelow },
|
|
|
|
{ "ufermata", true, SymId::fermataAbove },
|
|
|
|
{ "dfermata", false, SymId::fermataBelow },
|
|
|
|
{ "ushortfermata", true, SymId::fermataShortAbove },
|
|
|
|
{ "dshortfermata", false, SymId::fermataShortBelow },
|
|
|
|
{ "ulongfermata", true, SymId::fermataLongAbove },
|
|
|
|
{ "dlongfermata", false, SymId::fermataLongBelow },
|
|
|
|
{ "uverylongfermata", true, SymId::fermataVeryLongAbove },
|
|
|
|
{ "dverylongfermata", false, SymId::fermataVeryLongBelow },
|
|
|
|
|
|
|
|
// watch out, bug in 1.2 uportato and dportato are reversed
|
|
|
|
{ "dportato", true, SymId::articTenutoStaccatoAbove },
|
|
|
|
{ "uportato", false, SymId::articTenutoStaccatoBelow },
|
|
|
|
{ "ustaccatissimo", true, SymId::articStaccatissimoAbove },
|
|
|
|
{ "dstaccatissimo", false, SymId::articStaccatissimoBelow }
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
int n = sizeof(al) / sizeof(*al);
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
if (s == al[i].name) {
|
2018-01-16 13:38:17 +01:00
|
|
|
sym = al[i].id;
|
|
|
|
bool up = al[i].up;
|
|
|
|
direction = up ? Direction::UP : Direction::DOWN;
|
2016-10-06 12:21:28 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-01-16 13:38:17 +01:00
|
|
|
if (i == n) {
|
|
|
|
sym = Sym::name2id(s);
|
|
|
|
if (sym == SymId::noSym)
|
|
|
|
qDebug("Articulation: unknown type <%s>", qPrintable(s));
|
|
|
|
}
|
2016-10-06 12:21:28 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-16 13:38:17 +01:00
|
|
|
switch (sym) {
|
|
|
|
case SymId::fermataAbove:
|
|
|
|
case SymId::fermataBelow:
|
|
|
|
case SymId::fermataShortAbove:
|
|
|
|
case SymId::fermataShortBelow:
|
|
|
|
case SymId::fermataLongAbove:
|
|
|
|
case SymId::fermataLongBelow:
|
|
|
|
case SymId::fermataVeryLongAbove:
|
|
|
|
case SymId::fermataVeryLongBelow:
|
|
|
|
el = new Fermata(sym, cr->score());
|
2018-01-22 16:50:52 +01:00
|
|
|
setFermataPlacement(el, anchor, direction);
|
2018-01-16 13:38:17 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
el = new Articulation(sym, cr->score());
|
|
|
|
toArticulation(el)->setDirection(direction);
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else if (tag == "anchor") {
|
|
|
|
if (!el)
|
|
|
|
anchor = ArticulationAnchor(e.readInt());
|
|
|
|
else {
|
|
|
|
if (el->isFermata()) {
|
|
|
|
anchor = ArticulationAnchor(e.readInt());
|
2018-01-22 16:50:52 +01:00
|
|
|
setFermataPlacement(el, anchor, direction);
|
2018-01-16 13:38:17 +01:00
|
|
|
}
|
|
|
|
else
|
2018-08-27 22:57:15 +02:00
|
|
|
el->readProperties(e);
|
2018-01-16 13:38:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "direction") {
|
|
|
|
if (!el)
|
|
|
|
direction = toDirection(e.readElementText());
|
|
|
|
else {
|
|
|
|
if (!el->isFermata())
|
2018-08-27 22:57:15 +02:00
|
|
|
el->readProperties(e);
|
2018-01-16 13:38:17 +01:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 15:17:49 +02:00
|
|
|
else if (tag == "timeStretch") {
|
|
|
|
if (el && el->isFermata())
|
2018-10-18 11:53:01 +02:00
|
|
|
el->setProperty(Pid::TIME_STRETCH ,e.readDouble());
|
2018-09-05 15:17:49 +02:00
|
|
|
}
|
2018-01-16 13:38:17 +01:00
|
|
|
else {
|
|
|
|
if (!el) {
|
|
|
|
qDebug("not handled <%s>", qPrintable(tag.toString()));
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
if (!el || !el->readProperties(e))
|
2018-01-16 13:38:17 +01:00
|
|
|
e.unknown();
|
2016-10-06 12:21:28 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-01 21:35:37 +02:00
|
|
|
// Special case for "no type" = ufermata, with missing subtype tag
|
|
|
|
if (!el) {
|
|
|
|
el = new Fermata(sym, cr->score());
|
|
|
|
setFermataPlacement(el, anchor, direction);
|
|
|
|
}
|
2018-08-23 09:38:09 +02:00
|
|
|
el->setTrack(cr->track());
|
2018-01-16 13:38:17 +01:00
|
|
|
return el;
|
2016-10-06 12:21:28 +02:00
|
|
|
}
|
|
|
|
|
2018-08-27 22:57:15 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readSlurTieProperties
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool readSlurTieProperties(XmlReader& e, SlurTie* st)
|
|
|
|
{
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (st->readProperty(tag, e, Pid::SLUR_DIRECTION))
|
|
|
|
;
|
|
|
|
else if (tag == "lineType")
|
|
|
|
st->setLineType(e.readInt());
|
|
|
|
else if (tag == "SlurSegment") {
|
|
|
|
SlurTieSegment* s = st->newSlurTieSegment();
|
|
|
|
s->read(e);
|
|
|
|
st->add(s);
|
|
|
|
}
|
|
|
|
else if (!st->Element::readProperties(e))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readSlur206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void readSlur206(XmlReader& e, Slur* s)
|
|
|
|
{
|
|
|
|
s->setTrack(e.track()); // set staff
|
|
|
|
e.addSpanner(e.intAttribute("id"), s);
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "track2")
|
|
|
|
s->setTrack2(e.readInt());
|
|
|
|
else if (tag == "startTrack") // obsolete
|
|
|
|
s->setTrack(e.readInt());
|
|
|
|
else if (tag == "endTrack") // obsolete
|
|
|
|
e.readInt();
|
|
|
|
else if (!readSlurTieProperties(e, s))
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (s->track2() == -1)
|
|
|
|
s->setTrack2(s->track());
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readTie206
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void readTie206(XmlReader& e, Tie* t)
|
|
|
|
{
|
|
|
|
e.addSpanner(e.intAttribute("id"), t);
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
if (readSlurTieProperties(e, t))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (t->score()->mscVersion() <= 114 && t->spannerSegments().size() == 1) {
|
|
|
|
// ignore manual adjustments to single-segment ties in older scores
|
|
|
|
TieSegment* ss = t->frontSegment();
|
|
|
|
QPointF zeroP;
|
|
|
|
ss->ups(Grip::START).off = zeroP;
|
|
|
|
ss->ups(Grip::BEZIER1).off = zeroP;
|
|
|
|
ss->ups(Grip::BEZIER2).off = zeroP;
|
|
|
|
ss->ups(Grip::END).off = zeroP;
|
2018-10-18 11:53:01 +02:00
|
|
|
ss->setOffset(zeroP);
|
2018-08-27 22:57:15 +02:00
|
|
|
ss->setUserOff2(zeroP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-21 15:22:51 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readMeasure
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readMeasure(Measure* m, int staffIdx, XmlReader& e)
|
|
|
|
{
|
|
|
|
Segment* segment = 0;
|
|
|
|
qreal _spatium = m->spatium();
|
|
|
|
Score* score = m->score();
|
|
|
|
|
|
|
|
QList<Chord*> graceNotes;
|
|
|
|
e.tuplets().clear();
|
|
|
|
e.setTrack(staffIdx * VOICES);
|
|
|
|
|
2016-12-12 14:55:35 +01:00
|
|
|
m->createStaves(staffIdx);
|
2016-09-21 15:22:51 +02:00
|
|
|
|
|
|
|
// tick is obsolete
|
|
|
|
if (e.hasAttribute("tick"))
|
|
|
|
e.initTick(score->fileDivision(e.intAttribute("tick")));
|
|
|
|
|
|
|
|
bool irregular;
|
|
|
|
if (e.hasAttribute("len")) {
|
|
|
|
QStringList sl = e.attribute("len").split('/');
|
|
|
|
if (sl.size() == 2)
|
|
|
|
m->setLen(Fraction(sl[0].toInt(), sl[1].toInt()));
|
|
|
|
else
|
|
|
|
qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
|
|
|
|
irregular = true;
|
|
|
|
score->sigmap()->add(m->tick(), SigEvent(m->len(), m->timesig()));
|
|
|
|
score->sigmap()->add(m->endTick(), SigEvent(m->timesig()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
irregular = false;
|
|
|
|
|
|
|
|
Staff* staff = score->staff(staffIdx);
|
|
|
|
Fraction timeStretch(staff->timeStretch(m->tick()));
|
|
|
|
|
|
|
|
// keep track of tick of previous element
|
|
|
|
// this allows markings that need to apply to previous element to do so
|
|
|
|
// even though we may have already advanced to next tick position
|
|
|
|
int lastTick = e.tick();
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "move")
|
|
|
|
e.initTick(e.readFraction().ticks() + m->tick());
|
|
|
|
else if (tag == "tick") {
|
|
|
|
e.initTick(score->fileDivision(e.readInt()));
|
|
|
|
lastTick = e.tick();
|
|
|
|
}
|
|
|
|
else if (tag == "BarLine") {
|
2017-03-04 15:01:42 +01:00
|
|
|
BarLine* bl = new BarLine(score);
|
|
|
|
bl->setTrack(e.track());
|
|
|
|
while (e.readNextStartElement()) {
|
2018-08-17 15:06:15 +02:00
|
|
|
const QStringRef& t(e.name());
|
|
|
|
if (t == "subtype")
|
2017-03-04 15:01:42 +01:00
|
|
|
bl->setBarLineType(e.readElementText());
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "customSubtype") // obsolete
|
2017-03-04 15:01:42 +01:00
|
|
|
e.readInt();
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "span") {
|
2017-05-29 14:59:10 +02:00
|
|
|
//TODO bl->setSpanFrom(e.intAttribute("from", bl->spanFrom())); // obsolete
|
|
|
|
// bl->setSpanTo(e.intAttribute("to", bl->spanTo())); // obsolete
|
|
|
|
int span = e.readInt();
|
|
|
|
if (span)
|
|
|
|
span--;
|
|
|
|
bl->setSpanStaff(span);
|
2017-03-04 15:01:42 +01:00
|
|
|
}
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "spanFromOffset")
|
2017-03-04 15:01:42 +01:00
|
|
|
bl->setSpanFrom(e.readInt());
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "spanToOffset")
|
2017-03-04 15:01:42 +01:00
|
|
|
bl->setSpanTo(e.readInt());
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "Articulation") {
|
2017-03-04 15:01:42 +01:00
|
|
|
Articulation* a = new Articulation(score);
|
2018-08-27 22:57:15 +02:00
|
|
|
a->read(e);
|
2017-03-04 15:01:42 +01:00
|
|
|
bl->add(a);
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!bl->Element::readProperties(e))
|
2017-03-04 15:01:42 +01:00
|
|
|
e.unknown();
|
|
|
|
}
|
2016-09-21 15:22:51 +02:00
|
|
|
//
|
|
|
|
// StartRepeatBarLine: always at the beginning tick of a measure, always BarLineType::START_REPEAT
|
|
|
|
// BarLine: in the middle of a measure, has no semantic
|
|
|
|
// EndBarLine: at the end tick of a measure
|
|
|
|
// BeginBarLine: first segment of a measure
|
|
|
|
|
2017-03-08 13:12:26 +01:00
|
|
|
SegmentType st;
|
2016-09-21 15:22:51 +02:00
|
|
|
if ((e.tick() != m->tick()) && (e.tick() != m->endTick()))
|
2017-03-08 13:12:26 +01:00
|
|
|
st = SegmentType::BarLine;
|
2017-03-04 15:01:42 +01:00
|
|
|
else if (bl->barLineType() == BarLineType::START_REPEAT && e.tick() == m->tick())
|
2017-03-08 13:12:26 +01:00
|
|
|
st = SegmentType::StartRepeatBarLine;
|
2016-09-21 15:22:51 +02:00
|
|
|
else if (e.tick() == m->tick() && segment == 0)
|
2017-03-08 13:12:26 +01:00
|
|
|
st = SegmentType::BeginBarLine;
|
2016-09-21 15:22:51 +02:00
|
|
|
else
|
2017-03-08 13:12:26 +01:00
|
|
|
st = SegmentType::EndBarLine;
|
2016-09-21 15:22:51 +02:00
|
|
|
segment = m->getSegment(st, e.tick());
|
2017-03-04 15:01:42 +01:00
|
|
|
segment->add(bl);
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Chord") {
|
|
|
|
Chord* chord = new Chord(score);
|
|
|
|
chord->setTrack(e.track());
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2018-01-16 13:38:17 +01:00
|
|
|
chord->setParent(segment);
|
|
|
|
readChord(chord, e);
|
2016-09-22 12:02:27 +02:00
|
|
|
if (chord->noteType() != NoteType::NORMAL)
|
2016-09-21 15:22:51 +02:00
|
|
|
graceNotes.push_back(chord);
|
|
|
|
else {
|
|
|
|
segment->add(chord);
|
|
|
|
for (int i = 0; i < graceNotes.size(); ++i) {
|
|
|
|
Chord* gc = graceNotes[i];
|
|
|
|
gc->setGraceIndex(i);
|
|
|
|
chord->add(gc);
|
|
|
|
}
|
|
|
|
graceNotes.clear();
|
|
|
|
int crticks = chord->actualTicks();
|
2016-09-22 12:02:27 +02:00
|
|
|
lastTick = e.tick();
|
2016-09-21 15:22:51 +02:00
|
|
|
e.incTick(crticks);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "Rest") {
|
|
|
|
Rest* rest = new Rest(score);
|
|
|
|
rest->setDurationType(TDuration::DurationType::V_MEASURE);
|
|
|
|
rest->setDuration(m->timesig()/timeStretch);
|
|
|
|
rest->setTrack(e.track());
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2018-04-01 21:35:37 +02:00
|
|
|
rest->setParent(segment);
|
|
|
|
readRest(rest, e);
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(rest);
|
|
|
|
|
|
|
|
if (!rest->duration().isValid()) // hack
|
|
|
|
rest->setDuration(m->timesig()/timeStretch);
|
|
|
|
|
|
|
|
lastTick = e.tick();
|
|
|
|
e.incTick(rest->actualTicks());
|
|
|
|
}
|
|
|
|
else if (tag == "Breath") {
|
|
|
|
Breath* breath = new Breath(score);
|
|
|
|
breath->setTrack(e.track());
|
|
|
|
int tick = e.tick();
|
2018-08-27 22:57:15 +02:00
|
|
|
breath->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
// older scores placed the breath segment right after the chord to which it applies
|
|
|
|
// rather than before the next chordrest segment with an element for the staff
|
|
|
|
// result would be layout too far left if there are other segments due to notes in other staves
|
|
|
|
// we need to find tick of chord to which this applies, and add its duration
|
|
|
|
int prevTick;
|
|
|
|
if (e.tick() < tick)
|
|
|
|
prevTick = e.tick(); // use our own tick if we explicitly reset to earlier position
|
|
|
|
else
|
|
|
|
prevTick = lastTick; // otherwise use tick of previous tick/chord/rest tag
|
|
|
|
// find segment
|
2017-03-08 13:12:26 +01:00
|
|
|
Segment* prev = m->findSegment(SegmentType::ChordRest, prevTick);
|
2016-09-21 15:22:51 +02:00
|
|
|
if (prev) {
|
|
|
|
// find chordrest
|
2017-12-20 16:49:30 +01:00
|
|
|
ChordRest* lastCR = toChordRest(prev->element(e.track()));
|
2016-09-21 15:22:51 +02:00
|
|
|
if (lastCR)
|
|
|
|
tick = prevTick + lastCR->actualTicks();
|
|
|
|
}
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::Breath, tick);
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(breath);
|
|
|
|
}
|
|
|
|
else if (tag == "endSpanner") {
|
|
|
|
int id = e.attribute("id").toInt();
|
|
|
|
Spanner* spanner = e.findSpanner(id);
|
|
|
|
if (spanner) {
|
|
|
|
spanner->setTicks(e.tick() - spanner->tick());
|
|
|
|
// if (spanner->track2() == -1)
|
|
|
|
// the absence of a track tag [?] means the
|
|
|
|
// track is the same as the beginning of the slur
|
|
|
|
if (spanner->track2() == -1)
|
|
|
|
spanner->setTrack2(spanner->track() ? spanner->track() : e.track());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// remember "endSpanner" values
|
|
|
|
SpannerValues sv;
|
|
|
|
sv.spannerId = id;
|
|
|
|
sv.track2 = e.track();
|
|
|
|
sv.tick2 = e.tick();
|
|
|
|
e.addSpannerValues(sv);
|
|
|
|
}
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "Slur") {
|
|
|
|
Slur *sl = new Slur(score);
|
|
|
|
sl->setTick(e.tick());
|
2018-08-27 22:57:15 +02:00
|
|
|
readSlur206(e, sl);
|
2016-09-21 15:22:51 +02:00
|
|
|
//
|
|
|
|
// check if we already saw "endSpanner"
|
|
|
|
//
|
|
|
|
int id = e.spannerId(sl);
|
|
|
|
const SpannerValues* sv = e.spannerValues(id);
|
|
|
|
if (sv) {
|
|
|
|
sl->setTick2(sv->tick2);
|
|
|
|
sl->setTrack2(sv->track2);
|
|
|
|
}
|
|
|
|
score->addSpanner(sl);
|
|
|
|
}
|
|
|
|
else if (tag == "HairPin"
|
|
|
|
|| tag == "Pedal"
|
|
|
|
|| tag == "Ottava"
|
|
|
|
|| tag == "Trill"
|
|
|
|
|| tag == "TextLine"
|
|
|
|
|| tag == "Volta") {
|
2017-12-20 16:49:30 +01:00
|
|
|
Spanner* sp = toSpanner(Element::name2Element(tag, score));
|
2016-09-21 15:22:51 +02:00
|
|
|
sp->setTrack(e.track());
|
|
|
|
sp->setTick(e.tick());
|
2018-11-25 23:35:00 +01:00
|
|
|
sp->eraseSpannerSegments();
|
2017-02-09 11:57:10 +01:00
|
|
|
e.addSpanner(e.intAttribute("id", -1), sp);
|
|
|
|
|
|
|
|
if (tag == "Volta")
|
2018-05-14 10:07:46 +02:00
|
|
|
readVolta206(e, toVolta(sp));
|
2017-02-09 11:57:10 +01:00
|
|
|
else if (tag == "Pedal")
|
|
|
|
readPedal(e, toPedal(sp));
|
|
|
|
else if (tag == "Ottava")
|
|
|
|
readOttava(e, toOttava(sp));
|
2017-02-13 19:26:43 +01:00
|
|
|
else if (tag == "HairPin")
|
2018-08-27 22:57:15 +02:00
|
|
|
readHairpin206(e, toHairpin(sp));
|
2017-03-13 10:24:49 +01:00
|
|
|
else if (tag == "Trill")
|
2018-08-27 22:57:15 +02:00
|
|
|
readTrill206(e, toTrill(sp));
|
2017-02-09 11:57:10 +01:00
|
|
|
else
|
2018-05-14 10:07:46 +02:00
|
|
|
readTextLine206(e, toTextLineBase(sp));
|
2016-09-21 15:22:51 +02:00
|
|
|
score->addSpanner(sp);
|
|
|
|
//
|
|
|
|
// check if we already saw "endSpanner"
|
|
|
|
//
|
|
|
|
int id = e.spannerId(sp);
|
|
|
|
const SpannerValues* sv = e.spannerValues(id);
|
|
|
|
if (sv) {
|
|
|
|
sp->setTicks(sv->tick2 - sp->tick());
|
|
|
|
sp->setTrack2(sv->track2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "RepeatMeasure") {
|
|
|
|
RepeatMeasure* rm = new RepeatMeasure(score);
|
|
|
|
rm->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
readRest(rm, e);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(rm);
|
|
|
|
lastTick = e.tick();
|
|
|
|
e.incTick(m->ticks());
|
|
|
|
}
|
|
|
|
else if (tag == "Clef") {
|
|
|
|
Clef* clef = new Clef(score);
|
|
|
|
clef->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
clef->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
clef->setGenerated(false);
|
2016-11-26 15:44:11 +01:00
|
|
|
if (e.tick() == 0) {
|
2017-02-16 11:17:52 +01:00
|
|
|
if (score->staff(staffIdx)->clef(0) != clef->clefType())
|
2016-11-26 15:44:11 +01:00
|
|
|
score->staff(staffIdx)->setDefaultClefType(clef->clefType());
|
2017-02-16 11:17:52 +01:00
|
|
|
if (clef->links() && clef->links()->size() == 1) {
|
|
|
|
e.linkIds().remove(clef->links()->lid());
|
|
|
|
qDebug("remove link %d", clef->links()->lid());
|
2016-11-26 15:44:11 +01:00
|
|
|
}
|
|
|
|
delete clef;
|
|
|
|
continue;
|
|
|
|
}
|
2016-09-21 15:22:51 +02:00
|
|
|
// there may be more than one clef segment for same tick position
|
|
|
|
if (!segment) {
|
|
|
|
// this is the first segment of measure
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::Clef, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
bool firstSegment = false;
|
|
|
|
// the first clef may be missing and is added later in layout
|
|
|
|
for (Segment* s = m->segments().first(); s && s->tick() == e.tick(); s = s->next()) {
|
2017-03-08 13:12:26 +01:00
|
|
|
if (s->segmentType() == SegmentType::Clef
|
2016-09-21 15:22:51 +02:00
|
|
|
// hack: there may be other segment types which should
|
|
|
|
// generate a clef at current position
|
2017-03-08 13:12:26 +01:00
|
|
|
|| s->segmentType() == SegmentType::StartRepeatBarLine
|
2016-09-21 15:22:51 +02:00
|
|
|
) {
|
|
|
|
firstSegment = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (firstSegment) {
|
|
|
|
Segment* ns = 0;
|
|
|
|
if (segment->next()) {
|
|
|
|
ns = segment->next();
|
|
|
|
while (ns && ns->tick() < e.tick())
|
|
|
|
ns = ns->next();
|
|
|
|
}
|
|
|
|
segment = 0;
|
|
|
|
for (Segment* s = ns; s && s->tick() == e.tick(); s = s->next()) {
|
2017-03-08 13:12:26 +01:00
|
|
|
if (s->segmentType() == SegmentType::Clef) {
|
2016-09-21 15:22:51 +02:00
|
|
|
segment = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!segment) {
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = new Segment(m, SegmentType::Clef, e.tick() - m->tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
m->segments().insert(segment, ns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// this is the first clef: move to left
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::Clef, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (e.tick() != m->tick())
|
|
|
|
clef->setSmall(true); // TODO: layout does this ?
|
|
|
|
segment->add(clef);
|
|
|
|
}
|
|
|
|
else if (tag == "TimeSig") {
|
|
|
|
TimeSig* ts = new TimeSig(score);
|
|
|
|
ts->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
ts->read(e);
|
2018-02-14 20:20:21 +01:00
|
|
|
// if time sig not at beginning of measure => courtesy time sig
|
2016-09-21 15:22:51 +02:00
|
|
|
int currTick = e.tick();
|
|
|
|
bool courtesySig = (currTick > m->tick());
|
|
|
|
if (courtesySig) {
|
|
|
|
// if courtesy sig., just add it without map processing
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::TimeSigAnnounce, currTick);
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(ts);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if 'real' time sig., do full process
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::TimeSig, currTick);
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(ts);
|
|
|
|
|
|
|
|
timeStretch = ts->stretch().reduced();
|
|
|
|
m->setTimesig(ts->sig() / timeStretch);
|
|
|
|
|
|
|
|
if (irregular) {
|
|
|
|
score->sigmap()->add(m->tick(), SigEvent(m->len(), m->timesig()));
|
|
|
|
score->sigmap()->add(m->endTick(), SigEvent(m->timesig()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m->setLen(m->timesig());
|
|
|
|
score->sigmap()->add(m->tick(), SigEvent(m->timesig()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "KeySig") {
|
|
|
|
KeySig* ks = new KeySig(score);
|
|
|
|
ks->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
ks->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
int curTick = e.tick();
|
|
|
|
if (!ks->isCustom() && !ks->isAtonal() && ks->key() == Key::C && curTick == 0) {
|
|
|
|
// ignore empty key signature
|
|
|
|
qDebug("remove keysig c at tick 0");
|
|
|
|
if (ks->links()) {
|
|
|
|
if (ks->links()->size() == 1)
|
|
|
|
e.linkIds().remove(ks->links()->lid());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if key sig not at beginning of measure => courtesy key sig
|
|
|
|
bool courtesySig = (curTick == m->endTick());
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(courtesySig ? SegmentType::KeySigAnnounce : SegmentType::KeySig, curTick);
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(ks);
|
|
|
|
if (!courtesySig)
|
|
|
|
staff->setKey(curTick, ks->keySigEvent());
|
|
|
|
}
|
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
else if (tag == "Text" || tag == "StaffText") {
|
2018-11-19 14:12:00 +01:00
|
|
|
// MuseScore 3 has different types for system text and
|
|
|
|
// staff text while MuseScore 2 didn't.
|
|
|
|
// We need to decide first which one we should create.
|
|
|
|
QIODevice* dev = e.device();
|
|
|
|
QString styleName;
|
|
|
|
if (dev && !dev->isSequential()) { // we want to be able to seek a position
|
|
|
|
const auto pos = dev->pos();
|
|
|
|
dev->seek(e.characterOffset());
|
|
|
|
const QString closeTag = QString("</").append(tag).append(">");
|
|
|
|
QByteArray arrLine = dev->readLine();
|
|
|
|
while (!arrLine.isEmpty()) {
|
|
|
|
QString line(arrLine);
|
|
|
|
if (line.contains("<style>")) {
|
|
|
|
QRegExp re("<style>([A-z0-9]+)</style>");
|
|
|
|
if (re.indexIn(line) > -1)
|
|
|
|
styleName = re.cap(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (line.contains(closeTag))
|
|
|
|
break;
|
|
|
|
arrLine = dev->readLine();
|
|
|
|
}
|
|
|
|
dev->seek(pos);
|
|
|
|
}
|
|
|
|
StaffTextBase* t;
|
|
|
|
if (styleName == "System" || styleName == "Tempo"
|
|
|
|
|| styleName == "Marker" || styleName == "Jump"
|
|
|
|
|| styleName == "Volta") // TODO: is it possible to get it from style?
|
|
|
|
t = new SystemText(score);
|
|
|
|
else
|
|
|
|
t = new StaffText(score);
|
2016-09-21 15:22:51 +02:00
|
|
|
t->setTrack(e.track());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, t, t);
|
2016-09-21 15:22:51 +02:00
|
|
|
if (t->empty()) {
|
2018-08-16 11:31:57 +02:00
|
|
|
if (t->links()) {
|
|
|
|
if (t->links()->size() == 1) {
|
|
|
|
qDebug("reading empty text: deleted lid = %d", t->links()->lid());
|
|
|
|
e.linkIds().remove(t->links()->lid());
|
|
|
|
delete t;
|
|
|
|
}
|
|
|
|
}
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-07-17 11:54:10 +02:00
|
|
|
if (!t->autoplace()) {
|
|
|
|
// adjust position
|
2018-10-18 11:53:01 +02:00
|
|
|
qreal userY = t->offset().y() / t->spatium();
|
2018-07-17 11:54:10 +02:00
|
|
|
qreal yo = -(-2.0 - userY) * t->spatium();
|
|
|
|
t->layout();
|
|
|
|
t->setAlign(Align::LEFT | Align::TOP);
|
2018-10-18 11:53:01 +02:00
|
|
|
t->ryoffset() = yo;
|
2018-07-17 11:54:10 +02:00
|
|
|
}
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------
|
|
|
|
// Annotation
|
|
|
|
|
|
|
|
else if (tag == "Dynamic") {
|
|
|
|
Dynamic* dyn = new Dynamic(score);
|
|
|
|
dyn->setTrack(e.track());
|
2018-11-02 18:38:07 +01:00
|
|
|
readDynamic(dyn, e);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(dyn);
|
|
|
|
}
|
2017-05-23 16:52:04 +02:00
|
|
|
else if (tag == "RehearsalMark") {
|
|
|
|
RehearsalMark* el = new RehearsalMark(score);
|
|
|
|
el->setTrack(e.track());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, el, el);
|
2018-10-25 18:32:06 +02:00
|
|
|
// el->setOffset(el->offset() - el->score()->styleValue(Pid::OFFSET, Sid::rehearsalMarkPosAbove).toPointF());
|
|
|
|
// if (el->offset().isNull())
|
|
|
|
// el->setAutoplace(true);
|
2017-05-23 16:52:04 +02:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
|
|
|
segment->add(el);
|
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
#if 0
|
2017-05-23 16:52:04 +02:00
|
|
|
else if (tag == "StaffText") {
|
|
|
|
StaffText* el = new StaffText(score);
|
|
|
|
el->setTrack(e.track());
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "foregroundColor")
|
|
|
|
e.skipCurrentElement();
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!el->readProperties(e))
|
2017-05-23 16:52:04 +02:00
|
|
|
e.unknown();
|
|
|
|
}
|
2018-04-05 14:35:31 +02:00
|
|
|
TextBase* tt = static_cast<TextBase*>(el);
|
|
|
|
tt->setXmlText(tt->xmlText().replace("<sym>unicode", "<sym>met"));
|
2017-05-23 16:52:04 +02:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
|
|
|
segment->add(el);
|
|
|
|
}
|
2018-06-27 09:04:11 +02:00
|
|
|
#endif
|
2016-09-21 15:22:51 +02:00
|
|
|
else if (tag == "Harmony"
|
|
|
|
|| tag == "FretDiagram"
|
|
|
|
|| tag == "TremoloBar"
|
|
|
|
|| tag == "Symbol"
|
|
|
|
|| tag == "InstrumentChange"
|
|
|
|
|| tag == "StaffState"
|
|
|
|
|| tag == "FiguredBass"
|
|
|
|
) {
|
|
|
|
Element* el = Element::name2Element(tag, score);
|
|
|
|
// hack - needed because tick tags are unreliable in 1.3 scores
|
|
|
|
// for symbols attached to anything but a measure
|
|
|
|
el->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
el->read(e);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(el);
|
|
|
|
}
|
2018-04-05 14:35:31 +02:00
|
|
|
else if (tag == "Tempo") {
|
2018-06-27 09:04:11 +02:00
|
|
|
TempoText* tt = new TempoText(score);
|
2018-04-05 14:35:31 +02:00
|
|
|
// hack - needed because tick tags are unreliable in 1.3 scores
|
|
|
|
// for symbols attached to anything but a measure
|
2018-06-27 09:04:11 +02:00
|
|
|
tt->setTrack(e.track());
|
|
|
|
readTempoText(tt, e);
|
2018-04-05 14:35:31 +02:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2018-06-27 09:04:11 +02:00
|
|
|
segment->add(tt);
|
2018-07-26 13:14:06 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Marker" || tag == "Jump") {
|
2016-09-21 15:22:51 +02:00
|
|
|
Element* el = Element::name2Element(tag, score);
|
|
|
|
el->setTrack(e.track());
|
2018-11-02 18:38:07 +01:00
|
|
|
if (tag == "Marker") {
|
|
|
|
Marker* ma = toMarker(el);
|
|
|
|
readMarker(ma, e);
|
|
|
|
Element* markerEl = toElement(ma);
|
|
|
|
m->add(markerEl);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
el->read(e);
|
|
|
|
m->add(el);
|
|
|
|
}
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "Image") {
|
|
|
|
if (MScore::noImages)
|
|
|
|
e.skipCurrentElement();
|
|
|
|
else {
|
|
|
|
Element* el = Element::name2Element(tag, score);
|
|
|
|
el->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
el->read(e);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::ChordRest, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(el);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
|
|
else if (tag == "stretch") {
|
|
|
|
double val = e.readDouble();
|
|
|
|
if (val < 0.0)
|
|
|
|
val = 0;
|
|
|
|
m->setUserStretch(val);
|
|
|
|
}
|
|
|
|
else if (tag == "noOffset")
|
|
|
|
m->setNoOffset(e.readInt());
|
|
|
|
else if (tag == "measureNumberMode")
|
|
|
|
m->setMeasureNumberMode(MeasureNumberMode(e.readInt()));
|
|
|
|
else if (tag == "irregular")
|
|
|
|
m->setIrregular(e.readBool());
|
|
|
|
else if (tag == "breakMultiMeasureRest")
|
|
|
|
m->setBreakMultiMeasureRest(e.readBool());
|
|
|
|
else if (tag == "sysInitBarLineType") {
|
|
|
|
const QString& val(e.readElementText());
|
|
|
|
BarLine* barLine = new BarLine(score);
|
|
|
|
barLine->setTrack(e.track());
|
|
|
|
barLine->setBarLineType(val);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::BeginBarLine, m->tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
segment->add(barLine);
|
|
|
|
}
|
|
|
|
else if (tag == "Tuplet") {
|
|
|
|
Tuplet* tuplet = new Tuplet(score);
|
|
|
|
tuplet->setTrack(e.track());
|
|
|
|
tuplet->setTick(e.tick());
|
|
|
|
tuplet->setParent(m);
|
2016-11-09 17:12:52 +01:00
|
|
|
readTuplet(tuplet, e);
|
2016-09-21 15:22:51 +02:00
|
|
|
e.addTuplet(tuplet);
|
|
|
|
}
|
|
|
|
else if (tag == "startRepeat") {
|
|
|
|
m->setRepeatStart(true);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "endRepeat") {
|
|
|
|
m->setRepeatCount(e.readInt());
|
|
|
|
m->setRepeatEnd(true);
|
|
|
|
}
|
|
|
|
else if (tag == "vspacer" || tag == "vspacerDown") {
|
2016-12-12 14:55:35 +01:00
|
|
|
if (!m->vspacerDown(staffIdx)) {
|
2016-09-21 15:22:51 +02:00
|
|
|
Spacer* spacer = new Spacer(score);
|
|
|
|
spacer->setSpacerType(SpacerType::DOWN);
|
|
|
|
spacer->setTrack(staffIdx * VOICES);
|
|
|
|
m->add(spacer);
|
|
|
|
}
|
2016-12-12 14:55:35 +01:00
|
|
|
m->vspacerDown(staffIdx)->setGap(e.readDouble() * _spatium);
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "vspacer" || tag == "vspacerUp") {
|
2016-12-12 14:55:35 +01:00
|
|
|
if (!m->vspacerUp(staffIdx)) {
|
2016-09-21 15:22:51 +02:00
|
|
|
Spacer* spacer = new Spacer(score);
|
|
|
|
spacer->setSpacerType(SpacerType::UP);
|
|
|
|
spacer->setTrack(staffIdx * VOICES);
|
|
|
|
m->add(spacer);
|
|
|
|
}
|
2016-12-12 14:55:35 +01:00
|
|
|
m->vspacerUp(staffIdx)->setGap(e.readDouble() * _spatium);
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "visible")
|
2016-12-12 14:55:35 +01:00
|
|
|
m->setStaffVisible(staffIdx, e.readInt());
|
2016-09-21 15:22:51 +02:00
|
|
|
else if (tag == "slashStyle")
|
2016-12-12 14:55:35 +01:00
|
|
|
m->setStaffSlashStyle(staffIdx, e.readInt());
|
2016-09-21 15:22:51 +02:00
|
|
|
else if (tag == "Beam") {
|
|
|
|
Beam* beam = new Beam(score);
|
|
|
|
beam->setTrack(e.track());
|
2018-08-27 22:57:15 +02:00
|
|
|
beam->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
beam->setParent(0);
|
|
|
|
e.addBeam(beam);
|
|
|
|
}
|
|
|
|
else if (tag == "Segment")
|
2018-08-27 22:57:15 +02:00
|
|
|
segment->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
else if (tag == "MeasureNumber") {
|
2018-10-24 10:40:03 +02:00
|
|
|
MeasureNumber* noText = new MeasureNumber(score);
|
2018-08-27 22:57:15 +02:00
|
|
|
readText206(e, noText, m);
|
2016-09-21 15:22:51 +02:00
|
|
|
noText->setTrack(e.track());
|
|
|
|
noText->setParent(m);
|
2016-12-12 14:55:35 +01:00
|
|
|
m->setNoText(noText->staffIdx(), noText);
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "SystemDivider") {
|
|
|
|
SystemDivider* sd = new SystemDivider(score);
|
2018-08-27 22:57:15 +02:00
|
|
|
sd->read(e);
|
2016-09-21 15:22:51 +02:00
|
|
|
m->add(sd);
|
|
|
|
}
|
|
|
|
else if (tag == "Ambitus") {
|
|
|
|
Ambitus* range = new Ambitus(score);
|
2016-10-18 17:58:38 +02:00
|
|
|
readAmbitus(range, e);
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = m->getSegment(SegmentType::Ambitus, e.tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
range->setParent(segment); // a parent segment is needed for setTrack() to work
|
|
|
|
range->setTrack(trackZeroVoice(e.track()));
|
|
|
|
segment->add(range);
|
|
|
|
}
|
|
|
|
else if (tag == "multiMeasureRest") {
|
|
|
|
m->setMMRestCount(e.readInt());
|
|
|
|
// set tick to previous measure
|
|
|
|
m->setTick(e.lastMeasure()->tick());
|
|
|
|
e.initTick(e.lastMeasure()->tick());
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (m->MeasureBase::readProperties(e))
|
2016-09-21 15:22:51 +02:00
|
|
|
;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
2016-09-26 10:15:20 +02:00
|
|
|
e.checkTuplets();
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
|
2017-11-20 14:46:46 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readBox
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readBox(Box* b, XmlReader& e)
|
|
|
|
{
|
|
|
|
b->setLeftMargin(0.0);
|
|
|
|
b->setRightMargin(0.0);
|
|
|
|
b->setTopMargin(0.0);
|
|
|
|
b->setBottomMargin(0.0);
|
|
|
|
|
|
|
|
b->setBoxHeight(Spatium(0)); // override default set in constructor
|
|
|
|
b->setBoxWidth(Spatium(0));
|
|
|
|
bool keepMargins = false; // whether original margins have to be kept when reading old file
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "HBox") {
|
|
|
|
HBox* hb = new HBox(b->score());
|
2018-08-27 22:57:15 +02:00
|
|
|
hb->read(e);
|
2017-11-20 14:46:46 +01:00
|
|
|
b->add(hb);
|
|
|
|
keepMargins = true; // in old file, box nesting used outer box margins
|
|
|
|
}
|
|
|
|
else if (tag == "VBox") {
|
|
|
|
VBox* vb = new VBox(b->score());
|
2018-08-27 22:57:15 +02:00
|
|
|
vb->read(e);
|
2017-11-20 14:46:46 +01:00
|
|
|
b->add(vb);
|
|
|
|
keepMargins = true; // in old file, box nesting used outer box margins
|
|
|
|
}
|
|
|
|
else if (tag == "Text") {
|
|
|
|
Text* t;
|
|
|
|
if (b->isTBox()) {
|
|
|
|
t = toTBox(b)->text();
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, t, t);
|
2017-11-20 14:46:46 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
t = new Text(b->score());
|
2018-05-14 10:07:46 +02:00
|
|
|
readText206(e, t, t);
|
2017-11-20 14:46:46 +01:00
|
|
|
if (t->empty()) {
|
|
|
|
qDebug("read empty text");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
b->add(t);
|
|
|
|
}
|
|
|
|
}
|
2018-08-27 22:57:15 +02:00
|
|
|
else if (!b->readProperties(e))
|
2017-11-20 14:46:46 +01:00
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
|
|
|
|
// with .msc versions prior to 1.17, box margins were only used when nesting another box inside this box:
|
|
|
|
// for backward compatibility set them to 0 in all other cases
|
|
|
|
|
|
|
|
if (b->score()->mscVersion() <= 114 && (b->isHBox() || b->isVBox()) && !keepMargins) {
|
|
|
|
b->setLeftMargin(0.0);
|
|
|
|
b->setRightMargin(0.0);
|
|
|
|
b->setTopMargin(0.0);
|
|
|
|
b->setBottomMargin(0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-21 15:22:51 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// readStaffContent
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void readStaffContent(Score* score, XmlReader& e)
|
|
|
|
{
|
|
|
|
int staff = e.intAttribute("id", 1) - 1;
|
|
|
|
e.initTick(0);
|
|
|
|
e.setTrack(staff * VOICES);
|
|
|
|
|
|
|
|
if (staff == 0) {
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "Measure") {
|
|
|
|
Measure* measure = 0;
|
|
|
|
measure = new Measure(score);
|
|
|
|
measure->setTick(e.tick());
|
|
|
|
//
|
|
|
|
// inherit timesig from previous measure
|
|
|
|
//
|
|
|
|
Measure* m = e.lastMeasure(); // measure->prevMeasure();
|
|
|
|
Fraction f(m ? m->timesig() : Fraction(4,4));
|
|
|
|
measure->setLen(f);
|
|
|
|
measure->setTimesig(f);
|
|
|
|
|
|
|
|
readMeasure(measure, staff, e);
|
|
|
|
measure->checkMeasure(staff);
|
|
|
|
if (!measure->isMMRest()) {
|
|
|
|
score->measures()->add(measure);
|
|
|
|
e.setLastMeasure(measure);
|
|
|
|
e.initTick(measure->tick() + measure->ticks());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// this is a multi measure rest
|
|
|
|
// always preceded by the first measure it replaces
|
2018-08-17 15:06:15 +02:00
|
|
|
Measure* lm = e.lastMeasure();
|
2016-09-21 15:22:51 +02:00
|
|
|
|
2018-08-17 15:06:15 +02:00
|
|
|
if (lm) {
|
|
|
|
lm->setMMRest(measure);
|
|
|
|
measure->setTick(lm->tick());
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "HBox" || tag == "VBox" || tag == "TBox" || tag == "FBox") {
|
2017-11-20 14:46:46 +01:00
|
|
|
Box* b = toBox(Element::name2Element(tag, score));
|
|
|
|
readBox(b, e);
|
|
|
|
b->setTick(e.tick());
|
|
|
|
score->measures()->add(b);
|
2016-09-21 15:22:51 +02:00
|
|
|
}
|
|
|
|
else if (tag == "tick")
|
|
|
|
e.initTick(score->fileDivision(e.readInt()));
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Measure* measure = score->firstMeasure();
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
if (tag == "Measure") {
|
|
|
|
if (measure == 0) {
|
|
|
|
qDebug("Score::readStaff(): missing measure!");
|
|
|
|
measure = new Measure(score);
|
|
|
|
measure->setTick(e.tick());
|
|
|
|
score->measures()->add(measure);
|
|
|
|
}
|
|
|
|
e.initTick(measure->tick());
|
|
|
|
readMeasure(measure, staff, e);
|
|
|
|
measure->checkMeasure(staff);
|
|
|
|
if (measure->isMMRest())
|
|
|
|
measure = e.lastMeasure()->nextMeasure();
|
|
|
|
else {
|
|
|
|
e.setLastMeasure(measure);
|
|
|
|
if (measure->mmRest())
|
|
|
|
measure = measure->mmRest();
|
|
|
|
else
|
|
|
|
measure = measure->nextMeasure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "tick")
|
|
|
|
e.initTick(score->fileDivision(e.readInt()));
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-23 21:53:51 +01:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// readStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-09-22 10:03:59 +02:00
|
|
|
static void readStyle(MStyle* style, XmlReader& e)
|
|
|
|
{
|
2018-03-27 15:36:00 +02:00
|
|
|
QString oldChordDescriptionFile = style->value(Sid::chordDescriptionFile).toString();
|
2016-09-22 10:03:59 +02:00
|
|
|
bool chordListTag = false;
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
QString tag = e.name().toString();
|
|
|
|
|
2017-01-25 15:54:46 +01:00
|
|
|
if (tag == "TextStyle")
|
2017-10-13 12:12:11 +02:00
|
|
|
readTextStyle206(style, e);
|
2016-09-22 10:03:59 +02:00
|
|
|
else if (tag == "Spatium")
|
2018-03-27 15:36:00 +02:00
|
|
|
style->set(Sid::spatium, e.readDouble() * DPMM);
|
2017-03-21 16:21:36 +01:00
|
|
|
else if (tag == "page-layout")
|
|
|
|
readPageFormat(style, e);
|
2016-09-22 10:03:59 +02:00
|
|
|
else if (tag == "displayInConcertPitch")
|
2018-03-27 15:36:00 +02:00
|
|
|
style->set(Sid::concertPitch, QVariant(bool(e.readInt())));
|
2017-10-12 11:10:30 +02:00
|
|
|
else if (tag == "pedalY") {
|
|
|
|
qreal y = e.readDouble();
|
2018-10-18 11:53:01 +02:00
|
|
|
style->set(Sid::pedalPosBelow, QPointF(0.0, y));
|
2017-10-12 11:10:30 +02:00
|
|
|
}
|
|
|
|
else if (tag == "lyricsDistance") {
|
|
|
|
qreal y = e.readDouble();
|
2018-10-18 11:53:01 +02:00
|
|
|
style->set(Sid::lyricsPosBelow, QPointF(0.0, y));
|
2017-10-12 11:10:30 +02:00
|
|
|
}
|
2018-07-11 13:17:15 +02:00
|
|
|
else if (tag == "ottavaHook") {
|
|
|
|
qreal y = qAbs(e.readDouble());
|
|
|
|
style->set(Sid::ottavaHookAbove, y);
|
|
|
|
style->set(Sid::ottavaHookBelow, -y);
|
|
|
|
}
|
2017-10-13 12:51:37 +02:00
|
|
|
else if (tag == "endBarDistance") {
|
|
|
|
double d = e.readDouble();
|
2018-03-27 15:36:00 +02:00
|
|
|
d += style->value(Sid::barWidth).toDouble();
|
|
|
|
d += style->value(Sid::endBarWidth).toDouble();
|
|
|
|
style->set(Sid::endBarDistance, QVariant(d));
|
2017-10-13 12:51:37 +02:00
|
|
|
}
|
2016-09-22 10:03:59 +02:00
|
|
|
else if (tag == "ChordList") {
|
|
|
|
style->chordList()->clear();
|
|
|
|
style->chordList()->read(e);
|
|
|
|
style->setCustomChordList(true);
|
2016-10-14 21:39:31 +02:00
|
|
|
for (ChordFont f : style->chordList()->fonts) {
|
|
|
|
if (f.family == "MuseJazz") {
|
|
|
|
f.family = "MuseJazz Text";
|
|
|
|
}
|
|
|
|
}
|
2016-09-22 10:03:59 +02:00
|
|
|
chordListTag = true;
|
|
|
|
}
|
2017-01-23 21:53:51 +01:00
|
|
|
else
|
2018-07-10 17:19:16 +02:00
|
|
|
if (!style->readProperties(e)) {
|
|
|
|
e.skipCurrentElement();
|
|
|
|
}
|
2016-09-22 10:03:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// if we just specified a new chord description file
|
|
|
|
// and didn't encounter a ChordList tag
|
|
|
|
// then load the chord description file
|
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
QString newChordDescriptionFile = style->value(Sid::chordDescriptionFile).toString();
|
2016-09-22 10:03:59 +02:00
|
|
|
if (newChordDescriptionFile != oldChordDescriptionFile && !chordListTag) {
|
2018-03-27 15:36:00 +02:00
|
|
|
if (!newChordDescriptionFile.startsWith("chords_") && style->value(Sid::chordStyle).toString() == "std") {
|
2016-09-22 10:03:59 +02:00
|
|
|
// should not normally happen,
|
|
|
|
// but treat as "old" (114) score just in case
|
2018-03-27 15:36:00 +02:00
|
|
|
style->set(Sid::chordStyle, QVariant(QString("custom")));
|
|
|
|
style->set(Sid::chordsXmlFile, QVariant(true));
|
2016-09-22 10:03:59 +02:00
|
|
|
qDebug("StyleData::load: custom chord description file %s with chordStyle == std", qPrintable(newChordDescriptionFile));
|
|
|
|
}
|
2018-03-27 15:36:00 +02:00
|
|
|
if (style->value(Sid::chordStyle).toString() == "custom")
|
2016-09-22 10:03:59 +02:00
|
|
|
style->setCustomChordList(true);
|
|
|
|
else
|
|
|
|
style->setCustomChordList(false);
|
|
|
|
style->chordList()->unload();
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we have a chordlist
|
|
|
|
if (!style->chordList()->loaded() && !chordListTag) {
|
2018-03-27 15:36:00 +02:00
|
|
|
if (style->value(Sid::chordsXmlFile).toBool())
|
2016-09-22 10:03:59 +02:00
|
|
|
style->chordList()->read("chords.xml");
|
|
|
|
style->chordList()->read(newChordDescriptionFile);
|
|
|
|
}
|
|
|
|
}
|
2016-09-21 15:22:51 +02:00
|
|
|
|
2016-09-13 09:39:50 +02:00
|
|
|
//---------------------------------------------------------
|
2016-09-20 11:12:44 +02:00
|
|
|
// readScore
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static bool readScore(Score* score, XmlReader& e)
|
|
|
|
{
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
e.setTrack(-1);
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "Staff")
|
2016-09-21 15:22:51 +02:00
|
|
|
readStaffContent(score, e);
|
2016-09-20 11:12:44 +02:00
|
|
|
else if (tag == "siglist")
|
|
|
|
score->sigmap()->read(e, score->fileDivision());
|
|
|
|
else if (tag == "Omr") {
|
|
|
|
#ifdef OMR
|
|
|
|
score->masterScore()->setOmr(new Omr(score));
|
|
|
|
score->masterScore()->omr()->read(e);
|
|
|
|
#else
|
|
|
|
e.skipCurrentElement();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (tag == "Audio") {
|
|
|
|
score->setAudio(new Audio);
|
|
|
|
score->audio()->read(e);
|
|
|
|
}
|
|
|
|
else if (tag == "showOmr")
|
|
|
|
score->masterScore()->setShowOmr(e.readInt());
|
|
|
|
else if (tag == "playMode")
|
|
|
|
score->setPlayMode(PlayMode(e.readInt()));
|
|
|
|
else if (tag == "LayerTag") {
|
|
|
|
int id = e.intAttribute("id");
|
2018-08-17 15:06:15 +02:00
|
|
|
const QString& t = e.attribute("tag");
|
2016-09-20 11:12:44 +02:00
|
|
|
QString val(e.readElementText());
|
|
|
|
if (id >= 0 && id < 32) {
|
2018-08-17 15:06:15 +02:00
|
|
|
score->layerTags()[id] = t;
|
2016-09-20 11:12:44 +02:00
|
|
|
score->layerTagComments()[id] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "Layer") {
|
|
|
|
Layer layer;
|
|
|
|
layer.name = e.attribute("name");
|
|
|
|
layer.tags = e.attribute("mask").toUInt();
|
|
|
|
score->layer().append(layer);
|
|
|
|
e.readNext();
|
|
|
|
}
|
|
|
|
else if (tag == "currentLayer")
|
|
|
|
score->setCurrentLayer(e.readInt());
|
|
|
|
else if (tag == "Synthesizer")
|
|
|
|
score->synthesizerState().read(e);
|
|
|
|
else if (tag == "Division")
|
|
|
|
score->setFileDivision(e.readInt());
|
|
|
|
else if (tag == "showInvisible")
|
|
|
|
score->setShowInvisible(e.readInt());
|
|
|
|
else if (tag == "showUnprintable")
|
|
|
|
score->setShowUnprintable(e.readInt());
|
|
|
|
else if (tag == "showFrames")
|
|
|
|
score->setShowFrames(e.readInt());
|
|
|
|
else if (tag == "showMargins")
|
|
|
|
score->setShowPageborders(e.readInt());
|
|
|
|
else if (tag == "Style") {
|
2018-03-27 15:36:00 +02:00
|
|
|
qreal sp = score->style().value(Sid::spatium).toDouble();
|
2017-01-05 11:23:47 +01:00
|
|
|
readStyle(&score->style(), e);
|
2018-03-27 15:36:00 +02:00
|
|
|
if (score->style().value(Sid::MusicalTextFont).toString() == "MuseJazz")
|
|
|
|
score->style().set(Sid::MusicalTextFont, "MuseJazz Text");
|
2016-09-20 11:12:44 +02:00
|
|
|
// if (_layoutMode == LayoutMode::FLOAT || _layoutMode == LayoutMode::SYSTEM) {
|
|
|
|
if (score->layoutMode() == LayoutMode::FLOAT) {
|
|
|
|
// style should not change spatium in
|
|
|
|
// float mode
|
2018-03-27 15:36:00 +02:00
|
|
|
score->style().set(Sid::spatium, sp);
|
2016-09-20 11:12:44 +02:00
|
|
|
}
|
2018-03-27 15:36:00 +02:00
|
|
|
score->setScoreFont(ScoreFont::fontFactory(score->style().value(Sid::MusicalSymbolFont).toString()));
|
2016-09-20 11:12:44 +02:00
|
|
|
}
|
|
|
|
else if (tag == "copyright" || tag == "rights") {
|
|
|
|
Text* text = new Text(score);
|
2018-08-27 22:57:15 +02:00
|
|
|
readText206(e, text, text);
|
2016-09-20 11:12:44 +02:00
|
|
|
score->setMetaTag("copyright", text->xmlText());
|
|
|
|
delete text;
|
|
|
|
}
|
|
|
|
else if (tag == "movement-number")
|
|
|
|
score->setMetaTag("movementNumber", e.readElementText());
|
|
|
|
else if (tag == "movement-title")
|
|
|
|
score->setMetaTag("movementTitle", e.readElementText());
|
|
|
|
else if (tag == "work-number")
|
|
|
|
score->setMetaTag("workNumber", e.readElementText());
|
|
|
|
else if (tag == "work-title")
|
|
|
|
score->setMetaTag("workTitle", e.readElementText());
|
|
|
|
else if (tag == "source")
|
|
|
|
score->setMetaTag("source", e.readElementText());
|
|
|
|
else if (tag == "metaTag") {
|
|
|
|
QString name = e.attribute("name");
|
|
|
|
score->setMetaTag(name, e.readElementText());
|
|
|
|
}
|
|
|
|
else if (tag == "Part") {
|
|
|
|
Part* part = new Part(score);
|
2016-10-20 10:13:12 +02:00
|
|
|
readPart(part, e);
|
2016-09-20 11:12:44 +02:00
|
|
|
score->parts().push_back(part);
|
|
|
|
}
|
2017-02-16 11:17:52 +01:00
|
|
|
else if ((tag == "HairPin") // TODO: do this elements exist here?
|
2016-09-20 11:12:44 +02:00
|
|
|
|| (tag == "Ottava")
|
|
|
|
|| (tag == "TextLine")
|
|
|
|
|| (tag == "Volta")
|
|
|
|
|| (tag == "Trill")
|
|
|
|
|| (tag == "Slur")
|
|
|
|
|| (tag == "Pedal")) {
|
2017-12-20 16:49:30 +01:00
|
|
|
Spanner* s = toSpanner(Element::name2Element(tag, score));
|
2018-08-27 22:57:15 +02:00
|
|
|
if (tag == "HairPin")
|
|
|
|
readHairpin206(e, toHairpin(s));
|
|
|
|
else if (tag == "Ottava")
|
|
|
|
readOttava(e, toOttava(s));
|
|
|
|
else if (tag == "TextLine")
|
|
|
|
readTextLine206(e, toTextLine(s));
|
|
|
|
else if (tag == "Volta")
|
|
|
|
readVolta206(e, toVolta(s));
|
|
|
|
else if (tag == "Trill")
|
|
|
|
readTrill206(e, toTrill(s));
|
|
|
|
else if (tag == "Slur")
|
|
|
|
readSlur206(e, toSlur(s));
|
|
|
|
else {
|
|
|
|
Q_ASSERT(tag == "Pedal");
|
|
|
|
readPedal(e, toPedal(s));
|
|
|
|
}
|
2016-09-20 11:12:44 +02:00
|
|
|
score->addSpanner(s);
|
|
|
|
}
|
|
|
|
else if (tag == "Excerpt") {
|
|
|
|
if (MScore::noExcerpts)
|
|
|
|
e.skipCurrentElement();
|
|
|
|
else {
|
|
|
|
if (score->isMaster()) {
|
|
|
|
Excerpt* ex = new Excerpt(static_cast<MasterScore*>(score));
|
|
|
|
ex->read(e);
|
|
|
|
score->excerpts().append(ex);
|
|
|
|
}
|
|
|
|
else {
|
2018-09-02 15:17:11 +02:00
|
|
|
qDebug("read206: readScore(): part cannot have parts");
|
2016-09-20 11:12:44 +02:00
|
|
|
e.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "Score") { // recursion
|
|
|
|
if (MScore::noExcerpts)
|
|
|
|
e.skipCurrentElement();
|
|
|
|
else {
|
|
|
|
e.tracks().clear();
|
|
|
|
MasterScore* m = score->masterScore();
|
2017-03-15 13:35:27 +01:00
|
|
|
Score* s = new Score(m, MScore::defaultStyle());
|
2016-09-20 11:12:44 +02:00
|
|
|
Excerpt* ex = new Excerpt(m);
|
|
|
|
|
|
|
|
ex->setPartScore(s);
|
2016-10-10 18:37:28 +02:00
|
|
|
ex->setTracks(e.tracks());
|
2016-12-05 17:14:34 +01:00
|
|
|
e.setLastMeasure(nullptr);
|
2017-02-16 11:17:52 +01:00
|
|
|
readScore(s, e);
|
2016-10-10 18:37:28 +02:00
|
|
|
m->addExcerpt(ex);
|
2016-09-20 11:12:44 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-23 21:53:51 +01:00
|
|
|
else if (tag == "PageList")
|
2017-01-05 11:23:47 +01:00
|
|
|
e.skipCurrentElement();
|
2016-09-20 11:12:44 +02:00
|
|
|
else if (tag == "name") {
|
|
|
|
QString n = e.readElementText();
|
2016-10-10 18:37:28 +02:00
|
|
|
if (!score->isMaster()) //ignore the name if it's not a child score
|
|
|
|
score->excerpt()->setTitle(n);
|
2016-09-20 11:12:44 +02:00
|
|
|
}
|
|
|
|
else if (tag == "layoutMode") {
|
|
|
|
QString s = e.readElementText();
|
|
|
|
if (s == "line")
|
|
|
|
score->setLayoutMode(LayoutMode::LINE);
|
|
|
|
else if (s == "system")
|
|
|
|
score->setLayoutMode(LayoutMode::SYSTEM);
|
|
|
|
else
|
|
|
|
qDebug("layoutMode: %s", qPrintable(s));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
if (e.error() != QXmlStreamReader::NoError) {
|
|
|
|
qDebug("%s: xml read error at line %lld col %lld: %s",
|
|
|
|
qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(),
|
|
|
|
e.name().toUtf8().data());
|
2016-09-28 17:25:01 +02:00
|
|
|
MScore::lastError = QObject::tr("XML read error at line %1 column %2: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.name().toString());
|
2016-09-20 11:12:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
score->connectTies();
|
|
|
|
|
|
|
|
score->setFileDivision(MScore::division);
|
|
|
|
|
|
|
|
//
|
|
|
|
// sanity check for barLineSpan
|
|
|
|
//
|
2016-12-18 14:31:13 +01:00
|
|
|
#if 0 // TODO:barline
|
2016-09-20 11:12:44 +02:00
|
|
|
for (Staff* st : score->staves()) {
|
|
|
|
int barLineSpan = st->barLineSpan();
|
2016-09-28 21:13:05 +02:00
|
|
|
int idx = st->idx();
|
2016-09-20 11:12:44 +02:00
|
|
|
int n = score->nstaves();
|
|
|
|
if (idx + barLineSpan > n) {
|
|
|
|
qDebug("bad span: idx %d span %d staves %d", idx, barLineSpan, n);
|
|
|
|
// span until last staff
|
|
|
|
barLineSpan = n - idx;
|
|
|
|
st->setBarLineSpan(barLineSpan);
|
|
|
|
}
|
|
|
|
else if (idx == 0 && barLineSpan == 0) {
|
|
|
|
qDebug("bad span: idx %d span %d staves %d", idx, barLineSpan, n);
|
|
|
|
// span from the first staff until the start of the next span
|
|
|
|
barLineSpan = 1;
|
|
|
|
for (int i = 1; i < n; ++i) {
|
|
|
|
if (score->staff(i)->barLineSpan() == 0)
|
|
|
|
++barLineSpan;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
st->setBarLineSpan(barLineSpan);
|
|
|
|
}
|
|
|
|
// check spanFrom
|
2016-12-13 13:16:17 +01:00
|
|
|
int minBarLineFrom = st->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : MIN_BARLINE_SPAN_FROMTO;
|
2016-09-20 11:12:44 +02:00
|
|
|
if (st->barLineFrom() < minBarLineFrom)
|
|
|
|
st->setBarLineFrom(minBarLineFrom);
|
2016-12-13 13:16:17 +01:00
|
|
|
if (st->barLineFrom() > st->lines(0) * 2)
|
|
|
|
st->setBarLineFrom(st->lines(0) * 2);
|
2016-09-20 11:12:44 +02:00
|
|
|
// check spanTo
|
|
|
|
Staff* stTo = st->barLineSpan() <= 1 ? st : score->staff(idx + st->barLineSpan() - 1);
|
|
|
|
// 1-line staves have special bar line spans
|
2016-12-13 13:16:17 +01:00
|
|
|
int maxBarLineTo = stTo->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_TO : stTo->lines(0)*2;
|
|
|
|
int defaultBarLineTo = stTo->lines(0) == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (stTo->lines(0) - 1) * 2;
|
2016-09-20 11:12:44 +02:00
|
|
|
if (st->barLineTo() == UNKNOWN_BARLINE_TO)
|
|
|
|
st->setBarLineTo(defaultBarLineTo);
|
|
|
|
if (st->barLineTo() < MIN_BARLINE_SPAN_FROMTO)
|
|
|
|
st->setBarLineTo(MIN_BARLINE_SPAN_FROMTO);
|
|
|
|
if (st->barLineTo() > maxBarLineTo)
|
|
|
|
st->setBarLineTo(maxBarLineTo);
|
|
|
|
// on single staff span, check spanFrom and spanTo are distant enough
|
|
|
|
if (st->barLineSpan() == 1) {
|
|
|
|
if (st->barLineTo() - st->barLineFrom() < MIN_BARLINE_FROMTO_DIST) {
|
|
|
|
st->setBarLineFrom(0);
|
|
|
|
st->setBarLineTo(defaultBarLineTo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-18 14:31:13 +01:00
|
|
|
#endif
|
2016-09-20 11:12:44 +02:00
|
|
|
score->fixTicks();
|
2017-02-16 11:17:52 +01:00
|
|
|
if (score->isMaster()) {
|
|
|
|
MasterScore* ms = static_cast<MasterScore*>(score);
|
|
|
|
if (!ms->omr())
|
|
|
|
ms->setShowOmr(false);
|
|
|
|
ms->rebuildMidiMapping();
|
|
|
|
ms->updateChannel();
|
|
|
|
ms->createPlayEvents();
|
|
|
|
}
|
2016-09-20 11:12:44 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-23 21:53:51 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// read
|
|
|
|
// <page-layout>
|
|
|
|
// <page-height>
|
|
|
|
// <page-width>
|
|
|
|
// <landscape>1</landscape>
|
|
|
|
// <page-margins type="both">
|
|
|
|
// <left-margin>28.3465</left-margin>
|
|
|
|
// <right-margin>28.3465</right-margin>
|
|
|
|
// <top-margin>28.3465</top-margin>
|
|
|
|
// <bottom-margin>56.6929</bottom-margin>
|
|
|
|
// </page-margins>
|
|
|
|
// </page-layout>
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void PageFormat::read(XmlReader& e)
|
|
|
|
{
|
|
|
|
qreal _oddRightMargin = 0.0;
|
|
|
|
qreal _evenRightMargin = 0.0;
|
|
|
|
QString type;
|
|
|
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "page-margins") {
|
|
|
|
type = e.attribute("type","both");
|
|
|
|
qreal lm = 0.0, rm = 0.0, tm = 0.0, bm = 0.0;
|
|
|
|
while (e.readNextStartElement()) {
|
2018-08-17 15:06:15 +02:00
|
|
|
const QStringRef& t(e.name());
|
2017-01-23 21:53:51 +01:00
|
|
|
qreal val = e.readDouble() * 0.5 / PPI;
|
2018-08-17 15:06:15 +02:00
|
|
|
if (t == "left-margin")
|
2017-01-23 21:53:51 +01:00
|
|
|
lm = val;
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "right-margin")
|
2017-01-23 21:53:51 +01:00
|
|
|
rm = val;
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "top-margin")
|
2017-01-23 21:53:51 +01:00
|
|
|
tm = val;
|
2018-08-17 15:06:15 +02:00
|
|
|
else if (t == "bottom-margin")
|
2017-01-23 21:53:51 +01:00
|
|
|
bm = val;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
_twosided = type == "odd" || type == "even";
|
|
|
|
if (type == "odd" || type == "both") {
|
|
|
|
_oddLeftMargin = lm;
|
|
|
|
_oddRightMargin = rm;
|
|
|
|
_oddTopMargin = tm;
|
|
|
|
_oddBottomMargin = bm;
|
|
|
|
}
|
|
|
|
if (type == "even" || type == "both") {
|
|
|
|
_evenLeftMargin = lm;
|
|
|
|
_evenRightMargin = rm;
|
|
|
|
_evenTopMargin = tm;
|
|
|
|
_evenBottomMargin = bm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tag == "page-height")
|
|
|
|
_size.rheight() = e.readDouble() * 0.5 / PPI;
|
|
|
|
else if (tag == "page-width")
|
|
|
|
_size.rwidth() = e.readDouble() * .5 / PPI;
|
|
|
|
else
|
|
|
|
e.unknown();
|
|
|
|
}
|
|
|
|
qreal w1 = _size.width() - _oddLeftMargin - _oddRightMargin;
|
|
|
|
qreal w2 = _size.width() - _evenLeftMargin - _evenRightMargin;
|
|
|
|
_printableWidth = qMin(w1, w2); // silently adjust right margins
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:54:46 +01:00
|
|
|
|
2016-09-20 11:12:44 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// read206
|
2016-12-23 15:27:57 +01:00
|
|
|
// import old version > 1.3 and < 3.x files
|
2016-09-13 09:39:50 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-09-19 13:25:54 +02:00
|
|
|
Score::FileError MasterScore::read206(XmlReader& e)
|
2016-09-13 09:39:50 +02:00
|
|
|
{
|
2017-10-13 12:12:11 +02:00
|
|
|
// qDebug("read206");
|
2017-01-23 21:53:51 +01:00
|
|
|
|
2016-09-22 10:03:59 +02:00
|
|
|
for (unsigned int i = 0; i < sizeof(style206)/sizeof(*style206); ++i)
|
2017-01-05 11:23:47 +01:00
|
|
|
style().set(style206[i].idx, style206[i].val);
|
2017-05-23 16:52:04 +02:00
|
|
|
|
2017-01-23 21:53:51 +01:00
|
|
|
|
2016-09-20 11:12:44 +02:00
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
if (tag == "programVersion") {
|
|
|
|
setMscoreVersion(e.readElementText());
|
|
|
|
parseVersion(mscoreVersion());
|
|
|
|
}
|
|
|
|
else if (tag == "programRevision")
|
2016-12-23 15:27:57 +01:00
|
|
|
setMscoreRevision(e.readIntHex());
|
2016-09-20 11:12:44 +02:00
|
|
|
else if (tag == "Score") {
|
|
|
|
if (!readScore(this, e))
|
|
|
|
return FileError::FILE_BAD_FORMAT;
|
|
|
|
}
|
|
|
|
else if (tag == "Revision") {
|
|
|
|
Revision* revision = new Revision;
|
|
|
|
revision->read(e);
|
|
|
|
revisions()->add(revision);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int id = 1;
|
|
|
|
for (LinkedElements* le : e.linkIds())
|
|
|
|
le->setLid(this, id++);
|
|
|
|
|
|
|
|
for (Staff* s : staves())
|
|
|
|
s->updateOttava();
|
|
|
|
|
2017-05-29 14:59:10 +02:00
|
|
|
// fix segment span
|
|
|
|
SegmentType st = SegmentType::BarLineType;
|
|
|
|
for (Segment* s = firstSegment(st); s; s = s->next1(st)) {
|
|
|
|
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
|
|
|
|
BarLine* b = toBarLine(s->element(staffIdx * VOICES));
|
|
|
|
if (!b)
|
|
|
|
continue;
|
|
|
|
int sp = b->spanStaff();
|
2018-11-23 10:45:58 +01:00
|
|
|
if (sp <= 0)
|
2017-05-29 14:59:10 +02:00
|
|
|
continue;
|
|
|
|
for (int span = 1; span <= sp; ++span) {
|
|
|
|
BarLine* nb = toBarLine(s->element((staffIdx + span) * VOICES));
|
|
|
|
if (!nb) {
|
|
|
|
nb = b->clone();
|
|
|
|
nb->setTrack((staffIdx + span) * VOICES);
|
|
|
|
s->add(nb);
|
|
|
|
}
|
|
|
|
nb->setSpanStaff(sp - span);
|
|
|
|
}
|
|
|
|
staffIdx += sp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
|
|
|
|
Staff* s = staff(staffIdx);
|
|
|
|
int sp = s->barLineSpan();
|
2018-11-23 10:45:58 +01:00
|
|
|
if (sp <= 0)
|
2017-05-29 14:59:10 +02:00
|
|
|
continue;
|
|
|
|
for (int span = 1; span <= sp; ++span) {
|
|
|
|
Staff* ns = staff(staffIdx + span);
|
|
|
|
ns->setBarLineSpan(sp - span);
|
|
|
|
}
|
|
|
|
staffIdx += sp;
|
|
|
|
}
|
|
|
|
|
2016-12-20 08:53:26 +01:00
|
|
|
// treat reading a 2.06 file as import
|
|
|
|
// on save warn if old file will be overwritten
|
|
|
|
setCreated(true);
|
2017-02-03 09:38:35 +01:00
|
|
|
// don't autosave (as long as there's no change to the score)
|
|
|
|
setAutosaveDirty(false);
|
2016-12-20 08:53:26 +01:00
|
|
|
|
2016-09-20 11:12:44 +02:00
|
|
|
return FileError::FILE_NO_ERROR;
|
2016-09-13 09:39:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|