Merge pull request #17664 from alexpavlov96/stretched_bend_config

gp-import: removed define for stretched bend, refactored stretched bend import
This commit is contained in:
Alexander Pavlov 2023-05-22 16:27:17 +03:00 committed by GitHub
commit a91cf02a6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 433 additions and 152 deletions

View file

@ -1266,13 +1266,13 @@ void Note::add(EngravingItem* e)
case ElementType::NOTEDOT:
_dots.push_back(toNoteDot(e));
break;
case ElementType::BEND:
case ElementType::STRETCHED_BEND:
m_bend = toStretchedBend(e);
m_bend = toBend(e);
// fallthrough
case ElementType::FINGERING:
case ElementType::IMAGE:
case ElementType::TEXT:
case ElementType::BEND:
_el.push_back(e);
break;
case ElementType::SYMBOL: {
@ -1325,13 +1325,13 @@ void Note::remove(EngravingItem* e)
_dots.pop_back();
break;
case ElementType::BEND:
case ElementType::STRETCHED_BEND:
m_bend = nullptr;
// fallthrough
case ElementType::TEXT:
case ElementType::IMAGE:
case ElementType::FINGERING:
case ElementType::BEND:
if (!_el.remove(e)) {
LOGD("Note::remove(): cannot find %s", e->typeName());
}

View file

@ -441,7 +441,7 @@ public:
void relateSlide(Note& start) { _relatedSlide = &start._attachedSlide; }
StretchedBend* bend() const { return m_bend; }
Bend* bend() const { return m_bend; }
bool isHammerOn() const { return _isHammerOn; }
void setIsHammerOn(bool hammerOn) { _isHammerOn = hammerOn; }
@ -508,7 +508,7 @@ private:
bool _play = true; ///< note is not played if false
mutable bool _mark = false; ///< for use in sequencer
bool _fixed = false; ///< for slash notation
StretchedBend* m_bend = nullptr;
Bend* m_bend = nullptr;
DirectionH _userMirror = DirectionH::AUTO; ///< user override of mirror
DirectionV _userDotPosition = DirectionV::AUTO; ///< user override of dot position

View file

@ -56,7 +56,7 @@ static int bendTone(int notePitch);
// static values
//---------------------------------------------------------
static constexpr double s_bendHeightMultiplier = .2; /// how much height differs for bend pitches
static constexpr double BEND_HEIGHT_MULTIPLIER = .2; /// how much height differs for bend pitches
//---------------------------------------------------------
// StretchedBend
@ -78,16 +78,7 @@ void StretchedBend::fillDrawPoints()
}
m_drawPoints.clear();
if (Tie* tie = toNote(parent())->tieBack()) {
Note* backTied = tie->startNote();
if (StretchedBend* lastBend = (backTied ? backTied->bend() : nullptr)) {
auto lastBendPoints = lastBend->m_drawPoints;
if (!lastBendPoints.empty() && lastBendPoints.back() == m_points[0].pitch) {
m_skipFirstPoint = true;
}
}
}
m_skipFirstPoint = firstPointShouldBeSkipped();
for (size_t i = 0; i < m_points.size(); i++) {
m_drawPoints.push_back(m_points[i].pitch);
@ -111,7 +102,7 @@ void StretchedBend::fillSegments()
PointF upBendDefaultSrc = PointF(m_noteWidth + m_spatium * .8, 0);
PointF downBendDefaultSrc = PointF(m_noteWidth * .5, -m_noteHeight * .5 - m_spatium * .2);
PointF src = m_drawPoints[0] == 0 ? upBendDefaultSrc : downBendDefaultSrc;
PointF src = m_drawPoints.at(0) == 0 ? upBendDefaultSrc : downBendDefaultSrc;
PointF dest(0, 0);
int lastPointPitch = m_drawPoints.back();
@ -121,8 +112,8 @@ void StretchedBend::fillSegments()
BendSegmentType prevLineType = BendSegmentType::NO_TYPE;
for (size_t pt = 0; pt < n - 1; pt++) {
int pitch = m_drawPoints[pt];
int nextPitch = m_drawPoints[pt + 1];
int pitch = m_drawPoints.at(pt);
int nextPitch = m_drawPoints.at(pt + 1);
BendSegmentType type = BendSegmentType::NO_TYPE;
int tone = bendTone(nextPitch);
@ -148,7 +139,7 @@ void StretchedBend::fillSegments()
bool bendUp = pitch < nextPitch;
if (bendUp && isPrevBendUp && pt > 0) {
// prevent double bendUp rendering
int prevBendPitch = m_drawPoints[pt - 1];
int prevBendPitch = m_drawPoints.at(pt - 1);
// remove prev segment if there are two bendup in a row
if (!m_bendSegments.empty()) {
m_bendSegments.pop_back();
@ -356,33 +347,6 @@ void StretchedBend::setupPainter(mu::draw::Painter* painter) const
painter->setFont(f);
}
//---------------------------------------------------------
// glueNeighbor
//---------------------------------------------------------
void StretchedBend::glueNeighbor()
{
if (m_reduntant) {
return;
}
std::vector<Note*> ties = toNote(parent())->tiedNotes();
for (Note* t : ties) {
assert(!!t);
if (t->bend() && t != parent()) {
auto bend = t->bend();
auto& lastPoints = bend->points();
for (size_t i = 1; i < lastPoints.size(); ++i) {
m_points.push_back(lastPoints[i]);
}
t->remove(bend);
bend->m_reduntant = true;
}
}
}
//---------------------------------------------------------
// fillArrows
//---------------------------------------------------------
@ -447,7 +411,7 @@ double StretchedBend::nextSegmentX() const
}
//---------------------------------------------------------
// bendPitch
// bendTone
//---------------------------------------------------------
int bendTone(int notePitch)
@ -461,13 +425,40 @@ int bendTone(int notePitch)
double StretchedBend::bendHeight(int bendIdx) const
{
return m_spatium * (bendIdx + 1) * s_bendHeightMultiplier;
return m_spatium * (bendIdx + 1) * BEND_HEIGHT_MULTIPLIER;
}
//---------------------------------------------------------
// prepareBends
//---------------------------------------------------------
void StretchedBend::prepareBends(std::vector<StretchedBend*>& bends)
{
for (StretchedBend* bend : bends) {
bend->fillDrawPoints();
}
}
//---------------------------------------------------------
// firstPointShouldBeSkipped
//---------------------------------------------------------
bool StretchedBend::firstPointShouldBeSkipped() const
{
if (Tie* tie = toNote(parent())->tieBack()) {
Note* backTied = tie->startNote();
if (Bend* lastBend = (backTied ? backTied->bend() : nullptr)) {
if (lastBend && lastBend->isStretchedBend()) {
StretchedBend* lastStretchedBend = toStretchedBend(lastBend);
const auto& lastBendPoints = lastStretchedBend->m_drawPoints;
if (!lastBendPoints.empty() && lastBendPoints.back() == m_points.at(0).pitch) {
return true;
}
}
}
}
return false;
}
}

View file

@ -54,7 +54,6 @@ private:
void fillDrawPoints(); // filling the points which specify how bend will be drawn
void fillSegments(); // converting points from file to bend segments
void stretchSegments(); // stretching until end of chord duration
void glueNeighbor(); // fixing the double appearance of some bends
void layoutDraw(const bool layoutMode, mu::draw::Painter* painter = nullptr) const; /// loop for both layout and draw logic
@ -62,8 +61,7 @@ private:
void fillArrows();
double nextSegmentX() const;
double bendHeight(int bendIdx) const;
bool m_reduntant = false; // marks that the bend was 'glued' to neighbour and is now unnecessary
bool firstPointShouldBeSkipped() const;
bool m_stretchedMode = false; // layout with fixed size or stretched to next segment

View file

@ -50,12 +50,7 @@
#include "libmscore/tripletfeel.h"
#include "libmscore/tuplet.h"
#include "libmscore/volta.h"
#ifdef ENGRAVING_USE_STRETCHED_BENDS
#include "libmscore/stretchedbend.h"
#else
#include "libmscore/bend.h"
#endif
#include "types/symid.h"
@ -285,6 +280,7 @@ GPConverter::GPConverter(Score* score, std::unique_ptr<GPDomModel>&& gpDom)
_drumResolver = std::make_unique<GPDrumSetResolver>();
_drumResolver->initGPDrum();
m_useStretchedBends = engravingConfiguration()->guitarProImportExperimental();
}
const std::unique_ptr<GPDomModel>& GPConverter::gpDom() const
@ -391,13 +387,8 @@ void GPConverter::convert(const std::vector<std::unique_ptr<GPMasterBar> >& mast
}
addTempoMap();
addInstrumentChanges();
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend::prepareBends(m_bends);
#endif
StretchedBend::prepareBends(m_stretchedBends);
addFermatas();
addContinuousSlideHammerOn();
}
@ -1901,27 +1892,20 @@ void GPConverter::collectHammerOn(const GPNote* gpnote, Note* note)
void GPConverter::addBend(const GPNote* gpnote, Note* note)
{
if (!gpnote->bend()) {
if (!gpnote->bend() || gpnote->bend()->isEmpty()) {
return;
}
if (gpnote->bend()->isEmpty()) {
return;
}
using namespace mu::engraving;
auto gpTimeToMuTime = [] (float time) {
return time * PitchValue::MAX_TIME / 100;
};
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend* bend = mu::engraving::Factory::createStretchedBend(note);
#else
Bend* bend = mu::engraving::Factory::createBend(note);
#endif
Bend* bend = m_useStretchedBends ? Factory::createStretchedBend(note) : Factory::createBend(note);
const GPNote::Bend* gpBend = gpnote->bend();
auto gpBend = gpnote->bend();
bool bendHasMiddleValue{ true };
bool bendHasMiddleValue = true;
if (gpBend->middleOffset1 == 12 || gpBend->middleOffset2 == 12) {
bendHasMiddleValue = false;
}
@ -1935,6 +1919,7 @@ void GPConverter::addBend(const GPNote* gpnote, Note* note)
gpBend->middleOffset1 >= 0 && gpBend->middleOffset1 < gpBend->destinationOffset && value != lastPoint) {
bend->points().push_back(std::move(value));
}
if (PitchValue value(gpTimeToMuTime(gpBend->middleOffset2), gpBend->middleValue);
gpBend->middleOffset2 >= 0 && gpBend->middleOffset2 != gpBend->middleOffset1
&& gpBend->middleOffset2 < gpBend->destinationOffset
@ -1965,7 +1950,12 @@ void GPConverter::addBend(const GPNote* gpnote, Note* note)
bend->setTrack(note->track());
note->add(bend);
m_bends.push_back(bend);
if (m_useStretchedBends) {
m_stretchedBends.push_back(toStretchedBend(bend));
} else {
m_bends.push_back(bend);
}
}
void GPConverter::buildContiniousElement(ChordRest* cr, std::vector<SLine*>& elements, ElementType muType, LineImportType importType,

View file

@ -265,11 +265,9 @@ private:
static constexpr int LOWEST_BASE = 1024;
} m_nextTupletInfo;
#ifdef ENGRAVING_USE_STRETCHED_BENDS
std::vector<StretchedBend*> m_bends;
#else
std::vector<Bend*> m_bends;
#endif
std::vector<StretchedBend*> m_stretchedBends;
bool m_useStretchedBends = false;
static constexpr voice_idx_t VOICES = 4;

View file

@ -1141,10 +1141,7 @@ bool GuitarPro4::read(IODevice* io)
}
}
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend::prepareBends(m_bends);
#endif
StretchedBend::prepareBends(m_stretchedBends);
return true;
}
}

