864 lines
28 KiB
C++
864 lines
28 KiB
C++
//=============================================================================
|
|
// 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 "tablature.h"
|
|
#include "stafftype.h"
|
|
#include "undo.h"
|
|
#include "cleflist.h"
|
|
#include "timesig.h"
|
|
#include "instrtemplate.h"
|
|
#include "barline.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// 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 NO_BRACKET;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// 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)
|
|
{
|
|
for (int i = _brackets.size(); i <= idx; ++i)
|
|
_brackets.append(BracketItem());
|
|
_brackets[idx]._bracket = val;
|
|
while (!_brackets.isEmpty() && (_brackets.last()._bracket == NO_BRACKET))
|
|
_brackets.removeLast();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setBracketSpan
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setBracketSpan(int idx, int val)
|
|
{
|
|
Q_ASSERT(idx >= 0);
|
|
Q_ASSERT(val >= 0);
|
|
for (int i = _brackets.size(); i <= idx; ++i)
|
|
_brackets.append(BracketItem());
|
|
_brackets[idx]._bracketSpan = val;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addBracket
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::addBracket(BracketItem b)
|
|
{
|
|
if (!_brackets.isEmpty() && _brackets[0]._bracket == NO_BRACKET) {
|
|
_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 == NO_BRACKET)
|
|
continue;
|
|
int span = _brackets[i]._bracketSpan;
|
|
if (span > (n - index)) {
|
|
span = n - index;
|
|
_brackets[i]._bracketSpan = span;
|
|
}
|
|
}
|
|
for (int i = 0; i < _brackets.size(); ++i) {
|
|
if (_brackets[i]._bracket == NO_BRACKET)
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// partName
|
|
//---------------------------------------------------------
|
|
|
|
QString Staff::partName() const
|
|
{
|
|
return _part->partName();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Staff
|
|
//---------------------------------------------------------
|
|
|
|
Staff::Staff(Score* s)
|
|
{
|
|
_score = s;
|
|
_rstaff = 0;
|
|
_part = 0;
|
|
_keymap[0] = KeySigEvent(0); // default to C major
|
|
_staffType = _score->staffType(PITCHED_STAFF_TYPE);
|
|
_small = false;
|
|
_invisible = false;
|
|
_userDist = .0;
|
|
_barLineSpan = 1;
|
|
_barLineFrom = 0;
|
|
_barLineTo = (lines()-1)*2;
|
|
_updateKeymap = true;
|
|
_linkedStaves = 0;
|
|
_initialClef = ClefTypeList(CLEF_G, CLEF_G);
|
|
}
|
|
|
|
Staff::Staff(Score* s, Part* p, int rs)
|
|
{
|
|
_score = s;
|
|
_rstaff = rs;
|
|
_part = p;
|
|
_keymap[0] = KeySigEvent(0); // default to C major
|
|
_staffType = _score->staffType(PITCHED_STAFF_TYPE);
|
|
_small = false;
|
|
_invisible = false;
|
|
_userDist = .0;
|
|
_barLineSpan = 1;
|
|
_barLineFrom = 0;
|
|
_barLineTo = (lines()-1)*2;
|
|
_updateKeymap = true;
|
|
_linkedStaves = 0;
|
|
_initialClef = ClefTypeList(CLEF_G, CLEF_G);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// ~Staff
|
|
//---------------------------------------------------------
|
|
|
|
Staff::~Staff()
|
|
{
|
|
if (_linkedStaves) {
|
|
_linkedStaves->remove(this);
|
|
if (_linkedStaves->isEmpty())
|
|
delete _linkedStaves;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Staff::clefTypeList
|
|
//---------------------------------------------------------
|
|
|
|
ClefTypeList Staff::clefTypeList(int tick) const
|
|
{
|
|
ClefTypeList ctl = _initialClef;
|
|
int track = idx() * VOICES;
|
|
for (Segment* s = score()->firstSegment(); s; s = s->next1()) {
|
|
if (s->tick() > tick)
|
|
break;
|
|
if (s->segmentType() != Segment::SegClef)
|
|
continue;
|
|
if (s->element(track) && !s->element(track)->generated())
|
|
ctl = static_cast<Clef*>(s->element(track))->clefTypeList();
|
|
}
|
|
return ctl;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Staff::clef
|
|
//---------------------------------------------------------
|
|
|
|
ClefType Staff::clef(int tick) const
|
|
{
|
|
auto i = clefs.upper_bound(tick);
|
|
if (i != clefs.begin())
|
|
--i;
|
|
if (i == clefs.end())
|
|
return score()->concertPitch() ? _initialClef._concertClef : _initialClef._transposingClef;
|
|
else
|
|
return i->second->clefType();
|
|
}
|
|
|
|
ClefType Staff::clef(Segment* segment) const
|
|
{
|
|
ClefType ct = score()->concertPitch() ? _initialClef._concertClef : _initialClef._transposingClef;
|
|
int track = idx() * VOICES;
|
|
for (;;) {
|
|
segment = segment->prev1(Segment::SegClef);
|
|
if (segment == 0)
|
|
break;
|
|
if (segment->element(track)) {
|
|
ct = static_cast<Clef*>(segment->element(track))->clefType();
|
|
break;
|
|
}
|
|
}
|
|
return ct;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// timeStretch
|
|
//---------------------------------------------------------
|
|
|
|
Fraction Staff::timeStretch(int tick) const
|
|
{
|
|
TimeSig* timesig = timeSig(tick);
|
|
return timesig == 0 ? Fraction(1,1) : timesig->stretch();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// timeSig
|
|
// lookup time signature before or at tick
|
|
//---------------------------------------------------------
|
|
|
|
TimeSig* Staff::timeSig(int tick) const
|
|
{
|
|
auto i = timesigs.upper_bound(tick);
|
|
if (i != timesigs.begin())
|
|
--i;
|
|
return (i == timesigs.end()) ? 0 : i->second;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// group
|
|
//---------------------------------------------------------
|
|
|
|
const Groups& Staff::group(int tick) const
|
|
{
|
|
TimeSig* ts = timeSig(tick);
|
|
if (ts) {
|
|
if (!ts->groups().empty())
|
|
return ts->groups();
|
|
return Groups::endings(ts->sig());
|
|
}
|
|
Measure* m = score()->tick2measure(tick);
|
|
return Groups::endings(m->timesig());
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addClef
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::addClef(Clef* clef)
|
|
{
|
|
if (clef->generated()) {
|
|
if (clef->segment()->tick() == 0)
|
|
_initialClef = clef->clefTypeList();
|
|
return;
|
|
}
|
|
if (clef->segment()->measure() == 0)
|
|
abort();
|
|
int tick = clef->segment()->tick();
|
|
clefs.insert(std::pair<int,Clef*>(tick, clef));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addTimeSig
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::addTimeSig(TimeSig* timesig)
|
|
{
|
|
timesigs[timesig->segment()->tick()] = timesig;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// removeClef
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::removeClef(Clef* clef)
|
|
{
|
|
if (clef->generated())
|
|
return;
|
|
int tick = clef->segment()->tick();
|
|
for (auto i = clefs.lower_bound(tick); i != clefs.upper_bound(tick); ++i) {
|
|
if (i->second == clef) {
|
|
clefs.erase(i);
|
|
return;
|
|
}
|
|
}
|
|
qDebug("Staff::removeClef: Clef at %d not found", tick);
|
|
// abort();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// removeTimeSig
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::removeTimeSig(TimeSig* timesig)
|
|
{
|
|
int tick = timesig->segment()->tick();
|
|
timesigs.erase(tick);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Staff::key
|
|
//
|
|
// locates the key sig currently in effect at tick
|
|
//---------------------------------------------------------
|
|
|
|
KeySigEvent Staff::key(int tick) const
|
|
{
|
|
return _keymap.key(tick);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// 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
|
|
{
|
|
return _keymap.nextKeyTick(tick);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// write
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::write(Xml& xml) const
|
|
{
|
|
int idx = score()->staffIdx(this);
|
|
xml.stag(QString("Staff id=\"%1\"").arg(idx + 1));
|
|
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);
|
|
}
|
|
}
|
|
xml.tag("type", score()->staffTypeIdx(_staffType));
|
|
if (small() && !xml.excerptmode) // switch small staves to normal ones when extracting part
|
|
xml.tag("small", small());
|
|
if (invisible())
|
|
xml.tag("invisible", invisible());
|
|
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);
|
|
}
|
|
if (_userDist != 0.0)
|
|
xml.tag("distOffset", _userDist / spatium());
|
|
xml.etag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// read
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::read(XmlReader& e)
|
|
{
|
|
while (e.readNextStartElement()) {
|
|
const QStringRef& tag(e.name());
|
|
if (tag == "type") {
|
|
StaffType* st = score()->staffType(e.readInt());
|
|
if (st) {
|
|
_staffType = st;
|
|
// set default barLineTo according to staff type (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);
|
|
}
|
|
}
|
|
else if (tag == "small")
|
|
setSmall(e.readInt());
|
|
else if (tag == "invisible")
|
|
setInvisible(e.readInt());
|
|
else if (tag == "keylist")
|
|
_keymap.read(e, _score);
|
|
else if (tag == "bracket") {
|
|
BracketItem b;
|
|
b._bracket = BracketType(e.intAttribute("type", -1));
|
|
b._bracketSpan = e.intAttribute("span", 0);
|
|
_brackets.append(b);
|
|
e.readNext();
|
|
}
|
|
else if (tag == "barLineSpan") {
|
|
// WARNING: following statement assumes number of staff lines to be correctly set
|
|
// must read attributes before reading the main value
|
|
int defaultSpan = (lines() == 1 ? BARLINE_SPAN_1LINESTAFF_FROM : 0);
|
|
_barLineFrom = e.attribute("from", QString::number(defaultSpan)).toInt();
|
|
// 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;
|
|
}
|
|
else if (tag == "distOffset")
|
|
_userDist = e.readDouble() * spatium();
|
|
else if (tag == "linkedTo") {
|
|
int v = e.readInt() - 1;
|
|
//
|
|
// if this is an excerpt, link staff to parentScore()
|
|
//
|
|
if (score()->parentScore()) {
|
|
Staff* st = score()->parentScore()->staff(v);
|
|
if (st)
|
|
linkTo(st);
|
|
else {
|
|
qDebug("staff %d not found in parent", v);
|
|
}
|
|
}
|
|
else {
|
|
int idx = score()->staffIdx(this);
|
|
if (v >= 0 && v < idx)
|
|
linkTo(score()->staff(v));
|
|
}
|
|
}
|
|
else
|
|
e.unknown();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// height
|
|
//---------------------------------------------------------
|
|
|
|
qreal Staff::height() const
|
|
{
|
|
return (lines()-1) * spatium() * _staffType->lineDistance().val();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// spatium
|
|
//---------------------------------------------------------
|
|
|
|
qreal Staff::spatium() const
|
|
{
|
|
return _score->spatium() * mag();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mag
|
|
//---------------------------------------------------------
|
|
|
|
qreal Staff::mag() const
|
|
{
|
|
return _small ? score()->styleD(ST_smallStaffMag) : 1.0;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setKey
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setKey(int tick, int st)
|
|
{
|
|
KeySigEvent ke;
|
|
ke.setAccidentalType(st);
|
|
|
|
setKey(tick, ke);
|
|
}
|
|
|
|
void Staff::setKey(int tick, const KeySigEvent& st)
|
|
{
|
|
_keymap[tick] = st;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// removeKey
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::removeKey(int tick)
|
|
{
|
|
_keymap.erase(tick);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// channel
|
|
//---------------------------------------------------------
|
|
|
|
int Staff::channel(int tick, int voice) const
|
|
{
|
|
if (_channelList[voice].isEmpty())
|
|
return 0;
|
|
QMap<int, int>::const_iterator i = _channelList[voice].lowerBound(tick);
|
|
if (i == _channelList[voice].begin())
|
|
return _channelList[voice].begin().value();
|
|
--i;
|
|
return i.value();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// lines
|
|
//---------------------------------------------------------
|
|
|
|
int Staff::lines() const
|
|
{
|
|
return _staffType->lines();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setLines
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setLines(int val)
|
|
{
|
|
if (val == lines())
|
|
return;
|
|
//
|
|
// create new staff type
|
|
//
|
|
StaffType* st = _staffType->clone();
|
|
if(part() && !partName().isEmpty())
|
|
st->setName(partName());
|
|
st->setLines(val);
|
|
setStaffType(st);
|
|
score()->addStaffType(st);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// line distance
|
|
//---------------------------------------------------------
|
|
|
|
qreal Staff::lineDistance() const
|
|
{
|
|
return _staffType->lineDistance().val();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// slashStyle
|
|
//---------------------------------------------------------
|
|
|
|
bool Staff::slashStyle() const
|
|
{
|
|
return _staffType->slashStyle();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setSlashStyle
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setSlashStyle(bool val)
|
|
{
|
|
_staffType->setSlashStyle(val);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// 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 {
|
|
qDebug("Staff::linkTo: staff already linked\n");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// add
|
|
//---------------------------------------------------------
|
|
|
|
void LinkedStaves::add(Staff* staff)
|
|
{
|
|
_staves.append(staff);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// remove
|
|
//---------------------------------------------------------
|
|
|
|
void LinkedStaves::remove(Staff* staff)
|
|
{
|
|
_staves.removeOne(staff);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// 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
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setStaffType(StaffType* st)
|
|
{
|
|
if (_staffType == st)
|
|
return;
|
|
int linesOld = lines();
|
|
int linesNew = st->lines();
|
|
_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*/);
|
|
}
|
|
|
|
//
|
|
// check for right clef-type and fix
|
|
// if necessary
|
|
//
|
|
ClefType ct = clef(0);
|
|
StaffGroup csg = clefTable[ct].staffGroup;
|
|
|
|
if (_staffType->group() != csg) {
|
|
switch(_staffType->group()) {
|
|
case TAB_STAFF: ct = ClefType(score()->styleI(ST_tabClef)); break;
|
|
case PITCHED_STAFF: ct = CLEF_G; break; // TODO: use preferred clef for instrument
|
|
case PERCUSSION_STAFF: ct = CLEF_PERC; break;
|
|
}
|
|
setInitialClef(ct);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// init
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::init(const InstrumentTemplate* t, const StaffType* staffType, int cidx)
|
|
{
|
|
// set staff-type-independent parameters
|
|
if (cidx > MAX_STAVES) {
|
|
setSmall(false);
|
|
setInitialClef(t->clefTypes[0]);
|
|
}
|
|
else {
|
|
setSmall(t->smallStaff[cidx]);
|
|
setInitialClef(t->clefTypes[cidx]); // initial clef will be fixed to staff-type clef by setStaffType()
|
|
setBracket(0, t->bracket[cidx]);
|
|
setBracketSpan(0, t->bracketSpan[cidx]);
|
|
setBarLineSpan(t->barlineSpan[cidx]);
|
|
}
|
|
|
|
// determine staff type and set number of lines accordingly
|
|
// set lines AFTER setting the staff type, so if lines are different, the right staff type is cloned
|
|
StaffType* st = 0;
|
|
// get staff type if given or from instrument staff type, if not given
|
|
// (if none, get default for staff group)
|
|
const StaffType* presetStaffType = (staffType ? staffType : StaffType::preset(t->staffTypePreset) );
|
|
if (!presetStaffType)
|
|
presetStaffType = StaffType::getDefaultPreset(t->staffGroup, 0);
|
|
|
|
// look for a staff type with same structure among staff types already defined in the score
|
|
bool found = false;
|
|
foreach (StaffType** scoreStaffType, score()->staffTypes()) {
|
|
if ( (*scoreStaffType)->isSameStructure(*presetStaffType) ) {
|
|
st = *scoreStaffType; // staff type found in score: use for instrument staff
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
// if staff type not found in score, use from preset (for staff and adding to score staff types)
|
|
if (!found) {
|
|
st = presetStaffType->clone();
|
|
score()->addStaffType(st);
|
|
}
|
|
|
|
// use selected staff type
|
|
setStaffType(st);
|
|
// if (st->group() == 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
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// initFromStaffType
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::initFromStaffType(const StaffType* staffType)
|
|
{
|
|
// get staff type if given (if none, get default preset for default staff group)
|
|
const StaffType* presetStaffType = staffType;
|
|
if (!presetStaffType)
|
|
presetStaffType = StaffType::getDefaultPreset(PITCHED_STAFF, 0);
|
|
|
|
// look for a staff type with same structure among staff types already defined in the score
|
|
StaffType* st = 0;
|
|
foreach (StaffType** scoreStaffType, score()->staffTypes()) {
|
|
if ( (*scoreStaffType)->isSameStructure(*presetStaffType) ) {
|
|
st = *scoreStaffType; // staff type found in score: use for instrument staff
|
|
break;
|
|
}
|
|
}
|
|
// if staff type not found in score, use from preset (for staff and adding to score staff types)
|
|
if (!st) {
|
|
st = presetStaffType->clone();
|
|
score()->addStaffType(st);
|
|
}
|
|
|
|
// use selected staff type
|
|
setStaffType(st);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// spatiumChanged
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::spatiumChanged(qreal oldValue, qreal newValue)
|
|
{
|
|
_userDist = (_userDist / oldValue) * newValue;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// show
|
|
//---------------------------------------------------------
|
|
|
|
bool Staff::show() const
|
|
{
|
|
return _part->show();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setInitialClef
|
|
//---------------------------------------------------------
|
|
|
|
void Staff::setInitialClef(const ClefTypeList& cl)
|
|
{
|
|
_initialClef = cl;
|
|
}
|
|
|
|
void Staff::setInitialClef(ClefType ct)
|
|
{
|
|
_initialClef = ClefTypeList(ct, ct);
|
|
}
|
|
|
|
bool Staff::genKeySig()
|
|
{
|
|
switch(_staffType->group()) {
|
|
case TAB_STAFF:
|
|
return false;
|
|
case PITCHED_STAFF:
|
|
return static_cast<StaffTypePitched*>(_staffType)->genKeysig();
|
|
case PERCUSSION_STAFF:
|
|
return static_cast<StaffTypePercussion*>(_staffType)->genKeysig();
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Staff::showLedgerLines()
|
|
{
|
|
switch(_staffType->group()) {
|
|
case TAB_STAFF:
|
|
return false;
|
|
case PITCHED_STAFF:
|
|
return static_cast<StaffTypePitched*>(_staffType)->showLedgerLines();
|
|
case PERCUSSION_STAFF:
|
|
return static_cast<StaffTypePercussion*>(_staffType)->showLedgerLines();
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|