fix #11687: displaying imported gp-dives as line segment
This commit is contained in:
parent
6eb6034bec
commit
f640864759
17 changed files with 445 additions and 77 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
276
src/engraving/libmscore/whammybar.cpp
Normal file
276
src/engraving/libmscore/whammybar.cpp
Normal 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);
|
||||
}
|
||||
}
|
70
src/engraving/libmscore/whammybar.h
Normal file
70
src/engraving/libmscore/whammybar.h
Normal 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
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue