fix #11687: displaying imported gp-dives as line segment

This commit is contained in:
Alexander Pavlov 2022-05-19 16:07:39 +03:00
parent 6eb6034bec
commit f640864759
17 changed files with 445 additions and 77 deletions

View file

@ -156,6 +156,8 @@ class Vibrato;
class VibratoSegment;
class PalmMute;
class PalmMuteSegment;
class WhammyBar;
class WhammyBarSegment;
class MeasureNumber;
class MMRestRange;
@ -369,6 +371,8 @@ public:
CONVERT(Vibrato, VIBRATO)
CONVERT(PalmMute, PALM_MUTE)
CONVERT(PalmMuteSegment, PALM_MUTE_SEGMENT)
CONVERT(WhammyBar, WHAMMY_BAR)
CONVERT(WhammyBarSegment, WHAMMY_BAR_SEGMENT)
CONVERT(VibratoSegment, VIBRATO_SEGMENT)
CONVERT(Symbol, SYMBOL)
CONVERT(FSymbol, FSYMBOL)
@ -417,6 +421,7 @@ public:
|| isTextLineSegment()
|| isOttavaSegment()
|| isPalmMuteSegment()
|| isWhammyBarSegment()
|| isPedalSegment()
|| isVoltaSegment()
;
@ -446,6 +451,7 @@ public:
|| isNoteLine()
|| isOttava()
|| isPalmMute()
|| isWhammyBar()
|| isPedal()
|| isTextLine()
|| isVolta()
@ -687,6 +693,8 @@ CONVERT(Vibrato)
CONVERT(VibratoSegment)
CONVERT(PalmMute)
CONVERT(PalmMuteSegment)
CONVERT(WhammyBar)
CONVERT(WhammyBarSegment)
CONVERT(Symbol)
CONVERT(FSymbol)
CONVERT(Fingering)

View file

