Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MusicXML] add support for playing techniques #26037

Merged
merged 6 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
#include "engraving/dom/pedal.h"
#include "engraving/dom/pickscrape.h"
#include "engraving/dom/pitchspelling.h"
#include "engraving/dom/playtechannotation.h"
#include "engraving/dom/rasgueado.h"
#include "engraving/dom/rehearsalmark.h"
#include "engraving/dom/rest.h"
Expand Down Expand Up @@ -385,6 +386,7 @@ class ExportMusicXml : public muse::Injectable
void hairpin(Hairpin const* const hp, staff_idx_t staff, const Fraction& tick);
void ottava(Ottava const* const ot, staff_idx_t staff, const Fraction& tick);
void pedal(Pedal const* const pd, staff_idx_t staff, const Fraction& tick);
void playText(PlayTechAnnotation const* const annot, staff_idx_t staff);
void textLine(TextLineBase const* const tl, staff_idx_t staff, const Fraction& tick);
void dynamic(Dynamic const* const dyn, staff_idx_t staff);
void symbol(Symbol const* const sym, staff_idx_t staff);
Expand Down Expand Up @@ -467,6 +469,7 @@ class ExportMusicXml : public muse::Injectable
TrillHash m_trillStart;
TrillHash m_trillStop;
MusicXmlInstrumentMap m_instrMap;
PlayingTechniqueType m_currPlayTechnique;
};

//---------------------------------------------------------
Expand Down Expand Up @@ -5044,6 +5047,46 @@ void ExportMusicXml::tempoText(TempoText const* const text, staff_idx_t staff)
m_xml.endElement();
}

//---------------------------------------------------------
// playText
//---------------------------------------------------------

void ExportMusicXml::playText(PlayTechAnnotation const* const annot, staff_idx_t staff)
{
const int offset = calculateTimeDeltaInDivisions(annot->tick(), tick(), m_div);

if (annot->plainText() == "") {
// sometimes empty Texts are present, exporting would result
// in invalid MusicXML (as an empty direction-type would be created)
return;
}

directionTag(m_xml, m_attr, annot);
wordsMetronome(m_xml, m_score->style(), annot, offset);

const PlayingTechniqueType type = annot->techniqueType();
if (type == PlayingTechniqueType::Pizzicato) {
m_xml.tag("sound", { { "pizzicato", "yes" } });
} else if ((type != PlayingTechniqueType::Pizzicato) && (m_currPlayTechnique == PlayingTechniqueType::Pizzicato)) {
m_xml.tag("sound", { { "pizzicato", "no" } });
} else if ((type != PlayingTechniqueType::Undefined) && (type != PlayingTechniqueType::Natural)) {
m_xml.startElement("sound");
m_xml.startElement("play");
if (type == PlayingTechniqueType::Mute) {
m_xml.tag("mute", "on");
} else if (type == PlayingTechniqueType::Open) {
m_xml.tag("mute", "off");
} else {
m_xml.tag("other-play", { { "type", TConv::toXml(type) } }, TConv::userName(type).translated());
}
m_xml.endElement();
m_xml.endElement();
}
m_currPlayTechnique = type;

directionETag(m_xml, staff);
}

