added score write hook

This commit is contained in:
Igor Korsukov 2021-07-22 16:21:29 +02:00 committed by pereverzev+v
parent 73281014c3
commit 641a5bc566
20 changed files with 243 additions and 76 deletions

View file

@ -76,6 +76,10 @@ set(YOUTUBE_API_KEY "" CACHE STRING "YouTube API key")
option(USE_SCORE_ACCESSIBLE_TREE "Use score accessible tree" OFF)
# Temporary flags for MU3 compatibility to make testing easier.
option(ENGRAVING_COMPAT_WRITESTYLE_302 "Write style to score xml file" ON)
# -----
option(SOUNDFONT3 "Ogg Vorbis compressed fonts" ON) # Enable Ogg Vorbis compressed fonts, requires Ogg & Vorbis
option(DOWNLOAD_SOUNDFONT "Download the latest soundfont version as part of the build process" ON)

View file

@ -63,6 +63,7 @@
#cmakedefine BUILD_VST
#cmakedefine USE_SCORE_ACCESSIBLE_TREE
#cmakedefine ENGRAVING_COMPAT_WRITESTYLE_302
#cmakedefine WIN_SPARKLE_ENABLED
#cmakedefine MAC_SPARKLE_ENABLED

View file

@ -100,10 +100,12 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/compat/pageformat.h
${CMAKE_CURRENT_LIST_DIR}/compat/chordlist.cpp
${CMAKE_CURRENT_LIST_DIR}/compat/chordlist.h
${CMAKE_CURRENT_LIST_DIR}/compat/readscore.cpp
${CMAKE_CURRENT_LIST_DIR}/compat/readscore.h
${CMAKE_CURRENT_LIST_DIR}/compat/readstyle.cpp
${CMAKE_CURRENT_LIST_DIR}/compat/readstyle.h
${CMAKE_CURRENT_LIST_DIR}/compat/readscorehook.cpp
${CMAKE_CURRENT_LIST_DIR}/compat/readscorehook.h
${CMAKE_CURRENT_LIST_DIR}/compat/writescorehook.cpp
${CMAKE_CURRENT_LIST_DIR}/compat/writescorehook.h
${CMAKE_CURRENT_LIST_DIR}/style/styledef.cpp
${CMAKE_CURRENT_LIST_DIR}/style/styledef.h

View file

@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA 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 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "readscorehook.h"
#include "readstyle.h"
#include "libmscore/score.h"
#include "libmscore/scorefont.h"
using namespace mu::engraving::compat;
using namespace Ms;
void ReadScoreHook::installReadStyleHook(Ms::MasterScore* score, const QByteArray& scoreData, const QString& completeBaseName)
{
m_readStyle = std::make_shared<ReadStyleHook>(score, scoreData, completeBaseName);
}
void ReadScoreHook::setupDefaultStyle()
{
if (!m_readStyle) {
return;
}
m_readStyle->setupDefaultStyle();
}
void ReadScoreHook::onReadStyleTag302(Ms::Score* score, Ms::XmlReader& xml)
{
if (!m_readStyle) {
return;
}
qreal sp = score->style().value(Sid::spatium).toDouble();
compat::ReadStyleHook::readStyleTag(score, xml);
// if (_layoutMode == LayoutMode::FLOAT || _layoutMode == LayoutMode::SYSTEM) {
if (score->_layoutMode == LayoutMode::FLOAT) {
// style should not change spatium in
// float mode
score->style().set(Sid::spatium, sp);
}
score->_scoreFont = ScoreFont::fontByName(score->style().value(Sid::MusicalSymbolFont).toString());
}

View file

@ -19,6 +19,34 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "readscore.h"
using namespace mu::engraving::compat;
#ifndef MU_ENGRAVING_READSCOREHOOK_H
#define MU_ENGRAVING_READSCOREHOOK_H
#include <memory>
#include <QByteArray>
#include <QString>
namespace Ms {
class MasterScore;
class Score;
class XmlReader;
}
namespace mu::engraving::compat {
class ReadStyleHook;
class ReadScoreHook
{
public:
// Style
void installReadStyleHook(Ms::MasterScore* score, const QByteArray& scoreData, const QString& completeBaseName);
void setupDefaultStyle();
void onReadStyleTag302(Ms::Score* score, Ms::XmlReader& xml);
private:
std::shared_ptr<ReadStyleHook> m_readStyle = nullptr;
};
}
#endif // MU_ENGRAVING_READSCOREHOOK_H