@ -40,6 +40,7 @@
#include "tempochangeranged.h"
#include "vibrato.h"
#include "palmmute.h"
#include "whammybar.h"
#include "pedal.h"
#include "hairpin.h"
#include "keysig.h"
@ -169,6 +170,7 @@ static const ElementName elementNames[] = {
{ ElementType::TEMPO_RANGED_CHANGE_SEGMENT, "TempoChangeRangedSegment", QT_TRANSLATE_NOOP("elementName", "Tempo change ranged segment") },
{ ElementType::VIBRATO_SEGMENT, "VibratoSegment", QT_TRANSLATE_NOOP("elementName", "Vibrato segment") },
{ ElementType::PALM_MUTE_SEGMENT, "PalmMuteSegment", QT_TRANSLATE_NOOP("elementName", "Palm mute segment") },
{ ElementType::WHAMMY_BAR_SEGMENT, "WhammyBarSegment", QT_TRANSLATE_NOOP("elementName", "Whammy bar segment") },
{ ElementType::TEXTLINE_SEGMENT, "TextLineSegment", QT_TRANSLATE_NOOP("elementName", "Text line segment") },
{ ElementType::VOLTA_SEGMENT, "VoltaSegment", QT_TRANSLATE_NOOP("elementName", "Volta segment") },
{ ElementType::PEDAL_SEGMENT, "PedalSegment", QT_TRANSLATE_NOOP("elementName", "Pedal segment") },
@ -196,6 +198,7 @@ static const ElementName elementNames[] = {
{ ElementType::TEMPO_RANGED_CHANGE, "TempoChangeRanged", QT_TRANSLATE_NOOP("elementName", "Tempo changed ranged") },
{ ElementType::VIBRATO, "Vibrato", QT_TRANSLATE_NOOP("elementName", "Vibrato") },
{ ElementType::PALM_MUTE, "PalmMute", QT_TRANSLATE_NOOP("elementName", "Palm mute") },
{ ElementType::WHAMMY_BAR, "WhammyBar", QT_TRANSLATE_NOOP("elementName", "Whammy bar") },
{ ElementType::TEXTLINE, "TextLine", QT_TRANSLATE_NOOP("elementName", "Text line") },
{ ElementType::TEXTLINE_BASE, "TextLineBase", QT_TRANSLATE_NOOP("elementName", "Text line base") }, // remove
{ ElementType::NOTELINE, "NoteLine", QT_TRANSLATE_NOOP("elementName", "Note line") },
@ -245,6 +248,7 @@ EngravingItem* Factory::doCreateItem(ElementType type, EngravingItem* parent)
case ElementType::TEMPO_RANGED_CHANGE: return new TempoChangeRanged(parent);
case ElementType::VIBRATO: return new Vibrato(parent);
case ElementType::PALM_MUTE: return new PalmMute(parent);
case ElementType::WHAMMY_BAR: return new WhammyBar(parent);
case ElementType::PEDAL: return new Pedal(parent);
case ElementType::HAIRPIN: return new Hairpin(parent->isSegment() ? toSegment(parent) : dummy->segment());
case ElementType::CLEF: return new Clef(parent->isSegment() ? toSegment(parent) : dummy->segment());
@ -336,6 +340,7 @@ EngravingItem* Factory::doCreateItem(ElementType type, EngravingItem* parent)
case ElementType::TEMPO_RANGED_CHANGE_SEGMENT:
case ElementType::VIBRATO_SEGMENT:
case ElementType::PALM_MUTE_SEGMENT:
case ElementType::WHAMMY_BAR_SEGMENT:
case ElementType::VOLTA_SEGMENT:
case ElementType::PEDAL_SEGMENT:
case ElementType::LYRICSLINE_SEGMENT:
@ -733,6 +738,8 @@ CREATE_ITEM_IMPL(TempoChangeRanged, ElementType::TEMPO_RANGED_CHANGE, EngravingI
CREATE_ITEM_IMPL(PalmMute, ElementType::PALM_MUTE, EngravingItem, isAccessibleEnabled)
CREATE_ITEM_IMPL(WhammyBar, ElementType::WHAMMY_BAR, EngravingItem, isAccessibleEnabled)
CREATE_ITEM_IMPL(Volta, ElementType::VOLTA, EngravingItem, isAccessibleEnabled)
CREATE_ITEM_IMPL(Pedal, ElementType::PEDAL, EngravingItem, isAccessibleEnabled)

View file

@ -231,6 +231,8 @@ public:
static Ms::PalmMute* createPalmMute(Ms::EngravingItem* parent, bool isAccessibleEnabled = true);
static Ms::WhammyBar* createWhammyBar(Ms::EngravingItem* parent, bool isAccessibleEnabled = true);
static Ms::Volta* createVolta(Ms::EngravingItem* parent, bool isAccessibleEnabled = true);
static Ms::Pedal* createPedal(Ms::EngravingItem* parent, bool isAccessibleEnabled = true);

View file

@ -339,6 +339,8 @@ set(LIBMSCORE_SRC
${CMAKE_CURRENT_LIST_DIR}/vibrato.h
${CMAKE_CURRENT_LIST_DIR}/volta.cpp
${CMAKE_CURRENT_LIST_DIR}/volta.h
${CMAKE_CURRENT_LIST_DIR}/whammybar.cpp
${CMAKE_CURRENT_LIST_DIR}/whammybar.h
${CMAKE_CURRENT_LIST_DIR}/playtechannotation.cpp
${CMAKE_CURRENT_LIST_DIR}/playtechannotation.h
${CMAKE_CURRENT_LIST_DIR}/tempochangeranged.cpp

View file

@ -2039,6 +2039,7 @@ void Measure::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
case ElementType::TEMPO_RANGED_CHANGE:
case ElementType::VIBRATO:
case ElementType::PALM_MUTE:
case ElementType::WHAMMY_BAR:
case ElementType::VOLTA:
{
Spanner* sp = toSpanner(info->connector());

View file

@ -655,6 +655,7 @@ EngravingItem* Score::nextElement()
case ElementType::LET_RING_SEGMENT:
case ElementType::TEMPO_RANGED_CHANGE_SEGMENT:
case ElementType::PALM_MUTE_SEGMENT:
case ElementType::WHAMMY_BAR_SEGMENT:
case ElementType::PEDAL_SEGMENT: {
SpannerSegment* s = toSpannerSegment(e);
Spanner* sp = s->spanner();

View file

@ -576,6 +576,7 @@ void Score::readAddConnector(ConnectorInfoReader* info, bool pasteMode)
case ElementType::TEXTLINE:
case ElementType::VOLTA:
case ElementType::PALM_MUTE:
case ElementType::WHAMMY_BAR:
case ElementType::LET_RING:
case ElementType::TEMPO_RANGED_CHANGE:
case ElementType::VIBRATO:

View file

@ -1562,6 +1562,7 @@ void Score::addElement(EngravingItem* element)
case ElementType::LET_RING:
case ElementType::TEMPO_RANGED_CHANGE:
case ElementType::PALM_MUTE:
case ElementType::WHAMMY_BAR:
{
Spanner* spanner = toSpanner(element);
if (et == ElementType::TEXTLINE && spanner->anchor() == Spanner::Anchor::NOTE) {
@ -1717,6 +1718,7 @@ void Score::removeElement(EngravingItem* element)
case ElementType::LET_RING:
case ElementType::TEMPO_RANGED_CHANGE:
case ElementType::PALM_MUTE:
case ElementType::WHAMMY_BAR:
case ElementType::TEXTLINE:
case ElementType::HAIRPIN:
{

View file

@ -1131,6 +1131,7 @@ void System::add(EngravingItem* el)
case ElementType::LET_RING_SEGMENT:
case ElementType::TEMPO_RANGED_CHANGE_SEGMENT:
case ElementType::PALM_MUTE_SEGMENT:
case ElementType::WHAMMY_BAR_SEGMENT:
{
SpannerSegment* ss = toSpannerSegment(el);
#ifndef NDEBUG

View file

@ -112,6 +112,7 @@ enum class ElementType {
TEMPO_RANGED_CHANGE_SEGMENT,
VIBRATO_SEGMENT,
PALM_MUTE_SEGMENT,
WHAMMY_BAR_SEGMENT,
TEXTLINE_SEGMENT,
VOLTA_SEGMENT,
PEDAL_SEGMENT,
@ -139,6 +140,7 @@ enum class ElementType {
TEMPO_RANGED_CHANGE,
VIBRATO,
PALM_MUTE,
WHAMMY_BAR,
TEXTLINE,
TEXTLINE_BASE,
NOTELINE,

View file

@ -0,0 +1,276 @@
/*
* 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 "whammybar.h"
#include "rw/xml.h"
#include "system.h"
#include "measure.h"
#include "chordrest.h"
#include "score.h"
using namespace mu;
using namespace mu::engraving;
namespace Ms {
static const ElementStyle whammyBarStyle {
{ Sid::letRingFontFace, Pid::BEGIN_FONT_FACE },
{ Sid::letRingFontFace, Pid::CONTINUE_FONT_FACE },
{ Sid::letRingFontFace, Pid::END_FONT_FACE },
{ Sid::letRingFontSize, Pid::BEGIN_FONT_SIZE },
{ Sid::letRingFontSize, Pid::CONTINUE_FONT_SIZE },
{ Sid::letRingFontSize, Pid::END_FONT_SIZE },
{ Sid::letRingFontStyle, Pid::BEGIN_FONT_STYLE },
{ Sid::letRingFontStyle, Pid::CONTINUE_FONT_STYLE },
{ Sid::letRingFontStyle, Pid::END_FONT_STYLE },
{ Sid::letRingTextAlign, Pid::BEGIN_TEXT_ALIGN },
{ Sid::letRingTextAlign, Pid::CONTINUE_TEXT_ALIGN },
{ Sid::letRingTextAlign, Pid::END_TEXT_ALIGN },
{ Sid::letRingHookHeight, Pid::BEGIN_HOOK_HEIGHT },
{ Sid::letRingHookHeight, Pid::END_HOOK_HEIGHT },
{ Sid::letRingLineStyle, Pid::LINE_STYLE },
{ Sid::letRingBeginTextOffset, Pid::BEGIN_TEXT_OFFSET },
{ Sid::letRingEndHookType, Pid::END_HOOK_TYPE },
{ Sid::letRingLineWidth, Pid::LINE_WIDTH },
{ Sid::ottava8VAPlacement, Pid::PLACEMENT }
};
WhammyBarSegment::WhammyBarSegment(WhammyBar* sp, System* parent)
: TextLineBaseSegment(ElementType::WHAMMY_BAR_SEGMENT, sp, parent, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
{
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void WhammyBarSegment::layout()
{
TextLineBaseSegment::layout();
autoplaceSpannerSegment();
}
//---------------------------------------------------------
// WhammyBar
//---------------------------------------------------------
WhammyBar::WhammyBar(EngravingItem* parent)
: TextLineBase(ElementType::WHAMMY_BAR, parent)
{
initElementStyle(&whammyBarStyle);
resetProperty(Pid::LINE_VISIBLE);
resetProperty(Pid::BEGIN_TEXT_PLACE);
resetProperty(Pid::BEGIN_TEXT);
resetProperty(Pid::CONTINUE_TEXT_PLACE);
resetProperty(Pid::CONTINUE_TEXT);
resetProperty(Pid::END_TEXT_PLACE);
resetProperty(Pid::END_TEXT);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void WhammyBar::read(XmlReader& e)
{
if (score()->mscVersion() < 301) {
e.context()->addSpanner(e.intAttribute("id", -1), this);
}
while (e.readNextStartElement()) {
if (readProperty(e.name(), e, Pid::LINE_WIDTH)) {
setPropertyFlags(Pid::LINE_WIDTH, PropertyFlags::UNSTYLED);
} else if (!TextLineBase::readProperties(e)) {
e.unknown();
}
}
}
static const ElementStyle whammyBarSegmentStyle {
{ Sid::letRingMinDistance, Pid::MIN_DISTANCE },
};
//---------------------------------------------------------
// createLineSegment
//---------------------------------------------------------
LineSegment* WhammyBar::createLineSegment(System* parent)
{
WhammyBarSegment* wb = new WhammyBarSegment(this, parent);
wb->setTrack(track());
wb->initElementStyle(&whammyBarSegmentStyle);
return wb;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
PropertyValue WhammyBar::propertyDefault(Pid propertyId) const
{
switch (propertyId) {
case Pid::LINE_WIDTH:
return score()->styleV(Sid::letRingLineWidth);
case Pid::ALIGN:
return Align(AlignH::LEFT, AlignV::BASELINE);
case Pid::LINE_STYLE:
return score()->styleV(Sid::letRingLineStyle);
case Pid::LINE_VISIBLE:
return true;
case Pid::CONTINUE_TEXT_OFFSET:
case Pid::END_TEXT_OFFSET:
return PropertyValue::fromValue(PointF(0, 0));
case Pid::BEGIN_FONT_STYLE:
return score()->styleV(Sid::letRingFontStyle);
case Pid::BEGIN_TEXT:
return PropertyValue::fromValue("w/bar"); // TODO: fix the style
case Pid::CONTINUE_TEXT:
case Pid::END_TEXT:
return "";
case Pid::BEGIN_HOOK_TYPE:
return HookType::NONE;
case Pid::BEGIN_TEXT_PLACE:
case Pid::CONTINUE_TEXT_PLACE:
case Pid::END_TEXT_PLACE:
return TextPlace::AUTO;
default:
return TextLineBase::propertyDefault(propertyId);
}
}
//---------------------------------------------------------
// getPropertyStyle
//---------------------------------------------------------
Sid WhammyBar::getPropertyStyle(Pid id) const
{
switch (id) {
case Pid::PLACEMENT:
return Sid::ottava8VAPlacement; // TODO: fix the style
case Pid::BEGIN_FONT_FACE:
return Sid::letRingFontFace;
case Pid::BEGIN_FONT_SIZE:
case Pid::CONTINUE_FONT_SIZE:
case Pid::END_FONT_SIZE:
return Sid::letRingFontSize;
case Pid::BEGIN_FONT_STYLE:
case Pid::CONTINUE_FONT_STYLE:
case Pid::END_FONT_STYLE:
return Sid::letRingFontStyle;
case Pid::BEGIN_TEXT_ALIGN:
case Pid::CONTINUE_TEXT_ALIGN:
case Pid::END_TEXT_ALIGN:
return Sid::letRingTextAlign;
case Pid::BEGIN_HOOK_HEIGHT:
case Pid::END_HOOK_HEIGHT:
return Sid::letRingHookHeight;
default:
break;
}
return TextLineBase::getPropertyStyle(id);
}
//---------------------------------------------------------
// linePos
// return System() coordinates
//---------------------------------------------------------
PointF WhammyBar::linePos(Grip grip, System** sys) const
{
qreal x = 0.0;
qreal nhw = score()->noteHeadWidth();
System* s = nullptr;
if (grip == Grip::START) {
ChordRest* c = toChordRest(startElement());
if (!c) {
return PointF();
}
s = c->segment()->system();
x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x();
if (c->isRest() && c->durationType() == DurationType::V_MEASURE) {
x -= c->x();
}
} else {
EngravingItem* e = endElement();
ChordRest* c = toChordRest(endElement());
if (!e || e == startElement() || (endHookType() == HookType::HOOK_90)) {
// pedal marking on single note or ends with non-angled hook:
// extend to next note or end of measure
Segment* seg = nullptr;
if (!e) {
seg = startSegment();
} else {
seg = c->segment();
}
if (seg) {
seg = seg->next();
for (; seg; seg = seg->next()) {
if (seg->segmentType() == SegmentType::ChordRest) {
// look for a chord/rest in any voice on this staff
bool crFound = false;
track_idx_t track = staffIdx() * VOICES;
for (voice_idx_t i = 0; i < VOICES; ++i) {
if (seg->element(track + i)) {
crFound = true;
break;
}
}
if (crFound) {
break;
}
} else if (seg->segmentType() == SegmentType::EndBarLine) {
break;
}
}
}
if (seg) {
s = seg->system();
x = seg->pos().x() + seg->measure()->pos().x() - nhw * 2;
}
} else if (c) {
s = c->segment()->system();
x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x();
if (c->isRest() && c->durationType() == DurationType::V_MEASURE) {
x -= c->x();
}
}
if (!s) {
Fraction t = tick2();
Measure* m = score()->tick2measure(t);
s = m->system();
x = m->tick2pos(t);
}
x += nhw;
}
*sys = s;
return PointF(x, 0);
}
}

View file

@ -0,0 +1,70 @@
/*
* 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/>.
*/
#ifndef __WHAMMYBAR_H__
#define __WHAMMYBAR_H__
#include "textlinebase.h"
namespace Ms {
class WhammyBar;
//---------------------------------------------------------
// @@ WhammyBarSegment
//---------------------------------------------------------
class WhammyBarSegment final : public TextLineBaseSegment
{
public:
WhammyBarSegment(WhammyBar* sp, System* parent);
WhammyBarSegment* clone() const override { return new WhammyBarSegment(*this); }
WhammyBar* whammyBar() const { return (WhammyBar*)spanner(); }
void layout() override;
friend class WhammyBar;
};
//---------------------------------------------------------
// @@ WhammyBar
//---------------------------------------------------------
class WhammyBar final : public TextLineBase
{
protected:
mu::PointF linePos(Grip, System**) const override;
public:
WhammyBar(EngravingItem* parent);
WhammyBar* clone() const override { return new WhammyBar(*this); }
void read(XmlReader&) override;
LineSegment* createLineSegment(System* parent) override;
mu::engraving::PropertyValue propertyDefault(Pid propertyId) const override;
Sid getPropertyStyle(Pid) const override;
};
} // namespace Ms
#endif

View file

@ -667,6 +667,9 @@ std::pair<int, std::shared_ptr<GPBeat> > GP67DomBuilder::createGPBeat(QDomNode*
beat->setLyrics(str.toStdString());
} else if (nodeName == "Ottavia") {
beat->setOttavaType(ottavaType(innerNode.toElement().text()));
} else if (nodeName == "Whammy" || nodeName == "WhammyExtend") {
// TODO-gp: implement dives
beat->setDive(true);
} else if (nodeName == "XProperties") {
readBeatXProperties(innerNode, beat.get());
} else if (sUnused.find(nodeName) != sUnused.end()) {

View file

@ -134,6 +134,9 @@ public:
void setId(int id) { _id = id; }
int id() const { return _id; }
void setDive(bool dive) { m_dive = dive; }
bool dive() const { return m_dive; }
const std::vector<std::shared_ptr<GPNote> >& notes() const { return _notes; }
//! NOTE В текущей версии GP 6.2.0 (и позднее) в биты записывается уже расставленная лирика,
@ -219,6 +222,7 @@ private:
Golpe m_golpe = Golpe::None;
Barre _barre;
double _arpeggioStretch = 0.0;
bool m_dive = false; // TODO-gp: implement dives
};
}

View file

@ -393,6 +393,7 @@ Fraction GPConverter::convertBeat(const GPBeat* beat, ChordRestContainer& graceG
addLyrics(beat, cr, ctx);
addLegato(beat, cr);
addOttava(beat, cr);
addDive(beat, cr);
ctx.curTick += cr->actualTicks();
@ -1551,93 +1552,49 @@ void GPConverter::addBend(const GPNote* gpnote, Note* note)
note->add(bend);
}
void GPConverter::addLetRing(const GPNote* gpnote, Note* note)
void GPConverter::addLineElement(Chord* chord, std::vector<TextLineBase*>& elements, ElementType type)
{
if (!gpnote->letRing()) {
return;
track_idx_t track = chord->track();
while (elements.size() < track + 1) {
elements.push_back(0);
}
track_idx_t track = note->track();
while (_letRings.size() < track + 1) {
_letRings.push_back(0);
}
Chord* chord = note->chord();
if (_letRings[track]) {
LetRing* lr = _letRings[track];
Chord* lastChord = toChord(lr->endCR());
if (elements[track]) {
auto elem = elements[track];
Chord* lastChord = toChord(elem->endCR());
if (lastChord == chord) {
return;
}
//
// extend the current "let ring" or start a new one
// extend the current element or start a new one
//
Fraction tick = chord->segment()->tick();
if (lr->tick2() < tick) {
_letRings[track] = 0;
if (elem->tick2() < tick) {
elements[track] = 0;
} else {
lr->setTick2(chord->tick() + chord->actualTicks());
lr->setEndElement(chord);
elem->setTick2(chord->tick() + chord->actualTicks());
elem->setEndElement(chord);
}
}
if (!_letRings[track]) {
LetRing* lr = Factory::createLetRing(_score->dummy());
_letRings[track] = lr;
if (!elements[track]) {
EngravingItem* engItem = Factory::createItem(type, _score->dummy());
TextLineBase* elem = dynamic_cast<TextLineBase*>(engItem);
if (!elem) {
qFatal("wrong type of imported element");
}
elements[track] = elem;
Segment* segment = chord->segment();
Fraction tick = segment->tick();
lr->setTick(tick);
lr->setTick2(tick + chord->actualTicks());
lr->setTrack(track);
lr->setTrack2(track);
lr->setStartElement(chord);
lr->setEndElement(chord);
_score->addElement(lr);
}
}
void GPConverter::addPalmMute(const GPNote* gpnote, Note* note)
{
if (!gpnote->palmMute()) {
return;
}
track_idx_t track = note->track();
while (_palmMutes.size() < track + 1) {
_palmMutes.push_back(0);
}
Chord* chord = note->chord();
if (_palmMutes[track]) {
PalmMute* pm = _palmMutes[track];
Chord* lastChord = toChord(pm->endCR());
if (lastChord == note->chord()) {
return;
}
//
// extend the current palm mute or start a new one
//
Fraction tick = note->chord()->segment()->tick();
if (pm->tick2() < tick) {
_palmMutes[track] = 0;
} else {
pm->setTick2(chord->tick() + chord->actualTicks());
pm->setEndElement(chord);
}
}
if (!_palmMutes[track]) {
PalmMute* pm = Factory::createPalmMute(_score->dummy());
_palmMutes[track] = pm;
Segment* segment = chord->segment();
Fraction tick = segment->tick();
pm->setTick(tick);
pm->setTick2(tick + chord->actualTicks());
pm->setTrack(track);
pm->setTrack2(track);
pm->setStartElement(chord);
pm->setEndElement(chord);
_score->addElement(pm);
elem->setTick(tick);
elem->setTick2(tick + chord->actualTicks());
elem->setTrack(track);
elem->setTrack2(track);
elem->setStartElement(chord);
elem->setEndElement(chord);
_score->addElement(elem);
}
}
@ -1937,6 +1894,27 @@ void GPConverter::addOttava(const GPBeat* gpb, ChordRest* cr)
}
}
void GPConverter::addLetRing(const GPNote* gpnote, Note* note)
{
if (gpnote->letRing()) {
addLineElement(note->chord(), m_letRings, ElementType::LET_RING);
}
}
void GPConverter::addPalmMute(const GPNote* gpnote, Note* note)
{
if (gpnote->palmMute()) {
addLineElement(note->chord(), m_palmMutes, ElementType::PALM_MUTE);
}
}
void GPConverter::addDive(const GPBeat* beat, ChordRest* cr)
{
if (beat->dive() && cr->type() == ElementType::CHORD) {
addLineElement(static_cast<Chord*>(cr), m_dives, ElementType::WHAMMY_BAR);
}
}
void GPConverter::addFretDiagram(const GPBeat* gpnote, ChordRest* cr, const Context& ctx)
{
static int last_idx = -1;

View file

@ -105,8 +105,7 @@ private:
void collectContinuousSlide(const GPNote* gpnote, Note* note);
void collectHammerOn(const GPNote* gpnote, Note* note);
void addBend(const GPNote* gpnote, Note* note);
void addLetRing(const GPNote* gpnote, Note* note);
void addPalmMute(const GPNote* gpnote, Note* note);
void addLineElement(Chord* chord, std::vector<TextLineBase*>& elements, ElementType type);
void setPitch(Note* note, const GPNote::MidiPitch& midiPitch);
int calculateDrumPitch(int element, int variation, const QString& instrumentName);
void addTextToNote(QString string, Note* note);
@ -121,6 +120,9 @@ private:
void addTimer(const GPBeat* beat, ChordRest* cr);
void addFreeText(const GPBeat* beat, ChordRest* cr);
void addTuplet(const GPBeat* beat, ChordRest* cr);
void addLetRing(const GPNote* gpnote, Note* note);
void addPalmMute(const GPNote* gpnote, Note* note);
void addDive(const GPBeat* beat, ChordRest* cr);
void setupTupletStyle(Tuplet* tuplet);
void addVibratoWTremBar(const GPBeat* beat, ChordRest* cr);
void addFadding(const GPBeat* beat, ChordRest* cr);
@ -157,8 +159,9 @@ private:
std::unordered_map<track_idx_t, GPBeat::DynamicType> _dynamics;
std::unordered_multimap<track_idx_t, Tie*> _ties; // map(track, tie)
std::unordered_map<track_idx_t, Slur*> _slurs; // map(track, slur)
std::vector<PalmMute*> _palmMutes;
std::vector<LetRing*> _letRings;
std::vector<TextLineBase*> m_palmMutes;
std::vector<TextLineBase*> m_letRings;
std::vector<TextLineBase*> m_dives;
std::vector<Vibrato*> _vibratos;
std::vector<Ottava*> _ottavas;
Volta* _lastVolta = nullptr;

View file

@ -114,6 +114,7 @@
#include "libmscore/letring.h"
#include "libmscore/tempochangeranged.h"
#include "libmscore/palmmute.h"
#include "libmscore/whammybar.h"
#include "libmscore/vibrato.h"
#include "musicxml.h"
@ -3957,7 +3958,7 @@ static void directionTag(XmlWriter& xml, Attributes& attr, EngravingItem const*
if (el->type() == ElementType::HAIRPIN || el->type() == ElementType::OTTAVA
|| el->type() == ElementType::PEDAL || el->type() == ElementType::TEXTLINE
|| el->type() == ElementType::LET_RING || el->type() == ElementType::PALM_MUTE
|| el->type() == ElementType::TEMPO_RANGED_CHANGE) {
|| el->type() == ElementType::WHAMMY_BAR || el->type() == ElementType::TEMPO_RANGED_CHANGE) {
// handle elements derived from SLine
// find the system containing the first linesegment
const SLine* sl = static_cast<const SLine*>(el);
@ -5747,6 +5748,9 @@ static void spannerStart(ExportMusicXml* exp, track_idx_t strack, track_idx_t et
case ElementType::PALM_MUTE:
exp->textLine(toPalmMute(e), sstaff, seg->tick());
break;
case ElementType::WHAMMY_BAR:
exp->textLine(toWhammyBar(e), sstaff, seg->tick());
break;
case ElementType::TRILL:
// ignore (written as <note><notations><ornaments><wavy-line>)
break;
@ -5807,6 +5811,9 @@ static void spannerStop(ExportMusicXml* exp, track_idx_t strack, track_idx_t etr
case ElementType::PALM_MUTE:
exp->textLine(toPalmMute(e), sstaff, Fraction(-1, 1));
break;
case ElementType::WHAMMY_BAR:
exp->textLine(toWhammyBar(e), sstaff, Fraction(-1, 1));
break;
case ElementType::TRILL:
// ignore (written as <note><notations><ornaments><wavy-line>
break;