diff --git a/libmscore/chordrest.cpp b/libmscore/chordrest.cpp index 6b0e109d72dd..6b922a80723c 100644 --- a/libmscore/chordrest.cpp +++ b/libmscore/chordrest.cpp @@ -773,11 +773,20 @@ Element* ChordRest::drop(const DropData& data) case Element::Type::BREATH: { Breath* b = static_cast(e); - b->setTrack(staffIdx() * VOICES); + int track = staffIdx() * VOICES; + b->setTrack(track); + + // find start tick of next note in staff +#if 0 + int bt = tick() + actualTicks(); // this could make sense if we allowed breath marks in voice > 1 +#else + Segment* next = segment()->nextCR(track); + int bt = next ? next->tick() : score()->lastSegment()->tick(); +#endif // TODO: insert automatically in all staves? - Segment* seg = m->undoGetSegment(Segment::Type::Breath, tick()); + Segment* seg = m->undoGetSegment(Segment::Type::Breath, bt); b->setParent(seg); score()->undoAddElement(b); } diff --git a/libmscore/measure.cpp b/libmscore/measure.cpp index b615f0adb878..0740e60a1eea 100644 --- a/libmscore/measure.cpp +++ b/libmscore/measure.cpp @@ -817,16 +817,17 @@ void Measure::add(Element* el) ; if (s) { if (st == Segment::Type::ChordRest) { + // add ChordRest segment after all other segments with same tick + // except EndBarLine while (s && s->segmentType() != st && s->tick() == t) { - if (s->segmentType() == Segment::Type::EndBarLine - || s->segmentType() == Segment::Type::Breath // place chord _before_ breath - ) { + if (s->segmentType() == Segment::Type::EndBarLine) { break; } s = s->next(); } } else { + // use order of segments in segment.h if (s && s->tick() == t) { while (s && s->segmentType() <= st) { if (s->next() && s->next()->tick() != t) @@ -834,11 +835,6 @@ void Measure::add(Element* el) s = s->next(); } } - // - // place breath _after_ chord - // - if (s && st == Segment::Type::Breath) - s = s->next(); } } seg->setParent(this); @@ -1941,10 +1937,25 @@ void Measure::read(XmlReader& e, int staffIdx) breath->setTrack(e.track()); int tick = e.tick(); breath->read(e); - if (e.tick() < tick) - tick = e.tick(); // use our own tick if we explicitly reset to earlier position - else - tick = lastTick; // otherwise use last tick (of previous tick, chord, or rest tag) + if (score()->mscVersion() < 205) { + // older scores placed the breath segment right after the chord to which it applies + // rather than before the next chordrest segment with an element for the staff + // result would be layout too far left if there are other segments due to notes in other staves + // we need to find tick of chord to which this applies, and add its duration + int prevTick; + if (e.tick() < tick) + prevTick = e.tick(); // use our own tick if we explicitly reset to earlier position + else + prevTick = lastTick; // otherwise use tick of previous tick/chord/rest tag + // find segment + Segment* prev = findSegment(Segment::Type::ChordRest, prevTick); + if (prev) { + // find chordrest + ChordRest* lastCR = static_cast(prev->element(e.track())); + if (lastCR) + tick = prevTick + lastCR->actualTicks(); + } + } segment = getSegment(Segment::Type::Breath, tick); segment->add(breath); } diff --git a/libmscore/mscore.h b/libmscore/mscore.h index fdef3fe80a90..2598dd47e9c1 100644 --- a/libmscore/mscore.h +++ b/libmscore/mscore.h @@ -15,8 +15,8 @@ namespace Ms { -#define MSC_VERSION "2.04" -static const int MSCVERSION = 204; +#define MSC_VERSION "2.05" +static const int MSCVERSION = 205; // History: // 1.3 added staff->_barLineSpan @@ -50,6 +50,7 @@ static const int MSCVERSION = 204; // 2.02 save instrumentId, note slashes // 2.03 save Box topGap, bottomGap in spatium units // 2.04 added hideSystemBarLine flag to Staff +// 2.05 breath segment changed to use tick of following chord rather than preceding chord diff --git a/libmscore/score.cpp b/libmscore/score.cpp index d63a76fdd6ca..5851277923d7 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -511,19 +511,12 @@ void Score::fixTicks() if (s->segmentType() == Segment::Type::Breath) { qreal length = 0.0; int tick = s->tick(); - // find breath elements + // find longest pause for (int i = 0, n = ntracks(); i < n; ++i) { Element* e = s->element(i); if (e && e->type() == Element::Type::BREATH) { Breath* b = static_cast(e); length = qMax(length, b->pause()); - // find start tick of next note - // currently, breaths are always added in voice 0 - Segment* next = s->nextCR(i); - if (next) - tick = qMax(tick, next->tick()); - else - tick = lastSegment()->tick(); } } if (length != 0.0) diff --git a/libmscore/segment.h b/libmscore/segment.h index 7c6c5160634c..27d360d63a8b 100644 --- a/libmscore/segment.h +++ b/libmscore/segment.h @@ -75,8 +75,8 @@ class Segment : public Element { TimeSig = 0x8, StartRepeatBarLine = 0x10, BarLine = 0x20, - ChordRest = 0x40, - Breath = 0x80, + Breath = 0x40, + ChordRest = 0x80, EndBarLine = 0x100, TimeSigAnnounce = 0x200, KeySigAnnounce = 0x400, diff --git a/libmscore/undo.cpp b/libmscore/undo.cpp index 9c026dbb67d0..13e5a1b5faf8 100644 --- a/libmscore/undo.cpp +++ b/libmscore/undo.cpp @@ -1267,6 +1267,9 @@ void Score::undoAddElement(Element* element) Breath* breath = static_cast(element); int tick = breath->segment()->tick(); Measure* m = score->tick2measure(tick); + // breath appears before barline + if (m->tick() == tick) + m = m->prevMeasure(); Segment* seg = m->undoGetSegment(Segment::Type::Breath, tick); Breath* nbreath = static_cast(ne); int ntrack = staffIdx * VOICES + nbreath->voice(); diff --git a/mscore/capella.cpp b/mscore/capella.cpp index 299aa05b3550..2f9455a82113 100644 --- a/mscore/capella.cpp +++ b/mscore/capella.cpp @@ -221,7 +221,7 @@ static void processBasicDrawObj(QList objects, Segment* s, int tr Breath* b = new Breath(score); b->setTrack(track); b->setBreathType(3); - Segment* seg = s->measure()->getSegment(Segment::Type::Breath, s->tick()); + Segment* seg = s->measure()->getSegment(Segment::Type::Breath, s->tick() + cr ? cr->actualTicks() : 0); seg->add(b); } break; diff --git a/mscore/exportxml.cpp b/mscore/exportxml.cpp index 338feca3d0ce..afe3c97fb700 100644 --- a/mscore/exportxml.cpp +++ b/mscore/exportxml.cpp @@ -1685,12 +1685,9 @@ void ExportMusicXml::wavyLineStartStop(Chord* chord, Notations& notations, Ornam static Breath* hasBreathMark(Chord* ch) { - Segment* s = ch->segment(); - s = s->next1(); - Breath* b = 0; - if (s && s->segmentType() == Segment::Type::Breath) - b = static_cast(s->element(ch->track())); - return b; + int tick = ch->tick() + ch->actualTicks(); + Segment* s = ch->measure()->findSegment(Segment::Type::Breath, tick); + return s ? static_cast(s->element(ch->track())) : 0; } //--------------------------------------------------------- @@ -4698,12 +4695,9 @@ void ExportMusicXml::write(QIODevice* dev) continue; // generate backup or forward to the start time of the element - // but not for breath, which has the same start time as the - // previous note, while tick is already at the end of that note if (tick != seg->tick()) { attr.doAttr(xml, false); - if (el->type() != Element::Type::BREATH) - moveToTick(seg->tick()); + moveToTick(seg->tick()); } // handle annotations and spanners (directions attached to this note or rest) diff --git a/mscore/importove.cpp b/mscore/importove.cpp index bc1c05aa579f..4df8b398329f 100644 --- a/mscore/importove.cpp +++ b/mscore/importove.cpp @@ -1750,11 +1750,12 @@ void OveToMScore::convertArticulation( case OVE::ArticulationType::Pause :{ Breath* b = new Breath(score_); b->setTrack(track); - Segment* seg = measure->getSegment(Segment::Type::Breath, absTick); + Segment* seg = measure->getSegment(Segment::Type::Breath, absTick + cr ? cr->actualTicks() : 0); seg->add(b); break; } case OVE::ArticulationType::Grand_Pause :{ + // TODO? break; } case OVE::ArticulationType::Up_Bow :{ diff --git a/mscore/importxml.cpp b/mscore/importxml.cpp index 3c6c64d3e28b..49ab64a2a52f 100644 --- a/mscore/importxml.cpp +++ b/mscore/importxml.cpp @@ -5085,7 +5085,7 @@ void MusicXml::xmlNotations(Note* note, ChordRest* cr, int trk, int tick, int ti // b->setTrack(trk + voice); TODO check next line b->setTrack(track); b->setBreathType(breath); - Segment* seg = measure->getSegment(Segment::Type::Breath, tick); + Segment* seg = measure->getSegment(Segment::Type::Breath, tick + ticks); seg->add(b); } diff --git a/mtest/libmscore/CMakeLists.txt b/mtest/libmscore/CMakeLists.txt index 60b791162672..865e8db942fc 100644 --- a/mtest/libmscore/CMakeLists.txt +++ b/mtest/libmscore/CMakeLists.txt @@ -12,7 +12,7 @@ #============================================================================= subdirs( - album barline beam chordsymbol clef clef_courtesy compat concertpitch copypaste + album barline beam breath chordsymbol clef clef_courtesy compat concertpitch copypaste copypastesymbollist dynamic element hairpin instrumentchange join keysig layout parts measure midi note plugins repeat selectionfilter selectionrangedelete split splitstaff timesig tools transpose tuplet text ) diff --git a/mtest/libmscore/breath/CMakeLists.txt b/mtest/libmscore/breath/CMakeLists.txt new file mode 100644 index 000000000000..1c6a6bca5970 --- /dev/null +++ b/mtest/libmscore/breath/CMakeLists.txt @@ -0,0 +1,17 @@ +#============================================================================= +# MuseScore +# Music Composition & Notation +# $Id:$ +# +# Copyright (C) 2011 Werner Schweer +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation and appearing in +# the file LICENSE.GPL +#============================================================================= + +set(TARGET tst_breath) + +include(${PROJECT_SOURCE_DIR}/mtest/cmake.inc) + diff --git a/mtest/libmscore/breath/breath.mscx b/mtest/libmscore/breath/breath.mscx new file mode 100644 index 000000000000..2cefdbf88af5 --- /dev/null +++ b/mtest/libmscore/breath/breath.mscx @@ -0,0 +1,240 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + stdNormal + + + + Flute + + Flute + Fl. + Flute + 59 + 98 + 60 + 93 + wind.flutes.flute + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + stdNormal + + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + F + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + 0 + + + 4 + 4 + 1 + + + 1 + half + + 72 + 14 + + + + quarter + + 72 + 14 + + + + + + half + + 72 + 14 + + + + half + + 72 + 14 + + + + end + 1 + + + + + + + 4 + 4 + 1 + + + half + + 72 + 14 + + + + half + + 72 + 14 + + + + + + 1 + half + + 72 + 14 + + + + quarter + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/breath/breath01-ref.mscx b/mtest/libmscore/breath/breath01-ref.mscx new file mode 100644 index 000000000000..4552598f01ce --- /dev/null +++ b/mtest/libmscore/breath/breath01-ref.mscx @@ -0,0 +1,261 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + stdNormal + + + + Flute + + Flute + Fl. + Flute + 59 + 98 + 60 + 93 + wind.flutes.flute + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + stdNormal + + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + F + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + 4 + 4 + 1 + + + 1 + half + + 72 + 14 + + + + 0 + + + quarter + + 72 + 14 + + + + 0 + + + + + half + + 72 + 14 + + + + 0 + + + half + + 72 + 14 + + + + 0 + + + end + 1 + + + + + + + 4 + 4 + 1 + + + half + + 72 + 14 + + + + 0 + + + half + + 72 + 14 + + + + 0 + + + + + 1 + half + + 72 + 14 + + + + 0 + + + quarter + + 72 + 14 + + + + 0 + + + end + 1 + + + + + diff --git a/mtest/libmscore/breath/breath02-ref.mscx b/mtest/libmscore/breath/breath02-ref.mscx new file mode 100644 index 000000000000..ae2d5fc89775 --- /dev/null +++ b/mtest/libmscore/breath/breath02-ref.mscx @@ -0,0 +1,237 @@ + + + + + 0 + 480 + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + stdNormal + + + + Flute + + Flute + Fl. + Flute + 59 + 98 + 60 + 93 + wind.flutes.flute + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + stdNormal + + + Piano + + Piano + Pno. + Piano + 21 + 108 + 21 + 108 + keyboard.piano + F + + 100 + 95 + + + 100 + 33 + + + 100 + 50 + + + 100 + 67 + + + 100 + 100 + + + 120 + 67 + + + 120 + 100 + + + + + + + + + + 4 + 4 + 1 + + + 1 + half + + 72 + 14 + + + + quarter + + 72 + 14 + + + + + + half + + 72 + 14 + + + + half + + 72 + 14 + + + + end + 1 + + + + + + + 4 + 4 + 1 + + + half + + 72 + 14 + + + + half + + 72 + 14 + + + + + + 1 + half + + 72 + 14 + + + + quarter + + 72 + 14 + + + + end + 1 + + + + + diff --git a/mtest/libmscore/breath/tst_breath.cpp b/mtest/libmscore/breath/tst_breath.cpp new file mode 100644 index 000000000000..ea972e6a2f30 --- /dev/null +++ b/mtest/libmscore/breath/tst_breath.cpp @@ -0,0 +1,86 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// $Id:$ +// +// Copyright (C) 2012 Werner Schweer +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 +// as published by the Free Software Foundation and appearing in +// the file LICENCE.GPL +//============================================================================= + +#include +#include "mtest/testutils.h" +#include "libmscore/score.h" +#include "libmscore/undo.h" +#include "libmscore/measure.h" +#include "libmscore/breath.h" + +#define DIR QString("libmscore/breath/") + +using namespace Ms; + +//--------------------------------------------------------- +// TestBreath +//--------------------------------------------------------- + +class TestBreath : public QObject, public MTest + { + Q_OBJECT + + private slots: + void initTestCase(); + void breath(); + }; + +//--------------------------------------------------------- +// initTestCase +//--------------------------------------------------------- + +void TestBreath::initTestCase() + { + initMTest(); + } + +//--------------------------------------------------------- +// breath +//--------------------------------------------------------- + +void TestBreath::breath() + { + QString readFile(DIR + "breath.mscx"); + QString writeFile1("breath01-test.mscx"); + QString reference1(DIR + "breath01-ref.mscx"); + QString writeFile2("breath02-test.mscx"); + QString reference2(DIR + "breath02-ref.mscx"); + + Score* score = readScore(readFile); + score->doLayout(); + + // do + score->startCmd(); + score->cmdSelectAll(); + for (Element* e : score->selection().elements()) { + DropData dd; + dd.view = 0; + Breath* b = new Breath(score); + b->setBreathType(0); + dd.element = b; + if (e->acceptDrop(dd)) + e->drop(dd); + } + score->endCmd(); + QVERIFY(saveCompareScore(score, writeFile1, reference1)); + + // undo + score->undo()->undo(); + QVERIFY(saveCompareScore(score, writeFile2, reference2)); + + delete score; + } + +QTEST_MAIN(TestBreath) +#include "tst_breath.moc" + diff --git a/mtest/libmscore/parts/part-breath-add.mscx b/mtest/libmscore/parts/part-breath-add.mscx index 665e8d561aeb..a318baab0804 100644 --- a/mtest/libmscore/parts/part-breath-add.mscx +++ b/mtest/libmscore/parts/part-breath-add.mscx @@ -165,12 +165,10 @@ 16 - 480 0 118 - 960 10 quarter @@ -804,12 +802,10 @@ 16 - 480 0 118 - 960 10 quarter diff --git a/mtest/libmscore/parts/part-breath-parts.mscx b/mtest/libmscore/parts/part-breath-parts.mscx index 63caafb98443..83d8b76e5195 100644 --- a/mtest/libmscore/parts/part-breath-parts.mscx +++ b/mtest/libmscore/parts/part-breath-parts.mscx @@ -170,12 +170,10 @@ 16 - 480 0 10 - 960 11 quarter @@ -444,12 +442,10 @@ 17 - 480 0 84 - 960 85 quarter @@ -822,12 +818,10 @@ 16 - 480 0 10 - 960 11 quarter @@ -1197,12 +1191,10 @@ 17 - 480 0 84 - 960 85 quarter diff --git a/mtest/libmscore/parts/part-breath-udel.mscx b/mtest/libmscore/parts/part-breath-udel.mscx index 5c47a0064915..cb375b55029d 100644 --- a/mtest/libmscore/parts/part-breath-udel.mscx +++ b/mtest/libmscore/parts/part-breath-udel.mscx @@ -165,12 +165,10 @@ 16 - 480 0 87 - 960 10 quarter @@ -804,12 +802,10 @@ 16 - 480 0 87 - 960 10 quarter diff --git a/mtest/libmscore/parts/part-breath-uradd.mscx b/mtest/libmscore/parts/part-breath-uradd.mscx index 7b2718326b11..454969b13168 100644 --- a/mtest/libmscore/parts/part-breath-uradd.mscx +++ b/mtest/libmscore/parts/part-breath-uradd.mscx @@ -165,12 +165,10 @@ 16 - 480 0 119 - 960 10 quarter @@ -804,12 +802,10 @@ 16 - 480 0 119 - 960 10 quarter diff --git a/mtest/libmscore/parts/part-breath.mscx b/mtest/libmscore/parts/part-breath.mscx index b27f13add69d..48d43af7a862 100644 --- a/mtest/libmscore/parts/part-breath.mscx +++ b/mtest/libmscore/parts/part-breath.mscx @@ -160,11 +160,9 @@ 16 - 480 0 - 960 quarter @@ -392,11 +390,9 @@ 17 - 480 0 - 960 quarter diff --git a/mtest/libmscore/selectionfilter/selectionfilter13-base-ref.xml b/mtest/libmscore/selectionfilter/selectionfilter13-base-ref.xml index 3c15f4ea0951..0e5a8b7fd22c 100644 --- a/mtest/libmscore/selectionfilter/selectionfilter13-base-ref.xml +++ b/mtest/libmscore/selectionfilter/selectionfilter13-base-ref.xml @@ -21,12 +21,10 @@ 16 - 480 0 0 - 960 0 quarter @@ -45,7 +43,6 @@ 13 - 1440 0 0 diff --git a/vtest/breath-1-ref.png b/vtest/breath-1-ref.png new file mode 100644 index 000000000000..6fe05aa15341 Binary files /dev/null and b/vtest/breath-1-ref.png differ diff --git a/vtest/breath-1.mscz b/vtest/breath-1.mscz new file mode 100644 index 000000000000..33b63cc989ae Binary files /dev/null and b/vtest/breath-1.mscz differ diff --git a/vtest/gen b/vtest/gen index 670c3de4c9a5..cdaf6170969e 100755 --- a/vtest/gen +++ b/vtest/gen @@ -44,7 +44,7 @@ else chord-layout-11 chord-layout-12 chord-layout-13 chord-layout-14 chord-layout-15 cross-1\ accidental-1 accidental-2 accidental-3 accidental-4 accidental-5\ accidental-6 accidental-7 accidental-8 accidental-9\ - tie-1 tie-2 tie-3 grace-1 grace-2 grace-3 grace-4 tuplets-1\ + tie-1 tie-2 tie-3 grace-1 grace-2 grace-3 grace-4 tuplets-1 breath-1\ harmony-1 harmony-2 harmony-3 harmony-4 harmony-5 harmony-6 harmony-7 harmony-8 harmony-9 harmony-10 harmony-11\ beams-1 beams-2 beams-3 beams-4 beams-5 beams-6 beams-7 beams-8 beams-9\ user-offset-1 user-offset-2 chord-space-1 chord-space-2 tablature-1 image-1\ diff --git a/vtest/gen.bat b/vtest/gen.bat index c027e45b6f1c..8751055d6ede 100644 --- a/vtest/gen.bat +++ b/vtest/gen.bat @@ -19,7 +19,7 @@ set SRC=mmrest-1,bravura-mmrest,gonville-mmrest,mmrest-2,mmrest-4,mmrest-5,mmres chord-layout-11,chord-layout-12,chord-layout-13,chord-layout-14,chord-layout-15,cross-1, ^ accidental-1,accidental-2,accidental-3,accidental-4,accidental-5, ^ accidental-6,accidental-7,accidental-8,accidental-9, ^ - tie-1,tie-2,tie-3,grace-1,grace-2,grace-3,grace-4,tuplets-1, ^ + tie-1,tie-2,tie-3,grace-1,grace-2,grace-3,grace-4,tuplets-1,breath-1 ^ harmony-1,harmony-2,harmony-3,harmony-4,harmony-5,harmony-6,harmony-7,harmony-8,harmony-9,harmony-10,harmony-11, ^ beams-1,beams-2,beams-3,beams-4,beams-5,beams-6,beams-7,beams-8,beams-9, ^ user-offset-1,user-offset-2,chord-space-1,chord-space-2,tablature-1,image-1, ^