View file

@ -34,8 +34,9 @@ class MStyle;
}
namespace mu::engraving::compat {
struct ReadStyleHook
class ReadStyleHook
{
public:
ReadStyleHook(Ms::MasterScore* score, const QByteArray& scoreData, const QString& completeBaseName);
void setupDefaultStyle();

View file

@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore BVBA 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 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "writescorehook.h"
#include "libmscore/score.h"
#include "libmscore/xml.h"
#include "config.h"
using namespace mu::engraving::compat;
void WriteScoreHook::onWriteStyle302(Ms::Score* score, Ms::XmlWriter& xml)
{
bool isWriteStyle = false;
//! NOTE Write the style to the score file if the compatibility define is set
#ifdef ENGRAVING_COMPAT_WRITESTYLE_302
isWriteStyle = true;
#endif
//! NOTE If not the master score, because the Excerpts (parts) have not yet been write to separate files
if (!score->isMaster()) {
isWriteStyle = true;
}
//! NOTE If the test mode, because the tests have not yet been adapted to the new format
if (Ms::MScore::testMode) {
isWriteStyle = true;
}
if (score->isTopScore()) { // only top score (logic from 3.)
if (isWriteStyle) {
score->style().save(xml, true); // save only differences to buildin style (logic from 3.)
}
}
}

View file

@ -19,18 +19,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_ENGRAVING_WRITESCOREHOOK_H
#define MU_ENGRAVING_WRITESCOREHOOK_H
#ifndef MU_ENGRAVING_READSCORE_H
#define MU_ENGRAVING_READSCORE_H
#include <memory>
#include "readstyle.h"
namespace mu::engraving::compat {
struct ReadScoreHooks
{
std::shared_ptr<ReadStyleHook> readStyle = nullptr;
};
namespace Ms {
class Score;
class XmlWriter;
}
#endif // MU_ENGRAVING_READSCORE_H
namespace mu::engraving::compat {
class WriteScoreHook
{
public:
WriteScoreHook() = default;
void onWriteStyle302(Ms::Score* score, Ms::XmlWriter& xml);
};
}
#endif // MU_ENGRAVING_WRITESCOREHOOK_H

View file

@ -24,7 +24,7 @@
#include "style/defaultstyle.h"
#include "compat/chordlist.h"
#include "compat/readscore.h"
#include "compat/readscorehook.h"
#include "xml.h"
#include "score.h"
@ -50,7 +50,7 @@ namespace Ms {
// return false on error
//---------------------------------------------------------
bool Score::read(XmlReader& e, const compat::ReadScoreHooks& hooks)
bool Score::read(XmlReader& e, compat::ReadScoreHook& hooks)
{
// HACK
// style setting compatibility settings for minor versions
@ -111,17 +111,7 @@ bool Score::read(XmlReader& e, const compat::ReadScoreHooks& hooks)
} else if (tag == "markIrregularMeasures") {
_markIrregularMeasures = e.readInt();
} else if (tag == "Style") {
qreal sp = style().value(Sid::spatium).toDouble();
compat::ReadStyleHook::readStyleTag(this, e);
// if (_layoutMode == LayoutMode::FLOAT || _layoutMode == LayoutMode::SYSTEM) {
if (_layoutMode == LayoutMode::FLOAT) {
// style should not change spatium in
// float mode
style().set(Sid::spatium, sp);
}
_scoreFont = ScoreFont::fontByName(style().value(Sid::MusicalSymbolFont).toString());
hooks.onReadStyleTag302(this, e);
} else if (tag == "copyright" || tag == "rights") {
Text* text = new Text(this);
text->read(e);
@ -195,7 +185,7 @@ bool Score::read(XmlReader& e, const compat::ReadScoreHooks& hooks)
ex->setPartScore(s);
e.setLastMeasure(nullptr);
compat::ReadScoreHooks hooks;
compat::ReadScoreHook hooks;
s->read(e, hooks);
s->linkMeasures(m);
@ -344,7 +334,7 @@ void Score::linkMeasures(Score* score)
// read
//---------------------------------------------------------
bool MasterScore::read(XmlReader& e, const compat::ReadScoreHooks& hooks)
bool MasterScore::read(XmlReader& e, compat::ReadScoreHook& hooks)
{
if (!Score::read(e, hooks)) {
return false;
@ -379,7 +369,7 @@ void MasterScore::addMovement(MasterScore* score)
// read301
//---------------------------------------------------------
Score::FileError MasterScore::read302(XmlReader& e, const mu::engraving::compat::ReadScoreHooks& hooks)
Score::FileError MasterScore::read302(XmlReader& e, mu::engraving::compat::ReadScoreHook& hooks)
{
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());

View file

@ -34,7 +34,8 @@
#include "style/style.h"
#include "style/defaultstyle.h"
#include "compat/readscore.h"
#include "compat/readscorehook.h"
#include "compat/writescorehook.h"
#include "fermata.h"
#include "imageStore.h"
@ -2123,7 +2124,9 @@ MasterScore* MasterScore::clone()
xml.header();
xml.stag("museScore version=\"" MSC_VERSION "\"");
write(xml, false);
compat::WriteScoreHook hook;
write(xml, false, hook);
xml.etag();
buffer.close();
@ -2131,8 +2134,8 @@ MasterScore* MasterScore::clone()
QByteArray scoreData = buffer.buffer();
QString completeBaseName = masterScore()->fileInfo()->completeBaseName();
compat::ReadScoreHooks hooks;
hooks.readStyle = std::make_shared<compat::ReadStyleHook>(this, scoreData, completeBaseName);
compat::ReadScoreHook hooks;
hooks.installReadStyleHook(this, scoreData, completeBaseName);
XmlReader r(scoreData);
MasterScore* score = new MasterScore(style(), m_project);

View file

@ -56,7 +56,8 @@ class EngravingProject;
namespace mu::engraving::compat {
class ScoreAccess;
struct ReadScoreHooks;
class ReadScoreHook;
class WriteScoreHook;
}
namespace mu::score {
@ -458,6 +459,9 @@ public:
};
private:
friend class mu::engraving::compat::ReadScoreHook;
static std::set<Score*> validScores;
int _linkId { 0 };
MasterScore* _masterScore { 0 };
@ -649,7 +653,7 @@ public:
void removeStaff(Staff*);
void addMeasure(MeasureBase*, MeasureBase*);
void readStaff(XmlReader&);
bool read(XmlReader&, const mu::engraving::compat::ReadScoreHooks& hooks);
bool read(XmlReader&, mu::engraving::compat::ReadScoreHook& hooks);
void linkMeasures(Score* score);
Excerpt* excerpt() { return _excerpt; }
@ -703,10 +707,10 @@ public:
bool appendMeasuresFromScore(Score* score, const Fraction& startTick, const Fraction& endTick);
bool appendScore(Score*, bool addPageBreak = false, bool addSectionBreak = true);
void write(XmlWriter&, bool onlySelection);
void writeMovement(XmlWriter&, bool onlySelection);
void write(XmlWriter&, bool onlySelection, mu::engraving::compat::WriteScoreHook& hook);
void writeMovement(XmlWriter&, bool onlySelection, mu::engraving::compat::WriteScoreHook& hook);
bool writeScore(QIODevice* f, bool msczFormat, bool onlySelection = false);
bool writeScore(QIODevice* f, bool msczFormat, bool onlySelection, mu::engraving::compat::WriteScoreHook& hook);
QList<Staff*>& staves() { return _staves; }
const QList<Staff*>& staves() const { return _staves; }
@ -1402,17 +1406,17 @@ class MasterScore : public Score
QFileInfo _sessionStartBackupInfo;
QFileInfo info;
bool read(XmlReader&, const mu::engraving::compat::ReadScoreHooks& hooks);
FileError read1(XmlReader&, bool ignoreVersionError, const mu::engraving::compat::ReadScoreHooks& hooks);
bool read(XmlReader&, mu::engraving::compat::ReadScoreHook& hooks);
FileError read1(XmlReader&, bool ignoreVersionError, mu::engraving::compat::ReadScoreHook& hooks);
FileError read114(XmlReader&);
FileError read206(XmlReader&);
FileError read302(XmlReader&, const mu::engraving::compat::ReadScoreHooks& hooks);
FileError read302(XmlReader&, mu::engraving::compat::ReadScoreHook& hooks);
void setPrev(MasterScore* s) { _prev = s; }
void setNext(MasterScore* s) { _next = s; }
friend class mu::engraving::compat::ScoreAccess;
friend class mu::engraving::EngravingProject;
friend class mu::engraving::compat::ScoreAccess;
MasterScore(std::shared_ptr<mu::engraving::EngravingProject> project);
MasterScore(const MStyle&, std::shared_ptr<mu::engraving::EngravingProject> project);

View file

@ -24,6 +24,8 @@
#include <QRegularExpression>
#include "compat/writescorehook.h"
#include "duration.h"
#include "measure.h"
#include "score.h"
@ -36,6 +38,7 @@
#include <utility>
using namespace mu;
using namespace mu::engraving;
namespace Ms {
//---------------------------------------------------------
@ -761,7 +764,9 @@ static QString scoreToMscx(Score* s, XmlWriter& xml)
QString mscx;
xml.setString(&mscx, QIODevice::WriteOnly);
xml.setRecordElements(true);
s->write(xml, /* onlySelection */ false);
compat::WriteScoreHook hook;
s->write(xml, /* onlySelection */ false, hook);
xml.flush();
return mscx;
}

View file

@ -29,7 +29,8 @@
#include "style/defaultstyle.h"
#include "compat/chordlist.h"
#include "compat/readscore.h"
#include "compat/readscorehook.h"
#include "compat/writescorehook.h"
#include "config.h"
#include "score.h"
@ -101,7 +102,7 @@ static void writeMeasure(XmlWriter& xml, MeasureBase* m, int staffIdx, bool writ
// writeMovement
//---------------------------------------------------------
void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
void Score::writeMovement(XmlWriter& xml, bool selectionOnly, compat::WriteScoreHook& hook)
{
// if we have multi measure rests and some parts are hidden,
// then some layout information is missing:
@ -179,12 +180,7 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
xml.tag("Division", MScore::division);
xml.setCurTrack(-1);
if (isTopScore()) { // only top score
//! NOTE For the master score, the style is saved in a separate file
if (!isMaster() || MScore::testMode) {
style().save(xml, true); // save only differences to buildin style
}
}
hook.onWriteStyle302(this, xml);
xml.tag("showInvisible", _showInvisible);
xml.tag("showUnprintable", _showUnprintable);
@ -278,7 +274,7 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
if (!selectionOnly) {
for (const Excerpt* excerpt : excerpts()) {
if (excerpt->partScore() != this) {
excerpt->partScore()->write(xml, false); // recursion
excerpt->partScore()->write(xml, false, hook); // recursion
}
}
}
@ -296,7 +292,7 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly)
// write
//---------------------------------------------------------
void Score::write(XmlWriter& xml, bool selectionOnly)
void Score::write(XmlWriter& xml, bool selectionOnly, compat::WriteScoreHook& hook)
{
if (isMaster()) {
MasterScore* score = static_cast<MasterScore*>(this);
@ -304,11 +300,11 @@ void Score::write(XmlWriter& xml, bool selectionOnly)
score = score->prev();
}
while (score) {
score->writeMovement(xml, selectionOnly);
score->writeMovement(xml, selectionOnly, hook);
score = score->next();
}
} else {
writeMovement(xml, selectionOnly);
writeMovement(xml, selectionOnly, hook);
}
}
@ -414,7 +410,9 @@ bool Score::writeMscz(engraving::MscWriter& msczWriter, bool onlySelection, bool
QByteArray scoreData;
QBuffer scoreBuf(&scoreData);
scoreBuf.open(QIODevice::ReadWrite);
Score::writeScore(&scoreBuf, onlySelection);
compat::WriteScoreHook hook;
Score::writeScore(&scoreBuf, false, onlySelection, hook);
msczWriter.writeScoreFile(scoreData);
}
@ -550,7 +548,7 @@ bool Score::saveStyle(const QString& name)
//extern QString revision;
static QString revision;
bool Score::writeScore(QIODevice* f, bool msczFormat, bool onlySelection)
bool Score::writeScore(QIODevice* f, bool msczFormat, bool onlySelection, compat::WriteScoreHook& hook)
{
XmlWriter xml(this, f);
xml.setWriteOmr(msczFormat);
@ -562,7 +560,7 @@ bool Score::writeScore(QIODevice* f, bool msczFormat, bool onlySelection)
xml.tag("programVersion", VERSION);
xml.tag("programRevision", revision);
}
write(xml, onlySelection);
write(xml, onlySelection, hook);
xml.etag();
if (isMaster()) {
masterScore()->revisions()->write(xml);
@ -603,8 +601,8 @@ Score::FileError MasterScore::loadMscz(const mu::engraving::MscReader& mscReader
XmlReader e(scoreData);
e.setDocName(completeBaseName);
compat::ReadScoreHooks hooks;
hooks.readStyle = std::make_shared<compat::ReadStyleHook>(this, scoreData, completeBaseName);
compat::ReadScoreHook hooks;
hooks.installReadStyleHook(this, scoreData, completeBaseName);
retval = read1(e, ignoreVersionError, hooks);
}
@ -726,7 +724,7 @@ void MasterScore::parseVersion(const QString& val)
// return true on success
//---------------------------------------------------------
Score::FileError MasterScore::read1(XmlReader& e, bool ignoreVersionError, const mu::engraving::compat::ReadScoreHooks& hooks)
Score::FileError MasterScore::read1(XmlReader& e, bool ignoreVersionError, mu::engraving::compat::ReadScoreHook& hook)
{
while (e.readNextStartElement()) {
if (e.name() == "museScore") {
@ -746,9 +744,7 @@ Score::FileError MasterScore::read1(XmlReader& e, bool ignoreVersionError, const
}
}
if (hooks.readStyle) {
hooks.readStyle->setupDefaultStyle();
}
hook.setupDefaultStyle();
Score::FileError error;
if (mscVersion() <= 114) {
@ -756,7 +752,7 @@ Score::FileError MasterScore::read1(XmlReader& e, bool ignoreVersionError, const
} else if (mscVersion() <= 207) {
error = read206(e);
} else {
error = read302(e, hooks);
error = read302(e, hook);
}
setExcerptsChanged(false);
return error;

View file

@ -38,6 +38,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
#include "framework/global/globalmodule.h"
#include "framework/fonts/fontsmodule.h"
@ -143,7 +144,9 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
//---------------------------------------------------------

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
using namespace mu::engraving;
@ -85,7 +86,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
using namespace mu::engraving;
@ -83,7 +84,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
using namespace mu::engraving;
@ -79,7 +80,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
using namespace mu::engraving;
@ -90,7 +91,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
using namespace mu::engraving;
@ -82,7 +83,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)

View file

@ -32,6 +32,7 @@
#include "engraving/compat/mscxcompat.h"
#include "engraving/compat/scoreaccess.h"
#include "engraving/compat/writescorehook.h"
#include "importexport/musicxml/internal/musicxml/exportxml.h"
@ -95,7 +96,8 @@ bool MTest::saveScore(Score* score, const QString& name) const
if (!file.open(QIODevice::ReadWrite)) {
return false;
}
return score->Score::writeScore(&file, false);
compat::WriteScoreHook hook;
return score->writeScore(&file, false, false, hook);
}
bool MTest::compareFilesFromPaths(const QString& f1, const QString& f2)