View file

@ -997,10 +997,7 @@ bool GuitarPro5::read(IODevice* io)
}
}
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend::prepareBends(m_bends);
#endif
StretchedBend::prepareBends(m_stretchedBends);
return true;
}
@ -1013,11 +1010,12 @@ bool GuitarPro5::readNoteEffects(Note* note)
uint8_t modMask1 = readUInt8();
uint8_t modMask2 = readUInt8();
bool slur = false;
bool addBendToHarmonic = false;
std::vector<PitchValue> bendData;
Note* bendParent = nullptr;
if (modMask1 & EFFECT_BEND) {
addBendToHarmonic = true;
readBend(note);
bendData = readBendDataFromFile();
bendParent = note;
}
if (modMask1 & EFFECT_HAMMER) {
slur = true;
@ -1148,34 +1146,12 @@ bool GuitarPro5::readNoteEffects(Note* note)
note->attachSlide(sl);
}
if (false && !slideList.empty() && slideList.back()->chord()->segment() != note->chord()->segment()) {
Note* start = slideList.front();
slideList.pop_front();
bool skip = false;
for (auto e : start->el()) {
if (e->isChordLine()) {
skip = true;
}
}
if (!skip) {
Glissando* s = new Glissando(start);
s->setAnchor(Spanner::Anchor::NOTE);
s->setStartElement(start);
s->setTick(start->chord()->segment()->tick());
s->setTrack(start->staffIdx());
s->setParent(start);
s->setGlissandoType(GlissandoType::STRAIGHT);
s->setEndElement(note);
s->setTick2(note->chord()->segment()->tick());
s->setTrack2(note->staffIdx());
score->addElement(s);
}
}
if (slideKind & LEGATO_SLIDE) {
slideKind &= ~LEGATO_SLIDE;
slideList.push_back(nullptr);
createSlur(true, note->staffIdx(), note->chord());
}
if (slideKind & SHIFT_SLIDE) {
slideKind &= ~SHIFT_SLIDE;
slideList.push_back(note);
@ -1278,12 +1254,16 @@ bool GuitarPro5::readNoteEffects(Note* note)
addTextToNote(harmonicText, harmonicNote);
if (addBendToHarmonic) {
harmonicNote->add(note->bend()->clone());
if (!bendData.empty()) {
bendParent = harmonicNote;
}
}
}
if (bendParent) {
createBend(bendParent, bendData);
}
if (modMask2 & 0x40) {
addVibrato(note);
}

