MuseScore/libmscore/measure.cpp

3921 lines
152 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-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 LICENCE.GPL
//=============================================================================
/**
\file
Implementation of most part of class Measure.
*/
#include "measure.h"
#include "segment.h"
#include "note.h"
#include "rest.h"
#include "chord.h"
#include "xml.h"
#include "score.h"
#include "clef.h"
#include "key.h"
#include "dynamic.h"
#include "slur.h"
2013-08-22 12:18:14 +02:00
#include "tie.h"
2012-05-26 14:26:10 +02:00
#include "sig.h"
#include "beam.h"
#include "tuplet.h"
#include "system.h"
#include "undo.h"
#include "hairpin.h"
#include "text.h"
#include "select.h"
#include "staff.h"
#include "part.h"
#include "style.h"
#include "bracket.h"
#include "ottava.h"
#include "trill.h"
#include "pedal.h"
#include "timesig.h"
#include "barline.h"
#include "layoutbreak.h"
#include "page.h"
#include "lyrics.h"
#include "volta.h"
#include "image.h"
#include "hook.h"
#include "beam.h"
#include "pitchspelling.h"
#include "keysig.h"
#include "breath.h"
#include "tremolo.h"
#include "drumset.h"
#include "repeat.h"
#include "box.h"
#include "harmony.h"
#include "tempotext.h"
#include "sym.h"
#include "stafftext.h"
#include "utils.h"
#include "glissando.h"
#include "articulation.h"
#include "spacer.h"
#include "duration.h"
#include "fret.h"
#include "stafftype.h"
#include "stringdata.h"
2012-05-26 14:26:10 +02:00
#include "tiemap.h"
#include "tupletmap.h"
#include "accidental.h"
#include "layout.h"
#include "icon.h"
2013-11-25 12:17:12 +01:00
#include "ambitus.h"
2012-05-26 14:26:10 +02:00
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// MStaff
//---------------------------------------------------------
MStaff::MStaff()
{
_noText = 0;
2012-05-26 14:26:10 +02:00
distanceUp = .0;
distanceDown = .0;
lines = 0;
hasVoices = false;
_vspacerUp = 0;
_vspacerDown = 0;
_visible = true;
_slashStyle = false;
}
MStaff::~MStaff()
{
delete _noText;
2012-05-26 14:26:10 +02:00
delete lines;
delete _vspacerUp;
delete _vspacerDown;
}
MStaff::MStaff(const MStaff& m)
{
_noText = 0;
distanceUp = m.distanceUp;
distanceDown = m.distanceDown;
lines = m.lines;
hasVoices = m.hasVoices;
_vspacerUp = 0;
_vspacerDown = 0;
_visible = m._visible;
_slashStyle = m._slashStyle;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
Measure::Measure(Score* s)
: MeasureBase(s),
_timesig(4,4), _len(4,4)
{
_repeatCount = 2;
_repeatFlags = 0;
int n = _score->nstaves();
staves.reserve(n);
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < n; ++staffIdx) {
MStaff* s = new MStaff;
Staff* staff = score()->staff(staffIdx);
s->lines = new StaffLines(score());
s->lines->setTrack(staffIdx * VOICES);
s->lines->setParent(this);
s->lines->setVisible(!staff->invisible());
staves.push_back(s);
}
_minWidth1 = 0.0;
_minWidth2 = 0.0;
2012-05-26 14:26:10 +02:00
_no = 0;
_noOffset = 0;
_noMode = MeasureNumberMode::AUTO;
2012-05-26 14:26:10 +02:00
_userStretch = 1.0; // ::style->measureSpacing;
_irregular = false;
_breakMultiMeasureRest = false;
_breakMMRest = false;
_endBarLineGenerated = true;
_endBarLineVisible = true;
_endBarLineType = NORMAL_BAR;
_mmRest = 0;
_mmRestCount = 0;
2012-05-26 14:26:10 +02:00
setFlag(ELEMENT_MOVABLE, true);
}
//---------------------------------------------------------
// measure
//---------------------------------------------------------
Measure::Measure(const Measure& m)
: MeasureBase(m)
{
_segments = m._segments.clone();
_timesig = m._timesig;
_len = m._len;
_repeatCount = m._repeatCount;
_repeatFlags = m._repeatFlags;
2013-05-29 10:31:26 +02:00
staves.reserve(m.staves.size());
2012-05-26 14:26:10 +02:00
foreach(MStaff* ms, m.staves)
staves.append(new MStaff(*ms));
_minWidth1 = m._minWidth1;
_minWidth2 = m._minWidth2;
2012-05-26 14:26:10 +02:00
_no = m._no;
_noOffset = m._noOffset;
_userStretch = m._userStretch;
2012-05-26 14:26:10 +02:00
_irregular = m._irregular;
_breakMultiMeasureRest = m._breakMultiMeasureRest;
_breakMMRest = m._breakMMRest;
_endBarLineGenerated = m._endBarLineGenerated;
_endBarLineVisible = m._endBarLineVisible;
_endBarLineType = m._endBarLineType;
_mmRest = m._mmRest;
_mmRestCount = m._mmRestCount;
2012-05-26 14:26:10 +02:00
_playbackCount = m._playbackCount;
_endBarLineColor = m._endBarLineColor;
}
//---------------------------------------------------------
// setScore
//---------------------------------------------------------
void Measure::setScore(Score* score)
{
MeasureBase::setScore(score);
for (Segment* s = first(); s; s = s->next())
s->setScore(score);
}
//---------------------------------------------------------
// MStaff::setScore
//---------------------------------------------------------
void MStaff::setScore(Score* score)
{
if (lines)
lines->setScore(score);
if (_vspacerUp)
_vspacerUp->setScore(score);
if (_vspacerDown)
_vspacerDown->setScore(score);
}
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
Measure::~Measure()
{
for (Segment* s = first(); s;) {
Segment* ns = s->next();
delete s;
s = ns;
}
qDeleteAll(staves);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// dump
//---------------------------------------------------------
/**
Debug only.
*/
void Measure::dump() const
{
qDebug("dump measure:");
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void Measure::remove(Segment* el)
{
#ifndef NDEBUG
2013-10-25 12:17:42 +02:00
if (score()->undoRedo()) {
qDebug("remove segment <%s> in undo/redo", el->subTypeName());
2013-10-30 14:21:08 +01:00
// abort(); can happen for mmrest
2013-10-25 12:17:42 +02:00
}
// Q_ASSERT(!score()->undoRedo());
2012-05-26 14:26:10 +02:00
Q_ASSERT(el->type() == SEGMENT);
if (el->prev()) {
Q_ASSERT(el->prev()->next() == el);
}
else {
Q_ASSERT(el == _segments.first());
}
if (el->next()) {
Q_ASSERT(el->next()->prev() == el);
}
else {
Q_ASSERT(el == _segments.last());
}
#endif
int tracks = staves.size() * VOICES;
for (int track = 0; track < tracks; track += VOICES) {
if (!el->element(track))
continue;
if (el->segmentType() == Segment::SegKeySig)
2012-05-26 14:26:10 +02:00
score()->staff(track/VOICES)->setUpdateKeymap(true);
}
_segments.remove(el);
2012-08-08 20:46:29 +02:00
setDirty();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// AcEl
//---------------------------------------------------------
struct AcEl {
Note* note;
qreal x;
};
2013-10-15 15:39:01 +02:00
#if 0
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// layoutChords0
//---------------------------------------------------------
void Measure::layoutChords0(Segment* segment, int startTrack)
{
int staffIdx = startTrack/VOICES;
Staff* staff = score()->staff(staffIdx);
qreal staffMag = staff->mag();
int endTrack = startTrack + VOICES;
for (int track = startTrack; track < endTrack; ++track) {
ChordRest* cr = static_cast<ChordRest*>(segment->element(track));
if (!cr)
continue;
2013-06-20 10:19:04 +02:00
layoutCR0(cr, staffMag);
}
}
2013-10-15 15:39:01 +02:00
#endif
2012-05-26 14:26:10 +02:00
2013-06-20 10:19:04 +02:00
//---------------------------------------------------------
// layoutCR0
//---------------------------------------------------------
2013-01-02 14:33:23 +01:00
2013-06-20 10:19:04 +02:00
void Measure::layoutCR0(ChordRest* cr, qreal mm)
{
Drumset* drumset = 0;
if (cr->staff()->part()->instr()->useDrumset())
drumset = cr->staff()->part()->instr()->drumset();
qreal m = mm;
if (cr->small())
m *= score()->styleD(ST_smallNoteMag);
if (cr->type() == CHORD) {
Chord* chord = static_cast<Chord*>(cr);
for (Chord* c : chord->graceNotes())
layoutCR0(c, mm);
if (chord->noteType() != NOTE_NORMAL)
m *= score()->styleD(ST_graceNoteMag);
if (drumset) {
foreach(Note* note, chord->notes()) {
int pitch = note->pitch();
if (!drumset->isValid(pitch)) {
// qDebug("unmapped drum note %d", pitch);
}
else {
note->setHeadGroup(drumset->noteHead(pitch));
note->setLine(drumset->line(pitch));
continue;
2012-05-26 14:26:10 +02:00
}
}
2012-08-01 18:00:27 +02:00
}
2013-06-20 10:19:04 +02:00
chord->computeUp();
chord->layoutStem1();
}
if (m != mag()) {
cr->setMag(m);
setDirty();
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// layoutChords10
// computes note lines and accidentals
//---------------------------------------------------------
void Measure::layoutChords10(Segment* segment, int startTrack, AccidentalState* as)
{
int endTrack = startTrack + VOICES;
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
if (!e || e->type() != CHORD)
continue;
Chord* chord = static_cast<Chord*>(e);
2013-06-10 21:13:04 +02:00
chord->layout10(as);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// findAccidental
2012-08-07 12:44:19 +02:00
/// return current accidental value at note position
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2012-08-08 20:46:29 +02:00
AccidentalVal Measure::findAccidental(Note* note) const
2012-05-26 14:26:10 +02:00
{
AccidentalState tversatz; // state of already set accidentals for this measure
tversatz.init(note->chord()->staff()->keymap()->key(tick()));
2013-06-12 14:23:57 +02:00
Segment::SegmentTypes st = Segment::SegChordRest;
2012-05-26 14:26:10 +02:00
for (Segment* segment = first(st); segment; segment = segment->next(st)) {
int startTrack = note->staffIdx() * VOICES;
int endTrack = startTrack + VOICES;
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
if (!e || e->type() != CHORD)
continue;
Chord* chord = static_cast<Chord*>(e);
for (Chord* chord1 : chord->graceNotes()) {
for (Note* note1 : chord1->notes()) {
if (note1->tieBack())
continue;
//
// compute accidental
//
int tpc = note1->tpc();
int line = absStep(tpc, note1->pitch());
2012-05-26 14:26:10 +02:00
if (note == note1)
return tversatz.accidentalVal(line);
tversatz.setAccidentalVal(line, tpc2alter(tpc));
}
}
for (Note* note1 : chord->notes()) {
2012-05-26 14:26:10 +02:00
if (note1->tieBack())
continue;
//
// compute accidental
//
2012-08-06 21:55:51 +02:00
int tpc = note1->tpc();
2012-08-07 16:05:37 +02:00
int line = absStep(tpc, note1->pitch());
2012-05-26 14:26:10 +02:00
if (note == note1)
return tversatz.accidentalVal(line);
2012-08-06 21:55:51 +02:00
tversatz.setAccidentalVal(line, tpc2alter(tpc));
2012-05-26 14:26:10 +02:00
}
}
}
qDebug("Measure::findAccidental: note not found");
2012-08-08 20:46:29 +02:00
return NATURAL;
2012-05-26 14:26:10 +02:00
}
2012-08-07 12:44:19 +02:00
//---------------------------------------------------------
// findAccidental
/// Compute accidental state at segment/staffIdx for
/// relative staff line.
//---------------------------------------------------------
2012-08-08 20:46:29 +02:00
AccidentalVal Measure::findAccidental(Segment* s, int staffIdx, int line) const
2012-08-06 21:55:51 +02:00
{
AccidentalState tversatz; // state of already set accidentals for this measure
Staff* staff = score()->staff(staffIdx);
tversatz.init(staff->keymap()->key(tick()));
2013-06-12 14:23:57 +02:00
Segment::SegmentTypes st = Segment::SegChordRest;
2012-08-06 21:55:51 +02:00
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
for (Segment* segment = first(st); segment; segment = segment->next(st)) {
if (segment == s) {
2012-08-07 12:44:19 +02:00
ClefType clef = staff->clef(s->tick());
2012-08-07 16:05:37 +02:00
int l = relStep(line, clef);
2012-08-06 21:55:51 +02:00
return tversatz.accidentalVal(l);
}
for (int track = startTrack; track < endTrack; ++track) {
Element* e = segment->element(track);
if (!e || e->type() != CHORD)
continue;
Chord* chord = static_cast<Chord*>(e);
for (Chord* chord1 : chord->graceNotes()) {
for (Note* note : chord1->notes()) {
if (note->tieBack())
continue;
int tpc = note->tpc();
int l = absStep(tpc, note->pitch());
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
2012-08-06 21:55:51 +02:00
for (Note* note : chord->notes()) {
2012-08-06 21:55:51 +02:00
if (note->tieBack())
continue;
int tpc = note->tpc();
2012-08-07 16:05:37 +02:00
int l = absStep(tpc, note->pitch());
2012-08-06 21:55:51 +02:00
tversatz.setAccidentalVal(l, tpc2alter(tpc));
}
}
}
qDebug("segment not found");
2012-08-08 20:46:29 +02:00
return NATURAL;
2012-08-06 21:55:51 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure::layout
/// Layout measure; must fit into \a width.
///
/// Note: minWidth = width - stretch
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::layout(qreal width)
{
int nstaves = _score->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
staves[staffIdx]->distanceUp = 0.0;
staves[staffIdx]->distanceDown = 0.0;
StaffLines* sl = staves[staffIdx]->lines;
if (sl)
sl->setMag(score()->staff(staffIdx)->mag());
staves[staffIdx]->lines->layout();
}
// height of boundingRect will be set in system->layout2()
// keep old value for relayout
2013-01-02 09:29:17 +01:00
bbox().setRect(0.0, 0.0, width, height());
layoutX(width);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// tick2pos
2013-06-19 16:25:29 +02:00
// return x position for tick relative to System
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
qreal Measure::tick2pos(int tck) const
{
if (isMMRest()) {
Segment* s = first(Segment::SegChordRest);
qreal x1 = s->x();
qreal w = width() - x1;
return x1 + (tck * w) / (ticks() * mmRestCount());
}
2012-05-26 14:26:10 +02:00
Segment* s;
qreal x1 = 0;
qreal x2 = 0;
int tick1 = tick();
int tick2 = tick1;
2013-06-19 16:25:29 +02:00
for (s = first(Segment::SegChordRest); s; s = s->next(Segment::SegChordRest)) {
x2 = s->x();
2012-05-26 14:26:10 +02:00
tick2 = s->tick();
2013-06-19 16:25:29 +02:00
if (tck == tick2)
return x2 + pos().x();
if (tck <= tick2)
2012-05-26 14:26:10 +02:00
break;
x1 = x2;
tick1 = tick2;
}
if (s == 0) {
x2 = width();
2013-06-19 16:25:29 +02:00
tick2 = endTick();
2012-05-26 14:26:10 +02:00
}
2013-06-19 16:25:29 +02:00
qreal dx = x2 - x1;
int dt = tick2 - tick1;
x1 += (dt == 0) ? 0.0 : (dx * (tck - tick1) / dt);
return x1 + pos().x();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// layout2
// called after layout of all pages
//---------------------------------------------------------
void Measure::layout2()
{
if (parent() == 0)
return;
Q_ASSERT(score()->nstaves() == staves.size());
int tracks = score()->nstaves() * VOICES;
2012-05-26 14:26:10 +02:00
qreal _spatium = spatium();
2013-06-12 14:23:57 +02:00
static const Segment::SegmentTypes st = Segment::SegChordRest;
2012-05-26 14:26:10 +02:00
for (int track = 0; track < tracks; ++track) {
for (Segment* s = first(st); s; s = s->next(st)) {
ChordRest* cr = s->cr(track);
2012-05-26 14:26:10 +02:00
if (!cr)
continue;
int n = cr->lyricsList().size();
for (int i = 0; i < n; ++i) {
Lyrics* lyrics = cr->lyricsList().at(i);
2012-05-26 14:26:10 +02:00
if (lyrics)
system()->layoutLyrics(lyrics, s, track/VOICES);
}
}
if (track % VOICES == 0) {
int staffIdx = track / VOICES;
qreal y = system()->staff(staffIdx)->y();
Spacer* sp = staves[staffIdx]->_vspacerDown;
if (sp) {
sp->layout();
int n = score()->staff(staffIdx)->lines() - 1;
sp->setPos(_spatium * .5, y + n * _spatium);
}
sp = staves[staffIdx]->_vspacerUp;
if (sp) {
sp->layout();
sp->setPos(_spatium * .5, y - sp->gap());
}
}
}
for (MStaff* ms : staves)
ms->lines->setWidth(width());
2012-05-26 14:26:10 +02:00
MeasureBase::layout(); // layout LAYOUT_BREAK elements
//
// set measure number
//
bool smn = false;
2012-10-17 10:39:39 +02:00
// if (!_noText || _noText->generated()) {
if (_noMode == MeasureNumberMode::SHOW)
smn = true;
else if (_noMode == MeasureNumberMode::HIDE)
smn = false;
else {
if (score()->styleB(ST_showMeasureNumber)
&& !_irregular
&& (_no || score()->styleB(ST_showMeasureNumberOne))) {
if (score()->styleB(ST_measureNumberSystem))
smn = system()->firstMeasure() == this;
else {
smn = (_no == 0 && score()->styleB(ST_showMeasureNumberOne)) ||
( ((_no+1) % score()->style(ST_measureNumberInterval).toInt()) == 0 );
}
2012-10-17 10:39:39 +02:00
}
}
QString s;
if (smn)
s = QString("%1").arg(_no + 1);
int nn = 1;
if (!score()->styleB(ST_measureNumberAllStaffs)) {
//find first non invisible staff
for (int staffIdx = 0; staffIdx < staves.size(); ++staffIdx) {
MStaff* ms = staves.at(staffIdx);
SysStaff* s = system()->staff(staffIdx);
Staff* staff = score()->staff(staffIdx);
if (ms->visible() && staff->show() && s->show()) {
nn = staffIdx;
break;
}
}
}
for (int staffIdx = 0; staffIdx < staves.size(); ++staffIdx) {
MStaff* ms = staves.at(staffIdx);
Text* t = ms->noText();
if (smn) {
if (t == 0 && (staffIdx == nn || score()->styleB(ST_measureNumberAllStaffs))) {
t = new Text(score());
t->setFlag(ELEMENT_ON_STAFF, true);
// t->setFlag(ELEMENT_MOVABLE, false); ??
t->setTrack(staffIdx * VOICES);
t->setGenerated(true);
t->setTextStyleType(TEXT_STYLE_MEASURE_NUMBER);
t->setParent(this);
score()->undoAddElement(t);
}
if(t) {
t->setText(s);
t->layout();
smn = score()->styleB(ST_measureNumberAllStaffs);
}
}
else {
if (t)
score()->undoRemoveElement(t);
2012-10-17 10:39:39 +02:00
}
2012-05-26 14:26:10 +02:00
}
// }
2012-05-26 14:26:10 +02:00
//
// slur layout needs articulation layout first
//
for (Segment* s = first(st); s; s = s->next(st)) {
for (int track = 0; track < tracks; ++track) {
if (!score()->staff(track / VOICES)->show()) {
2013-03-14 16:36:24 +01:00
track += VOICES-1;
continue;
}
2012-05-26 14:26:10 +02:00
Element* el = s->element(track);
if (el) {
ChordRest* cr = static_cast<ChordRest*>(el);
2012-09-12 16:19:03 +02:00
if (cr->type() == CHORD) {
Chord* c = static_cast<Chord*>(cr);
foreach(const Note* note, c->notes()) {
2013-06-10 11:03:34 +02:00
foreach (Spanner* sp, note->spannerFor())
2012-09-12 16:19:03 +02:00
sp->layout();
}
}
2012-05-26 14:26:10 +02:00
DurationElement* de = cr;
while (de->tuplet() && de->tuplet()->elements().front() == de) {
de->tuplet()->layout();
de = de->tuplet();
}
}
}
}
}
//---------------------------------------------------------
// findChord
2013-06-24 13:46:21 +02:00
/// Search for chord at position \a tick in \a track
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2013-06-24 13:46:21 +02:00
Chord* Measure::findChord(int tick, int track)
2012-05-26 14:26:10 +02:00
{
for (Segment* seg = last(); seg; seg = seg->prev()) {
if (seg->tick() < tick)
return 0;
if (seg->tick() == tick) {
Element* el = seg->element(track);
2013-06-24 13:46:21 +02:00
if (el && el->type() == CHORD)
return static_cast<Chord*>(el);
2012-05-26 14:26:10 +02:00
}
}
return 0;
}
//---------------------------------------------------------
// findChordRest
2013-06-24 13:46:21 +02:00
/// Search for chord or rest at position \a tick at \a staff in \a voice.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
ChordRest* Measure::findChordRest(int tick, int track)
{
for (Segment* seg = first(); seg; seg = seg->next()) {
if (seg->tick() > tick)
return 0;
if (seg->tick() == tick) {
Element* el = seg->element(track);
if (el && (el->type() == CHORD || el->type() == REST)) {
return (ChordRest*)el;
}
}
}
return 0;
}
//---------------------------------------------------------
// tick2segment
//---------------------------------------------------------
2013-06-16 23:33:37 +02:00
Segment* Measure::tick2segment(int tick) const
2012-05-26 14:26:10 +02:00
{
for (Segment* s = first(); s; s = s->next()) {
if (s->tick() == tick) {
if (s->segmentType() == Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
return s;
}
if (s->tick() > tick)
return 0;
}
return 0;
}
//---------------------------------------------------------
// findSegment
2013-05-29 10:31:26 +02:00
/// Search for a segment of type \a st at position \a t.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::findSegment(Segment::SegmentType st, int t)
2012-05-26 14:26:10 +02:00
{
Segment* s;
for (s = first(); s && s->tick() < t; s = s->next())
;
2013-06-25 19:52:00 +02:00
for (; s && s->tick() == t; s = s->next()) {
if (s->segmentType() == st)
return s;
}
return 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// undoGetSegment
//---------------------------------------------------------
Segment* Measure::undoGetSegment(Segment::SegmentType type, int tick)
2012-05-26 14:26:10 +02:00
{
Segment* s = findSegment(type, tick);
if (s == 0) {
s = new Segment(this, type, tick);
score()->undoAddElement(s);
}
return s;
}
//---------------------------------------------------------
// getSegment
//---------------------------------------------------------
Segment* Measure::getSegment(Element* e, int tick)
{
2013-06-25 19:52:00 +02:00
return getSegment(Segment::segmentType(e->type()), tick);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// getSegment
2012-09-10 16:10:25 +02:00
/// Get a segment of type \a st at tick position \a t.
/// If the segment does not exist, it is created.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
Segment* Measure::getSegment(Segment::SegmentType st, int tick)
2012-05-26 14:26:10 +02:00
{
Segment* s = findSegment(st, tick);
2012-05-26 14:26:10 +02:00
if (!s) {
s = new Segment(this, st, tick);
2012-05-26 14:26:10 +02:00
add(s);
}
return s;
}
//---------------------------------------------------------
// add
/// Add new Element \a el to Measure.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::add(Element* el)
{
2012-08-08 20:46:29 +02:00
setDirty();
2012-05-26 14:26:10 +02:00
el->setParent(this);
ElementType type = el->type();
// if (MScore::debugMode)
// qDebug("measure %p(%d): add %s %p", this, _no, el->name(), el);
switch (type) {
2012-10-17 10:39:39 +02:00
case TEXT:
staves[el->staffIdx()]->setNoText(static_cast<Text*>(el));
2012-10-17 10:39:39 +02:00
break;
2012-05-26 14:26:10 +02:00
case TUPLET:
qDebug("Measure::add(Tuplet) ??");
break;
case SPACER:
{
Spacer* sp = static_cast<Spacer*>(el);
if (sp->spacerType() == SPACER_UP)
2012-05-26 14:26:10 +02:00
staves[el->staffIdx()]->_vspacerUp = sp;
else if (sp->spacerType() == SPACER_DOWN)
2012-05-26 14:26:10 +02:00
staves[el->staffIdx()]->_vspacerDown = sp;
}
break;
case SEGMENT:
{
Segment* seg = static_cast<Segment*>(el);
int tracks = staves.size() * VOICES;
if (seg->segmentType() == Segment::SegKeySig) {
2012-10-02 13:52:23 +02:00
for (int track = 0; track < tracks; track += VOICES) {
if (!seg->element(track))
continue;
2012-05-26 14:26:10 +02:00
score()->staff(track/VOICES)->setUpdateKeymap(true);
2012-10-02 13:52:23 +02:00
}
2012-05-26 14:26:10 +02:00
}
// insert segment at specific position
if (seg->next()) {
_segments.insert(seg, seg->next());
break;
}
2012-05-26 14:26:10 +02:00
int t = seg->tick();
Segment::SegmentType st = seg->segmentType();
Segment* s;
2013-06-12 14:23:57 +02:00
for (s = first(); s && s->tick() < t; s = s->next())
;
if (s) {
if (st == Segment::SegChordRest) {
while (s && s->segmentType() != st && s->tick() == t) {
if (s->segmentType() == Segment::SegEndBarLine)
break;
s = s->next();
}
2013-06-12 14:23:57 +02:00
}
else {
if (s && s->tick() == t) {
while (s && s->segmentType() <= st) {
if (s->next() && s->next()->tick() != t)
break;
s = s->next();
}
2012-05-26 14:26:10 +02:00
}
2013-06-12 14:23:57 +02:00
//
// place breath _after_ chord
//
if (s && st == Segment::SegBreath)
s = s->next();
2012-05-26 14:26:10 +02:00
}
}
seg->setParent(this);
_segments.insert(seg, s);
if ((seg->segmentType() == Segment::SegTimeSig) && seg->element(0)) {
2012-05-26 14:26:10 +02:00
#if 0
Fraction nfraction(static_cast<TimeSig*>(seg->element(0))->getSig());
setTimesig2(nfraction);
for (Measure* m = nextMeasure(); m; m = m->nextMeasure()) {
if (m->first(SegTimeSig))
break;
m->setTimesig2(nfraction);
}
#endif
score()->addLayoutFlags(LAYOUT_FIX_TICKS);
}
}
break;
case JUMP:
_repeatFlags |= RepeatJump;
2013-03-25 16:27:20 +01:00
_el.push_back(el);
2012-05-26 14:26:10 +02:00
break;
case HBOX:
if (el->staff())
el->setMag(el->staff()->mag()); // ?!
2013-03-25 16:27:20 +01:00
_el.push_back(el);
2012-05-26 14:26:10 +02:00
break;
2013-10-30 14:21:08 +01:00
case MEASURE:
_mmRest = static_cast<Measure*>(el);
break;
2012-05-26 14:26:10 +02:00
default:
MeasureBase::add(el);
break;
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// remove
2012-08-08 20:46:29 +02:00
/// Remove Element \a el from Measure.
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::remove(Element* el)
{
2012-08-08 20:46:29 +02:00
setDirty();
2012-05-26 14:26:10 +02:00
switch(el->type()) {
2012-10-17 10:39:39 +02:00
case TEXT:
staves[el->staffIdx()]->setNoText(static_cast<Text*>(0));
2012-10-17 10:39:39 +02:00
break;
2012-05-26 14:26:10 +02:00
case SPACER:
if (static_cast<Spacer*>(el)->spacerType() == SPACER_DOWN)
2012-05-26 14:26:10 +02:00
staves[el->staffIdx()]->_vspacerDown = 0;
else if (static_cast<Spacer*>(el)->spacerType() == SPACER_UP)
2012-05-26 14:26:10 +02:00
staves[el->staffIdx()]->_vspacerUp = 0;
break;
case SEGMENT:
remove(static_cast<Segment*>(el));
break;
case JUMP:
_repeatFlags &= ~RepeatJump;
// fall through
case HBOX:
if (!_el.remove(el)) {
qDebug("Measure(%p)::remove(%s,%p) not found",
this, el->name(), el);
}
break;
case CLEF:
case CHORD:
case REST:
case TIMESIG:
for (Segment* segment = first(); segment; segment = segment->next()) {
int staves = _score->nstaves();
int tracks = staves * VOICES;
for (int track = 0; track < tracks; ++track) {
Element* e = segment->element(track);
if (el == e) {
segment->setElement(track, 0);
return;
}
}
}
qDebug("Measure::remove: %s %p not found", el->name(), el);
break;
2013-10-30 14:21:08 +01:00
case MEASURE:
_mmRest = 0;
break;
2012-05-26 14:26:10 +02:00
default:
MeasureBase::remove(el);
break;
}
}
//---------------------------------------------------------
// change
//---------------------------------------------------------
void Measure::change(Element* o, Element* n)
{
if (o->type() == TUPLET) {
Tuplet* t = static_cast<Tuplet*>(n);
foreach(DurationElement* e, t->elements()) {
e->setTuplet(t);
}
}
else {
remove(o);
add(n);
}
}
//-------------------------------------------------------------------
// moveTicks
// Also adjust endBarLine if measure len has changed. For this
// diff == 0 cannot be optimized away
//-------------------------------------------------------------------
void Measure::moveTicks(int diff)
{
setTick(tick() + diff);
for (Segment* segment = first(); segment; segment = segment->next()) {
if (segment->segmentType() & (Segment::SegEndBarLine | Segment::SegTimeSigAnnounce))
2012-05-26 14:26:10 +02:00
segment->setTick(tick() + ticks());
}
}
//---------------------------------------------------------
// removeStaves
//---------------------------------------------------------
void Measure::removeStaves(int sStaff, int eStaff)
{
for (Segment* s = first(); s; s = s->next()) {
for (int staff = eStaff-1; staff >= sStaff; --staff) {
s->removeStaff(staff);
}
}
foreach (Element* e, _el) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
if (staffIdx >= eStaff) {
staffIdx -= eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
}
//---------------------------------------------------------
// insertStaves
//---------------------------------------------------------
void Measure::insertStaves(int sStaff, int eStaff)
{
foreach (Element* e, _el) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff) {
int voice = e->voice();
staffIdx += eStaff - sStaff;
e->setTrack(staffIdx * VOICES + voice);
}
}
for (Segment* s = first(); s; s = s->next()) {
for (int staff = sStaff; staff < eStaff; ++staff) {
s->insertStaff(staff);
}
}
}
//---------------------------------------------------------
// cmdRemoveStaves
//---------------------------------------------------------
void Measure::cmdRemoveStaves(int sStaff, int eStaff)
{
2013-09-25 10:13:00 +02:00
// qDebug("cmdRemoveStaves %d-%d", sStaff, eStaff);
2012-05-26 14:26:10 +02:00
int sTrack = sStaff * VOICES;
int eTrack = eStaff * VOICES;
for (Segment* s = first(); s; s = s->next()) {
2013-09-25 10:13:00 +02:00
// qDebug(" seg %d <%s>", s->tick(), s->subTypeName());
2012-05-26 14:26:10 +02:00
for (int track = eTrack - 1; track >= sTrack; --track) {
Element* el = s->element(track);
2013-07-15 07:53:16 +02:00
// if (el && !el->generated()) {
if (el) {
2013-09-25 10:13:00 +02:00
// qDebug(" remove %s track %d", el->name(), track);
2012-05-26 14:26:10 +02:00
_score->undoRemoveElement(el);
}
}
foreach(Element* e, s->annotations()) {
int staffIdx = e->staffIdx();
if ((staffIdx >= sStaff) && (staffIdx < eStaff)) {
2014-02-24 13:53:43 +01:00
qDebug(" remove annotation %s %p staffIdx %d", e->name(), e, staffIdx);
2012-05-26 14:26:10 +02:00
_score->undoRemoveElement(e);
}
}
}
foreach(Element* e, _el) {
if (e->track() == -1)
continue;
int staffIdx = e->staffIdx();
if (staffIdx >= sStaff && staffIdx < eStaff)
_score->undoRemoveElement(e);
}
_score->undo(new RemoveStaves(this, sStaff, eStaff));
for (int i = eStaff - 1; i >= sStaff; --i)
_score->undo(new RemoveMStaff(this, *(staves.begin()+i), i));
// barLine
// TODO
}
//---------------------------------------------------------
// cmdAddStaves
//---------------------------------------------------------
void Measure::cmdAddStaves(int sStaff, int eStaff, bool createRest)
{
_score->undo(new InsertStaves(this, sStaff, eStaff));
Segment* ts = findSegment(Segment::SegTimeSig, tick());
2012-05-26 14:26:10 +02:00
for (int i = sStaff; i < eStaff; ++i) {
Staff* staff = _score->staff(i);
MStaff* ms = new MStaff;
ms->lines = new StaffLines(score());
ms->lines->setTrack(i * VOICES);
// ms->lines->setLines(staff->lines());
ms->lines->setParent(this);
ms->lines->setVisible(!staff->invisible());
_score->undo(new InsertMStaff(this, ms, i));
if (createRest) {
if (_timesig != len()) {
score()->setRest(tick(), i * VOICES, len(), false, 0, false);
}
else {
score()->setRest(tick(), i * VOICES, len(), false, 0, true);
}
2012-05-26 14:26:10 +02:00
}
// replicate time signature
if (ts) {
TimeSig* ots = 0;
for (int track = 0; track < staves.size() * VOICES; ++track) {
if (ts->element(track)) {
ots = (TimeSig*)ts->element(track);
break;
}
}
if (ots) {
TimeSig* timesig = new TimeSig(*ots);
timesig->setTrack(i * VOICES);
timesig->setSig(ots->sig(), ots->timeSigType());
2012-05-26 14:26:10 +02:00
score()->undoAddElement(timesig);
}
}
}
}
//---------------------------------------------------------
// setTrack
//---------------------------------------------------------
void MStaff::setTrack(int track)
{
if (lines)
lines->setTrack(track);
if (_vspacerUp)
_vspacerUp->setTrack(track);
if (_vspacerDown)
_vspacerDown->setTrack(track);
}
//---------------------------------------------------------
// insertMStaff
//---------------------------------------------------------
void Measure::insertMStaff(MStaff* staff, int idx)
{
staves.insert(idx, staff);
for (int staffIdx = 0; staffIdx < staves.size(); ++staffIdx)
staves[staffIdx]->setTrack(staffIdx * VOICES);
}
//---------------------------------------------------------
// removeMStaff
//---------------------------------------------------------
void Measure::removeMStaff(MStaff* /*staff*/, int idx)
{
staves.removeAt(idx);
for (int staffIdx = 0; staffIdx < staves.size(); ++staffIdx)
staves[staffIdx]->setTrack(staffIdx * VOICES);
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
void Measure::insertStaff(Staff* staff, int staffIdx)
{
qDebug("Measure::insertStaff: %d", staffIdx);
for (Segment* s = first(); s; s = s->next())
s->insertStaff(staffIdx);
MStaff* ms = new MStaff;
ms->lines = new StaffLines(score());
ms->lines->setParent(this);
ms->lines->setTrack(staffIdx * VOICES);
// ms->distanceUp = 0.0;
// ms->distanceDown = 0.0; // TODO point(staffIdx == 0 ? score()->styleS(ST_minSystemDistance) : score()->styleS(ST_staffDistance));
ms->lines->setVisible(!staff->invisible());
insertMStaff(ms, staffIdx);
}
//---------------------------------------------------------
// staffabbox
//---------------------------------------------------------
QRectF Measure::staffabbox(int staffIdx) const
{
System* s = system();
QRectF sb(s->staff(staffIdx)->bbox());
QRectF rrr(sb.translated(s->pagePos()));
QRectF rr(abbox());
QRectF r(rr.x(), rrr.y(), rr.width(), rrr.height());
return r;
}
//---------------------------------------------------------
// acceptDrop
//---------------------------------------------------------
/**
Return true if an Element of type \a type can be dropped on a Measure
at canvas relative position \a p.
Note special handling for clefs (allow drop if left of rightmost chord or rest in this staff)
and key- and timesig (allow drop if left of first chord or rest).
*/
bool Measure::acceptDrop(MuseScoreView* viewer, const QPointF& p, Element* e) const
{
int type = e->type();
// convert p from canvas to measure relative position and take x and y coordinates
QPointF mrp = p - canvasPos(); // pos() - system()->pos() - system()->page()->pos();
qreal mrpx = mrp.x();
qreal mrpy = mrp.y();
System* s = system();
int idx = s->y2staff(p.y());
if (idx == -1) {
return false; // staff not found
}
QRectF sb(s->staff(idx)->bbox());
qreal t = sb.top(); // top of staff
qreal b = sb.bottom(); // bottom of staff
// compute rectangle of staff in measure
QRectF rrr(sb.translated(s->pagePos()));
QRectF rr(abbox());
QRectF r(rr.x(), rrr.y(), rr.width(), rrr.height());
Page* page = system()->page();
r.translate(page->pos());
rr.translate(page->pos());
switch(type) {
case STAFF_LIST:
viewer->setDropRectangle(r);
return true;
case MEASURE_LIST:
case JUMP:
case MARKER:
case LAYOUT_BREAK:
viewer->setDropRectangle(rr);
return true;
case BRACKET:
case REPEAT_MEASURE:
case MEASURE:
case SPACER:
case IMAGE:
viewer->setDropRectangle(r);
return true;
case BAR_LINE:
case SYMBOL:
// accept drop only inside staff
if (mrpy < t || mrpy > b)
return false;
viewer->setDropRectangle(r);
return true;
case CLEF:
{
// accept drop only inside staff
if (mrpy < t || mrpy > b)
return false;
viewer->setDropRectangle(r);
// search segment list backwards for segchordrest
for (Segment* seg = last(); seg; seg = seg->prev()) {
if (seg->segmentType() != Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
continue;
// SegChordRest found, check if it contains anything in this staff
for (int track = idx * VOICES; track < idx * VOICES + VOICES; ++track)
if (seg->element(track)) {
// LVIFIX: for the rest in newly created empty measures,
// seg->pos().x() is incorrect
return mrpx < seg->pos().x();
}
}
}
return false;
case ICON:
switch(static_cast<Icon*>(e)->iconType()) {
2012-05-26 14:26:10 +02:00
case ICON_VFRAME:
case ICON_HFRAME:
case ICON_TFRAME:
case ICON_FFRAME:
case ICON_MEASURE:
viewer->setDropRectangle(rr);
return true;
}
break;
case KEYSIG:
case TIMESIG:
// accept drop only inside staff
if (mrpy < t || mrpy > b)
return false;
viewer->setDropRectangle(r);
2013-07-18 15:54:05 +02:00
return true;
2012-05-26 14:26:10 +02:00
default:
break;
}
return false;
}
//---------------------------------------------------------
// drop
/// Drop element.
/// Handle a dropped element at position \a pos of given
/// element \a type and \a subtype.
//---------------------------------------------------------
Element* Measure::drop(const DropData& data)
{
Element* e = data.element;
int staffIdx;
Segment* seg;
_score->pos2measure(data.pos, &staffIdx, 0, &seg, 0);
if (e->systemFlag())
staffIdx = 0;
QPointF mrp(data.pos - pagePos());
Staff* staff = score()->staff(staffIdx);
switch(e->type()) {
case MEASURE_LIST:
qDebug("drop measureList or StaffList");
delete e;
break;
case STAFF_LIST:
qDebug("drop staffList");
//TODO score()->pasteStaff(e, this, staffIdx);
delete e;
break;
case MARKER:
case JUMP:
e->setParent(seg);
e->setTrack(0);
score()->undoAddElement(e);
return e;
case DYNAMIC:
case FRET_DIAGRAM:
e->setParent(seg);
e->setTrack(staffIdx * VOICES);
score()->undoAddElement(e);
return e;
case IMAGE:
case SYMBOL:
e->setParent(seg);
e->setTrack(staffIdx * VOICES);
e->layout();
{
QPointF uo(data.pos - e->canvasPos() - data.dragOffset);
e->setUserOff(uo);
}
score()->undoAddElement(e);
return e;
case BRACKET:
2013-06-28 17:46:24 +02:00
{
Bracket* b = static_cast<Bracket*>(e);
int level = 0;
int firstStaff = 0;
foreach (Staff* s, score()->staves()) {
foreach (const BracketItem& bi, s->brackets()) {
int lastStaff = firstStaff + bi._bracketSpan - 1;
if (staffIdx >= firstStaff && staffIdx <= lastStaff)
++level;
}
firstStaff++;
2013-06-28 17:46:24 +02:00
}
score()->undoAddBracket(staff, level, b->bracketType(), 1);
delete b;
}
return 0;
2012-05-26 14:26:10 +02:00
case CLEF:
score()->undoChangeClef(staff, first(), static_cast<Clef*>(e)->clefType());
delete e;
break;
case KEYSIG:
{
KeySig* ks = static_cast<KeySig*>(e);
KeySigEvent k = ks->keySigEvent();
//add custom key to score if not exist
if (k.custom()) {
int customIdx = score()->customKeySigIdx(ks);
if (customIdx == -1) {
customIdx = score()->addCustomKeySig(ks);
k.setCustomType(customIdx);
}
else
delete ks;
}
else
delete ks;
if (data.modifiers & Qt::ControlModifier) {
// apply only to this stave
score()->undoChangeKeySig(staff, tick(), k);
}
else {
2012-05-26 14:26:10 +02:00
// apply to all staves:
foreach(Staff* s, score()->staves())
score()->undoChangeKeySig(s, tick(), k);
}
2012-08-10 10:14:17 +02:00
2012-05-26 14:26:10 +02:00
break;
}
case TIMESIG:
score()->cmdAddTimeSig(this, staffIdx, static_cast<TimeSig*>(e),
data.modifiers & Qt::ControlModifier);
2012-05-26 14:26:10 +02:00
return 0;
case LAYOUT_BREAK:
{
LayoutBreak* lb = static_cast<LayoutBreak*>(e);
if (
2013-10-05 23:13:33 +02:00
(lb->layoutBreakType() == LayoutBreak::PAGE && _pageBreak)
|| (lb->layoutBreakType() == LayoutBreak::LINE && _lineBreak)
|| (lb->layoutBreakType() == LayoutBreak::SECTION && _sectionBreak)
2012-05-26 14:26:10 +02:00
) {
//
// if break already set
//
delete lb;
break;
}
2013-10-05 23:13:33 +02:00
// make sure there is only LayoutBreak::LINE or LayoutBreak::PAGE
if ((lb->layoutBreakType() != LayoutBreak::SECTION) && (_pageBreak || _lineBreak)) {
2012-05-26 14:26:10 +02:00
foreach(Element* le, _el) {
if (le->type() == LAYOUT_BREAK
2013-10-05 23:13:33 +02:00
&& (static_cast<LayoutBreak*>(le)->layoutBreakType() == LayoutBreak::LINE
|| static_cast<LayoutBreak*>(le)->layoutBreakType() == LayoutBreak::PAGE)) {
2012-05-26 14:26:10 +02:00
score()->undoChangeElement(le, e);
break;
}
}
break;
}
lb->setTrack(-1); // this are system elements
lb->setParent(this);
score()->undoAddElement(lb);
return lb;
}
case SPACER:
{
Spacer* spacer = static_cast<Spacer*>(e);
spacer->setTrack(staffIdx * VOICES);
spacer->setParent(this);
score()->undoAddElement(spacer);
return spacer;
}
case BAR_LINE:
{
BarLine* bl = static_cast<BarLine*>(e);
// if dropped bar line refers to span rather than to subtype
if (bl->spanFrom() != 0 && bl->spanTo() != DEFAULT_BARLINE_TO) {
// get existing bar line for this staff, and drop the change to it
Segment* seg = undoGetSegment(Segment::SegEndBarLine, tick() + ticks());
BarLine* cbl = static_cast<BarLine*>(seg->element(staffIdx * VOICES));
if (cbl)
cbl->drop(data);
}
// if dropped bar line refers to line subtype
else {
score()->undoChangeBarLine(this, bl->barLineType());
delete e;
}
2012-05-26 14:26:10 +02:00
break;
}
2012-05-26 14:26:10 +02:00
case REPEAT_MEASURE:
{
delete e;
return cmdInsertRepeatMeasure(staffIdx);
2012-05-26 14:26:10 +02:00
}
case ICON:
switch(static_cast<Icon*>(e)->iconType()) {
2012-05-26 14:26:10 +02:00
case ICON_VFRAME:
score()->insertMeasure(VBOX, this);
break;
case ICON_HFRAME:
score()->insertMeasure(HBOX, this);
break;
case ICON_TFRAME:
score()->insertMeasure(TBOX, this);
break;
case ICON_FFRAME:
score()->insertMeasure(FBOX, this);
break;
case ICON_MEASURE:
score()->insertMeasure(MEASURE, this);
break;
}
break;
default:
qDebug("Measure: cannot drop %s here", e->name());
delete e;
break;
}
return 0;
}
//---------------------------------------------------------
// cmdRemoveEmptySegment
//---------------------------------------------------------
void Measure::cmdRemoveEmptySegment(Segment* s)
{
if (s->isEmpty())
_score->undoRemoveElement(s);
}
//---------------------------------------------------------
// cmdInsertRepeatMeasure
//---------------------------------------------------------
RepeatMeasure* Measure::cmdInsertRepeatMeasure(int staffIdx)
{
//
// see also cmdDeleteSelection()
//
_score->select(0, SELECT_SINGLE, 0);
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() & Segment::SegChordRest) {
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* el = s->element(track);
if (el)
_score->undoRemoveElement(el);
}
if (s->isEmpty())
_score->undoRemoveElement(s);
}
}
//
// add repeat measure
//
Segment* seg = undoGetSegment(Segment::SegChordRest, tick());
RepeatMeasure* rm = new RepeatMeasure(_score);
rm->setTrack(staffIdx * VOICES);
rm->setParent(seg);
_score->undoAddElement(rm);
foreach(Element* el, _el) {
if (el->type() == SLUR && el->staffIdx() == staffIdx)
_score->undoRemoveElement(el);
}
return rm;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// adjustToLen
// change actual measure len, adjust elements to
// new len
//---------------------------------------------------------
void Measure::adjustToLen(Fraction nf)
{
int ol = len().ticks();
int nl = nf.ticks();
int diff = nl - ol;
int startTick = endTick();
if (diff < 0)
startTick += diff;
score()->undoInsertTime(startTick, diff);
2012-05-26 14:26:10 +02:00
2013-10-21 13:11:04 +02:00
score()->undo(new ChangeMeasureLen(this, nf));
2012-05-26 14:26:10 +02:00
int staves = score()->nstaves();
if (nl > ol) {
2013-10-21 13:11:04 +02:00
// move EndBarLine, TimeSigAnnounce, KeySigAnnounce
2012-05-26 14:26:10 +02:00
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() & (Segment::SegEndBarLine|Segment::SegTimeSigAnnounce|Segment::SegKeySigAnnounce)) {
2012-05-26 14:26:10 +02:00
s->setTick(tick() + nl);
}
}
}
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int rests = 0;
int chords = 0;
Rest* rest = 0;
for (Segment* segment = first(); segment; segment = segment->next()) {
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = segment->element(track);
2013-10-21 13:11:04 +02:00
if (e) {
if (e->type() == REST) {
++rests;
rest = static_cast<Rest*>(e);
}
else if (e->type() == CHORD)
++chords;
2012-05-26 14:26:10 +02:00
}
}
}
2013-10-21 13:11:04 +02:00
if (rests == 1 && chords == 0) {
if (rest->durationType().type() == TDuration::V_MEASURE) {
if (_timesig == nf) {
score()->undo(new ChangeChordRestDuration(rest, nf));
continue;
}
else {
score()->undo(new ChangeChordRestLen(rest, _timesig));
// DON'T continue here because we want the rest broken up below
}
2013-10-21 13:11:04 +02:00
}
else if (_timesig == nf) {
score()->undo(new ChangeChordRestLen(rest, TDuration(TDuration::V_MEASURE)));
continue;
}
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
int strack = staffIdx * VOICES;
int etrack = strack + VOICES;
for (int trk = strack; trk < etrack; ++trk) {
int n = diff;
bool rFlag = false;
if (n < 0) {
for (Segment* segment = last(); segment;) {
Segment* pseg = segment->prev();
Element* e = segment->element(trk);
if (e && e->isChordRest()) {
ChordRest* cr = static_cast<ChordRest*>(e);
if (cr->durationType() == TDuration::V_MEASURE) {
int actualTicks = cr->actualTicks();
n += actualTicks;
cr->setDurationType(TDuration(actualTicks));
}
2013-10-21 13:11:04 +02:00
else
n += cr->actualTicks();
score()->undoRemoveElement(e);
if (segment->isEmpty())
score()->undoRemoveElement(segment);
if (n >= 0)
break;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
segment = pseg;
2012-05-26 14:26:10 +02:00
}
2013-10-21 13:11:04 +02:00
rFlag = true;
}
int voice = trk % VOICES;
if ((n > 0) && (rFlag || voice == 0)) {
// add rest to measure
int rtick = tick() + nl - n;
int track = staffIdx * VOICES + voice;
score()->setRest(rtick, track, Fraction::fromTicks(n), false, 0, false);
2012-05-26 14:26:10 +02:00
}
}
}
if (diff < 0) {
//
// CHECK: do not remove all slurs
//
foreach(Element* e, _el) {
if (e->type() == SLUR)
score()->undoRemoveElement(e);
}
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Measure::write(Xml& xml, int staff, bool writeSystemElements) const
{
int mno = _no + 1;
if (_len != _timesig) {
// this is an irregular measure
xml.stag(QString("Measure number=\"%1\" len=\"%2/%3\"").arg(mno).arg(_len.numerator()).arg(_len.denominator()));
}
else
xml.stag(QString("Measure number=\"%1\"").arg(mno));
2014-02-28 14:25:47 +01:00
2012-05-26 14:26:10 +02:00
xml.curTick = tick();
2014-02-26 19:06:42 +01:00
if (_mmRestCount > 0)
xml.tag("multiMeasureRest", _mmRestCount);
2012-05-26 14:26:10 +02:00
if (writeSystemElements) {
if (_repeatFlags & RepeatStart)
xml.tagE("startRepeat");
if (_repeatFlags & RepeatEnd)
xml.tag("endRepeat", _repeatCount);
if (_irregular)
xml.tagE("irregular");
if (_breakMultiMeasureRest)
xml.tagE("breakMultiMeasureRest");
if (_userStretch != 1.0)
xml.tag("stretch", _userStretch);
if (_noOffset)
xml.tag("noOffset", _noOffset);
}
qreal _spatium = spatium();
MStaff* mstaff = staves[staff];
if (mstaff->noText() && !mstaff->noText()->generated()) {
xml.stag("MeasureNumber");
mstaff->noText()->writeProperties(xml);
xml.etag();
}
2012-05-26 14:26:10 +02:00
if (mstaff->_vspacerUp)
xml.tag("vspacerUp", mstaff->_vspacerUp->gap() / _spatium);
if (mstaff->_vspacerDown)
xml.tag("vspacerDown", mstaff->_vspacerDown->gap() / _spatium);
if (!mstaff->_visible)
xml.tag("visible", mstaff->_visible);
if (mstaff->_slashStyle)
xml.tag("slashStyle", mstaff->_slashStyle);
int strack = staff * VOICES;
int etrack = strack + VOICES;
foreach (const Element* el, _el) {
2012-09-21 12:23:18 +02:00
if (!el->generated() && ((el->staffIdx() == staff) || (el->systemFlag() && writeSystemElements))) {
2012-05-26 14:26:10 +02:00
el->write(xml);
}
}
Q_ASSERT(first());
Q_ASSERT(last());
2013-10-13 13:06:32 +02:00
score()->writeSegments(xml, strack, etrack, first(), last()->next1(), writeSystemElements, false, false);
2012-05-26 14:26:10 +02:00
xml.etag();
}
2014-02-26 19:06:42 +01:00
//---------------------------------------------------------
// ticks
//---------------------------------------------------------
int Measure::ticks() const
{
return _len.ticks();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Measure::read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Measure::read(XmlReader& e, int staffIdx)
2012-05-26 14:26:10 +02:00
{
Segment* segment = 0;
qreal _spatium = spatium();
2013-06-16 23:33:37 +02:00
QList<Chord*> graceNotes;
//sort tuplet elements. needed for nested tuplets #22537
if (score()->mscVersion() <= 114) {
for(Tuplet* t : e.tuplets()) {
t->sortElements();
}
}
2013-01-23 14:14:09 +01:00
e.tuplets().clear();
2013-06-10 21:13:04 +02:00
e.setTrack(staffIdx * VOICES);
2013-01-23 14:14:09 +01:00
2012-05-26 14:26:10 +02:00
for (int n = staves.size(); n <= staffIdx; ++n) {
Staff* staff = score()->staff(n);
2012-09-14 10:09:06 +02:00
MStaff* s = new MStaff;
2012-05-26 14:26:10 +02:00
s->lines = new StaffLines(score());
s->lines->setParent(this);
s->lines->setTrack(n * VOICES);
s->lines->setVisible(!staff->invisible());
staves.append(s);
}
// tick is obsolete
2013-01-11 18:10:18 +01:00
if (e.hasAttribute("tick"))
2013-01-21 20:21:41 +01:00
e.setTick(score()->fileDivision(e.intAttribute("tick")));
2013-06-24 19:01:31 +02:00
// setTick(e.tick());
2013-06-10 21:13:04 +02:00
// e.setTick(tick());
2012-05-26 14:26:10 +02:00
2013-06-04 18:29:14 +02:00
bool irregular;
2013-01-11 18:10:18 +01:00
if (e.hasAttribute("len")) {
QStringList sl = e.attribute("len").split('/');
2012-05-26 14:26:10 +02:00
if (sl.size() == 2)
_len = Fraction(sl[0].toInt(), sl[1].toInt());
else
2013-01-11 18:10:18 +01:00
qDebug("illegal measure size <%s>", qPrintable(e.attribute("len")));
2012-05-26 14:26:10 +02:00
irregular = true;
score()->sigmap()->add(tick(), SigEvent(_len, _timesig));
score()->sigmap()->add(tick() + ticks(), SigEvent(_timesig));
}
2013-06-04 18:29:14 +02:00
else
irregular = false;
2013-06-04 18:29:14 +02:00
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
2012-06-28 15:12:17 +02:00
Fraction timeStretch(staff->timeStretch(tick()));
2012-05-26 14:26:10 +02:00
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
2013-01-11 18:10:18 +01:00
if (tag == "tick")
2013-01-21 20:21:41 +01:00
e.setTick(e.readInt());
2012-05-26 14:26:10 +02:00
else if (tag == "BarLine") {
BarLine* barLine = new BarLine(score());
2013-01-21 20:21:41 +01:00
barLine->setTrack(e.track());
2012-05-26 14:26:10 +02:00
barLine->read(e);
Segment::SegmentType st;
//
// SegStartRepeatBarLine: always at the beginning tick of a measure
// SegBarLine: in the middle of a measure, has no semantic
// SegEndBarLine: at the end tick of a measure
2014-02-26 19:06:42 +01:00
if (isMMRest()) {
// this is a multi measure rest
// always preceded by the first measure it replaces
Measure* m = e.lastMeasure();
Q_ASSERT(m); // debug
if (m) {
m->setMMRest(this);
setTick(m->tick());
}
}
if ((e.tick() != tick()) && (e.tick() != endTick())) {
st = Segment::SegBarLine;
2014-02-26 19:06:42 +01:00
}
else if (barLine->barLineType() == START_REPEAT && e.tick() == tick())
st = Segment::SegStartRepeatBarLine;
2012-05-26 14:26:10 +02:00
else {
setEndBarLineType(barLine->barLineType(), false, true);
if(!barLine->customSpan()) {
Staff* staff = score()->staff(staffIdx);
barLine->setSpan(staff->barLineSpan());
}
st = Segment::SegEndBarLine;
2012-05-26 14:26:10 +02:00
}
segment = getSegment(st, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(barLine);
}
else if (tag == "Chord") {
2013-06-19 18:20:09 +02:00
2013-06-16 23:33:37 +02:00
Chord* chord = new Chord(score());
chord->setTrack(e.track());
chord->read(e);
segment = getSegment(Segment::SegChordRest, e.tick());
2013-06-10 21:13:04 +02:00
2013-06-16 23:33:37 +02:00
if (chord->noteType() != NOTE_NORMAL)
graceNotes.push_back(chord);
2012-05-26 14:26:10 +02:00
else {
2013-06-16 23:33:37 +02:00
segment->add(chord);
2013-06-24 13:46:21 +02:00
Q_ASSERT(segment->segmentType() == Segment::SegChordRest);
2013-06-16 23:33:37 +02:00
for (int i = 0; i < graceNotes.size(); ++i) {
Chord* gc = graceNotes[i];
gc->setGraceIndex(i);
chord->add(gc);
}
graceNotes.clear();
2013-06-10 21:13:04 +02:00
Fraction ts(timeStretch * chord->globalDuration());
int crticks = ts.ticks();
if (chord->tremolo() && chord->tremolo()->tremoloType() < TREMOLO_R8) {
//
// old style tremolo found
//
Tremolo* tremolo = chord->tremolo();
TremoloType st;
switch (tremolo->tremoloType()) {
default:
case OLD_TREMOLO_R8: st = TREMOLO_R8; break;
case OLD_TREMOLO_R16: st = TREMOLO_R16; break;
case OLD_TREMOLO_R32: st = TREMOLO_R32; break;
case OLD_TREMOLO_C8: st = TREMOLO_C8; break;
case OLD_TREMOLO_C16: st = TREMOLO_C16; break;
case OLD_TREMOLO_C32: st = TREMOLO_C32; break;
}
tremolo->setTremoloType(st);
if (tremolo->twoNotes()) {
int track = chord->track();
Segment* ss = 0;
for (Segment* ps = first(Segment::SegChordRest); ps; ps = ps->next(Segment::SegChordRest)) {
if (ps->tick() >= e.tick())
break;
if (ps->element(track))
ss = ps;
}
Chord* pch = 0; // previous chord
if (ss) {
ChordRest* cr = static_cast<ChordRest*>(ss->element(track));
if (cr && cr->type() == CHORD)
pch = static_cast<Chord*>(cr);
}
if (pch) {
tremolo->setParent(pch);
pch->setTremolo(tremolo);
chord->setTremolo(0);
// force duration to half
2013-06-27 10:03:36 +02:00
Fraction pts(timeStretch * pch->globalDuration());
int pcrticks = pts.ticks();
pch->setDuration(pcrticks / 2);
chord->setDuration(crticks / 2);
2013-06-10 21:13:04 +02:00
}
else {
qDebug("tremolo: first note not found");
}
crticks /= 2;
}
else {
tremolo->setParent(chord);
}
}
2013-06-04 18:29:14 +02:00
e.rtick() += crticks;
2012-05-26 14:26:10 +02:00
}
}
else if (tag == "Rest") {
Rest* rest = new Rest(score());
rest->setDurationType(TDuration::V_MEASURE);
rest->setDuration(timesig()/timeStretch);
2013-01-21 20:21:41 +01:00
rest->setTrack(e.track());
rest->read(e);
2012-05-26 14:26:10 +02:00
2013-01-21 20:21:41 +01:00
segment = getSegment(rest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rest);
if (!rest->duration().isValid()) // hack
rest->setDuration(timesig()/timeStretch);
Fraction ts(timeStretch * rest->globalDuration());
2013-06-04 18:29:14 +02:00
e.rtick() += ts.ticks();
2012-05-26 14:26:10 +02:00
}
else if (tag == "Breath") {
Breath* breath = new Breath(score());
2013-01-21 20:21:41 +01:00
breath->setTrack(e.track());
2012-05-26 14:26:10 +02:00
breath->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegBreath, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(breath);
}
else if (tag == "endSpanner") {
int id = e.attribute("id").toInt();
2013-01-11 18:10:18 +01:00
Spanner* spanner = score()->findSpanner(id);
if (spanner) {
spanner->setTick2(e.tick());
// if (spanner->track2() == -1)
// the absence of a track tag [?] means the
// track is the same as the beginning of the slur
if(spanner->track2() == -1)
spanner->setTrack2(spanner->track() ? spanner->track() : e.track());
2013-01-11 18:10:18 +01:00
if (spanner->type() == OTTAVA) {
Ottava* o = static_cast<Ottava*>(spanner);
2013-07-16 09:03:47 +02:00
o->staff()->updateOttava(o);
2012-05-26 14:26:10 +02:00
}
2013-01-11 18:10:18 +01:00
else if (spanner->type() == HAIRPIN) {
Hairpin* hp = static_cast<Hairpin*>(spanner);
2012-05-26 14:26:10 +02:00
score()->updateHairpin(hp);
}
}
2013-10-13 13:06:32 +02:00
else {
// remember "endSpanner" values
SpannerValues sv;
sv.spannerId = id;
sv.track2 = e.track();
sv.tick2 = e.tick();
e.addSpannerValues(sv);
}
2013-01-11 18:10:18 +01:00
e.readNext();
2012-05-26 14:26:10 +02:00
}
else if (tag == "Slur") {
Slur *sl = new Slur(score());
sl->setTick(e.tick());
sl->read(e);
score()->addSpanner(sl);
//
// check if we already saw "endSpanner"
//
const SpannerValues* sv = e.spannerValues(sl->id());
if (sv) {
sl->setTick2(sv->tick2);
}
}
2012-05-26 14:26:10 +02:00
else if (tag == "HairPin"
|| tag == "Pedal"
|| tag == "Ottava"
|| tag == "Trill"
|| tag == "TextLine"
|| tag == "Volta") {
2013-01-18 10:55:52 +01:00
Spanner* sp = static_cast<Spanner*>(Element::name2Element(tag, score()));
2013-06-10 11:03:34 +02:00
sp->setTrack(e.track());
sp->setTick(e.tick());
2013-06-16 23:33:37 +02:00
sp->setAnchor(Spanner::ANCHOR_SEGMENT);
2012-05-26 14:26:10 +02:00
sp->read(e);
2013-06-20 13:57:15 +02:00
score()->addSpanner(sp);
2013-10-13 13:06:32 +02:00
//
// check if we already saw "endSpanner"
//
const SpannerValues* sv = e.spannerValues(sp->id());
if (sv) {
sp->setTick2(sv->tick2);
sp->setTrack2(sv->track2);
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "RepeatMeasure") {
RepeatMeasure* rm = new RepeatMeasure(score());
2013-01-21 20:21:41 +01:00
rm->setTrack(e.track());
rm->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(rm);
2013-01-21 20:21:41 +01:00
e.setTick(e.tick() + ticks());
2012-05-26 14:26:10 +02:00
}
else if (tag == "Clef") {
Clef* clef = new Clef(score());
2013-01-21 20:21:41 +01:00
clef->setTrack(e.track());
2012-05-26 14:26:10 +02:00
clef->read(e);
clef->setGenerated(false);
2013-07-12 18:41:33 +02:00
// there may be more than one clef segment for same tick position
if (!segment)
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegClef, e.tick());
2013-07-12 18:41:33 +02:00
else {
Segment* ns = 0;
if (segment->next()) {
ns = segment->next();
while (ns && ns->tick() < e.tick())
ns = ns->next();
}
segment = 0;
for (Segment* s = ns; s && s->tick() == e.tick(); s = s->next()) {
if (s->segmentType() == Segment::SegClef) {
segment = s;
break;
}
}
if (!segment) {
segment = new Segment(this, Segment::SegClef, e.tick());
_segments.insert(segment, ns);
}
2012-05-26 14:26:10 +02:00
}
segment->add(clef);
}
else if (tag == "TimeSig") {
TimeSig* ts = new TimeSig(score());
2013-01-21 20:21:41 +01:00
ts->setTrack(e.track());
2012-10-24 13:15:46 +02:00
ts->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegTimeSig, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(ts);
2013-06-04 18:29:14 +02:00
timeStretch = ts->stretch().reduced();
2013-07-15 15:40:32 +02:00
_timesig = ts->sig() * timeStretch;
if (score()->mscVersion() > 114) {
2013-06-04 18:29:14 +02:00
if (irregular) {
score()->sigmap()->add(tick(), SigEvent(_len, _timesig));
score()->sigmap()->add(tick() + ticks(), SigEvent(_timesig));
}
else {
_len = _timesig;
score()->sigmap()->add(tick(), SigEvent(_timesig));
}
2012-06-28 15:12:17 +02:00
}
2012-05-26 14:26:10 +02:00
}
else if (tag == "KeySig") {
KeySig* ks = new KeySig(score());
2013-01-21 20:21:41 +01:00
ks->setTrack(e.track());
2012-05-26 14:26:10 +02:00
ks->read(e);
2013-01-21 20:21:41 +01:00
int tick = e.tick();
segment = getSegment(Segment::SegKeySig, tick);
2012-05-26 14:26:10 +02:00
segment->add(ks);
staff->setKey(tick, ks->keySigEvent());
}
else if (tag == "Lyrics") { // obsolete, keep for compatibility with version 114
Element* element = Element::name2Element(tag, score());
element->setTrack(e.track());
element->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegChordRest, e.tick());
ChordRest* cr = static_cast<ChordRest*>(segment->element(e.track()));
2012-05-26 14:26:10 +02:00
if (!cr)
qDebug("Internal Error: no Chord/Rest for lyrics");
else
cr->add(element);
2012-05-26 14:26:10 +02:00
}
else if (tag == "Text") {
Text* t = new Text(score());
2013-01-21 20:21:41 +01:00
t->setTrack(e.track());
2012-05-26 14:26:10 +02:00
t->read(e);
// previous versions stored measure number, delete it
if ((score()->mscVersion() <= 114) && (t->textStyleType() == TEXT_STYLE_MEASURE_NUMBER))
2012-09-21 12:23:18 +02:00
delete t;
else {
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegChordRest, e.tick());
2012-09-21 12:23:18 +02:00
segment->add(t);
}
2012-05-26 14:26:10 +02:00
}
//----------------------------------------------------
// Annotation
else if (tag == "Dynamic") {
Dynamic* dyn = new Dynamic(score());
2013-01-21 20:21:41 +01:00
dyn->setTrack(e.track());
2012-05-26 14:26:10 +02:00
dyn->read(e);
2013-02-14 13:50:59 +01:00
if (score()->mscVersion() <= 114)
dyn->setDynamicType(dyn->text());
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(dyn);
}
else if (tag == "Harmony"
|| tag == "FretDiagram"
|| tag == "Symbol"
|| tag == "Tempo"
|| tag == "StaffText"
|| tag == "RehearsalMark"
|| tag == "InstrumentChange"
|| tag == "Marker"
|| tag == "Jump"
|| tag == "StaffState"
|| tag == "FiguredBass"
2013-06-10 11:03:34 +02:00
|| tag == "Image"
2012-05-26 14:26:10 +02:00
) {
2013-01-18 10:55:52 +01:00
Element* el = Element::name2Element(tag, score());
2013-01-21 20:21:41 +01:00
el->setTrack(e.track());
2012-05-26 14:26:10 +02:00
el->read(e);
2013-01-21 20:21:41 +01:00
segment = getSegment(Segment::SegChordRest, e.tick());
2012-05-26 14:26:10 +02:00
segment->add(el);
}
//----------------------------------------------------
else if (tag == "stretch")
2013-01-11 18:10:18 +01:00
_userStretch = e.readDouble();
2012-05-26 14:26:10 +02:00
else if (tag == "LayoutBreak") {
LayoutBreak* lb = new LayoutBreak(score());
lb->read(e);
add(lb);
}
else if (tag == "noOffset")
2013-01-11 18:10:18 +01:00
_noOffset = e.readInt();
2013-01-17 12:56:14 +01:00
else if (tag == "irregular") {
2012-05-26 14:26:10 +02:00
_irregular = true;
2013-01-17 12:56:14 +01:00
e.readNext();
}
else if (tag == "breakMultiMeasureRest") {
2012-05-26 14:26:10 +02:00
_breakMultiMeasureRest = true;
2013-01-17 12:56:14 +01:00
e.readNext();
}
2012-05-26 14:26:10 +02:00
else if (tag == "Tuplet") {
Tuplet* tuplet = new Tuplet(score());
2013-01-21 20:21:41 +01:00
tuplet->setTrack(e.track());
tuplet->setTick(e.tick());
2012-05-26 14:26:10 +02:00
tuplet->setParent(this);
tuplet->read(e);
2013-01-21 20:21:41 +01:00
e.addTuplet(tuplet);
2012-05-26 14:26:10 +02:00
}
2013-01-11 18:10:18 +01:00
else if (tag == "startRepeat") {
2012-05-26 14:26:10 +02:00
_repeatFlags |= RepeatStart;
2013-01-11 18:10:18 +01:00
e.readNext();
}
2012-05-26 14:26:10 +02:00
else if (tag == "endRepeat") {
2013-01-11 18:10:18 +01:00
_repeatCount = e.readInt();
2012-05-26 14:26:10 +02:00
_repeatFlags |= RepeatEnd;
}
else if (tag == "vspacer" || tag == "vspacerDown") {
if (staves[staffIdx]->_vspacerDown == 0) {
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SPACER_DOWN);
2012-05-26 14:26:10 +02:00
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
2013-01-11 18:10:18 +01:00
staves[staffIdx]->_vspacerDown->setGap(e.readDouble() * _spatium);
2012-05-26 14:26:10 +02:00
}
else if (tag == "vspacer" || tag == "vspacerUp") {
if (staves[staffIdx]->_vspacerUp == 0) {
Spacer* spacer = new Spacer(score());
spacer->setSpacerType(SPACER_UP);
2012-05-26 14:26:10 +02:00
spacer->setTrack(staffIdx * VOICES);
add(spacer);
}
2013-01-11 18:10:18 +01:00
staves[staffIdx]->_vspacerUp->setGap(e.readDouble() * _spatium);
2012-05-26 14:26:10 +02:00
}
else if (tag == "visible")
2013-01-11 18:10:18 +01:00
staves[staffIdx]->_visible = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "slashStyle")
2013-01-11 18:10:18 +01:00
staves[staffIdx]->_slashStyle = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "Beam") {
Beam* beam = new Beam(score());
2013-01-21 20:21:41 +01:00
beam->setTrack(e.track());
2012-05-26 14:26:10 +02:00
beam->read(e);
beam->setParent(0);
2013-01-21 20:21:41 +01:00
e.addBeam(beam);
2012-05-26 14:26:10 +02:00
}
else if (tag == "Segment")
2013-06-24 19:01:31 +02:00
segment->read(e);
2012-10-17 10:39:39 +02:00
else if (tag == "MeasureNumber") {
Text* noText = new Text(score());
noText->read(e);
noText->setFlag(ELEMENT_ON_STAFF, true);
// noText->setFlag(ELEMENT_MOVABLE, false); ??
noText->setTrack(e.track());
noText->setParent(this);
staves[noText->staffIdx()]->setNoText(noText);
2012-10-17 10:39:39 +02:00
}
2013-11-25 12:17:12 +01:00
else if (tag == "Ambitus") {
Ambitus* range = new Ambitus(score());
range->read(e);
2013-11-25 12:17:12 +01:00
segment = getSegment(Segment::SegAmbitus, e.tick());
range->setParent(segment); // a parent segment is needed for setTrack() to work
range->setTrack(trackZeroVoice(e.track()));
segment->add(range);
}
2014-02-26 19:06:42 +01:00
else if (tag == "multiMeasureRest")
_mmRestCount = e.readInt();
2013-01-17 12:56:14 +01:00
else if (Element::readProperties(e))
;
2012-05-26 14:26:10 +02:00
else
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
if (staffIdx == 0) {
Segment* s = last();
if (s && s->segmentType() == Segment::SegBarLine) {
2012-05-26 14:26:10 +02:00
BarLine* b = static_cast<BarLine*>(s->element(0));
setEndBarLineType(b->barLineType(), false, b->visible(), b->color());
2012-05-26 14:26:10 +02:00
// s->remove(b);
// delete b;
}
}
//
// for compatibility with 1.22:
//
if (score()->mscVersion() == 122) {
int ticks1 = 0;
for (Segment* s = last(); s; s = s->prev()) {
if (s->segmentType() == Segment::SegChordRest) {
if (s->element(0)) {
ChordRest* cr = static_cast<ChordRest*>(s->element(0));
if (cr->type() == REPEAT_MEASURE)
ticks1 = ticks();
else
ticks1 = s->rtick() + cr->actualTicks();
break;
}
}
}
if (ticks() != ticks1) {
// this is a irregular measure
_len = Fraction::fromTicks(ticks1);
_len.reduce();
for (Segment* s = last(); s; s = s->prev()) {
if (s->tick() < tick() + ticks())
break;
if (s->segmentType() == Segment::SegBarLine) {
qDebug("reduce BarLine to EndBarLine");
s->setSegmentType(Segment::SegEndBarLine);
}
}
}
2012-05-26 14:26:10 +02:00
}
2013-01-21 20:21:41 +01:00
foreach (Tuplet* tuplet, e.tuplets()) {
2012-05-26 14:26:10 +02:00
if (tuplet->elements().isEmpty()) {
// this should not happen and is a sign of input file corruption
2013-01-24 09:31:41 +01:00
qDebug("Measure:read(): empty tuplet id %d (%p), input file corrupted?",
tuplet->id(), tuplet);
2012-05-26 14:26:10 +02:00
delete tuplet;
}
else
tuplet->setParent(this);
}
}
//---------------------------------------------------------
// visible
//---------------------------------------------------------
bool Measure::visible(int staffIdx) const
{
if (system() && (system()->staves()->isEmpty() || !system()->staff(staffIdx)->show()))
return false;
return score()->staff(staffIdx)->show() && staves[staffIdx]->_visible;
}
//---------------------------------------------------------
// slashStyle
//---------------------------------------------------------
bool Measure::slashStyle(int staffIdx) const
{
return score()->staff(staffIdx)->slashStyle() || staves[staffIdx]->_slashStyle || score()->staff(staffIdx)->staffType()->slashStyle();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// scanElements
//---------------------------------------------------------
void Measure::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
MeasureBase::scanElements(data, func, all);
int nstaves = score()->nstaves();
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!all && !(visible(staffIdx) && score()->staff(staffIdx)->show()))
2012-05-26 14:26:10 +02:00
continue;
MStaff* ms = staves[staffIdx];
if (ms->lines)
func(data, ms->lines);
if (ms->_vspacerUp)
func(data, ms->_vspacerUp);
if (ms->_vspacerDown)
func(data, ms->_vspacerDown);
if (ms->noText())
func(data, ms->noText());
2012-05-26 14:26:10 +02:00
}
int tracks = nstaves * VOICES;
for (Segment* s = first(); s; s = s->next()) {
// bar line visibility depends on spanned staves,
// not simply on visibility of first staff
if (s->segmentType() == Segment::SegBarLine || s->segmentType() == Segment::SegEndBarLine
|| s->segmentType() == Segment::SegStartRepeatBarLine) {
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
Element* e = s->element(staffIdx*VOICES);
if (e == 0) // if no element, skip
continue;
// if staff not visible
if (!all && !(visible(staffIdx) && score()->staff(staffIdx)->show())) {
// if bar line spans just this staff...
if (static_cast<BarLine*>(e)->span() <= 1
// ...or span another staff but without entering INTO it...
|| (static_cast<BarLine*>(e)->span() < 2 &&
static_cast<BarLine*>(e)->spanTo() < 1) )
continue; // ...skip
}
e->scanElements(data, func, all);
2012-05-26 14:26:10 +02:00
}
}
else
for (int track = 0; track < tracks; ++track) {
int staffIdx = track/VOICES;
if (!all && !(visible(staffIdx) && score()->staff(staffIdx)->show())) {
track += VOICES - 1;
continue;
}
Element* e = s->element(track);
if (e == 0)
continue;
e->scanElements(data, func, all);
}
2012-09-19 14:45:05 +02:00
foreach(Element* e, s->annotations()) {
if (all || e->systemFlag() || visible(e->staffIdx()))
2012-09-19 14:45:05 +02:00
e->scanElements(data, func, all);
}
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// createVoice
// Create a voice on demand by filling the measure
// with a whole measure rest.
// Check if there are any chord/rests in track; if
// not create a whole measure rest
//---------------------------------------------------------
void Measure::createVoice(int track)
{
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() != Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track) == 0)
score()->setRest(s->tick(), track, len(), true, 0);
break;
}
}
//---------------------------------------------------------
// setStartRepeatBarLine
// return true if bar line type changed
//---------------------------------------------------------
bool Measure::setStartRepeatBarLine(bool val)
{
bool changed = false;
Segment* s = findSegment(Segment::SegStartRepeatBarLine, tick());
bool customSpan = false;
int numStaves = score()->nstaves();
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < numStaves;) {
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES;
Staff* staff = score()->staff(staffIdx);
BarLine* bl = s ? static_cast<BarLine*>(s->element(track)) : nullptr;
int span, spanFrom, spanTo;
// if there is a bar line and has custom span, take span from it
if (bl && bl->customSpan()) {
span = bl->span();
spanFrom = bl->spanFrom();
spanTo = bl->spanTo();
customSpan = bl->customSpan();
}
else {
span = staff->barLineSpan();
spanFrom = staff->barLineFrom();
spanTo = staff->barLineTo();
if (span == 0 && customSpan) {
// spanned staves have already been skipped by the loop at the end;
// if a staff with span 0 is found and the previous bar line had custom span
// this staff shall have an aditional bar line, because the previous staff bar
// line has been shortened
int staffLines = staff->lines();
span = 1;
spanFrom = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0;
spanTo = staffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (staffLines-1) * 2;
}
customSpan = false;
}
// make sure we do not span more staves than actually exist
if (staffIdx + span > numStaves)
span = numStaves - staffIdx;
2012-05-26 14:26:10 +02:00
if (span && val && (bl == 0)) {
// no barline were we need one:
bl = new BarLine(score());
bl->setTrack(track);
bl->setBarLineType(START_REPEAT);
if (s == 0) {
if (score()->undoRedo()) {
return false;
}
s = undoGetSegment(Segment::SegStartRepeatBarLine, tick());
}
2012-05-26 14:26:10 +02:00
bl->setParent(s);
score()->undoAddElement(bl);
changed = true;
}
else if (bl && !val) {
// barline were we do not need one:
2013-10-25 12:17:42 +02:00
if (!score()->undoRedo()) // DEBUG
score()->undoRemoveElement(bl);
2012-05-26 14:26:10 +02:00
changed = true;
}
if (bl && val && span) {
2012-05-26 14:26:10 +02:00
bl->setSpan(span);
bl->setSpanFrom(spanFrom);
bl->setSpanTo(spanTo);
}
2012-05-26 14:26:10 +02:00
++staffIdx;
//
// remove any unwanted barlines:
//
// if spanning several staves but not entering INTO last staff,
if (span > 1 && spanTo <= 0)
span--; // count one span less
2012-05-26 14:26:10 +02:00
if (s) {
for (int i = 1; i < span; ++i) {
BarLine* bl = static_cast<BarLine*>(s->element(staffIdx * VOICES));
if (bl) {
score()->undoRemoveElement(bl);
changed = true;
}
++staffIdx;
}
}
}
return changed;
}
//---------------------------------------------------------
// createEndBarLines
// actually creates or modifies barlines
// returns true if layout changes
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
bool Measure::createEndBarLines()
{
bool changed = false;
int nstaves = score()->nstaves();
2014-02-26 19:06:42 +01:00
Segment* seg = undoGetSegment(Segment::SegEndBarLine, endTick());
2012-05-26 14:26:10 +02:00
2012-09-19 14:13:07 +02:00
BarLine* bl = 0;
int span = 0; // span counter
int aspan = 0; // actual span
bool mensur = false; // keep note of mensurstrich case
int spanTot; // to keep track of the target span
2012-10-14 09:25:33 +02:00
int spanFrom;
int spanTo;
2012-09-19 14:13:07 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
2012-05-26 14:26:10 +02:00
Staff* staff = score()->staff(staffIdx);
2012-10-14 09:25:33 +02:00
int track = staffIdx * VOICES;
// get existing bar line for this staff, if any
2012-09-19 14:13:07 +02:00
BarLine* cbl = static_cast<BarLine*>(seg->element(track));
// if span counter has been counted off, get new span values
// and forget about any previous bar line
2012-09-19 14:13:07 +02:00
if (span == 0) {
if(cbl && cbl->customSpan()) { // if there is a bar line and has custom span,
span = cbl->span(); // get span values from it
spanFrom = cbl->spanFrom();
spanTo = cbl->spanTo();
// if bar span values == staff span values, set bar as not custom
if(span == staff->barLineSpan() && spanFrom == staff->barLineFrom()
&& spanTo == staff->barLineTo())
cbl->setCustomSpan(false);
}
else { // otherwise, get from staff
span = staff->barLineSpan();
// if some span OR last staff (span=0) of a mensurstrich case, get From/To from staff
if (span || mensur) {
spanFrom = staff->barLineFrom();
spanTo = staff->barLineTo();
mensur = false;
}
// but if staff is set to no span, a multi-staff spanning bar line
// has been shortened to span less staves and following staves left without bars;
// set bar line span values to default
else {
span = 1;
spanFrom = 0;
spanTo = (staff->lines()-1)*2;
}
}
2012-09-19 14:13:07 +02:00
if ((staffIdx + span) > nstaves)
span = nstaves - staffIdx;
spanTot = span;
2012-09-19 14:13:07 +02:00
bl = 0;
}
if (staff->show() && span) {
//
// there should be a barline in this staff
//
// if we already have a bar line, keep extending this bar line down until span exhausted;
// if no barline yet, re-use the bar line existing in this staff if any,
// restarting actual span
2012-09-19 14:13:07 +02:00
if (!bl) {
bl = cbl;
aspan = 0;
2012-05-26 14:26:10 +02:00
}
2012-09-19 14:13:07 +02:00
if (!bl) {
// no suitable bar line: create a new one
2012-09-19 14:13:07 +02:00
bl = new BarLine(score());
bl->setVisible(_endBarLineVisible);
bl->setColor(_endBarLineColor);
2013-03-25 16:27:20 +01:00
bl->setGenerated(bl->el()->empty() && _endBarLineGenerated);
bl->setBarLineType(_endBarLineType);
2012-09-19 14:13:07 +02:00
bl->setParent(seg);
bl->setTrack(track);
score()->undoAddElement(bl);
changed = true;
}
else {
// a bar line is there (either existing or newly created):
// adjust subtype, if not fitting
if (bl->barLineType() != _endBarLineType && !bl->customSubtype()) {
score()->undoChangeProperty(bl, P_SUBTYPE, _endBarLineType);
2013-03-25 16:27:20 +01:00
bl->setGenerated(bl->el()->empty() && _endBarLineGenerated);
2012-05-26 14:26:10 +02:00
changed = true;
}
// or clear custom subtype flag if same type as measure
if (bl->barLineType() == _endBarLineType && bl->customSubtype())
bl->setCustomSubtype(false);
// if a bar line exists for this staff (cbl) but
// it is not the bar line we are dealing with (bl),
// we are extending down the bar line of a staff above (bl)
// and the bar line for this staff (cbl) is not needed:
// DELETE it
2012-09-19 14:13:07 +02:00
if (cbl && cbl != bl) {
// mensurstrich special case:
// if span arrives inside the end staff (spanTo>0) OR
// span is not multi-staff (spanTot<=1) OR
// current staff is not the last spanned staff (span!=1) OR
// staff is the last score staff
// remove bar line for this staff
// If NONE of the above conditions holds, the staff is the last staff of
// a mensurstrich(-like) span: keep its bar line, as it may span to next staff
2013-01-02 20:13:58 +01:00
if (spanTo > 0 || spanTot <= 1 || span != 1 || staffIdx == nstaves-1) {
score()->undoRemoveElement(cbl);
changed = true;
}
2012-05-26 14:26:10 +02:00
}
}
}
2012-09-19 14:13:07 +02:00
else {
//
2012-09-19 14:13:07 +02:00
// there should be no barline in this staff
//
2012-09-19 14:13:07 +02:00
if (cbl) {
score()->undoRemoveElement(cbl);
changed = true;
}
}
// if span not counted off AND we have a bar line AND this staff is shown,
// set bar line span values (this may result in extending down a bar line
// for a previous staff, if we are counting off a span > 1)
2012-09-19 14:13:07 +02:00
if (span) {
if (bl) {
++aspan;
2012-10-14 09:25:33 +02:00
if (staff->show()) { // update only if visible
2012-09-19 14:13:07 +02:00
bl->setSpan(aspan);
2012-10-14 09:25:33 +02:00
bl->setSpanFrom(spanFrom);
// if current actual span < target span, set spanTo to full staff height
if(aspan < spanTot)
bl->setSpanTo((staff->lines()-1)*2);
// if we reached target span, set spanTo to intended value
else
bl->setSpanTo(spanTo);
2012-10-14 09:25:33 +02:00
}
2012-09-19 14:13:07 +02:00
}
--span;
}
// if just finished (span==0) a multi-staff span (spanTot>1) ending at the top of a staff (spanTo<=0)
// scan this staff again, as it may have its own bar lines (mensurstich(-like) span)
if (spanTot > 1 && spanTo <= 0 && span == 0) {
mensur = true;
staffIdx--;
}
2012-05-26 14:26:10 +02:00
}
return changed;
}
//---------------------------------------------------------
// setEndBarLineType
//---------------------------------------------------------
void Measure::setEndBarLineType(BarLineType val, bool g, bool visible, QColor color)
{
_endBarLineType = val;
_endBarLineGenerated = g;
_endBarLineVisible = visible;
if(color.isValid())
_endBarLineColor = color;
else
_endBarLineColor = curColor();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// sortStaves
//---------------------------------------------------------
void Measure::sortStaves(QList<int>& dst)
{
QList<MStaff*> ms;
foreach (int idx, dst)
2012-05-26 14:26:10 +02:00
ms.push_back(staves[idx]);
staves = ms;
for (int staffIdx = 0; staffIdx < staves.size(); ++staffIdx) {
if (staves[staffIdx]->lines)
staves[staffIdx]->lines->setTrack(staffIdx * VOICES);
}
for (Segment* s = first(); s; s = s->next())
s->sortStaves(dst);
2013-10-14 15:34:46 +02:00
foreach (Element* e, _el) {
2012-05-26 14:26:10 +02:00
if (e->track() == -1)
continue;
int voice = e->voice();
int staffIdx = e->staffIdx();
int idx = dst.indexOf(staffIdx);
e->setTrack(idx * VOICES + voice);
}
}
//---------------------------------------------------------
// exchangeVoice
//---------------------------------------------------------
void Measure::exchangeVoice(int v1, int v2, int staffIdx1, int staffIdx2)
{
for (int staffIdx = staffIdx1; staffIdx < staffIdx2; ++ staffIdx) {
for (Segment* s = first(Segment::SegChordRest); s; s = s->next(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
int strack = staffIdx * VOICES + v1;
int dtrack = staffIdx * VOICES + v2;
s->swapElements(strack, dtrack);
}
MStaff* ms = mstaff(staffIdx);
ms->hasVoices = true;
}
}
//---------------------------------------------------------
// checkMultiVoices
2012-08-02 18:33:43 +02:00
/// Check for more than on voice in this measure and staff and
/// set MStaff->hasVoices
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::checkMultiVoices(int staffIdx)
{
int strack = staffIdx * VOICES + 1;
int etrack = staffIdx * VOICES + VOICES;
staves[staffIdx]->hasVoices = false;
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() != Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
continue;
for (int track = strack; track < etrack; ++track) {
if (s->element(track)) {
staves[staffIdx]->hasVoices = true;
return;
}
}
}
}
//---------------------------------------------------------
// hasVoice
//---------------------------------------------------------
bool Measure::hasVoice(int track) const
{
for (Segment* s = first(); s; s = s->next()) {
if (s->segmentType() != Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
continue;
if (s->element(track))
return true;
}
return false;
}
2012-08-02 18:33:43 +02:00
//-------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
// isMeasureRest
2012-08-02 18:33:43 +02:00
/// Check if the measure is filled by a full-measure rest or full
/// of rests on this staff. If staff is -1, then check for
/// all staves.
//-------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
bool Measure::isMeasureRest(int staffIdx)
{
int strack;
int etrack;
if (staffIdx < 0) {
strack = 0;
etrack = score()->nstaves() * VOICES;
}
else {
strack = staffIdx * VOICES;
etrack = staffIdx * VOICES + VOICES;
}
for (Segment* s = first(Segment::SegChordRest); s; s = s->next(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e && e->type() != REST)
return false;
}
}
return true;
}
//---------------------------------------------------------
// isFullMeasureRest
// Check for an empty measure, filled with full measure
// rests.
//---------------------------------------------------------
bool Measure::isFullMeasureRest()
{
int strack = 0;
int etrack = score()->nstaves() * VOICES;
Segment* s = first(Segment::SegChordRest);
2012-05-26 14:26:10 +02:00
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e) {
if (e->type() != REST)
return false;
Rest* rest = static_cast<Rest*>(e);
if (rest->durationType().type() != TDuration::V_MEASURE)
return false;
}
}
return true;
}
//---------------------------------------------------------
// isRepeatMeasure
//---------------------------------------------------------
bool Measure::isRepeatMeasure(Part* part)
2012-05-26 14:26:10 +02:00
{
int firstStaffIdx = score()->staffIdx(part);
int nextStaffIdx = firstStaffIdx + part->nstaves();
2012-08-02 18:33:43 +02:00
int strack = firstStaffIdx * VOICES;
int etrack = nextStaffIdx * VOICES;
Segment* s = first(Segment::SegChordRest);
2012-05-26 14:26:10 +02:00
2012-08-02 18:33:43 +02:00
if (s == 0)
2012-05-26 14:26:10 +02:00
return false;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e && e->type() == REPEAT_MEASURE)
return true;
}
return false;
}
//---------------------------------------------------------
// distanceDown
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
qreal Measure::distanceDown(int i) const
2012-05-26 14:26:10 +02:00
{
if (staves[i]->_vspacerDown)
return qMax(staves[i]->distanceDown, staves[i]->_vspacerDown->gap());
return staves[i]->distanceDown;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// distanceUp
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
qreal Measure::distanceUp(int i) const
2012-05-26 14:26:10 +02:00
{
if (staves[i]->_vspacerUp)
return qMax(staves[i]->distanceUp, staves[i]->_vspacerUp->gap());
return staves[i]->distanceUp;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// isEmpty
//---------------------------------------------------------
bool Measure::isEmpty() const
{
if (_irregular)
return false;
int n = 0;
int tracks = staves.size() * VOICES;
static const Segment::SegmentType st = Segment::SegChordRest;
for (const Segment* s = first(st); s; s = s->next(st)) {
bool restFound = false;
for (int track = 0; track < tracks; ++track) {
if ((track % VOICES) == 0 && !score()->staff(track/VOICES)->show()) {
track += VOICES-1;
continue;
}
if (s->element(track)) {
if (s->element(track)->type() != REST)
2012-05-26 14:26:10 +02:00
return false;
restFound = true;
2012-05-26 14:26:10 +02:00
}
}
if (restFound)
++n;
// measure is not empty if there is more than one rest
if (n > 1)
return false;
2012-05-26 14:26:10 +02:00
}
return true;
}
//---------------------------------------------------------
// isOnlyRests
//---------------------------------------------------------
bool Measure::isOnlyRests(int track) const
{
static const Segment::SegmentType st = Segment::SegChordRest;
for (const Segment* s = first(st); s; s = s->next(st)) {
if (s->segmentType() != Segment::SegChordRest || !s->element(track))
continue;
if (s->element(track)->type() != REST)
return false;
}
return true;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Space::max
//---------------------------------------------------------
void Space::max(const Space& s)
{
if (s._lw > _lw)
_lw = s._lw;
if (s._rw > _rw)
_rw = s._rw;
}
2012-08-01 18:00:27 +02:00
//---------------------------------------------------------
// setDirty
//---------------------------------------------------------
2012-08-01 18:00:27 +02:00
void Measure::setDirty()
{
_minWidth1 = 0.0;
_minWidth2 = 0.0;
}
//---------------------------------------------------------
// systemHeader
2012-08-02 18:33:43 +02:00
/// return true if the measure contains a system header
// The system header is identified by a generated Clef in
// the first segment.
//---------------------------------------------------------
bool Measure::systemHeader() const
{
Segment* s = first();
return s && (s->segmentType() == Segment::SegClef) && s->element(0) && s->element(0)->generated();
}
//---------------------------------------------------------
// minWidth1
2012-10-08 08:28:19 +02:00
/// return minimum width of measure excluding system
/// header
//---------------------------------------------------------
qreal Measure::minWidth1() const
{
2012-10-08 09:34:46 +02:00
if (_minWidth1 == 0.0) {
Segment* s = first();
2013-01-02 14:33:23 +01:00
Segment::SegmentTypes st = Segment::SegClef | Segment::SegKeySig | Segment::SegStartRepeatBarLine;
while ((s->segmentType() & st)
2013-03-04 12:00:02 +01:00
&& s->next()
&& (!s->element(0) || s->element(0)->generated())
) {
s = s->next();
2012-08-01 18:00:27 +02:00
}
_minWidth1 = score()->computeMinWidth(s);
2012-10-08 09:34:46 +02:00
}
return _minWidth1;
}
//---------------------------------------------------------
// minWidth2
2012-10-08 08:28:19 +02:00
/// return minimum width of measure
//---------------------------------------------------------
qreal Measure::minWidth2() const
{
2012-10-08 09:34:46 +02:00
if (_minWidth2 == 0.0)
_minWidth2 = score()->computeMinWidth(first());
return _minWidth2;
}
//-----------------------------------------------------------------------------
// computeStretch
/// \brief distribute stretch across a range of segments
//-----------------------------------------------------------------------------
void computeStretch(int minTick, qreal minimum, qreal stretch, int first, int last, int ticksList[], qreal xpos[], qreal width[])
{
SpringMap springs;
for (int i = first; i < last; ++i) {
qreal str = 1.0;
qreal d;
qreal w = width[i];
int t = ticksList[i];
if (t) {
if (minTick > 0)
// str += .6 * log(qreal(t) / qreal(minTick)) / log(2.0);
str = 1.0 + 0.865617 * log(qreal(t) / qreal(minTick));
d = w / str;
}
else {
str = 0.0; // dont stretch timeSig and key
d = 100000000.0; // CHECK
}
springs.insert(std::pair<qreal, Spring>(d, Spring(i, str, w)));
minimum += w;
}
//---------------------------------------------------
// distribute stretch to segments
//---------------------------------------------------
qreal force = sff(stretch, minimum, springs);
for (iSpring i = springs.begin(); i != springs.end(); ++i) {
qreal stretch = force * i->second.stretch;
if (stretch < i->second.fix)
stretch = i->second.fix;
width[i->second.seg] = stretch;
}
qreal x = xpos[first];
for (int i = first; i < last; ++i) {
x += width[i];
xpos[i+1] = x;
}
}
2012-05-26 14:26:10 +02:00
//-----------------------------------------------------------------------------
// layoutX
/// \brief main layout routine for note spacing
/// Return width of measure (in MeasureWidth), taking into account \a stretch.
//-----------------------------------------------------------------------------
void Measure::layoutX(qreal stretch)
2012-05-26 14:26:10 +02:00
{
int nstaves = _score->nstaves();
int segs = 0;
for (const Segment* s = first(); s; s = s->next()) {
if (s->segmentType() == Segment::SegClef && (s != first()))
2012-05-26 14:26:10 +02:00
continue;
++segs;
}
if (nstaves == 0 || segs == 0)
2012-05-26 14:26:10 +02:00
return;
qreal _spatium = spatium();
int tracks = nstaves * VOICES;
qreal clefKeyRightMargin = score()->styleS(ST_clefKeyRightMargin).val() * _spatium;
qreal minHarmonyDistance = score()->styleS(ST_minHarmonyDistance).val() * _spatium;
2012-05-26 14:26:10 +02:00
qreal rest[nstaves]; // fixed space needed from previous segment
memset(rest, 0, nstaves * sizeof(qreal));
qreal hRest[nstaves]; // fixed space needed from previous harmony
memset(hRest, 0, nstaves * sizeof(qreal));
2012-05-26 14:26:10 +02:00
//--------tick table for segments
int ticksList[segs];
memset(ticksList, 0, segs * sizeof(int));
qreal xpos[segs+1];
qreal width[segs];
int segmentIdx = 0;
qreal x = 0.0;
qreal lastx = 0.0;
2012-05-26 14:26:10 +02:00
int minTick = 100000;
int hMinTick = 100000;
int hLastIdx = -1;
2013-05-06 14:20:31 +02:00
int ntick = ticks(); // position of next measure
2012-05-26 14:26:10 +02:00
2013-05-29 11:49:58 +02:00
if (system()->firstMeasure() == this && system()->barLine()) {
BarLine* bl = system()->barLine();
x += BarLine::layoutWidth(score(), bl->barLineType(), bl->magS());
}
2013-03-04 12:00:02 +01:00
2012-05-26 14:26:10 +02:00
qreal minNoteDistance = score()->styleS(ST_minNoteDistance).val() * _spatium;
qreal clefWidth[nstaves];
memset(clefWidth, 0, nstaves * sizeof(qreal));
2013-04-08 18:26:53 +02:00
std::vector<QRectF> hLastBbox(nstaves); // bbox of previous harmony to test vertical separation
const Segment* s = first();
const Segment* pSeg = 0;
for (; s; s = s->next(), ++segmentIdx) {
qreal elsp = s->extraLeadingSpace().val() * _spatium;
2012-05-26 14:26:10 +02:00
qreal etsp = s->extraTrailingSpace().val() * _spatium;
if ((s->segmentType() == Segment::SegClef) && (s != first())) {
2012-05-26 14:26:10 +02:00
--segmentIdx;
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES;
Element* e = s->element(track);
if (e) {
clefWidth[staffIdx] = e->width() + _spatium + elsp;
}
}
pSeg = s;
2012-05-26 14:26:10 +02:00
continue;
}
bool gotHarmony = false;
bool rest2[nstaves];
bool hRest2[nstaves];
Segment::SegmentType segType = s->segmentType();
2012-05-26 14:26:10 +02:00
qreal segmentWidth = 0.0;
qreal harmonyWidth = 0.0;
2012-05-26 14:26:10 +02:00
qreal stretchDistance = 0.0;
int pt = pSeg ? pSeg->segmentType() : Segment::SegBarLine;
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
2012-05-26 14:26:10 +02:00
qreal minDistance = 0.0;
Space space;
Space hSpace;
QRectF hBbox;
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES;
bool found = false;
bool hFound = false;
bool eFound = false;
2013-06-12 14:23:57 +02:00
if (segType & (Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
qreal llw = 0.0;
qreal rrw = 0.0;
Lyrics* lyrics = 0;
bool accidentalStaff = false;
2012-05-26 14:26:10 +02:00
for (int voice = 0; voice < VOICES; ++voice) {
ChordRest* cr = static_cast<ChordRest*>(s->element(track+voice));
if (!cr)
continue;
found = true;
if (pt & (Segment::SegStartRepeatBarLine | Segment::SegBarLine) && !accidentalStaff) {
// check for accidentals in chord
bool accidental = false;
if (cr->type() == Element::CHORD) {
Chord* c = static_cast<Chord*>(cr);
if (!c->graceNotes().empty())
accidental = true;
else {
for (Note* note : c->notes()) {
if (note->accidental()) {
accidental = true;
break;
}
}
}
}
2013-07-18 15:54:05 +02:00
// no distance to full measure rest
if (!(cr->type() == REST && static_cast<Rest*>(cr)->durationType() == TDuration::V_MEASURE)) {
accidentalStaff = true;
2013-07-18 15:54:05 +02:00
StyleIdx si = accidental ? ST_barAccidentalDistance : ST_barNoteDistance;
qreal sp = score()->styleS(si).val() * _spatium;
sp += elsp;
minDistance = qMax(minDistance, sp);
}
2012-05-26 14:26:10 +02:00
}
2013-06-12 14:23:57 +02:00
else if (pt & (Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
minDistance = qMax(minDistance, minNoteDistance);
}
else {
bool firstClef = (segmentIdx == 1) && (pt == Segment::SegClef);
if ((pt & (Segment::SegKeySig | Segment::SegTimeSig)) || firstClef)
2012-05-26 14:26:10 +02:00
minDistance = qMax(minDistance, clefKeyRightMargin);
}
space.max(cr->space());
int n = cr->lyricsList().size();
for (int i = 0; i < n; ++i) {
Lyrics* l = cr->lyricsList().at(i);
2012-10-23 14:42:00 +02:00
if (!l || l->isEmpty())
2012-05-26 14:26:10 +02:00
continue;
2012-10-23 14:42:00 +02:00
lyrics = l;
if (!lyrics->isMelisma()) {
QRectF b(l->bbox().translated(l->pos()));
llw = qMax(llw, -b.left());
rrw = qMax(rrw, b.right());
2012-05-26 14:26:10 +02:00
}
}
}
if (lyrics) {
2012-08-01 18:00:27 +02:00
qreal y = lyrics->ipos().y() + score()->styleS(ST_lyricsMinBottomDistance).val() * _spatium;
2012-05-26 14:26:10 +02:00
if (y > staves[staffIdx]->distanceDown)
staves[staffIdx]->distanceDown = y;
space.max(Space(llw, rrw));
}
// add spacing for chord symbols
2013-05-06 14:20:31 +02:00
foreach (const Element* e, s->annotations()) {
if (e->type() != Element::HARMONY || e->track() < track || e->track() >= track+VOICES)
continue;
2013-05-06 14:20:31 +02:00
const Harmony* h = static_cast<const Harmony*>(e);
QRectF b(h->bboxtight().translated(h->pos()));
if (hFound)
hBbox |= b;
else
hBbox = b;
hFound = true;
gotHarmony = true;
// allow chord at the beginning of a measure to be dragged left
hSpace.max(Space(s->rtick()?-b.left():0.0, b.right()));
}
2012-05-26 14:26:10 +02:00
}
else {
Element* e = s->element(track);
if ((segType == Segment::SegClef) && (pt != Segment::SegChordRest))
minDistance = score()->styleS(ST_clefLeftMargin).val() * _spatium;
else if (segType == Segment::SegStartRepeatBarLine)
2012-05-26 14:26:10 +02:00
minDistance = .5 * _spatium;
else if ((segType == Segment::SegEndBarLine) && segmentIdx) {
if (pt == Segment::SegClef)
minDistance = score()->styleS(ST_clefBarlineDistance).val() * _spatium;
2012-05-26 14:26:10 +02:00
else
stretchDistance = score()->styleS(ST_noteBarDistance).val() * _spatium;
2012-05-26 14:26:10 +02:00
if (e == 0) {
// look for barline
for (int i = track - VOICES; i >= 0; i -= VOICES) {
e = s->element(i);
if (e)
break;
}
}
}
if (e) {
eFound = true;
gotHarmony = true; // to avoid closing barline
2012-05-26 14:26:10 +02:00
space.max(e->space());
}
}
space += Space(elsp, etsp);
if (isMMRest())
minDistance = 0;
if (found || eFound) {
2012-05-26 14:26:10 +02:00
space.rLw() += clefWidth[staffIdx];
qreal sp = minDistance + rest[staffIdx] + qMax(space.lw(), stretchDistance);
2012-05-26 14:26:10 +02:00
rest[staffIdx] = space.rw();
rest2[staffIdx] = false;
segmentWidth = qMax(segmentWidth, sp);
}
else
rest2[staffIdx] = true;
// space chord symbols separately from segments
if (hFound || eFound) {
qreal sp = 0.0;
// space chord symbols unless they miss each other vertically
if (eFound || (hBbox.top() < hLastBbox[staffIdx].bottom() && hBbox.bottom() > hLastBbox[staffIdx].top()))
sp = hRest[staffIdx] + minHarmonyDistance + hSpace.lw();
hLastBbox[staffIdx] = hBbox;
hRest[staffIdx] = hSpace.rw();
hRest2[staffIdx] = false;
harmonyWidth = qMax(harmonyWidth, sp);
}
else
hRest2[staffIdx] = true;
2012-05-26 14:26:10 +02:00
clefWidth[staffIdx] = 0.0;
}
// set previous seg width before adding in harmony, to allow stretching
2012-05-26 14:26:10 +02:00
if (segmentIdx) {
width[segmentIdx-1] = segmentWidth;
if (pSeg)
pSeg->setbbox(QRectF(0.0, 0.0, segmentWidth, _spatium * 5)); //??
2012-05-26 14:26:10 +02:00
}
// make room for harmony if needed
segmentWidth = qMax(segmentWidth,harmonyWidth);
x += segmentWidth;
xpos[segmentIdx] = x;
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
2012-05-26 14:26:10 +02:00
if (rest2[staffIdx])
rest[staffIdx] -= qMin(rest[staffIdx],segmentWidth);
if (hRest2[staffIdx])
hRest[staffIdx] -= qMin(hRest[staffIdx],segmentWidth);
2012-05-26 14:26:10 +02:00
}
if ((s->segmentType() == Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
const Segment* nseg = s;
for (;;) {
nseg = nseg->next();
if (nseg == 0 || nseg->segmentType() == Segment::SegChordRest)
2012-05-26 14:26:10 +02:00
break;
}
2013-05-06 14:20:31 +02:00
int nticks = (nseg ? nseg->rtick() : ntick) - s->rtick();
2012-05-26 14:26:10 +02:00
if (nticks == 0) {
// this happens for tremolo notes
qDebug("layoutX: empty segment(%p)%s: measure: tick %d ticks %d",
s, s->subTypeName(), tick(), ticks());
qDebug(" nticks==0 segmente %d, segmentIdx: %d, segTick: %d nsegTick(%p) %d",
size(), segmentIdx-1, s->tick(), nseg, ntick
);
}
else {
if (nticks < minTick)
minTick = nticks;
if (nticks < hMinTick)
hMinTick = nticks;
2012-05-26 14:26:10 +02:00
}
ticksList[segmentIdx] = nticks;
}
else
ticksList[segmentIdx] = 0;
// if we are on a chord symbol, stretch the notes below it if necessary
if (gotHarmony) {
if (hLastIdx >= 0)
computeStretch(hMinTick, 0.0, x-lastx, hLastIdx, segmentIdx, ticksList, xpos, width);
hMinTick = 10000;
lastx = x;
hLastIdx = segmentIdx;
}
//
// set pSeg only to used segments
//
for (int voice = 0; voice < nstaves * VOICES; ++voice) {
if (!score()->staff(voice/VOICES)->show()) {
voice += VOICES-1;
continue;
}
if (s->element(voice)) {
pSeg = s;
break;
}
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------
// TAB: compute distance above and below
//---------------------------------------------------
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
qreal distAbove = 0.0;
qreal distBelow = 0.0;
2012-05-26 14:26:10 +02:00
Staff * staff = _score->staff(staffIdx);
if (staff->isTabStaff()) {
StaffTypeTablature* stt = static_cast<StaffTypeTablature*>(staff->staffType());
if (stt->slashStyle()) // if no stems
distAbove = stt->genDurations() ? -stt->durationBoxY() : 0.0;
else { // if stems
if (stt->stemsDown())
distBelow = (STAFFTYPE_TAB_DEFAULTSTEMLEN_UP + STAFFTYPE_TAB_DEFAULTSTEMDIST_UP)*_spatium;
else
distAbove = (STAFFTYPE_TAB_DEFAULTSTEMLEN_DN + STAFFTYPE_TAB_DEFAULTSTEMDIST_DN)*_spatium;
}
2012-05-26 14:26:10 +02:00
if (distAbove > staves[staffIdx]->distanceUp)
staves[staffIdx]->distanceUp = distAbove;
if (distBelow > staves[staffIdx]->distanceDown)
staves[staffIdx]->distanceDown = distBelow;
2012-05-26 14:26:10 +02:00
}
}
2012-05-26 14:26:10 +02:00
qreal segmentWidth = 0.0;
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
2012-05-26 14:26:10 +02:00
segmentWidth = qMax(segmentWidth, rest[staffIdx]);
segmentWidth = qMax(segmentWidth, hRest[staffIdx]);
}
if (segmentIdx)
width[segmentIdx-1] = segmentWidth;
2012-05-26 14:26:10 +02:00
xpos[segmentIdx] = x + segmentWidth;
//---------------------------------------------------
// compute stretches for whole measure
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
computeStretch(minTick, xpos[0], stretch, 0, segs, ticksList, xpos, width);
2012-05-26 14:26:10 +02:00
//---------------------------------------------------
// layout individual elements
//---------------------------------------------------
int seg = 0;
for (Segment* s = first(); s; s = s->next(), ++seg) {
if ((s->segmentType() == Segment::SegClef) && (s != first())) {
2013-07-18 15:54:05 +02:00
//
// clefs are not in xpos[] table
//
2012-05-26 14:26:10 +02:00
s->setPos(xpos[seg], 0.0);
for (int staffIdx = 0; staffIdx < nstaves; ++staffIdx) {
if (!score()->staff(staffIdx)->show())
continue;
2012-05-26 14:26:10 +02:00
int track = staffIdx * VOICES;
Element* e = s->element(track);
if (e) {
qreal lm = 0.0;
if (s->next()) {
for (int track = staffIdx * VOICES; track < staffIdx*VOICES+VOICES; ++track) {
if (s->next()->element(track)) {
qreal clm = s->next()->element(track)->space().lw();
lm = qMax(lm, clm);
}
}
}
e->setPos(-e->width() - lm - _spatium*.5, 0.0);
e->adjustReadPos();
}
}
--seg;
continue;
}
s->setPos(xpos[seg], 0.0);
2013-07-18 15:54:05 +02:00
}
2012-05-26 14:26:10 +02:00
2013-07-18 15:54:05 +02:00
for (Segment* s = first(); s; s = s->next(), ++seg) {
2012-05-26 14:26:10 +02:00
for (int track = 0; track < tracks; ++track) {
if (!score()->staff(track/VOICES)->show()) {
track += VOICES-1;
continue;
}
2012-05-26 14:26:10 +02:00
Element* e = s->element(track);
if (e == 0)
continue;
ElementType t = e->type();
Rest* rest = static_cast<Rest*>(e);
if (((track % VOICES) == 0) &&
(t == REPEAT_MEASURE || (t == REST && (isMMRest() || rest->isFullMeasureRest())))) {
//
// element has to be centered in free space
// x1 - left measure position of free space
// x2 - right measure position of free space
2013-09-10 15:11:30 +02:00
if (isMMRest()) {
//
// center multi measure rest
//
qreal x1 = 0.0, x2;
2013-09-19 17:17:22 +02:00
Segment* ss = first();
for (; ss->segmentType() != Segment::SegChordRest; ss = ss->next())
;
if (s != first()) {
2013-09-19 17:17:22 +02:00
ss = ss->prev();
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
int track = staffIdx * VOICES;
Element* e = ss->element(track);
if (e)
x1 = qMax(x1, ss->x() + e->x() + e->width());
}
}
Segment* ns = s->next();
x2 = this->width();
if (ns) {
x2 = ns->x();
if (ns->segmentType() != Segment::SegEndBarLine) {
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
int track = staffIdx * VOICES;
Element* e = ns->element(track);
if (e)
x2 = qMin(x2, ns->x() + e->x());
}
}
}
2013-07-18 15:54:05 +02:00
qreal d = point(score()->styleS(ST_multiMeasureRestMargin));
qreal w = x2 - x1 - 2 * d;
rest->setMMWidth(w);
StaffLines* sl = staves[track/VOICES]->lines;
qreal x = x1 - s->pos().x() + d;
e->setPos(x, sl->staffHeight() * .5); // center vertically in measure
}
2013-09-19 16:27:29 +02:00
else { // if (rest->isFullMeasureRest()) {
//
// center full measure rest
//
qreal x1 = 0.0;
qreal x2 = this->width();
2013-09-19 15:49:39 +02:00
Segment* ss = first();
for (; ss->segmentType() != Segment::SegChordRest; ss = ss->next())
;
if (ss != first()) {
ss = ss->prev();
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
int track = staffIdx * VOICES;
Element* e = ss->element(track);
if (e)
x1 = qMax(x1, ss->x() + e->x() + e->width());
}
2012-05-26 14:26:10 +02:00
}
Segment* ns = s->next();
while (ns && ns->segmentType() != Segment::SegEndBarLine) {
ns = ns->next();
}
if (ns)
x2 = ns->x();
rest->rxpos() = (x2 - x1 - e->width()) * .5 + x1 - s->x();
rest->adjustReadPos();
2012-05-26 14:26:10 +02:00
}
}
2013-07-18 15:54:05 +02:00
else if (t == REST)
e->rxpos() = 0;
else if (t == CHORD)
static_cast<Chord*>(e)->layout2();
2012-05-26 14:26:10 +02:00
else if (t == CLEF) {
2013-07-18 15:54:05 +02:00
if (s == first()) {
// clef at the beginning of measure
qreal gap = 0.0;
Segment* ps = s->prev();
if (ps)
gap = s->x() - (ps->x() + ps->width());
e->rxpos() = -gap * .5;
e->adjustReadPos();
}
2012-05-26 14:26:10 +02:00
}
else {
e->setPos(-e->bbox().x(), 0.0);
e->adjustReadPos();
}
}
}
}
//---------------------------------------------------------
// layoutStage1
2013-09-19 17:17:22 +02:00
// compute multi measure rest break
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Measure::layoutStage1()
{
2012-08-24 18:00:12 +02:00
setDirty();
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < score()->nstaves(); ++staffIdx) {
if (score()->styleB(ST_createMultiMeasureRests)) {
if ((repeatFlags() & RepeatStart) || (prevMeasure() && (prevMeasure()->repeatFlags() & RepeatEnd)))
setBreakMMRest(true);
2013-09-19 17:17:22 +02:00
else if (!breakMultiMeasureRest()) {
2012-05-26 14:26:10 +02:00
for (Segment* s = first(); s; s = s->next()) {
2013-10-15 15:39:01 +02:00
if (!s->annotations().empty()) { // break on any annotation
setBreakMMRest(true);
break;
}
#if 0
for (Element* e : s->annotations()) {
2012-05-26 14:26:10 +02:00
if (e->type() == REHEARSAL_MARK || e->type() == TEMPO_TEXT) {
setBreakMMRest(true);
break;
}
}
2013-10-15 15:39:01 +02:00
#endif
2013-09-19 17:17:22 +02:00
if (breakMultiMeasureRest()) // optimize
2012-05-26 14:26:10 +02:00
break;
}
}
}
int track = staffIdx * VOICES;
for (Segment* segment = first(); segment; segment = segment->next()) {
Element* e = segment->element(track);
2013-09-19 17:39:18 +02:00
if (e && !e->generated()) {
2013-10-15 15:39:01 +02:00
if (segment->segmentType() & (Segment::SegStartRepeatBarLine))
setBreakMMRest(true);
if (segment->segmentType() & (Segment::SegKeySig | Segment::SegTimeSig) && tick())
2012-05-26 14:26:10 +02:00
setBreakMMRest(true);
2013-09-19 17:39:18 +02:00
else if (segment->segmentType() == Segment::SegClef) {
if (segment->tick() == endTick()) {
Measure* m = nextMeasure();
if (m)
m->setBreakMMRest(true);
}
2013-10-15 15:39:01 +02:00
else if (tick())
2013-09-19 17:39:18 +02:00
setBreakMMRest(true);
}
2012-05-26 14:26:10 +02:00
}
2013-10-15 15:39:01 +02:00
if (segment->segmentType() == Segment::SegChordRest) {
Staff* staff = score()->staff(staffIdx);
qreal staffMag = staff->mag();
int endTrack = track + VOICES;
for (int t = track; t < endTrack; ++t) {
ChordRest* cr = static_cast<ChordRest*>(segment->element(t));
if (!cr)
continue;
layoutCR0(cr, staffMag);
}
}
2012-05-26 14:26:10 +02:00
}
}
2013-10-15 15:39:01 +02:00
if (!score()->styleB(ST_createMultiMeasureRests) || breakMultiMeasureRest())
return;
// break mm rest on any spanner
#if 0
for (auto i : sl) {
Spanner* sp = i.value;
if (sp->type() == Element::VOLTA) {
setBreakMMRest(true);
break;
}
}
2013-10-15 15:39:01 +02:00
#endif
MeasureBase* mb = prev();
if (mb && mb->type() == Element::MEASURE) {
Measure* pm = static_cast<Measure*>(mb);
if (pm->endBarLineType() != NORMAL_BAR
&& pm->endBarLineType() != BROKEN_BAR && pm->endBarLineType() != DOTTED_BAR)
setBreakMMRest(true);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// updateAccidentals
// recompute accidentals,
/// undoable add/remove
//---------------------------------------------------------
void Measure::updateAccidentals(Segment* segment, int staffIdx, AccidentalState* tversatz)
{
Staff* staff = score()->staff(staffIdx);
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
StaffGroup staffGroup = staff->staffType()->group();
const Instrument* instrument = staff->part()->instr();
for (int track = startTrack; track < endTrack; ++track) {
Chord* chord = static_cast<Chord*>(segment->element(track));
if (!chord || chord->type() != CHORD)
continue;
// TAB_STAFF is different, as each note has to be fretted
// in the context of the all of the chords of the whole segment
2012-05-26 14:26:10 +02:00
Re-factor presets and staff types. 1) Built-in staff types have been removed. 2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications. 3) Each new score is given by default one staff type for each preset with the same name. 4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet). 5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type. 6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5) 7) The Staff Type Editor lists all the staff types This should ensure consistency among the several lists of staff types and avoid duplication of similar items Terminology: 7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want. 8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard" 9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are: libmscore/score.cpp libmscore/stafftype.cpp/.h mscore/editstafftype.cpp (code for naming a new staff type) mscore/instrdialog.cpp (building type list) Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
if (staffGroup == TAB_STAFF_GROUP) {
for (Chord* ch : chord->graceNotes())
instrument->stringData()->fretChords(ch);
instrument->stringData()->fretChords(chord);
2012-05-26 14:26:10 +02:00
continue; // skip other staff type cases
}
// PITCHED_ and PERCUSSION_STAFF can go note by note
for (Chord* ch : chord->graceNotes()) {
for (Note* note : ch->notes())
note->updateAccidental(tversatz);
}
for (Note* note : chord->notes()) {
2012-05-26 14:26:10 +02:00
switch(staffGroup) {
Re-factor presets and staff types. 1) Built-in staff types have been removed. 2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications. 3) Each new score is given by default one staff type for each preset with the same name. 4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet). 5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type. 6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5) 7) The Staff Type Editor lists all the staff types This should ensure consistency among the several lists of staff types and avoid duplication of similar items Terminology: 7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want. 8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard" 9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are: libmscore/score.cpp libmscore/stafftype.cpp/.h mscore/editstafftype.cpp (code for naming a new staff type) mscore/instrdialog.cpp (building type list) Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
case STANDARD_STAFF_GROUP:
2012-05-26 14:26:10 +02:00
if (note->tieBack()) {
if (note->accidental() && note->tpc() == note->tieBack()->startNote()->tpc()) {
2012-05-26 14:26:10 +02:00
// TODO: remove accidental only if note is not
// on new system
score()->undoRemoveElement(note->accidental());
}
}
note->updateAccidental(tversatz);
2012-05-26 14:26:10 +02:00
break;
Re-factor presets and staff types. 1) Built-in staff types have been removed. 2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications. 3) Each new score is given by default one staff type for each preset with the same name. 4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet). 5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type. 6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5) 7) The Staff Type Editor lists all the staff types This should ensure consistency among the several lists of staff types and avoid duplication of similar items Terminology: 7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want. 8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard" 9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are: libmscore/score.cpp libmscore/stafftype.cpp/.h mscore/editstafftype.cpp (code for naming a new staff type) mscore/instrdialog.cpp (building type list) Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
case PERCUSSION_STAFF_GROUP:
2012-05-26 14:26:10 +02:00
{
Drumset* drumset = instrument->drumset();
int pitch = note->pitch();
2013-09-29 00:55:37 +02:00
if(drumset) {
if (!drumset->isValid(pitch)) {
// qDebug("unmapped drum note %d", pitch);
}
else {
note->setHeadGroup(drumset->noteHead(pitch));
note->setLine(drumset->line(pitch));
continue;
}
2012-05-26 14:26:10 +02:00
}
}
break;
Re-factor presets and staff types. 1) Built-in staff types have been removed. 2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications. 3) Each new score is given by default one staff type for each preset with the same name. 4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet). 5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type. 6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5) 7) The Staff Type Editor lists all the staff types This should ensure consistency among the several lists of staff types and avoid duplication of similar items Terminology: 7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want. 8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard" 9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are: libmscore/score.cpp libmscore/stafftype.cpp/.h mscore/editstafftype.cpp (code for naming a new staff type) mscore/instrdialog.cpp (building type list) Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
case TAB_STAFF_GROUP: // to avoid compiler warning
2012-05-26 14:26:10 +02:00
break;
}
}
}
}
//---------------------------------------------------------
// stretchedLen
//---------------------------------------------------------
Fraction Measure::stretchedLen(Staff* staff) const
{
return len() / staff->timeStretch(tick());
}
//---------------------------------------------------------
// cloneMeasure
//---------------------------------------------------------
2013-07-05 11:23:52 +02:00
Measure* Measure::cloneMeasure(Score* sc, TieMap* tieMap)
2012-05-26 14:26:10 +02:00
{
Measure* m = new Measure(sc);
m->_timesig = _timesig;
m->_len = _len;
m->_repeatCount = _repeatCount;
m->_repeatFlags = _repeatFlags;
foreach(MStaff* ms, staves)
m->staves.append(new MStaff(*ms));
m->_no = _no;
m->_noOffset = _noOffset;
m->_userStretch = _userStretch;
m->_irregular = _irregular;
m->_breakMultiMeasureRest = _breakMultiMeasureRest;
m->_breakMMRest = _breakMMRest;
m->_endBarLineGenerated = _endBarLineGenerated;
m->_endBarLineVisible = _endBarLineVisible;
m->_endBarLineType = _endBarLineType;
m->_playbackCount = _playbackCount;
m->_endBarLineColor = _endBarLineColor;
m->_minWidth1 = _minWidth1;
m->_minWidth2 = _minWidth2;
2012-05-26 14:26:10 +02:00
m->setTick(tick());
m->setLineBreak(lineBreak());
m->setPageBreak(pageBreak());
m->setSectionBreak(sectionBreak() ? new LayoutBreak(*sectionBreak()) : 0);
int tracks = sc->nstaves() * VOICES;
TupletMap tupletMap;
for (Segment* oseg = first(); oseg; oseg = oseg->next()) {
Segment* s = new Segment(m);
s->setSegmentType(oseg->segmentType());
2012-05-26 14:26:10 +02:00
s->setRtick(oseg->rtick());
m->_segments.push_back(s);
for (int track = 0; track < tracks; ++track) {
Element* oe = oseg->element(track);
if (oe) {
Element* ne = oe->clone();
if (oe->isChordRest()) {
ChordRest* ocr = static_cast<ChordRest*>(oe);
ChordRest* ncr = static_cast<ChordRest*>(ne);
Tuplet* ot = ocr->tuplet();
if (ot) {
Tuplet* nt = tupletMap.findNew(ot);
if (nt == 0) {
nt = new Tuplet(*ot);
nt->clear();
nt->setTrack(track);
nt->setScore(sc);
m->add(nt);
tupletMap.add(ot, nt);
}
ncr->setTuplet(nt);
}
if (oe->type() == CHORD) {
Chord* och = static_cast<Chord*>(ocr);
Chord* nch = static_cast<Chord*>(ncr);
int n = och->notes().size();
for (int i = 0; i < n; ++i) {
Note* on = och->notes().at(i);
Note* nn = nch->notes().at(i);
if (on->tieFor()) {
Tie* tie = new Tie(sc);
nn->setTieFor(tie);
tie->setStartNote(nn);
tieMap->add(on->tieFor(), tie);
}
if (on->tieBack()) {
Tie* tie = tieMap->findNew(on->tieBack());
if (tie) {
nn->setTieBack(tie);
tie->setEndNote(nn);
}
else {
qDebug("cloneMeasure: cannot find tie, track %d", track);
}
}
}
}
}
s->add(ne);
}
foreach(Element* e, oseg->annotations()) {
if (e->generated() || e->track() != track)
continue;
Element* ne = e->clone();
ne->setTrack(track);
s->add(ne);
}
}
}
foreach(Element* e, *el()) {
Element* ne = e->clone();
ne->setScore(sc);
m->add(ne);
}
return m;
}
//---------------------------------------------------------
// pos2sel
//---------------------------------------------------------
int Measure::snap(int tick, const QPointF p) const
{
Segment* s = first();
for (; s->next(); s = s->next()) {
qreal x = s->x();
qreal dx = s->next()->x() - x;
if (s->tick() == tick)
x += dx / 3.0 * 2.0;
else if (s->next()->tick() == tick)
x += dx / 3.0;
else
x += dx * .5;
if (p.x() < x)
break;
}
return s->tick();
}
//---------------------------------------------------------
// snapNote
//---------------------------------------------------------
int Measure::snapNote(int /*tick*/, const QPointF p, int staff) const
{
Segment* s = first();
for (;;) {
Segment* ns = s->next();
while (ns && ns->element(staff) == 0)
ns = ns->next();
if (ns == 0)
break;
qreal x = s->x();
qreal nx = x + (ns->x() - x) * .5;
if (p.x() < nx)
break;
s = ns;
}
return s->tick();
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Measure::getProperty(P_ID propertyId) const
2013-07-18 15:54:05 +02:00
{
switch(propertyId) {
case P_TIMESIG_NOMINAL:
return QVariant::fromValue(_timesig);
case P_TIMESIG_ACTUAL:
return QVariant::fromValue(_len);
case P_REPEAT_FLAGS:
return repeatFlags();
case P_MEASURE_NUMBER_MODE:
return int(measureNumberMode());
default:
return MeasureBase::getProperty(propertyId);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Measure::setProperty(P_ID propertyId, const QVariant& value)
{
switch(propertyId) {
case P_TIMESIG_NOMINAL:
_timesig = value.value<Fraction>();
break;
case P_TIMESIG_ACTUAL:
_len = value.value<Fraction>();
break;
case P_REPEAT_FLAGS:
setRepeatFlags(value.toInt());
break;
case P_MEASURE_NUMBER_MODE:
setMeasureNumberMode(MeasureNumberMode(value.toInt()));
break;
default:
return MeasureBase::setProperty(propertyId, value);
}
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Measure::propertyDefault(P_ID propertyId) const
{
switch(propertyId) {
case P_TIMESIG_NOMINAL:
case P_TIMESIG_ACTUAL:
return QVariant();
case P_REPEAT_FLAGS:
return 0;
case P_MEASURE_NUMBER_MODE:
return int(MeasureNumberMode::AUTO);
default:
break;
}
return MeasureBase::getProperty(propertyId);
}
2013-10-30 14:21:08 +01:00
//-------------------------------------------------------------------
// mmRestFirst
// this is a multi measure rest
// returns first measure of replaced sequence of empty measures
//-------------------------------------------------------------------
Measure* Measure::mmRestFirst() const
{
Q_ASSERT(isMMRest());
if (prev())
return static_cast<Measure*>(prev()->next());
return score()->firstMeasure();
}
//-------------------------------------------------------------------
// mmRestLast
// this is a multi measure rest
// returns last measure of replaced sequence of empty measures
//-------------------------------------------------------------------
Measure* Measure::mmRestLast() const
{
Q_ASSERT(isMMRest());
if (next())
return static_cast<Measure*>(next()->prev());
return score()->lastMeasure();
}
2013-05-13 18:49:17 +02:00
}