MuseScore/libmscore/staff.cpp

1118 lines
37 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
//=============================================================================
#include "mscore.h"
#include "staff.h"
#include "part.h"
#include "clef.h"
#include "xml.h"
#include "score.h"
#include "bracket.h"
#include "keysig.h"
#include "segment.h"
#include "style.h"
#include "measure.h"
#include "stringdata.h"
2012-05-26 14:26:10 +02:00
#include "stafftype.h"
#include "undo.h"
#include "cleflist.h"
#include "timesig.h"
#include "instrtemplate.h"
#include "barline.h"
2013-07-16 09:03:47 +02:00
#include "ottava.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
//---------------------------------------------------------
// idx
//---------------------------------------------------------
int Staff::idx() const
{
return _score->staffIdx(this);
}
//---------------------------------------------------------
// bracket
//---------------------------------------------------------
BracketType Staff::bracket(int idx) const
{
if (idx < _brackets.size())
return _brackets[idx]._bracket;
return BracketType::NO_BRACKET;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// bracketSpan
//---------------------------------------------------------
int Staff::bracketSpan(int idx) const
{
if (idx < _brackets.size())
return _brackets[idx]._bracketSpan;
return 0;
}
//---------------------------------------------------------
// setBracket
//---------------------------------------------------------
void Staff::setBracket(int idx, BracketType val)
{
2012-10-12 15:36:57 +02:00
for (int i = _brackets.size(); i <= idx; ++i)
_brackets.append(BracketItem());
2012-05-26 14:26:10 +02:00
_brackets[idx]._bracket = val;
while (!_brackets.isEmpty() && (_brackets.last()._bracket == BracketType::NO_BRACKET))
2012-05-26 14:26:10 +02:00
_brackets.removeLast();
}
//---------------------------------------------------------
// setBracketSpan
//---------------------------------------------------------
void Staff::setBracketSpan(int idx, int val)
{
2012-10-12 15:36:57 +02:00
Q_ASSERT(idx >= 0);
Q_ASSERT(val >= 0);
for (int i = _brackets.size(); i <= idx; ++i)
_brackets.append(BracketItem());
2012-05-26 14:26:10 +02:00
_brackets[idx]._bracketSpan = val;
}
//---------------------------------------------------------
// addBracket
//---------------------------------------------------------
void Staff::addBracket(BracketItem b)
{
if (!_brackets.isEmpty() && _brackets[0]._bracket == BracketType::NO_BRACKET) {
2012-05-26 14:26:10 +02:00
_brackets[0] = b;
}
else {
//
// create new bracket level
//
foreach(Staff* s, _score->staves()) {
if (s == this)
s->_brackets.append(b);
else
s->_brackets.append(BracketItem());
}
}
}
//---------------------------------------------------------
// cleanupBrackets
//---------------------------------------------------------
void Staff::cleanupBrackets()
{
int index = idx();
int n = _score->nstaves();
for (int i = 0; i < _brackets.size(); ++i) {
if (_brackets[i]._bracket == BracketType::NO_BRACKET)
2013-06-05 15:47:34 +02:00
continue;
int span = _brackets[i]._bracketSpan;
if (span > (n - index)) {
span = n - index;
_brackets[i]._bracketSpan = span;
2012-05-26 14:26:10 +02:00
}
}
for (int i = 0; i < _brackets.size(); ++i) {
if (_brackets[i]._bracket == BracketType::NO_BRACKET)
2013-06-05 15:47:34 +02:00
continue;
int span = _brackets[i]._bracketSpan;
if (span <= 1)
_brackets[i] = BracketItem();
else {
// delete all other brackets with same span
for (int k = i + 1; k < _brackets.size(); ++k) {
if (span == _brackets[k]._bracketSpan)
_brackets[k] = BracketItem();
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// partName
//---------------------------------------------------------
QString Staff::partName() const
{
return _part->partName();
}
//---------------------------------------------------------
// Staff
//---------------------------------------------------------
2012-07-06 14:21:05 +02:00
Staff::Staff(Score* s)
: ScoreElement(s)
2012-07-06 14:21:05 +02:00
{
_barLineTo = (lines() - 1) * 2;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// ~Staff
//---------------------------------------------------------
Staff::~Staff()
{
if (_linkedStaves) {
_linkedStaves->remove(this);
if (_linkedStaves->isEmpty())
delete _linkedStaves;
}
}
//---------------------------------------------------------
2014-08-16 11:21:56 +02:00
// Staff::clefType
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
2014-08-16 11:21:56 +02:00
ClefTypeList Staff::clefType(int tick) const
2012-05-26 14:26:10 +02:00
{
ClefTypeList ct = clefs.clef(tick);
if (ct._concertClef == ClefType::INVALID) {
switch(_staffType.group()) {
2014-08-16 11:21:56 +02:00
case StaffGroup::TAB:
ct = ClefTypeList(ClefType(score()->styleI(StyleIdx::tabClef)));
break;
case StaffGroup::STANDARD:
2014-08-16 11:21:56 +02:00
ct = defaultClefType();
break;
case StaffGroup::PERCUSSION:
2014-08-16 11:21:56 +02:00
ct = ClefTypeList(ClefType::PERC);
break;
}
}
return ct;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Staff::clef
//---------------------------------------------------------
ClefType Staff::clef(int tick) const
{
2014-08-16 11:21:56 +02:00
ClefTypeList c = clefType(tick);
2014-05-26 15:31:36 +02:00
return score()->styleB(StyleIdx::concertPitch) ? c._concertClef : c._transposingClef;
2012-05-26 14:26:10 +02:00
}
#ifndef NDEBUG
//---------------------------------------------------------
// dumpClef
//---------------------------------------------------------
void Staff::dumpClefs(const char* title) const
{
2015-02-14 17:17:07 +01:00
qDebug("dump clefs (%zd): %s", clefs.size(), title);
for (auto& i : clefs) {
qDebug(" %d: %d %d", i.first, int(i.second._concertClef), int(i.second._transposingClef));
}
}
//---------------------------------------------------------
// dumpKeys
//---------------------------------------------------------
void Staff::dumpKeys(const char* title) const
{
2015-02-14 17:17:07 +01:00
qDebug("dump keys (%zd): %s", _keys.size(), title);
for (auto& i : _keys) {
qDebug(" %d: %d", i.first, int(i.second.key()));
}
}
2015-02-16 12:12:23 +01:00
//---------------------------------------------------------
// dumpTimeSigs
//---------------------------------------------------------
void Staff::dumpTimeSigs(const char* title) const
{
qDebug("dump timesig size (%zd) staffIdx %d: %s", timesigs.size(), idx(), title);
for (auto& i : timesigs) {
qDebug(" %d: %d/%d", i.first, i.second->sig().numerator(), i.second->sig().denominator());
}
}
#endif
2013-09-05 16:37:49 +02:00
//---------------------------------------------------------
// setClef
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
void Staff::setClef(Clef* clef)
2013-09-05 16:37:49 +02:00
{
2014-08-05 14:10:22 +02:00
if (clef->generated())
return;
2014-07-25 17:13:27 +02:00
int tick = clef->segment()->tick();
for (Segment* s = clef->segment()->next(); s && s->tick() == tick; s = s->next()) {
if (s->segmentType() == Segment::Type::Clef && s->element(clef->track())) {
// adding this clef has no effect on the clefs list
return;
}
}
clefs.setClef(clef->segment()->tick(), clef->clefTypeList());
// dumpClefs("setClef");
2013-09-05 16:37:49 +02:00
}
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
// removeClef
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
2014-07-25 17:13:27 +02:00
void Staff::removeClef(Clef* clef)
2013-09-05 16:37:49 +02:00
{
2014-08-05 14:10:22 +02:00
if (clef->generated())
return;
2014-07-25 17:13:27 +02:00
int tick = clef->segment()->tick();
for (Segment* s = clef->segment()->next(); s && s->tick() == tick; s = s->next()) {
if (s->segmentType() == Segment::Type::Clef && s->element(clef->track())) {
// removal of this clef has no effect on the clefs list
return;
}
}
clefs.erase(clef->segment()->tick());
for (Segment* s = clef->segment()->prev(); s && s->tick() == tick; s = s->prev()) {
if (s->segmentType() == Segment::Type::Clef
&& s->element(clef->track())
&& !s->element(clef->track())->generated()) {
2014-07-25 17:13:27 +02:00
// a previous clef at the same tick position gets valid
clefs.setClef(tick, static_cast<Clef*>(s->element(clef->track()))->clefTypeList());
break;
}
}
// dumpClefs("removeClef");
2013-09-05 16:37:49 +02:00
}
//---------------------------------------------------------
2014-05-08 17:59:24 +02:00
// timeStretch
2013-09-05 16:37:49 +02:00
//---------------------------------------------------------
2014-05-08 17:59:24 +02:00
Fraction Staff::timeStretch(int tick) const
2013-09-05 16:37:49 +02:00
{
2014-05-08 17:59:24 +02:00
TimeSig* timesig = timeSig(tick);
return timesig == 0 ? Fraction(1,1) : timesig->stretch();
2013-09-05 16:37:49 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// timeSig
// lookup time signature before or at tick
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
TimeSig* Staff::timeSig(int tick) const
{
2013-05-06 14:20:31 +02:00
auto i = timesigs.upper_bound(tick);
if (i != timesigs.begin())
--i;
2014-11-27 13:04:03 +01:00
else if (tick < i->first)
return 0;
2013-05-06 14:20:31 +02:00
return (i == timesigs.end()) ? 0 : i->second;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// group
//---------------------------------------------------------
const Groups& Staff::group(int tick) const
{
TimeSig* ts = timeSig(tick);
if (ts) {
if (!ts->groups().empty())
return ts->groups();
2013-05-06 14:20:31 +02:00
return Groups::endings(ts->sig());
}
Measure* m = score()->tick2measure(tick);
2014-05-03 10:10:46 +02:00
return Groups::endings(m ? m->timesig() : Fraction(4,4));
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// addTimeSig
//---------------------------------------------------------
void Staff::addTimeSig(TimeSig* timesig)
{
if (timesig->segment()->segmentType() == Segment::Type::TimeSig)
timesigs[timesig->segment()->tick()] = timesig;
2015-02-16 12:12:23 +01:00
// dumpTimeSigs("after addTimeSig");
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeTimeSig
//---------------------------------------------------------
void Staff::removeTimeSig(TimeSig* timesig)
{
if (timesig->segment()->segmentType() == Segment::Type::TimeSig)
timesigs.erase(timesig->segment()->tick());
2015-02-16 12:12:23 +01:00
// dumpTimeSigs("after removeTimeSig");
2012-05-26 14:26:10 +02:00
}
2014-11-27 13:04:03 +01:00
//---------------------------------------------------------
// clearTimeSig
//---------------------------------------------------------
void Staff::clearTimeSig()
{
timesigs.clear();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// Staff::key
//
// locates the key sig currently in effect at tick
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
KeySigEvent Staff::keySigEvent(int tick) const
2012-05-26 14:26:10 +02:00
{
2014-06-03 15:28:10 +02:00
return _keys.key(tick);
}
2014-06-04 10:20:14 +02:00
//---------------------------------------------------------
// setKey
//---------------------------------------------------------
void Staff::setKey(int tick, KeySigEvent k)
2014-06-04 10:20:14 +02:00
{
_keys.setKey(tick, k);
// dumpKeys("setKey");
2014-06-04 10:20:14 +02:00
}
//---------------------------------------------------------
// removeKey
//---------------------------------------------------------
void Staff::removeKey(int tick)
{
2014-07-17 09:32:30 +02:00
_keys.erase(tick);
// dumpKeys("removeKey");
2014-06-04 10:20:14 +02:00
}
2014-06-03 15:28:10 +02:00
//---------------------------------------------------------
// prevkey
//---------------------------------------------------------
KeySigEvent Staff::prevKey(int tick) const
2014-06-03 15:28:10 +02:00
{
return _keys.prevKey(tick);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Staff::nextKeyTick
//
// return the tick at which the key sig after tick is located
// return 0, if no such a key sig
//---------------------------------------------------------
int Staff::nextKeyTick(int tick) const
{
2014-06-03 15:28:10 +02:00
return _keys.nextKeyTick(tick);
}
//---------------------------------------------------------
// Staff::currentKeyTick
//
// return the tick position of the key currently
// in effect at tick
// return 0, if no such a key sig
//---------------------------------------------------------
int Staff::currentKeyTick(int tick) const
{
return _keys.currentKeyTick(tick);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// write
//---------------------------------------------------------
void Staff::write(Xml& xml) const
{
int idx = score()->staffIdx(this);
xml.stag(QString("Staff id=\"%1\"").arg(idx + 1));
2012-05-26 14:26:10 +02:00
if (linkedStaves()) {
Score* s = score();
if (s->parentScore())
s = s->parentScore();
foreach(Staff* staff, linkedStaves()->staves()) {
if ((staff->score() == s) && (staff != this))
xml.tag("linkedTo", s->staffIdx(staff) + 1);
}
}
2014-04-30 10:08:38 +02:00
2014-05-05 15:38:40 +02:00
// for copy/paste we need to know the actual transposition
if (xml.clipboardmode) {
Interval v = part()->instr()->transpose();
2014-05-05 15:38:40 +02:00
if (v.diatonic)
xml.tag("transposeDiatonic", v.diatonic);
if (v.chromatic)
xml.tag("transposeChromatic", v.chromatic);
}
2014-04-28 18:38:50 +02:00
_staffType.write(xml);
2014-08-16 11:21:56 +02:00
ClefTypeList ct = _defaultClefType;
if (ct._concertClef == ct._transposingClef) {
if (ct._concertClef != ClefType::G)
xml.tag("defaultClef", ClefInfo::tag(ct._concertClef));
}
else {
xml.tag("defaultConcertClef", ClefInfo::tag(ct._concertClef));
xml.tag("defaultTransposingClef", ClefInfo::tag(ct._transposingClef));
}
2014-04-30 10:08:38 +02:00
2012-05-26 14:26:10 +02:00
if (small() && !xml.excerptmode) // switch small staves to normal ones when extracting part
xml.tag("small", small());
if (invisible())
xml.tag("invisible", invisible());
2014-07-31 18:46:41 +02:00
if (neverHide())
xml.tag("neverHide", neverHide());
if (showIfEmpty())
xml.tag("showIfSystemEmpty", showIfEmpty());
2015-01-05 17:55:06 +01:00
if (_hideSystemBarLine)
xml.tag("hideSystemBarLine", _hideSystemBarLine);
2014-07-31 18:46:41 +02:00
2012-05-26 14:26:10 +02:00
foreach(const BracketItem& i, _brackets)
xml.tagE("bracket type=\"%d\" span=\"%d\"", i._bracket, i._bracketSpan);
// for economy and consistency, only output "from" and "to" attributes if different from default
int defaultLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
int defaultLineTo;
if (_barLineSpan == 0) // if no bar line at all
defaultLineTo = _barLineTo; // whatever the current spanTo is, use as default
else { // if some bar line, default is the default for span target staff
int targetStaffIdx = idx + _barLineSpan - 1;
if (targetStaffIdx >= score()->nstaves()) {
qFatal("bad _barLineSpan %d for staff %d (nstaves %d)",
_barLineSpan, idx, score()->nstaves());
}
int targetStaffLines = score()->staff(targetStaffIdx)->lines();
defaultLineTo = (targetStaffLines == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (targetStaffLines-1) * 2);
}
if (_barLineSpan != 1 || _barLineFrom != defaultLineFrom || _barLineTo != defaultLineTo) {
if(_barLineFrom != defaultLineFrom || _barLineTo != defaultLineTo)
xml.tag(QString("barLineSpan from=\"%1\" to=\"%2\"").arg(_barLineFrom).arg(_barLineTo), _barLineSpan);
else
xml.tag("barLineSpan", _barLineSpan);
}
2012-05-26 14:26:10 +02:00
if (_userDist != 0.0)
xml.tag("distOffset", _userDist / spatium());
writeProperty(xml, P_ID::MAG);
writeProperty(xml, P_ID::COLOR);
2012-05-26 14:26:10 +02:00
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Staff::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
2014-04-30 10:08:38 +02:00
if (tag == "type") { // obsolete
int staffTypeIdx = e.readInt();
2014-08-13 15:42:40 +02:00
qDebug("obsolete: Staff::read staffTypeIdx %d", staffTypeIdx);
_staffType = *StaffType::preset(StaffTypes(staffTypeIdx));
// set default barLineFrom and barLineTo according to staff type num. of lines
// (1-line staff bar lines are special)
_barLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineTo = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2);
2014-04-30 10:08:38 +02:00
}
2014-05-08 17:59:24 +02:00
else if (tag == "StaffType") {
2014-04-28 18:38:50 +02:00
_staffType.read(e);
// set default barLineFrom and barLineTo according to staff type num. of lines
// (1-line staff bar lines are special)
_barLineFrom = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineTo = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2);
2014-05-08 17:59:24 +02:00
}
2014-08-16 11:21:56 +02:00
else if (tag == "defaultClef") { // sets both default transposing and concert clef
QString val(e.readElementText());
ClefType ct = Clef::clefType(val);
setDefaultClefType(ClefTypeList(ct, ct));
}
else if (tag == "defaultConcertClef") {
QString val(e.readElementText());
setDefaultClefType(ClefTypeList(Clef::clefType(val), defaultClefType()._transposingClef));
}
else if (tag == "defaultTransposingClef") {
QString val(e.readElementText());
setDefaultClefType(ClefTypeList(defaultClefType()._concertClef, Clef::clefType(val)));
}
2012-05-26 14:26:10 +02:00
else if (tag == "small")
2013-01-11 18:10:18 +01:00
setSmall(e.readInt());
2012-05-26 14:26:10 +02:00
else if (tag == "invisible")
2013-01-11 18:10:18 +01:00
setInvisible(e.readInt());
2014-07-31 18:46:41 +02:00
else if (tag == "neverHide")
setNeverHide(e.readInt());
else if (tag == "showIfSystemEmpty")
setShowIfEmpty(e.readInt());
2015-01-05 17:55:06 +01:00
else if (tag == "hideSystemBarLine")
_hideSystemBarLine = e.readInt();
2012-05-26 14:26:10 +02:00
else if (tag == "keylist")
2014-06-03 15:28:10 +02:00
_keys.read(e, _score);
2012-05-26 14:26:10 +02:00
else if (tag == "bracket") {
BracketItem b;
2013-01-17 12:56:14 +01:00
b._bracket = BracketType(e.intAttribute("type", -1));
2013-01-11 18:10:18 +01:00
b._bracketSpan = e.intAttribute("span", 0);
2012-05-26 14:26:10 +02:00
_brackets.append(b);
2013-01-17 12:56:14 +01:00
e.readNext();
2012-05-26 14:26:10 +02:00
}
2012-10-14 00:35:11 +02:00
else if (tag == "barLineSpan") {
// WARNING: following statement assumes number of staff lines to be correctly set
// must read <StaffType> before reading the <barLineSpan>
int defaultSpan = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
_barLineFrom = e.intAttribute("from", defaultSpan);
// the proper default SpanTo depends upon the barLineSpan
// as we do not know it yet, set a generic (UNKNOWN) default
defaultSpan = UNKNOWN_BARLINE_TO;
_barLineTo = e.intAttribute("to", defaultSpan);
// ready to read the main value...
_barLineSpan = e.readInt();
//...and to adjust the SpanTo value if the source did not provide an explicit value
// if no bar line or single staff span, set _barLineTo to this staff height
// if span to another staff (yet to be read), leave as unknown
// (Score::read() will retrieve the correct height of the target staff)
if (_barLineTo == UNKNOWN_BARLINE_TO && _barLineSpan <= 1)
_barLineTo = lines() == 1 ? BARLINE_SPAN_1LINESTAFF_TO : (lines() - 1) * 2;
2012-10-14 00:35:11 +02:00
}
2012-05-26 14:26:10 +02:00
else if (tag == "distOffset")
2013-01-11 18:10:18 +01:00
_userDist = e.readDouble() * spatium();
2015-01-15 14:50:50 +01:00
else if (tag == "mag")
_userMag = e.readDouble(0.1, 10.0);
2012-05-26 14:26:10 +02:00
else if (tag == "linkedTo") {
2013-01-11 18:10:18 +01:00
int v = e.readInt() - 1;
2012-05-26 14:26:10 +02:00
//
// if this is an excerpt, link staff to parentScore()
//
if (score()->parentScore()) {
2012-09-03 21:15:38 +02:00
Staff* st = score()->parentScore()->staff(v);
if (st)
linkTo(st);
else {
2012-09-20 11:35:34 +02:00
qDebug("staff %d not found in parent", v);
2012-09-03 21:15:38 +02:00
}
2012-05-26 14:26:10 +02:00
}
else {
int idx = score()->staffIdx(this);
if (v >= 0 && v < idx)
2012-05-26 14:26:10 +02:00
linkTo(score()->staff(v));
}
}
else if (tag == "color")
_color = e.readColor();
2014-05-05 15:38:40 +02:00
else if (tag == "transposeDiatonic")
e.setTransposeDiatonic(e.readInt());
else if (tag == "transposeChromatic")
e.setTransposeChromatic(e.readInt());
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
}
}
//---------------------------------------------------------
// height
//---------------------------------------------------------
qreal Staff::height() const
{
2014-06-19 15:27:44 +02:00
return (lines() == 1 ? 2 : lines()-1) * spatium() * _staffType.lineDistance().val();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// spatium
//---------------------------------------------------------
qreal Staff::spatium() const
{
return _score->spatium() * mag();
}
//---------------------------------------------------------
// mag
//---------------------------------------------------------
qreal Staff::mag() const
{
return (_small ? score()->styleD(StyleIdx::smallStaffMag) : 1.0) * userMag();
2012-05-26 14:26:10 +02:00
}
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
//---------------------------------------------------------
// swing
//---------------------------------------------------------
SwingParameters Staff::swing(int tick) const
{
SwingParameters sp;
int swingUnit = 0;
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
QString unit = score()->styleSt(StyleIdx::swingUnit);
int swingRatio = score()->styleI(StyleIdx::swingRatio);
if (unit == TDuration(TDuration::DurationType::V_EIGHTH).name()) {
Implementation of text swing (step1) added swing tab swing settings tab in staff text properties Implemented step 2 of swing implementation using staff texts Added call for updateSwing in stafftextproperties Initial page for dialog changed System flag enabled for swing parameters saving and loading with text specified swing implemented removed extra print statement fixed formatting Added groupbox to make the default behavior to no change in swing fixed indentation in stafftextproperties fixing conflicts in staff.h Removed writing of setSwing to file Removed SwingParameter member from staff and fixed layout of swing tab in dialog fixed the issue with disabled controls Added tests for staff text implementation of swing playback cleaned up the code Swing playback using staff texts implemented, facilitating local control over swing parameters and tests for the same added Cleaned up code Cleaned up code further Swing Playback using staff texts implemented Cleaned up code further Cleaning up code further Using MScore::division in place of 480 as ticks Modified test files according to new usage of MScore::division Removed unwanted printf statements Using strings to write to xml rather than doubles for swingUnit Replaced 240 and 120 in terms of MScore::division in stafftext:write Using TDuration to write to xml Replaced string literals by TDuration for style parameters Replaced "off" with "" in style.cpp Set defaults for unit and ratio in constructors Removed usage of two structs for SwingParameters Changed order of assignments in setSwingParameters Swing playback using staff-texts implemented and tests added
2014-07-24 20:09:49 +02:00
swingUnit = MScore::division / 2;
}
else if (unit == TDuration(TDuration::DurationType::V_16TH).name())
swingUnit = MScore::division / 4;
else if (unit == TDuration(TDuration::DurationType::V_ZERO).name())
swingUnit = 0;
sp.swingRatio = swingRatio;
sp.swingUnit = swingUnit;
if (_swingList.isEmpty())
return sp;
QMap<int, SwingParameters>::const_iterator i = _swingList.upperBound(tick);
if (i == _swingList.begin())
return sp;
--i;
return i.value();
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// channel
//---------------------------------------------------------
int Staff::channel(int tick, int voice) const
{
if (_channelList[voice].isEmpty())
return 0;
QMap<int, int>::const_iterator i = _channelList[voice].upperBound(tick);
2012-05-26 14:26:10 +02:00
if (i == _channelList[voice].begin())
return 0;
2012-05-26 14:26:10 +02:00
--i;
return i.value();
}
//---------------------------------------------------------
// lines
//---------------------------------------------------------
int Staff::lines() const
{
2014-04-28 18:38:50 +02:00
return _staffType.lines();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setLines
//---------------------------------------------------------
void Staff::setLines(int val)
{
if (val == lines())
return;
2014-04-28 18:38:50 +02:00
_staffType.setLines(val); // TODO: make undoable
2012-05-26 14:26:10 +02:00
}
2012-10-14 00:35:11 +02:00
//---------------------------------------------------------
// line distance
//---------------------------------------------------------
qreal Staff::lineDistance() const
{
2014-04-28 18:38:50 +02:00
return _staffType.lineDistance().val();
2012-10-14 00:35:11 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// slashStyle
//---------------------------------------------------------
bool Staff::slashStyle() const
{
2014-04-28 18:38:50 +02:00
return _staffType.slashStyle();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setSlashStyle
//---------------------------------------------------------
void Staff::setSlashStyle(bool val)
{
2014-04-28 18:38:50 +02:00
_staffType.setSlashStyle(val);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// linkTo
//---------------------------------------------------------
void Staff::linkTo(Staff* staff)
{
if (!_linkedStaves) {
if (staff->linkedStaves()) {
_linkedStaves = staff->linkedStaves();
}
else {
_linkedStaves = new LinkedStaves;
_linkedStaves->add(staff);
staff->setLinkedStaves(_linkedStaves);
}
_linkedStaves->add(this);
}
else {
2013-07-16 18:16:16 +02:00
_linkedStaves->add(staff);
2014-05-22 16:18:35 +02:00
if (!staff->linkedStaves())
staff->_linkedStaves = _linkedStaves;
2012-05-26 14:26:10 +02:00
}
}
2014-08-01 16:21:39 +02:00
//---------------------------------------------------------
// unlink
//---------------------------------------------------------
void Staff::unlink(Staff* staff)
{
2014-08-11 15:25:55 +02:00
if (!_linkedStaves)
return;
2014-08-01 16:21:39 +02:00
Q_ASSERT(_linkedStaves->staves().contains(staff));
_linkedStaves->remove(staff);
2014-08-07 19:39:18 +02:00
if (_linkedStaves->staves().size() <= 1) {
delete _linkedStaves;
_linkedStaves = 0;
}
staff->_linkedStaves = 0;
2014-08-01 16:21:39 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// add
//---------------------------------------------------------
void LinkedStaves::add(Staff* staff)
{
_staves.append(staff);
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void LinkedStaves::remove(Staff* staff)
{
_staves.removeOne(staff);
}
//---------------------------------------------------------
// isLinked
/// return true if staff is different and
/// linked to this staff
//---------------------------------------------------------
2014-04-24 15:03:03 +02:00
bool Staff::isLinked(Staff* staff)
{
if (staff == this || !_linkedStaves)
return false;
for(Staff* s : _linkedStaves->staves()) {
if(s == staff)
return true;
}
return false;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// primaryStaff
/// if there are linked staves, the primary staff is
/// the one who is played back
//---------------------------------------------------------
bool Staff::primaryStaff() const
{
QList<Staff*> s;
if (!_linkedStaves)
return true;
foreach(Staff* staff, _linkedStaves->staves()) {
if (staff->score() == score())
s.append(staff);
}
return s.front() == this;
}
//---------------------------------------------------------
// setStaffType
//---------------------------------------------------------
2014-04-28 18:38:50 +02:00
void Staff::setStaffType(const StaffType* st)
2012-05-26 14:26:10 +02:00
{
2014-05-03 11:33:47 +02:00
if (_staffType == *st)
return;
int linesOld = lines();
int linesNew = st->lines();
2014-04-28 18:38:50 +02:00
_staffType = *st;
if (linesNew != linesOld) {
int sIdx = score()->staffIdx(this);
if (sIdx < 0) { // staff does not belong to score (yet?)
if (linesNew == 1) { // 1-line staves have special bar lines
_barLineFrom = BARLINE_SPAN_1LINESTAFF_FROM;
_barLineTo = BARLINE_SPAN_1LINESTAFF_TO;
}
else { // set default barLineFrom/to (from first to last staff line)
_barLineFrom = 0;
_barLineTo = (linesNew-1)*2;
}
}
else // update barLineFrom/To in whole score context
score()->updateBarLineSpans(sIdx, linesOld, linesNew /*, true*/);
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// init
//---------------------------------------------------------
void Staff::init(const InstrumentTemplate* t, const StaffType* staffType, int cidx)
2012-05-26 14:26:10 +02:00
{
// set staff-type-independent parameters
if (cidx > MAX_STAVES) {
setSmall(false);
}
else {
setSmall(t->smallStaff[cidx]);
setBracket(0, t->bracket[cidx]);
setBracketSpan(0, t->bracketSpan[cidx]);
setBarLineSpan(t->barlineSpan[cidx]);
}
2014-04-30 10:08:38 +02:00
const StaffType* pst = staffType ? staffType : t->staffTypePreset;
if (!pst)
pst = StaffType::getDefaultPreset(t->staffGroup);
2012-05-26 14:26:10 +02:00
2014-04-30 10:08:38 +02:00
setStaffType(pst);
2014-08-16 11:21:56 +02:00
setDefaultClefType(t->clefType(cidx));
2014-05-24 17:03:30 +02:00
// if (pst->group() == ArticulationShowIn::PITCHED_STAFF) // if PITCHED (in other staff groups num of lines is determined by style)
// setLines(t->staffLines[cidx]); // use number of lines from instr. template
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// initFromStaffType
//---------------------------------------------------------
void Staff::initFromStaffType(const StaffType* staffType)
{
// get staff type if given (if none, get default preset for default staff group)
2014-04-30 10:08:38 +02:00
if (!staffType)
staffType = StaffType::getDefaultPreset(StaffGroup::STANDARD);
// use selected staff type
2014-04-28 18:38:50 +02:00
setStaffType(staffType);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void Staff::spatiumChanged(qreal oldValue, qreal newValue)
{
_userDist = (_userDist / oldValue) * newValue;
}
//---------------------------------------------------------
// show
//---------------------------------------------------------
bool Staff::show() const
{
return _part->show();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// genKeySig
//---------------------------------------------------------
bool Staff::genKeySig()
{
if (_staffType.group() == StaffGroup::TAB)
2014-04-28 18:38:50 +02:00
return false;
else
return _staffType.genKeysig();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// showLedgerLines
//---------------------------------------------------------
bool Staff::showLedgerLines()
{
if (_staffType.group() == StaffGroup::TAB)
2014-05-08 17:59:24 +02:00
return false;
2014-04-28 18:38:50 +02:00
else
return _staffType.showLedgerLines();
}
2013-07-16 09:03:47 +02:00
//---------------------------------------------------------
// updateOttava
//---------------------------------------------------------
2014-07-15 12:49:51 +02:00
void Staff::updateOttava()
{
int staffIdx = idx();
_pitchOffsets.clear();
for (auto i : score()->spanner()) {
const Spanner* s = i.second;
if (s->type() == Element::Type::OTTAVA && s->staffIdx() == staffIdx) {
const Ottava* o = static_cast<const Ottava*>(s);
_pitchOffsets.setPitchOffset(o->tick(), o->pitchShift());
_pitchOffsets.setPitchOffset(o->tick2(), 0);
}
}
2013-07-16 09:03:47 +02:00
}
//---------------------------------------------------------
// undoSetColor
//---------------------------------------------------------
2014-01-15 22:05:05 +01:00
void Staff::undoSetColor(const QColor& /*val*/)
{
2014-05-26 18:18:01 +02:00
// score()->undoChangeProperty(this, P_ID::COLOR, val);
}
2014-05-08 17:59:24 +02:00
//---------------------------------------------------------
// insertTime
//---------------------------------------------------------
void Staff::insertTime(int tick, int len)
{
qDebug("Staff: %d insertTime at %d len %d", idx(), tick, len);
// when inserting measures directly in front of a key change,
// using lower_bound() (for tick != 0) means the key change at that point is moved later
// so the measures being inserted get the old key signature
// if we wish to make this work like clefs (see below),
// we would need to move the key signature from this measure to the first inserted measure
// but either way, at the begining of the staff, we need to keep the original key,
// so we use upper_bound() in that case, and the initial key signature is moved in insertMeasure()
// ws: i don't understand this (and it does not work right: #46671)
2014-05-08 17:59:24 +02:00
KeyList kl2;
// for (auto i = tick ? _keys.lower_bound(tick) : _keys.upper_bound(tick); i != _keys.end();) {
for (auto i = _keys.upper_bound(tick); i != _keys.end();) {
KeySigEvent kse = i->second;
2014-06-20 17:07:22 +02:00
int k = i->first;
2014-06-03 15:28:10 +02:00
_keys.erase(i++);
2014-06-20 17:07:22 +02:00
kl2[k + len] = kse;
2014-05-08 17:59:24 +02:00
}
2014-06-03 15:28:10 +02:00
_keys.insert(kl2.begin(), kl2.end());
2014-05-08 17:59:24 +02:00
// when inserting measures directly in front of a clef change,
// using upper_bound() means the clef change remains in its original location
// so the measures being inserted get the new clef
// this make sense because the clef change technically happens at the end of the previous measure
// if we wish to make this work like key signatures (see above),
// we would need to move the clef from the previous measure to the last inserted measure
// and be sure to continue to handle the initial clef well
2014-05-08 17:59:24 +02:00
ClefList cl2;
for (auto i = clefs.upper_bound(tick); i != clefs.end();) {
2014-05-08 17:59:24 +02:00
ClefTypeList ctl = i->second;
int key = i->first;
clefs.erase(i++);
cl2.setClef(key + len, ctl);
}
clefs.insert(cl2.begin(), cl2.end());
}
2014-05-21 20:08:37 +02:00
//---------------------------------------------------------
// staffList
// return list of linked staves
//---------------------------------------------------------
QList<Staff*> Staff::staffList() const
{
QList<Staff*> staffList;
if (_linkedStaves)
staffList = _linkedStaves->staves();
else
staffList.append(const_cast<Staff*>(this));
return staffList;
}
2014-08-05 16:09:14 +02:00
//---------------------------------------------------------
// setBarLineTo
//---------------------------------------------------------
void Staff::setBarLineTo(int val)
{
_barLineTo = val;
}
2014-08-11 15:25:55 +02:00
//---------------------------------------------------------
// rstaff
//---------------------------------------------------------
int Staff::rstaff() const
{
return _part->staves()->indexOf((Staff*)this, 0);
}
//---------------------------------------------------------
// isTop
//---------------------------------------------------------
bool Staff::isTop() const
{
return _part->staves()->front() == this;
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant Staff::getProperty(P_ID id) const
{
switch (id) {
case P_ID::MAG:
return userMag();
case P_ID::COLOR:
return color();
default:
qDebug("Staff::setProperty: unhandled id");
return QVariant();
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool Staff::setProperty(P_ID id, const QVariant& v)
{
switch (id) {
case P_ID::MAG:
setUserMag(v.toDouble());
break;
case P_ID::COLOR:
setColor(v.value<QColor>());
break;
default:
qDebug("Staff::setProperty: unhandled id");
break;
}
score()->setLayoutAll(true);
return true;
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant Staff::propertyDefault(P_ID id) const
{
switch (id) {
case P_ID::MAG:
return 1.0;
case P_ID::COLOR:
return QColor(Qt::black);
default:
return QVariant();
}
}
2013-05-13 18:49:17 +02:00
}