View file

@ -733,6 +733,45 @@ void GuitarPro::readVolta(GPVolta* gpVolta, Measure* m)
}
}
std::vector<PitchValue> GuitarPro::readBendDataFromFile()
{
std::vector<PitchValue> bendData;
readUInt8(); // icon
/*int amplitude =*/ readInt(); // shown amplitude
int numPoints = readInt(); // the number of points in the bend
for (int i = 0; i < numPoints; ++i) {
int bendTime = readInt();
int bendPitch = readInt();
int bendVibrato = readUInt8();
bendData.emplace_back(bendTime, bendPitch, bendVibrato);
}
return bendData;
}
void GuitarPro::createBend(Note* note, std::vector<PitchValue>& bendData)
{
using namespace mu::engraving;
if (bendData.empty()) {
return;
}
bool useStretchedBends = engravingConfiguration()->guitarProImportExperimental();
Bend* bend = useStretchedBends ? Factory::createStretchedBend(note) : Factory::createBend(note);
bend->points() = std::move(bendData);
bend->setTrack(note->track());
note->add(bend);
if (useStretchedBends) {
m_stretchedBends.push_back(toStretchedBend(bend));
} else {
m_bends.push_back(bend);
}
}
//---------------------------------------------------------
// readBend
// bend graph
@ -740,32 +779,8 @@ void GuitarPro::readVolta(GPVolta* gpVolta, Measure* m)
void GuitarPro::readBend(Note* note)
{
readUInt8(); // icon
/*int amplitude =*/ readInt(); // shown amplitude
int numPoints = readInt(); // the number of points in the bend
// there are no notes in the bend, exit the function
if (numPoints == 0) {
return;
}
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend* bend = Factory::createStretchedBend(note);
#else
Bend* bend = Factory::createBend(note);
#endif
//TODO-ws bend->setNote(note);
for (int i = 0; i < numPoints; ++i) {
int bendTime = readInt();
int bendPitch = readInt();
int bendVibrato = readUInt8();
bend->points().push_back(PitchValue(bendTime, bendPitch, bendVibrato));
}
//TODO-ws bend->setAmplitude(amplitude);
bend->setTrack(note->track());
note->add(bend);
m_bends.push_back(bend);
std::vector<PitchValue> bendData = readBendDataFromFile();
createBend(note, bendData);
}
//---------------------------------------------------------
@ -2734,10 +2749,7 @@ bool GuitarPro3::read(IODevice* io)
}
}
#ifdef ENGRAVING_USE_STRETCHED_BENDS
StretchedBend::prepareBends(m_bends);
#endif
StretchedBend::prepareBends(m_stretchedBends);
return true;
}