//---------------------------------------------------------
// words
//---------------------------------------------------------
Expand Down Expand Up @@ -6435,8 +6478,9 @@ static bool commonAnnotations(ExportMusicXml* exp, const EngravingItem* e, staff
exp->symbol(toSymbol(e), sstaff);
} else if (e->isTempoText()) {
exp->tempoText(toTempoText(e), sstaff);
} else if (e->isPlayTechAnnotation() || e->isCapo() || e->isStringTunings() || e->isStaffText()
|| e->isTripletFeel() || e->isText()
} else if (e->isPlayTechAnnotation()) {
exp->playText(toPlayTechAnnotation(e), sstaff);
} else if (e->isCapo() || e->isStringTunings() || e->isStaffText() || e->isTripletFeel() || e->isText()
|| e->isExpression() || (e->isInstrumentChange() && e->visible()) || e->isSticking()) {
exp->words(toTextBase(e), sstaff);
} else if (e->isDynamic()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3451,7 +3451,13 @@ void MusicXmlParserDirection::direction(const String& partId,
}
} else {
if (!m_wordsText.empty() || !m_metroText.empty()) {
const PlayingTechniqueType technique = getPlayingTechnique();
PlayingTechniqueType technique = PlayingTechniqueType::Undefined;
if (!m_play.empty()) {
technique = TConv::fromXml(m_play.toAscii().constChar(), PlayingTechniqueType::Undefined);
m_play.clear();
} else {
technique = getPlayingTechnique();
}
isExpressionText = m_wordsText.contains(u"<i>") && m_metroText.empty() && placement() == u"below";
if (isExpressionText) {
t = Factory::createExpression(m_score->dummy()->segment());
Expand Down Expand Up @@ -3570,7 +3576,7 @@ void MusicXmlParserDirection::direction(const String& partId,
}
}

if (!m_dynaVelocity.isEmpty()) {
if (!m_dynaVelocity.empty()) {
int dynaValue = round(m_dynaVelocity.toDouble() * 0.9);
if (dynaValue > 127) {
dynaValue = 127;
Expand Down Expand Up @@ -3935,7 +3941,43 @@ void MusicXmlParserDirection::sound()
m_tpoSound = m_e.doubleAttribute("tempo");
m_dynaVelocity = m_e.attribute("dynamics");

m_e.skipCurrentElement();
const String pizz = m_e.attribute("pizzicato");
if (pizz == u"yes") {
m_play = u"pizzicato";
} else if (pizz == u"no") {
m_play = u"natural";
}

while (m_e.readNextStartElement()) {
if (m_e.name() == "play") {
play();
} else {
skipLogCurrElem();
}
}
}

//---------------------------------------------------------
// play
//---------------------------------------------------------

/**
Parse the /score-partwise/part/measure/direction/sound/play node.
*/

void MusicXmlParserDirection::play()
{
while (m_e.readNextStartElement()) {
if (m_e.name() == "mute") {
const String muted = m_e.readText();
m_play = (muted == u"off") ? u"open" : u"mute";
} else if (m_e.name() == "other-play") {
m_play = m_e.attribute("type");
m_e.skipCurrentElement();
} else {
skipLogCurrElem();
}
}
}

//---------------------------------------------------------
Expand Down Expand Up @@ -7404,7 +7446,7 @@ void MusicXmlParserPass2::harmony(const String& partId, Measure* measure, const
FretDiagram* fd = nullptr;
Harmony* ha = Factory::createHarmony(m_score->dummy()->segment());
Fraction offset;
if (!placement.isEmpty()) {
if (!placement.empty()) {
ha->setPlacement(placement == "below" ? PlacementV::BELOW : PlacementV::ABOVE);
ha->setPropertyFlags(Pid::PLACEMENT, PropertyFlags::UNSTYLED);
ha->resetProperty(Pid::OFFSET);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ class MusicXmlParserDirection
std::vector<MusicXmlSpannerDesc>& stops);
muse::String metronome(double& r);
void sound();
void play();
void dynamics();
void otherDirection();
void handleRepeats(engraving::Measure* measure, const engraving::Fraction tick, bool& measureHasCoda, SegnoStack& segnos,
Expand Down Expand Up @@ -615,7 +616,6 @@ class MusicXmlParserDirection
muse::String m_metroText;
muse::String m_rehearsalText;
muse::String m_dynaVelocity;
muse::String m_tempo;
muse::String m_sndCoda;
muse::String m_sndDacapo;
muse::String m_sndDalsegno;
Expand All @@ -625,6 +625,7 @@ class MusicXmlParserDirection
muse::String m_codaId;
muse::String m_segnoId;
muse::String m_placement;
muse::String m_play;
bool m_hasDefaultY = false;
double m_defaultY = 0.0;
bool m_hasRelativeY = false;
Expand Down
Loading