View file

@ -236,12 +236,8 @@ protected:
int slide = 0;
int voltaSequence = 0;
Slur** slurs { nullptr };
#ifdef ENGRAVING_USE_STRETCHED_BENDS
std::vector<StretchedBend*> m_bends;
#else
std::vector<Bend*> m_bends;
#endif
std::vector<StretchedBend*> m_stretchedBends;
void skip(int64_t len);
void read(void* p, int64_t len);
@ -254,7 +250,9 @@ protected:
int readInt();
String readDelphiString();
void readVolta(GPVolta*, Measure*);
virtual void readBend(Note*);
void readBend(Note*);
std::vector<PitchValue> readBendDataFromFile();
void createBend(Note* note, std::vector<PitchValue>& bendData);
virtual bool readMixChange(Measure* measure);
virtual int readBeatEffects(int track, Segment*) = 0;
void readLyrics();

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.00">
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Dis. Rhy.</trackName>
<Instrument id="electric-guitar">
<longName>Dis. Rhy.</longName>
<shortName>dist.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar.electric</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="30"/>
<controller ctrl="7" value="71"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<Text>
<style>title</style>
<text>Cemetary Gates</text>
</Text>
<Text>
<style>subtitle</style>
<text>:)
Pantera
Cowboys From Hell</text>
</Text>
<Text>
<style>composer</style>
<text>Music by Pantera</text>
</Text>
<Text>
<style>poet</style>
<text>Words by Pantera</text>
</Text>
</VBox>
<Measure>
<voice>
<KeySig>
<accidental>0</accidental>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<Tempo>
<tempo>2.333333</tempo>
<text><sym>metNoteQuarterUp</sym> = 140</text>
</Tempo>
<Spanner type="HarmonicMark">
<HarmonicMark>
<beginText>AH</beginText>
<beginTextOffset x="0" y="0"/>
<continueText>AH</continueText>
</HarmonicMark>
<next>
<location>
<fractions>1/2</fractions>
</location>
</next>
</Spanner>
<Chord>
<durationType>half</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
<play>0</play>
<fret>4</fret>
<string>2</string>
</Note>
<Note>
<Bend>
<point time="0" pitch="50" vibrato="0"/>
<point time="30" pitch="50" vibrato="0"/>
<point time="60" pitch="50" vibrato="0"/>
</Bend>
<pitch>83</pitch>
<tpc>19</tpc>
<head>diamond</head>
<fret>4</fret>
<string>2</string>
</Note>
</Chord>
<Spanner type="HarmonicMark">
<prev>
<location>
<fractions>-1/2</fractions>
</location>
</prev>
</Spanner>
<Rest>
<durationType>half</durationType>
</Rest>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.00">
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<defaultClef>G8vb</defaultClef>
</Staff>
<trackName>Dis. Rhy.</trackName>
<Instrument id="electric-guitar">
<longName>Dis. Rhy.</longName>
<trackName></trackName>
<instrumentId>pluck.guitar.electric</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>30</frets>
<string>40</string>
<string>45</string>
<string>50</string>
<string>55</string>
<string>59</string>
<string>64</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="30"/>
<controller ctrl="7" value="39"/>
<controller ctrl="10" value="63"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<Text>
<style>title</style>
<text>Cemetary Gates</text>
</Text>
<Text>
<style>subtitle</style>
<text>:)
Pantera
Cowboys From Hell</text>
</Text>
<Text>
<style>composer</style>
<text>Pantera</text>
</Text>
</VBox>
<Measure>
<voice>
<KeySig>
<accidental>0</accidental>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<StaffText>
<text>AH</text>
</StaffText>
<Chord>
<durationType>half</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
<play>0</play>
<fret>4</fret>
<string>2</string>
</Note>
<Note>
<Bend>
<point time="0" pitch="50" vibrato="0"/>
<point time="60" pitch="50" vibrato="0"/>
</Bend>
<pitch>71</pitch>
<tpc>19</tpc>
<head>diamond</head>
<fret>4</fret>
<string>2</string>
</Note>
</Chord>
<Rest>
<durationType>half</durationType>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -201,6 +201,12 @@ TEST_F(GuitarPro_Tests, gp4Bend) {
TEST_F(GuitarPro_Tests, gp3Bend) {
gpReadTest("bend", "gp3");
}
TEST_F(GuitarPro_Tests, gpBendAndHarmonic) {
gpReadTest("bend_and_harmonic", "gp");
}
TEST_F(GuitarPro_Tests, gp5BendAndHarmonic) {
gpReadTest("bend_and_harmonic", "gp5");
}
TEST_F(GuitarPro_Tests, gpKeysig) {
gpReadTest("keysig", "gp");
}