MuseScore/libmscore/score.cpp

3540 lines
116 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 class Score (partial).
*/
#include <assert.h>
#include "score.h"
#include "key.h"
#include "sig.h"
#include "clef.h"
#include "tempo.h"
#include "measure.h"
#include "page.h"
#include "undo.h"
#include "system.h"
#include "select.h"
#include "segment.h"
#include "xml.h"
#include "text.h"
#include "note.h"
#include "chord.h"
#include "rest.h"
#include "slur.h"
#include "staff.h"
#include "part.h"
#include "style.h"
#include "tuplet.h"
#include "lyrics.h"
#include "pitchspelling.h"
#include "line.h"
#include "volta.h"
#include "repeat.h"
#include "ottava.h"
#include "barline.h"
#include "box.h"
#include "utils.h"
#include "excerpt.h"
#include "stafftext.h"
#include "repeatlist.h"
#include "keysig.h"
#include "beam.h"
#include "stafftype.h"
#include "tempotext.h"
#include "articulation.h"
#include "revisions.h"
#include "tiemap.h"
#include "layoutbreak.h"
#include "harmony.h"
#include "mscore.h"
2012-07-06 17:42:20 +02:00
#ifdef OMR
2012-05-26 14:26:10 +02:00
#include "omr/omr.h"
2012-07-06 17:42:20 +02:00
#endif
2012-05-26 14:26:10 +02:00
#include "bracket.h"
#include "audio.h"
2012-06-07 09:24:05 +02:00
#include "instrtemplate.h"
#include "cursor.h"
2013-11-11 16:53:03 +01:00
#include "sym.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
Score* gscore; ///< system score, used for palettes etc.
QPoint scorePos(0,0);
QSize scoreSize(950, 500);
bool scriptDebug = false;
bool noSeq = false;
bool noMidi = false;
bool midiInputTrace = false;
bool midiOutputTrace = false;
bool showRubberBand = true;
//---------------------------------------------------------
// MeasureBaseList
//---------------------------------------------------------
MeasureBaseList::MeasureBaseList()
{
_first = 0;
_last = 0;
_size = 0;
};
//---------------------------------------------------------
// push_back
//---------------------------------------------------------
void MeasureBaseList::push_back(MeasureBase* e)
{
++_size;
if (_last) {
_last->setNext(e);
e->setPrev(_last);
e->setNext(0);
}
else {
_first = e;
e->setPrev(0);
e->setNext(0);
}
_last = e;
}
//---------------------------------------------------------
// push_front
//---------------------------------------------------------
void MeasureBaseList::push_front(MeasureBase* e)
{
++_size;
if (_first) {
_first->setPrev(e);
e->setNext(_first);
e->setPrev(0);
}
else {
_last = e;
e->setPrev(0);
e->setNext(0);
}
_first = e;
}
//---------------------------------------------------------
// add
// insert e before e->next()
//---------------------------------------------------------
void MeasureBaseList::add(MeasureBase* e)
{
MeasureBase* el = e->next();
if (el == 0) {
push_back(e);
return;
}
if (el == _first) {
push_front(e);
return;
}
++_size;
e->setPrev(el->prev());
el->prev()->setNext(e);
el->setPrev(e);
}
//---------------------------------------------------------
// erase
//---------------------------------------------------------
void MeasureBaseList::remove(MeasureBase* el)
{
--_size;
if (el->prev())
el->prev()->setNext(el->next());
else
_first = el->next();
if (el->next())
el->next()->setPrev(el->prev());
else
_last = el->prev();
}
//---------------------------------------------------------
// insert
//---------------------------------------------------------
void MeasureBaseList::insert(MeasureBase* fm, MeasureBase* lm)
{
++_size;
for (MeasureBase* m = fm; m != lm; m = m->next())
++_size;
MeasureBase* pm = fm->prev();
if (pm)
pm->setNext(fm);
else
_first = fm;
MeasureBase* nm = lm->next();
if (nm)
nm->setPrev(lm);
else
_last = lm;
}
//---------------------------------------------------------
// remove
//---------------------------------------------------------
void MeasureBaseList::remove(MeasureBase* fm, MeasureBase* lm)
{
--_size;
for (MeasureBase* m = fm; m != lm; m = m->next())
--_size;
MeasureBase* pm = fm->prev();
MeasureBase* nm = lm->next();
if (pm)
pm->setNext(nm);
else
_first = nm;
if (nm)
nm->setPrev(pm);
else
_last = pm;
}
//---------------------------------------------------------
// change
//---------------------------------------------------------
void MeasureBaseList::change(MeasureBase* ob, MeasureBase* nb)
{
nb->setPrev(ob->prev());
nb->setNext(ob->next());
if (ob->prev())
ob->prev()->setNext(nb);
if (ob->next())
ob->next()->setPrev(nb);
if (ob == _last)
_last = nb;
if (ob == _first)
_first = nb;
2012-09-13 18:01:34 +02:00
if (nb->type() == Element::HBOX || nb->type() == Element::VBOX
|| nb->type() == Element::TBOX || nb->type() == Element::FBOX)
2012-05-26 14:26:10 +02:00
nb->setSystem(ob->system());
foreach(Element* e, *nb->el())
e->setParent(nb);
}
//---------------------------------------------------------
// init
//---------------------------------------------------------
void Score::init()
{
_linkId = 0;
_currentLayer = 0;
_playMode = PLAYMODE_SYNTHESIZER;
Layer l;
l.name = "default";
l.tags = 1;
_layer.append(l);
_layerTags[0] = "default";
2013-07-19 18:03:35 +02:00
if (!_parentScore) {
#ifdef Q_OS_WIN
2013-07-19 18:03:35 +02:00
_metaTags.insert("platform", "WIN");
2012-05-26 14:26:10 +02:00
#endif
#ifdef Q_OS_MAC
2013-07-19 18:03:35 +02:00
_metaTags.insert("platform", "MAC");
2012-05-26 14:26:10 +02:00
#endif
2013-05-16 17:06:31 +02:00
#ifdef Q_OS_LINUX
2013-07-19 18:03:35 +02:00
_metaTags.insert("platform", "X11");
2012-05-26 14:26:10 +02:00
#endif
2013-07-19 18:03:35 +02:00
_metaTags.insert("movementNumber", "");
_metaTags.insert("movementTitle", "");
_metaTags.insert("workNumber", "");
_metaTags.insert("workTitle", "");
/* TODO enable following block of code
* This adds arranger, composer, lyricist, poet and translator fields
* to the File / Info dialog.
* As these fields are saved in every .msc[xz] file, it requires updating
* all regression test files in the mtest directory.
_metaTags.insert("arranger", "");
_metaTags.insert("composer", "");
_metaTags.insert("lyricist", "");
_metaTags.insert("poet", "");
_metaTags.insert("translator", "");
*/
2013-07-19 18:03:35 +02:00
_metaTags.insert("source", "");
_metaTags.insert("copyright", "");
_metaTags.insert("creationDate", QDate::currentDate().toString(Qt::ISODate));
_undo = new UndoStack();
_repeatList = new RepeatList(this);
}
else {
_undo = 0;
_repeatList = 0;
}
2012-05-26 14:26:10 +02:00
2013-11-06 15:58:05 +01:00
_revisions = new Revisions;
_scoreFont = ScoreFont::fontFactory("emmentaler");
2012-05-26 14:26:10 +02:00
_pageNumberOffset = 0;
2013-10-18 12:21:01 +02:00
_mscVersion = MSCVERSION;
_created = false;
_updateAll = true;
_layoutAll = true;
layoutFlags = 0;
_undoRedo = false;
_playNote = false;
_excerptsChanged = false;
_instrumentsChanged = false;
_selectionChanged = false;
keyState = 0;
_showInvisible = true;
_showUnprintable = true;
_showFrames = true;
_showPageborders = false;
_showInstrumentNames = true;
_showVBox = true;
_printing = false;
_playlistDirty = false;
_autosaveDirty = false;
_dirty = false;
_saved = false;
_pos[int(POS::CURRENT)] = 0;
_pos[int(POS::LEFT)] = 0;
_pos[int(POS::RIGHT)] = 0;
_fileDivision = MScore::division;
_defaultsRead = false;
_omr = 0;
_audio = 0;
_showOmr = false;
_sigmap = 0;
_tempomap = 0;
_layoutMode = LayoutPage;
2013-11-11 15:11:28 +01:00
_noteHeadWidth = 0.0; // set in doLayout()
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// Score
//---------------------------------------------------------
Score::Score()
2013-10-24 12:09:00 +02:00
: QObject(0), _is(this), _selection(this)
{
2013-07-19 18:03:35 +02:00
_parentScore = 0;
init();
_tempomap = new TempoMap;
_sigmap = new TimeSigMap();
_style = *(MScore::defaultStyle());
}
2012-05-26 14:26:10 +02:00
Score::Score(const MStyle* s)
2013-10-24 12:09:00 +02:00
: _is(this), _selection(this)
2012-05-26 14:26:10 +02:00
{
2013-07-19 18:03:35 +02:00
_parentScore = 0;
2012-05-26 14:26:10 +02:00
init();
_tempomap = new TempoMap;
_sigmap = new TimeSigMap();
_style = *s;
}
//
// a linked score shares some properties with parentScore():
// _undo
// _sigmap
// _tempomap
// _repeatList
// _links
// _staffTypes
2013-07-19 10:39:32 +02:00
// _metaTags
2014-02-25 14:14:59 +01:00
// _dirty
2012-05-26 14:26:10 +02:00
//
2013-07-19 10:39:32 +02:00
2012-05-26 14:26:10 +02:00
Score::Score(Score* parent)
2013-10-24 12:09:00 +02:00
: _is(this), _selection(this)
2012-05-26 14:26:10 +02:00
{
_parentScore = parent;
2013-07-19 18:03:35 +02:00
init();
2012-05-26 14:26:10 +02:00
if (MScore::defaultStyleForParts())
_style = *MScore::defaultStyleForParts();
else {
// inherit most style settings from parent
_style = *parent->style();
// but borrow defaultStyle page layout settings
const PageFormat* pf = MScore::defaultStyle()->pageFormat();
qreal sp = MScore::defaultStyle()->spatium();
_style.setPageFormat(*pf);
_style.setSpatium(sp);
2014-04-10 15:10:28 +02:00
//concert pitch is off for parts
_style.set(ST_concertPitch, false);
}
2014-01-30 13:10:45 +01:00
_synthesizerState = parent->_synthesizerState;
2012-05-26 14:26:10 +02:00
}
Score::Score(Score* parent, const MStyle* s)
: _is(this), _selection(this)
{
_parentScore = parent;
init();
_style = *s;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// ~Score
//---------------------------------------------------------
Score::~Score()
{
foreach(MuseScoreView* v, viewer)
v->removeScore();
2013-10-05 14:03:34 +02:00
// deselectAll();
2012-05-26 14:26:10 +02:00
for (MeasureBase* m = _measures.first(); m;) {
MeasureBase* nm = m->next();
delete m;
m = nm;
}
foreach(Part* p, _parts)
delete p;
foreach(Staff* staff, _staves)
delete staff;
foreach(System* s, _systems)
delete s;
foreach(Page* page, _pages)
delete page;
foreach(Excerpt* e, _excerpts)
delete e;
delete _revisions;
delete _undo; // this also removes _undoStack from Mscore::_undoGroup
delete _tempomap;
delete _sigmap;
delete _repeatList;
}
//---------------------------------------------------------
// elementAdjustReadPos
//---------------------------------------------------------
static void elementAdjustReadPos(void*, Element* e)
{
if (e->isMovable())
e->adjustReadPos();
}
//---------------------------------------------------------
// addMeasure
//---------------------------------------------------------
void Score::addMeasure(MeasureBase* m, MeasureBase* pos)
{
m->setNext(pos);
_measures.add(m);
}
//---------------------------------------------------------
// fixTicks
// update:
// - measure ticks
// - tempo map
// - time signature map
//---------------------------------------------------------
/**
This is needed after
2013-05-14 16:43:21 +02:00
- inserting or removing a measure
2012-05-26 14:26:10 +02:00
- changing the sigmap
- after inserting/deleting time (changes the sigmap)
*/
void Score::fixTicks()
{
int tick = 0;
2012-05-26 14:26:10 +02:00
Measure* fm = firstMeasure();
if (fm == 0)
return;
2014-05-03 11:33:47 +02:00
for (Staff* staff : _staves)
staff->clearTimeSig();
2012-05-26 14:26:10 +02:00
TimeSigMap* smap = sigmap();
Fraction sig(fm->len());
Fraction nsig(fm->timesig());
if (!parentScore()) {
tempomap()->clear();
smap->clear();
smap->add(0, SigEvent(sig, nsig, 0));
2012-05-26 14:26:10 +02:00
}
for (MeasureBase* mb = first(); mb; mb = mb->next()) {
2012-09-13 18:01:34 +02:00
if (mb->type() != Element::MEASURE) {
2012-05-26 14:26:10 +02:00
mb->setTick(tick);
continue;
}
2013-09-28 12:05:48 +02:00
Measure* m = static_cast<Measure*>(mb);
2012-05-26 14:26:10 +02:00
int mtick = m->tick();
int diff = tick - mtick;
int measureTicks = m->ticks();
m->moveTicks(diff);
2013-09-28 12:05:48 +02:00
if (m->mmRest())
m->mmRest()->moveTicks(diff);
2012-05-26 14:26:10 +02:00
if (!parentScore()) {
//
// implement section break rest
//
if (m->sectionBreak())
setPause(m->tick() + m->ticks(), m->pause());
//
// implement fermata as a tempo change
//
Segment::SegmentTypes st = Segment::SegChordRest | Segment::SegBreath;
2012-05-26 14:26:10 +02:00
for (Segment* s = m->first(st); s; s = s->next(st)) {
2014-05-03 11:33:47 +02:00
if (s->segmentType() == Segment::SegBreath)
2012-05-26 14:26:10 +02:00
setPause(s->tick(), .1);
2014-05-03 11:33:47 +02:00
else if (s->segmentType() == Segment::SegTimeSig) {
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
TimeSig* ts = static_cast<TimeSig*>(s->element(staffIdx * VOICES));
if (ts)
staff(staffIdx)->addTimeSig(ts);
}
2012-05-26 14:26:10 +02:00
}
else {
foreach(Element* e, s->annotations()) {
if (e->type() == Element::TEMPO_TEXT) {
const TempoText* tt = static_cast<const TempoText*>(e);
setTempo(tt->segment(), tt->tempo());
}
}
2013-06-03 14:39:59 +02:00
qreal stretch = 0.0;
for (int i = 0; i < s->elist().size(); ++i) {
Element* e = s->elist().at(i);
if (!e)
continue;
ChordRest* cr = static_cast<ChordRest*>(e);
int nn = cr->articulations().size();
for (int ii = 0; ii < nn; ++ii)
stretch = qMax(cr->articulations().at(ii)->timeStretch(), stretch);
if (stretch != 0.0 && stretch != 1.0) {
qreal otempo = tempomap()->tempo(cr->tick());
qreal ntempo = otempo / stretch;
setTempo(cr->tick(), ntempo);
2013-06-03 17:30:31 +02:00
int etick = cr->tick() + cr->actualTicks() - 1;
auto e = tempomap()->find(etick);
if (e == tempomap()->end())
setTempo(etick, otempo);
break;
}
2012-05-26 14:26:10 +02:00
}
}
}
}
//
// update time signature map
//
if (!parentScore() && (m->len() != sig)) {
sig = m->len();
smap->add(tick, SigEvent(sig, m->timesig(), m->no()));
2012-05-26 14:26:10 +02:00
}
tick += measureTicks;
}
if (tempomap()->empty())
tempomap()->setTempo(0, 2.0);
}
2012-11-08 12:59:30 +01:00
//---------------------------------------------------------
// validSegment
//---------------------------------------------------------
static bool validSegment(Segment* s, int startTrack, int endTrack)
{
for (int track = startTrack; track < endTrack; ++track) {
if (s->element(track))
return true;
}
return false;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// pos2measure
//---------------------------------------------------------
/**
Return measure for canvas relative position \a p.
*/
MeasureBase* Score::pos2measure(const QPointF& p, int* rst, int* pitch,
Segment** seg, QPointF* offset) const
{
Measure* m = searchMeasure(p);
if (m == 0)
return 0;
System* s = m->system();
// qreal sy1 = 0;
qreal y = p.y() - s->canvasPos().y();
int i;
for (i = 0; i < nstaves();) {
SysStaff* stff = s->staff(i);
if (!stff->show() || !staff(i)->show()) {
2012-05-26 14:26:10 +02:00
++i;
continue;
}
int ni = i;
for (;;) {
++ni;
if (ni == nstaves() || (s->staff(ni)->show() && staff(ni)->show()))
2012-05-26 14:26:10 +02:00
break;
}
qreal sy2;
if (ni != nstaves()) {
SysStaff* nstaff = s->staff(ni);
qreal s1y2 = stff->bbox().y() + stff->bbox().height();
2012-05-26 14:26:10 +02:00
sy2 = s1y2 + (nstaff->bbox().y() - s1y2)/2;
}
else
sy2 = s->page()->height() - s->pos().y(); // s->height();
if (y > sy2) {
// sy1 = sy2;
i = ni;
continue;
}
break;
}
// search for segment + offset
QPointF pppp = p - m->canvasPos();
2012-11-08 12:59:30 +01:00
int strack = i * VOICES;
int etrack = staff(i)->part()->nstaves() * VOICES + strack;
2012-05-26 14:26:10 +02:00
SysStaff* sstaff = m->system()->staff(i);
2013-06-12 14:23:57 +02:00
Segment::SegmentTypes st = Segment::SegChordRest;
2012-11-08 12:59:30 +01:00
for (Segment* segment = m->first(st); segment; segment = segment->next(st)) {
if (!validSegment(segment, strack, etrack))
2012-05-26 14:26:10 +02:00
continue;
2012-11-08 12:59:30 +01:00
Segment* ns = segment->next(st);
for (; ns; ns = ns->next(st)) {
if (validSegment(ns, strack, etrack))
2012-05-26 14:26:10 +02:00
break;
}
if (!ns || (pppp.x() < (segment->x() + (ns->x() - segment->x())/2.0))) {
*rst = i;
if (pitch) {
Staff* s = _staves[i];
2013-09-05 16:37:49 +02:00
ClefType clef = s->clef(segment->tick());
2012-05-26 14:26:10 +02:00
*pitch = y2pitch(pppp.y() - sstaff->bbox().y(), clef, s->spatium());
}
if (offset)
*offset = pppp - QPointF(segment->x(), sstaff->bbox().y());
if (seg)
*seg = segment;
return m;
}
}
return 0;
}
//---------------------------------------------------------
// staffIdx
//
/// Return index for the first staff of \a part.
//---------------------------------------------------------
int Score::staffIdx(const Part* part) const
{
int idx = 0;
foreach(Part* p, _parts) {
if (p == part)
break;
idx += p->nstaves();
}
return idx;
}
//---------------------------------------------------------
// setShowInvisible
//---------------------------------------------------------
void Score::setShowInvisible(bool v)
{
_showInvisible = v;
_updateAll = true;
end();
}
//---------------------------------------------------------
// setShowUnprintable
//---------------------------------------------------------
void Score::setShowUnprintable(bool v)
{
_showUnprintable = v;
_updateAll = true;
end();
}
//---------------------------------------------------------
// setShowFrames
//---------------------------------------------------------
void Score::setShowFrames(bool v)
{
_showFrames = v;
_updateAll = true;
end();
}
//---------------------------------------------------------
// setShowPageborders
//---------------------------------------------------------
void Score::setShowPageborders(bool v)
{
_showPageborders = v;
_updateAll = true;
end();
}
//---------------------------------------------------------
// setDirty
//---------------------------------------------------------
void Score::setDirty(bool val)
{
2014-02-25 14:14:59 +01:00
Score* s = rootScore();
if (s->dirty() != val) {
s->_dirty = val;
s->_playlistDirty = true;
2012-05-26 14:26:10 +02:00
}
2014-02-25 14:14:59 +01:00
if (s->dirty()) {
s->_playlistDirty = true;
s->_autosaveDirty = true;
2012-05-26 14:26:10 +02:00
}
}
2014-02-25 14:14:59 +01:00
//---------------------------------------------------------
// dirty
//---------------------------------------------------------
bool Score::dirty() const
{
return rootScore()->_dirty;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// spell
//---------------------------------------------------------
void Score::spell()
{
for (int i = 0; i < nstaves(); ++i) {
QList<Note*> notes;
for (Segment* s = firstSegment(); s; s = s->next1()) {
int strack = i * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
2012-09-13 18:01:34 +02:00
if (e && e->type() == Element::CHORD)
2012-05-26 14:26:10 +02:00
notes.append(static_cast<Chord*>(e)->notes());
}
}
spellNotelist(notes);
}
}
void Score::spell(int startStaff, int endStaff, Segment* startSegment, Segment* endSegment)
{
for (int i = startStaff; i < endStaff; ++i) {
QList<Note*> notes;
for (Segment* s = startSegment; s && s != endSegment; s = s->next()) {
int strack = i * VOICES;
int etrack = strack + VOICES;
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
2012-09-13 18:01:34 +02:00
if (e && e->type() == Element::CHORD)
2012-05-26 14:26:10 +02:00
notes.append(static_cast<Chord*>(e)->notes());
}
}
spellNotelist(notes);
}
}
//---------------------------------------------------------
// prevNote
//---------------------------------------------------------
Note* prevNote(Note* n)
{
Chord* chord = n->chord();
Segment* seg = chord->segment();
const QList<Note*> nl = chord->notes();
int i = nl.indexOf(n);
if (i)
return nl[i-1];
int staff = n->staffIdx();
int startTrack = staff * VOICES + n->voice() - 1;
int endTrack = 0;
while (seg) {
if (seg->segmentType() == Segment::SegChordRest) {
2012-05-26 14:26:10 +02:00
for (int track = startTrack; track >= endTrack; --track) {
Element* e = seg->element(track);
2012-09-13 18:01:34 +02:00
if (e && e->type() == Element::CHORD)
2012-05-26 14:26:10 +02:00
return static_cast<Chord*>(e)->upNote();
}
}
seg = seg->prev1();
startTrack = staff * VOICES + VOICES - 1;
}
return n;
}
//---------------------------------------------------------
// nextNote
//---------------------------------------------------------
Note* nextNote(Note* n)
{
Chord* chord = n->chord();
const QList<Note*> nl = chord->notes();
int i = nl.indexOf(n);
++i;
if (i < nl.size())
return nl[i];
Segment* seg = chord->segment();
int staff = n->staffIdx();
int startTrack = staff * VOICES + n->voice() + 1;
int endTrack = staff * VOICES + VOICES;
while (seg) {
if (seg->segmentType() == Segment::SegChordRest) {
2012-05-26 14:26:10 +02:00
for (int track = startTrack; track < endTrack; ++track) {
Element* e = seg->element(track);
2012-09-13 18:01:34 +02:00
if (e && e->type() == Element::CHORD) {
2012-05-26 14:26:10 +02:00
return ((Chord*)e)->downNote();
}
}
}
seg = seg->next1();
startTrack = staff * VOICES;
}
return n;
}
//---------------------------------------------------------
// spell
//---------------------------------------------------------
void Score::spell(Note* note)
{
QList<Note*> notes;
notes.append(note);
Note* nn = nextNote(note);
notes.append(nn);
nn = nextNote(nn);
notes.append(nn);
nn = nextNote(nn);
notes.append(nn);
nn = prevNote(note);
notes.prepend(nn);
nn = prevNote(nn);
notes.prepend(nn);
nn = prevNote(nn);
notes.prepend(nn);
2013-05-13 18:49:17 +02:00
int opt = Ms::computeWindow(notes, 0, 7);
note->setTpc(Ms::tpc(3, note->pitch(), opt));
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// isSavable
//---------------------------------------------------------
bool Score::isSavable() const
{
// TODO: check if file can be created if it does not exist
return info.isWritable() || !info.exists();
}
//---------------------------------------------------------
// appendPart
//---------------------------------------------------------
void Score::appendPart(Part* p)
{
_parts.append(p);
}
//---------------------------------------------------------
// rebuildMidiMapping
//---------------------------------------------------------
void Score::rebuildMidiMapping()
{
_midiMapping.clear();
int port = 0;
int channel = 0;
int idx = 0;
foreach(Part* part, _parts) {
InstrumentList* il = part->instrList();
2013-05-28 15:42:02 +02:00
for (auto i = il->begin(); i != il->end(); ++i) {
2012-05-26 14:26:10 +02:00
bool drum = i->second.useDrumset();
for (int k = 0; k < i->second.channel().size(); ++k) {
Channel* a = &(i->second.channel(k));
MidiMapping mm;
if (drum) {
mm.port = port;
mm.channel = 9;
}
else {
mm.port = port;
mm.channel = channel;
if (channel == 15) {
channel = 0;
++port;
}
else {
++channel;
if (channel == 9)
++channel;
}
}
mm.part = part;
mm.articulation = a;
_midiMapping.append(mm);
a->channel = idx;
++idx;
}
}
}
}
//---------------------------------------------------------
// midiPort
//---------------------------------------------------------
int Score::midiPort(int idx) const
{
return _midiMapping[idx].port;
}
//---------------------------------------------------------
// midiChannel
//---------------------------------------------------------
int Score::midiChannel(int idx) const
{
return _midiMapping[idx].channel;
}
//---------------------------------------------------------
// searchPage
// p is in canvas coordinates
//---------------------------------------------------------
Page* Score::searchPage(const QPointF& p) const
{
foreach(Page* page, pages()) {
if (page->bbox().translated(page->pos()).contains(p))
return page;
}
return 0;
}
//---------------------------------------------------------
// searchSystem
// return list of systems as there may be more than
// one system in a row
// p is in canvas coordinates
//---------------------------------------------------------
QList<System*> Score::searchSystem(const QPointF& pos) const
{
QList<System*> systems;
Page* page = searchPage(pos);
if (page == 0)
return systems;
qreal y = pos.y() - page->pos().y(); // transform to page relative
const QList<System*>* sl = page->systems();
qreal y2;
int n = sl->size();
for (int i = 0; i < n; ++i) {
System* s = sl->at(i);
System* ns = 0; // next system row
int ii = i + 1;
for (; ii < n; ++ii) {
ns = sl->at(ii);
if (ns->y() != s->y())
break;
}
if ((ii == n) || (ns == 0))
y2 = page->height();
else {
qreal sy2 = s->y() + s->bbox().height();
y2 = sy2 + (ns->y() - sy2) * .5;
}
if (y < y2) {
systems.append(s);
for (int ii = i+1; ii < n; ++ii) {
if (sl->at(ii)->y() != s->y())
break;
systems.append(sl->at(ii));
}
return systems;
}
}
return systems;
}
//---------------------------------------------------------
// searchMeasure
// p is in canvas coordinates
//---------------------------------------------------------
Measure* Score::searchMeasure(const QPointF& p) const
{
QList<System*> systems = searchSystem(p);
if (systems.isEmpty())
return 0;
foreach(System* system, systems) {
qreal x = p.x() - system->canvasPos().x();
foreach(MeasureBase* mb, system->measures()) {
2012-09-13 18:01:34 +02:00
if (mb->type() != Element::MEASURE)
2012-05-26 14:26:10 +02:00
continue;
if (x < (mb->x() + mb->bbox().width()))
return static_cast<Measure*>(mb);
}
}
return 0;
}
//---------------------------------------------------------
// getNextValidInputSegment
// - s is of type Segment::SegChordRest
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
static Segment* getNextValidInputSegment(Segment* s, int track, int voice)
{
if (s == 0)
return 0;
Q_ASSERT(s->segmentType() == Segment::SegChordRest);
2012-05-26 14:26:10 +02:00
// Segment* s1 = s;
ChordRest* cr1;
for (Segment* s1 = s; s1; s1 = s1->prev(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
cr1 = static_cast<ChordRest*>(s1->element(track + voice));
if (cr1)
break;
}
int nextTick = (cr1 == 0) ? s->measure()->tick() : cr1->tick() + cr1->actualTicks();
static const Segment::SegmentTypes st = Segment::SegChordRest;
2012-05-26 14:26:10 +02:00
while (s) {
if (s->element(track + voice))
break;
if (voice && s->tick() == nextTick)
return s;
#if 0
int v;
for (v = 0; v < VOICES; ++v) {
if (s->element(track + v))
break;
}
if ((v != VOICES) && voice) {
int ntick;
bool skipChord = false;
bool ns = false;
for (Segment* s1 = s->measure()->first(st); s1; s1 = s1->next(st)) {
ChordRest* cr = static_cast<ChordRest*>(s1->element(track + voice));
if (cr) {
if (ns)
return s1;
ntick = s1->tick() + cr->actualTicks();
skipChord = true;
}
if (s1 == s)
ns = true;
if (skipChord) {
if (s->tick() >= ntick)
skipChord = false;
}
if (!skipChord && ns)
return s1;
}
if (!skipChord)
return s;
}
#endif
s = s->next(st);
}
return s;
}
//---------------------------------------------------------
// getPosition
// return true if valid position found
//---------------------------------------------------------
bool Score::getPosition(Position* pos, const QPointF& p, int voice) const
{
2012-08-07 12:44:19 +02:00
Measure* measure = searchMeasure(p);
if (measure == 0)
2012-05-26 14:26:10 +02:00
return false;
pos->fret = FRET_NONE;
2012-05-26 14:26:10 +02:00
//
// search staff
//
pos->staffIdx = 0;
SysStaff* sstaff = 0;
2012-08-07 12:44:19 +02:00
System* system = measure->system();
2012-05-26 14:26:10 +02:00
qreal y = p.y() - system->pagePos().y();
for (; pos->staffIdx < nstaves(); ++pos->staffIdx) {
qreal sy2;
SysStaff* ss = system->staff(pos->staffIdx);
if ((pos->staffIdx+1) != nstaves()) {
SysStaff* nstaff = system->staff(pos->staffIdx+1);
qreal s1y2 = ss->bbox().y() + ss->bbox().height();
sy2 = s1y2 + (nstaff->bbox().y() - s1y2) * .5;
}
else
sy2 = system->page()->height() - system->pos().y(); // system->height();
if (y < sy2) {
sstaff = ss;
break;
}
}
if (sstaff == 0)
return false;
//
// search segment
//
2012-08-07 12:44:19 +02:00
QPointF pppp(p - measure->canvasPos());
2012-05-26 14:26:10 +02:00
qreal x = pppp.x();
Segment* segment = 0;
pos->segment = 0;
// int track = pos->staffIdx * VOICES + voice;
int track = pos->staffIdx * VOICES;
2012-08-07 12:44:19 +02:00
for (segment = measure->first(Segment::SegChordRest); segment;) {
2012-05-26 14:26:10 +02:00
segment = getNextValidInputSegment(segment, track, voice);
if (segment == 0)
break;
Segment* ns = getNextValidInputSegment(segment->next(Segment::SegChordRest), track, voice);
2012-05-26 14:26:10 +02:00
qreal x1 = segment->x();
qreal x2;
qreal d;
if (ns) {
x2 = ns->x();
d = x2 - x1;
}
else {
2012-08-07 12:44:19 +02:00
x2 = measure->bbox().width();
2012-05-26 14:26:10 +02:00
d = (x2 - x1) * 2.0;
x = x1;
pos->segment = segment;
break;
}
if (x < (x1 + d * .5)) {
x = x1;
pos->segment = segment;
break;
}
segment = ns;
}
if (segment == 0)
return false;
//
// TODO: restrict to reasonable values (pitch 0-127)
//
Staff* s = staff(pos->staffIdx);
qreal mag = s->mag();
// in TABs, step from one string to another; in other staves, step on and between lines
qreal lineDist = s->staffType()->lineDistance().val() * (s->isTabStaff() ? 1 : .5) * mag * spatium();
2012-05-26 14:26:10 +02:00
pos->line = lrint((pppp.y() - sstaff->bbox().y()) / lineDist);
if (s->isTabStaff()) {
2012-05-26 14:26:10 +02:00
if (pos->line < -1 || pos->line > s->lines()+1)
return false;
if (pos->line < 0)
pos->line = 0;
else if (pos->line >= s->lines())
pos->line = s->lines() - 1;
}
else {
2012-08-07 16:05:37 +02:00
int minLine = absStep(0);
2012-08-07 12:44:19 +02:00
ClefType clef = s->clef(pos->segment->tick());
2012-08-07 16:05:37 +02:00
minLine = relStep(minLine, clef);
int maxLine = absStep(127);
maxLine = relStep(maxLine, clef);
2012-05-26 14:26:10 +02:00
if (pos->line > minLine || pos->line < maxLine)
return false;
}
y = sstaff->y() + pos->line * lineDist;
2012-08-07 12:44:19 +02:00
pos->pos = QPointF(x, y) + measure->canvasPos();
2012-05-26 14:26:10 +02:00
return true;
}
//---------------------------------------------------------
// checkHasMeasures
//---------------------------------------------------------
bool Score::checkHasMeasures() const
{
Page* page = pages().front();
const QList<System*>* sl = page->systems();
if (sl == 0 || sl->empty() || sl->front()->measures().empty()) {
2013-07-25 17:22:49 +02:00
qDebug("first create measure, then repeat operation");
2012-05-26 14:26:10 +02:00
return false;
}
return true;
}
//---------------------------------------------------------
// moveBracket
// columns are counted from right to left
//---------------------------------------------------------
void Score::moveBracket(int staffIdx, int srcCol, int dstCol)
{
foreach(System* system, *systems()) {
if (system->isVbox())
continue;
2012-10-12 15:36:57 +02:00
foreach(Bracket* b, system->brackets()) {
if (b->staffIdx() == staffIdx && b->level() == srcCol)
b->setLevel(dstCol);
}
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// spatiumHasChanged
//---------------------------------------------------------
static void spatiumHasChanged(void* data, Element* e)
{
qreal* val = (qreal*)data;
e->spatiumChanged(val[0], val[1]);
}
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void Score::spatiumChanged(qreal oldValue, qreal newValue)
{
qreal data[2];
data[0] = oldValue;
data[1] = newValue;
scanElements(data, spatiumHasChanged, true);
foreach (Staff* staff, _staves)
staff->spatiumChanged(oldValue, newValue);
2013-11-11 15:11:28 +01:00
_noteHeadWidth = _scoreFont->width(SymId::noteheadBlack, newValue / (MScore::DPI * SPATIUM20));
2012-05-26 14:26:10 +02:00
}
2013-05-27 15:59:43 +02:00
void Score::setSpatium(qreal v)
{
style()->setSpatium(v);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// getCreateMeasure
// - return Measure for tick
// - create new Measure(s) if there is no measure for
// this tick
//---------------------------------------------------------
Measure* Score::getCreateMeasure(int tick)
{
Measure* last = lastMeasure();
if (last == 0 || ((last->tick() + last->ticks()) <= tick)) {
int lastTick = last ? (last->tick()+last->ticks()) : 0;
while (tick >= lastTick) {
Measure* m = new Measure(this);
Fraction ts = _sigmap->timesig(lastTick).timesig();
2013-07-25 17:22:49 +02:00
// qDebug("getCreateMeasure %d %d/%d", tick, ts.numerator(), ts.denominator());
2012-05-26 14:26:10 +02:00
m->setTick(lastTick);
m->setTimesig(ts);
m->setLen(ts);
add(m);
lastTick += ts.ticks();
}
}
return tick2measure(tick);
}
//---------------------------------------------------------
// addElement
//---------------------------------------------------------
/**
Add \a element to its parent.
Several elements (clef, keysig, timesig) need special handling, as they may cause
changes throughout the score.
*/
void Score::addElement(Element* element)
{
#if 0
2012-05-26 14:26:10 +02:00
if (MScore::debugMode) {
qDebug(" Score(%p)::addElement %p(%s) parent %p(%s)",
this, element, element->name(), element->parent(),
element->parent() ? element->parent()->name() : "");
}
#endif
2012-09-13 18:01:34 +02:00
if (element->parent() && element->parent()->type() == Element::SEGMENT)
2012-08-08 20:46:29 +02:00
static_cast<Segment*>(element->parent())->measure()->setDirty();
2012-09-13 18:01:34 +02:00
Element::ElementType et = element->type();
2013-06-05 15:47:34 +02:00
if (et == Element::TREMOLO)
setLayoutAll(true);
2012-09-13 18:01:34 +02:00
else if (et == Element::MEASURE
|| (et == Element::HBOX && element->parent()->type() != Element::VBOX)
|| et == Element::VBOX
|| et == Element::TBOX
|| et == Element::FBOX
2012-05-26 14:26:10 +02:00
) {
2014-02-28 14:25:47 +01:00
setLayoutAll(true);
2012-05-26 14:26:10 +02:00
add(element);
addLayoutFlags(LAYOUT_FIX_TICKS);
return;
}
if (element->parent() == 0)
add(element);
else
element->parent()->add(element);
switch(et) {
2013-06-20 18:48:28 +02:00
case Element::SLUR:
addLayoutFlags(LAYOUT_PLAY_EVENTS);
// fall through
2012-09-13 18:01:34 +02:00
case Element::VOLTA:
case Element::TRILL:
case Element::PEDAL:
case Element::TEXTLINE:
2013-06-19 16:25:29 +02:00
case Element::HAIRPIN:
2012-05-26 14:26:10 +02:00
{
Spanner* spanner = static_cast<Spanner*>(element);
2013-07-04 13:40:25 +02:00
if (et == Element::TEXTLINE && spanner->anchor() == Spanner::ANCHOR_NOTE)
break;
2012-05-26 14:26:10 +02:00
foreach(SpannerSegment* ss, spanner->spannerSegments()) {
if (ss->system())
ss->system()->add(ss);
}
}
break;
2012-09-13 18:01:34 +02:00
case Element::OTTAVA:
2012-05-26 14:26:10 +02:00
{
Ottava* o = static_cast<Ottava*>(element);
foreach(SpannerSegment* ss, o->spannerSegments()) {
if (ss->system())
ss->system()->add(ss);
}
2013-07-16 09:03:47 +02:00
o->staff()->updateOttava(o);
2012-05-26 14:26:10 +02:00
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
}
break;
2012-09-13 18:01:34 +02:00
case Element::DYNAMIC:
2012-05-26 14:26:10 +02:00
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
break;
2013-07-05 11:23:52 +02:00
2012-09-13 18:01:34 +02:00
case Element::CLEF:
2012-05-26 14:26:10 +02:00
{
2012-09-20 11:35:34 +02:00
Clef* clef = static_cast<Clef*>(element);
if (!clef->generated())
updateNoteLines(clef->segment(), clef->track());
2012-05-26 14:26:10 +02:00
}
break;
2013-07-05 11:23:52 +02:00
2012-09-13 18:01:34 +02:00
case Element::KEYSIG:
2012-05-26 14:26:10 +02:00
{
KeySig* ks = static_cast<KeySig*>(element);
Staff* staff = element->staff();
KeySigEvent keySigEvent = ks->keySigEvent();
if (!ks->generated()) {
2012-05-26 14:26:10 +02:00
staff->setKey(ks->segment()->tick(), keySigEvent);
ks->insertIntoKeySigChain();
}
2012-05-26 14:26:10 +02:00
}
break;
2013-07-05 11:23:52 +02:00
2012-09-13 18:01:34 +02:00
case Element::TEMPO_TEXT:
2012-05-26 14:26:10 +02:00
{
TempoText* tt = static_cast<TempoText*>(element);
setTempo(tt->segment(), tt->tempo());
}
break;
2013-07-05 11:23:52 +02:00
2012-09-13 18:01:34 +02:00
case Element::INSTRUMENT_CHANGE:
2012-05-26 14:26:10 +02:00
rebuildMidiMapping();
_instrumentsChanged = true;
break;
2012-11-21 15:57:35 +01:00
case Element::CHORD:
2013-07-01 16:28:39 +02:00
createPlayEvents(static_cast<Chord*>(element));
2012-11-21 15:57:35 +01:00
break;
case Element::NOTE: {
Note* note = static_cast<Note*>(element);
2014-04-22 17:02:03 +02:00
note->chord()->segment()->measure()->cmdUpdateNotes(element->staffIdx());
}
// fall through
2012-11-20 20:51:18 +01:00
case Element::TREMOLO:
case Element::ARTICULATION:
case Element::ARPEGGIO:
{
Element* cr = element->parent();
if (cr->type() == Element::CHORD)
2013-07-01 16:28:39 +02:00
createPlayEvents(static_cast<Chord*>(cr));
}
2012-11-20 20:51:18 +01:00
break;
2012-05-26 14:26:10 +02:00
default:
break;
}
setLayoutAll(true);
}
//---------------------------------------------------------
// removeElement
/// Remove \a element from its parent.
/// Several elements (clef, keysig, timesig) need special handling, as they may cause
/// changes throughout the score.
//---------------------------------------------------------
void Score::removeElement(Element* element)
{
Element* parent = element->parent();
#if 0
2012-05-26 14:26:10 +02:00
if (MScore::debugMode) {
qDebug(" Score(%p)::removeElement %p(%s) parent %p(%s)",
this, element, element->name(), parent, parent ? parent->name() : "");
}
#endif
2013-10-30 09:00:01 +01:00
if (parent && parent->type() == Element::SEGMENT)
static_cast<Segment*>(parent)->measure()->setDirty();
2012-05-26 14:26:10 +02:00
// special for MEASURE, HBOX, VBOX
// their parent is not static
2012-09-13 18:01:34 +02:00
Element::ElementType et = element->type();
2013-06-05 15:47:34 +02:00
if (et == Element::TREMOLO)
setLayoutAll(true);
2012-09-13 18:01:34 +02:00
else if (et == Element::MEASURE
|| (et == Element::HBOX && parent->type() != Element::VBOX)
|| et == Element::VBOX
|| et == Element::TBOX
|| et == Element::FBOX
2012-05-26 14:26:10 +02:00
) {
remove(element);
addLayoutFlags(LAYOUT_FIX_TICKS);
2013-06-16 23:33:37 +02:00
setLayoutAll(true);
2012-05-26 14:26:10 +02:00
return;
}
2012-09-13 18:01:34 +02:00
if (et == Element::BEAM) // beam parent does not survive layout
2012-05-26 14:26:10 +02:00
element->setParent(0);
if (parent)
parent->remove(element);
else
remove(element);
switch(et) {
2012-09-13 18:01:34 +02:00
case Element::SLUR:
2012-11-21 13:49:08 +01:00
addLayoutFlags(LAYOUT_PLAY_EVENTS);
2013-06-20 18:48:28 +02:00
// fall through
2012-05-26 14:26:10 +02:00
2012-09-13 18:01:34 +02:00
case Element::VOLTA:
case Element::TRILL:
case Element::PEDAL:
case Element::TEXTLINE:
2013-06-19 16:25:29 +02:00
case Element::HAIRPIN:
2012-05-26 14:26:10 +02:00
{
Spanner* spanner = static_cast<Spanner*>(element);
foreach(SpannerSegment* ss, spanner->spannerSegments()) {
if (ss->system())
ss->system()->remove(ss);
}
}
break;
2012-09-13 18:01:34 +02:00
case Element::OTTAVA:
2012-05-26 14:26:10 +02:00
{
Ottava* o = static_cast<Ottava*>(element);
foreach(SpannerSegment* ss, o->spannerSegments()) {
if (ss->system())
ss->system()->remove(ss);
}
Staff* s = o->staff();
2013-07-05 11:23:52 +02:00
s->pitchOffsets().remove(o->tick());
s->pitchOffsets().remove(o->tick2());
2012-05-26 14:26:10 +02:00
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
}
break;
2012-09-13 18:01:34 +02:00
case Element::DYNAMIC:
2012-05-26 14:26:10 +02:00
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
break;
2012-09-13 18:01:34 +02:00
case Element::CHORD:
case Element::REST:
2012-05-26 14:26:10 +02:00
{
ChordRest* cr = static_cast<ChordRest*>(element);
if (cr->beam())
cr->beam()->remove(cr);
}
break;
2012-09-13 18:01:34 +02:00
case Element::CLEF:
2012-05-26 14:26:10 +02:00
{
Clef* clef = static_cast<Clef*>(element);
if (!clef->generated())
updateNoteLines(clef->segment(), clef->track());
2012-05-26 14:26:10 +02:00
}
break;
2012-09-13 18:01:34 +02:00
case Element::KEYSIG:
2012-05-26 14:26:10 +02:00
{
KeySig* ks = static_cast<KeySig*>(element);
Staff* staff = element->staff();
if (!ks->generated()) {
ks->removeFromKeySigChain();
2012-05-26 14:26:10 +02:00
staff->removeKey(ks->segment()->tick());
}
2012-05-26 14:26:10 +02:00
}
break;
2012-09-13 18:01:34 +02:00
case Element::TEMPO_TEXT:
2012-05-26 14:26:10 +02:00
{
TempoText* tt = static_cast<TempoText*>(element);
int tick = tt->segment()->tick();
tempomap()->delTempo(tick);
}
break;
2012-09-13 18:01:34 +02:00
case Element::INSTRUMENT_CHANGE:
2012-05-26 14:26:10 +02:00
rebuildMidiMapping();
_instrumentsChanged = true;
break;
2012-11-20 20:51:18 +01:00
case Element::TREMOLO:
case Element::ARTICULATION:
case Element::ARPEGGIO:
{
Element* cr = element->parent();
if (cr->type() == Element::CHORD)
2013-07-01 16:28:39 +02:00
createPlayEvents(static_cast<Chord*>(cr));
}
2012-11-20 20:51:18 +01:00
break;
2012-05-26 14:26:10 +02:00
default:
break;
}
setLayoutAll(true);
}
//---------------------------------------------------------
// firstMeasure
//---------------------------------------------------------
Measure* Score::firstMeasure() const
{
MeasureBase* mb = _measures.first();
2012-09-13 18:01:34 +02:00
while (mb && mb->type() != Element::MEASURE)
2012-05-26 14:26:10 +02:00
mb = mb->next();
return static_cast<Measure*>(mb);
}
//---------------------------------------------------------
// firstMeasureMM
//---------------------------------------------------------
Measure* Score::firstMeasureMM() const
{
MeasureBase* mb = _measures.first();
while (mb && mb->type() != Element::MEASURE)
mb = mb->next();
Measure* m = static_cast<Measure*>(mb);
if (m && styleB(ST_createMultiMeasureRests) && m->hasMMRest())
return m->mmRest();
return m;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// firstMM
//---------------------------------------------------------
MeasureBase* Score::firstMM() const
{
MeasureBase* m = _measures.first();
if (m
&& m->type() == Element::MEASURE
&& styleB(ST_createMultiMeasureRests)
&& static_cast<Measure*>(m)->hasMMRest()) {
return static_cast<Measure*>(m)->mmRest();
}
return m;
}
2014-03-03 17:24:28 +01:00
#if 0
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// measureIdx
//---------------------------------------------------------
int Score::measureIdx(MeasureBase* m) const
{
int idx = 0;
for (MeasureBase* mb = _measures.first(); mb; mb = mb->nextMeasureMM()) {
2012-05-26 14:26:10 +02:00
if (mb == m)
return idx;
++idx;
}
return -1;
}
2014-03-03 17:24:28 +01:00
#endif
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// measure
//---------------------------------------------------------
MeasureBase* Score::measure(int idx) const
{
MeasureBase* mb = _measures.first();
for (int i = 0; i < idx; ++i) {
mb = mb->next();
if (mb == 0)
return 0;
}
return mb;
}
//---------------------------------------------------------
// lastMeasure
//---------------------------------------------------------
Measure* Score::lastMeasure() const
{
MeasureBase* mb = _measures.last();
2012-09-13 18:01:34 +02:00
while (mb && mb->type() != Element::MEASURE)
2012-05-26 14:26:10 +02:00
mb = mb->prev();
return static_cast<Measure*>(mb);
}
2013-10-06 16:43:43 +02:00
//---------------------------------------------------------
// lastMeasureMM
//---------------------------------------------------------
Measure* Score::lastMeasureMM() const
{
MeasureBase* mb = _measures.last();
for (; mb; mb = mb->prev()) {
if (mb->type() != Element::MEASURE)
continue;
if (!styleB(ST_createMultiMeasureRests))
break;
Measure* m = static_cast<Measure*>(mb);
if (m->mmRestCount() < 0)
continue;
if (m->hasMMRest())
mb = m->mmRest();
break;
}
return static_cast<Measure*>(mb);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// firstSegment
//---------------------------------------------------------
Segment* Score::firstSegment(Segment::SegmentTypes segType) const
2012-05-26 14:26:10 +02:00
{
Measure* m = firstMeasure();
return m ? m->first(segType) : 0;
}
2013-10-02 10:26:09 +02:00
//---------------------------------------------------------
// firstSegmentMM
//---------------------------------------------------------
Segment* Score::firstSegmentMM(Segment::SegmentTypes segType) const
{
Measure* m = firstMeasureMM();
return m ? m->first(segType) : 0;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// lastSegment
//---------------------------------------------------------
Segment* Score::lastSegment() const
{
Measure* m = lastMeasure();
return m ? m->last() : 0;
}
//---------------------------------------------------------
// utick2utime
//---------------------------------------------------------
qreal Score::utick2utime(int tick) const
{
return repeatList()->utick2utime(tick);
}
//---------------------------------------------------------
// utime2utick
//---------------------------------------------------------
int Score::utime2utick(qreal utime) const
{
return repeatList()->utime2utick(utime);
}
//---------------------------------------------------------
// inputPos
//---------------------------------------------------------
int Score::inputPos() const
{
return _is.tick();
}
//---------------------------------------------------------
// scanElements
// scan all elements
//---------------------------------------------------------
void Score::scanElements(void* data, void (*func)(void*, Element*), bool all)
{
for(MeasureBase* m = first(); m; m = m->next())
m->scanElements(data, func, all);
foreach(Page* page, pages())
page->scanElements(data, func, all);
}
//---------------------------------------------------------
// customKeySigIdx
// try to find custom key signature in table,
// return index or -1 if not found
//---------------------------------------------------------
int Score::customKeySigIdx(KeySig* ks) const
{
int idx = 0;
foreach(KeySig* k, customKeysigs) {
if (*k == *ks)
return idx;
++idx;
}
2013-07-25 17:22:49 +02:00
qDebug(" not found");
2012-05-26 14:26:10 +02:00
return -1;
}
//---------------------------------------------------------
// addCustomKeySig
//---------------------------------------------------------
int Score::addCustomKeySig(KeySig* ks)
{
customKeysigs.append(ks);
int idx = customKeysigs.size() - 1;
KeySigEvent k = ks->keySigEvent();
k.setCustomType(idx);
ks->setKeySigEvent(k);
ks->setScore(this);
return idx;
}
//---------------------------------------------------------
// customKeySig
//---------------------------------------------------------
KeySig* Score::customKeySig(int idx) const
{
return customKeysigs.value(idx);
}
//---------------------------------------------------------
// keySigFactory
//---------------------------------------------------------
KeySig* Score::keySigFactory(const KeySigEvent& e)
{
KeySig* ks;
if (!e.isValid())
return 0;
if (e.custom()) {
KeySig* cks = customKeysigs.value(e.customType());
if (cks)
ks = new KeySig(*cks);
else {
qDebug("Score::keySigFactory: invalid custom key index");
return 0;
}
}
else {
ks = new KeySig(this);
ks->setKeySigEvent(e);
}
return ks;
}
//---------------------------------------------------------
// setSelection
//---------------------------------------------------------
void Score::setSelection(const Selection& s)
{
deselectAll();
_selection = s;
2013-04-17 10:31:21 +02:00
2012-05-26 14:26:10 +02:00
foreach(Element* e, _selection.elements())
e->setSelected(true);
}
//---------------------------------------------------------
// getText
//---------------------------------------------------------
2012-11-27 13:19:24 +01:00
Text* Score::getText(int subtype)
2012-05-26 14:26:10 +02:00
{
2012-11-27 13:19:24 +01:00
MeasureBase* m = first();
if (m && m->type() == Element::VBOX) {
2012-05-26 14:26:10 +02:00
foreach(Element* e, *m->el()) {
2012-11-27 13:19:24 +01:00
if (e->type() == Element::TEXT && static_cast<Text*>(e)->textStyleType() == subtype)
2012-05-26 14:26:10 +02:00
return static_cast<Text*>(e);
}
}
return 0;
}
//---------------------------------------------------------
// rootScore
//---------------------------------------------------------
Score* Score::rootScore()
{
Score* score = this;
while (score->parentScore())
score = parentScore();
return score;
}
const Score* Score::rootScore() const
{
const Score* score = this;
while (score->parentScore())
score = parentScore();
return score;
}
//---------------------------------------------------------
// undo
//---------------------------------------------------------
UndoStack* Score::undo() const
{
return rootScore()->_undo;
}
//---------------------------------------------------------
// repeatList
//---------------------------------------------------------
RepeatList* Score::repeatList() const
{
return rootScore()->_repeatList;
}
//---------------------------------------------------------
// links
//---------------------------------------------------------
2013-05-16 12:48:23 +02:00
QMap<int, LinkedElements*>& Score::links()
2012-05-26 14:26:10 +02:00
{
return rootScore()->_elinks;
}
2013-10-07 12:09:11 +02:00
//---------------------------------------------------------
// setTempomap
//---------------------------------------------------------
void Score::setTempomap(TempoMap* tm)
{
delete _tempomap;
_tempomap = tm;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// tempomap
//---------------------------------------------------------
TempoMap* Score::tempomap() const
{
return rootScore()->_tempomap;
}
//---------------------------------------------------------
// sigmap
//---------------------------------------------------------
TimeSigMap* Score::sigmap() const
{
return rootScore()->_sigmap;
}
2013-07-19 10:39:32 +02:00
//---------------------------------------------------------
// metaTags
//---------------------------------------------------------
2013-07-19 18:03:35 +02:00
const QMap<QString, QString>& Score::metaTags() const
2013-07-19 10:39:32 +02:00
{
2013-07-19 18:03:35 +02:00
return _metaTags;
2013-07-19 10:39:32 +02:00
}
2013-07-19 11:24:56 +02:00
QMap<QString, QString>& Score::metaTags()
2013-07-19 10:39:32 +02:00
{
2013-07-19 18:03:35 +02:00
return _metaTags;
2013-07-19 10:39:32 +02:00
}
//---------------------------------------------------------
// metaTag
//---------------------------------------------------------
2013-07-19 11:24:56 +02:00
Q_INVOKABLE QString Score::metaTag(const QString& s) const
2013-07-19 10:39:32 +02:00
{
2013-07-19 18:03:35 +02:00
if (_metaTags.contains(s))
return _metaTags.value(s);
2013-07-19 10:39:32 +02:00
return rootScore()->_metaTags.value(s);
}
//---------------------------------------------------------
// setMetaTag
//---------------------------------------------------------
2013-07-19 11:24:56 +02:00
Q_INVOKABLE void Score::setMetaTag(const QString& tag, const QString& val)
2013-07-19 10:39:32 +02:00
{
2013-07-19 18:03:35 +02:00
_metaTags.insert(tag, val);
2013-07-19 10:39:32 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// addExcerpt
//---------------------------------------------------------
void Score::addExcerpt(Score* score)
{
Excerpt* ex = new Excerpt(score);
excerpts().append(ex);
ex->setTitle(score->name());
foreach(Staff* s, score->staves()) {
LinkedStaves* ls = s->linkedStaves();
if (ls == 0)
continue;
foreach(Staff* ps, ls->staves()) {
if (ps->score() == this) {
ex->parts().append(ps->part());
break;
}
}
}
setExcerptsChanged(true);
}
//---------------------------------------------------------
// removeExcerpt
//---------------------------------------------------------
void Score::removeExcerpt(Score* score)
{
foreach (Excerpt* ex, excerpts()) {
if (ex->score() == score) {
if (excerpts().removeOne(ex)) {
delete ex;
return;
}
else
2013-07-25 17:22:49 +02:00
qDebug("removeExcerpt:: ex not found");
2012-05-26 14:26:10 +02:00
}
}
2013-07-25 17:22:49 +02:00
qDebug("Score::removeExcerpt: excerpt not found");
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// updateNotes
2014-04-22 17:02:03 +02:00
/// recompute note lines and accidental
/// not undoable add/remove
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Score::updateNotes()
{
for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM()) {
2014-03-26 11:02:23 +01:00
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx)
2014-04-22 17:02:03 +02:00
m->updateNotes(staffIdx);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// cmdUpdateNotes
2014-04-22 17:02:03 +02:00
/// recompute note lines and accidental
/// undoable add/remove
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Score::cmdUpdateNotes()
{
for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM()) {
2012-05-26 14:26:10 +02:00
for (int staffIdx = 0; staffIdx < nstaves(); ++staffIdx)
2014-04-22 17:02:03 +02:00
m->cmdUpdateNotes(staffIdx);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// cmdUpdateAccidentals
/// update accidentals upto next keySig change
//---------------------------------------------------------
void Score::cmdUpdateAccidentals(Measure* beginMeasure, int staffIdx)
{
for (Measure* m = beginMeasure; m; m = m->nextMeasureMM()) {
2014-04-22 17:02:03 +02:00
m->cmdUpdateNotes(staffIdx);
2014-03-26 11:02:23 +01:00
if (m == beginMeasure)
continue;
for (Segment* s = m->first(Segment::SegKeySig); s; s = s->next(Segment::SegKeySig)) {
KeySig* ks = static_cast<KeySig*>(s->element(staffIdx * VOICES));
if (ks && (!ks->generated()))
return;
}
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// clone
//---------------------------------------------------------
Score* Score::clone()
{
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
Xml xml(&buffer);
xml.header();
xml.stag("museScore version=\"" MSC_VERSION "\"");
write(xml, false);
xml.etag();
buffer.close();
2013-01-11 18:10:18 +01:00
XmlReader r(buffer.buffer());
2012-05-26 14:26:10 +02:00
Score* score = new Score(style());
2013-01-11 18:10:18 +01:00
score->read1(r, true);
2012-05-26 14:26:10 +02:00
int staffIdx = 0;
foreach(Staff* st, score->staves()) {
if (st->updateKeymap())
st->keymap()->clear();
int track = staffIdx * VOICES;
KeySig* key1 = 0;
for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure()) {
for (Segment* s = m->first(); s; s = s->next()) {
if (!s->element(track))
continue;
Element* e = s->element(track);
if (e->generated())
continue;
if ((s->segmentType() == Segment::SegKeySig) && st->updateKeymap()) {
2012-05-26 14:26:10 +02:00
KeySig* ks = static_cast<KeySig*>(e);
int naturals = key1 ? key1->keySigEvent().accidentalType() : 0;
ks->setOldSig(naturals);
st->setKey(s->tick(), ks->keySigEvent());
key1 = ks;
}
}
if (m->sectionBreak())
key1 = 0;
}
st->setUpdateKeymap(false);
++staffIdx;
}
score->updateNotes();
score->addLayoutFlags(LAYOUT_FIX_TICKS | LAYOUT_FIX_PITCH_VELO);
score->doLayout();
score->scanElements(0, elementAdjustReadPos); //??
return score;
}
//---------------------------------------------------------
// setSynthesizerState
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void Score::setSynthesizerState(const SynthesizerState& s)
2012-05-26 14:26:10 +02:00
{
// TODO: make undoable
_dirty = true;
_synthesizerState = s;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// setLayoutAll
//---------------------------------------------------------
void Score::setLayoutAll(bool val)
{
foreach(Score* score, scoreList())
score->_layoutAll = val;
}
//---------------------------------------------------------
// removeOmr
//---------------------------------------------------------
void Score::removeOmr()
{
_showOmr = false;
2012-07-06 17:42:20 +02:00
#ifdef OMR
2012-05-26 14:26:10 +02:00
delete _omr;
_omr = 0;
2012-07-06 17:42:20 +02:00
#endif
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeAudio
//---------------------------------------------------------
void Score::removeAudio()
{
delete _audio;
_audio = 0;
}
//---------------------------------------------------------
// appendScore
//---------------------------------------------------------
bool Score::appendScore(Score* score)
{
TieMap tieMap;
MeasureBaseList* ml = &score->_measures;
for (MeasureBase* mb = ml->first(); mb; mb = mb->next()) {
MeasureBase* nmb;
2012-09-13 18:01:34 +02:00
if (mb->type() == Element::MEASURE)
2013-07-05 11:23:52 +02:00
nmb = static_cast<Measure*>(mb)->cloneMeasure(this, &tieMap);
2012-05-26 14:26:10 +02:00
else
nmb = mb->clone();
nmb->setNext(0);
nmb->setPrev(0);
nmb->setScore(this);
_measures.add(nmb);
}
fixTicks();
setLayoutAll(true);
2012-05-26 14:26:10 +02:00
return true;
}
//---------------------------------------------------------
// splitStaff
//---------------------------------------------------------
void Score::splitStaff(int staffIdx, int splitPoint)
{
2013-01-22 20:37:52 +01:00
qDebug("split staff %d point %d", staffIdx, splitPoint);
2012-05-26 14:26:10 +02:00
//
// create second staff
//
Staff* s = staff(staffIdx);
Part* p = s->part();
int rstaff = s->rstaff();
Staff* ns = new Staff(this, p, rstaff + 1);
ns->setRstaff(rstaff + 1);
undoInsertStaff(ns, staffIdx+1);
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
2012-05-26 14:26:10 +02:00
m->cmdAddStaves(staffIdx+1, staffIdx+2, false);
if (m->hasMMRest())
m->mmRest()->cmdAddStaves(staffIdx+1, staffIdx+2, false);
}
2012-05-26 14:26:10 +02:00
Clef* clef = new Clef(this);
2013-09-05 16:37:49 +02:00
clef->setClefType(ClefType::F);
2012-05-26 14:26:10 +02:00
clef->setTrack((staffIdx+1) * VOICES);
Segment* seg = firstMeasure()->getSegment(Segment::SegClef, 0);
2012-05-26 14:26:10 +02:00
clef->setParent(seg);
undoAddElement(clef);
undoChangeKeySig(ns, 0, s->key(0));
rebuildMidiMapping();
_instrumentsChanged = true;
doLayout();
//
// move notes
//
select(0, SELECT_SINGLE, 0);
int strack = staffIdx * VOICES;
int dtrack = (staffIdx + 1) * VOICES;
for (Segment* s = firstSegment(Segment::SegChordRest); s; s = s->next1(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
for (int voice = 0; voice < VOICES; ++voice) {
ChordRest* cr = static_cast<ChordRest*>(s->element(strack + voice));
2012-09-13 18:01:34 +02:00
if (cr == 0 || cr->type() == Element::REST)
2012-05-26 14:26:10 +02:00
continue;
Chord* c = static_cast<Chord*>(cr);
QList<Note*> removeNotes;
foreach(Note* note, c->notes()) {
if (note->pitch() >= splitPoint)
continue;
Chord* chord = static_cast<Chord*>(s->element(dtrack + voice));
Q_ASSERT(!chord || (chord->type() == Element::CHORD));
2012-05-26 14:26:10 +02:00
if (chord == 0) {
chord = new Chord(*c);
foreach(Note* note, chord->notes())
delete note;
chord->notes().clear();
chord->setTrack(dtrack + voice);
undoAddElement(chord);
}
Note* nnote = new Note(*note);
nnote->setTrack(dtrack + voice);
chord->add(nnote);
nnote->updateLine();
2012-05-26 14:26:10 +02:00
removeNotes.append(note);
}
2014-04-09 16:09:21 +02:00
c->sortNotes();
2012-05-26 14:26:10 +02:00
foreach(Note* note, removeNotes) {
undoRemoveElement(note);
if (note->chord()->notes().isEmpty())
undoRemoveElement(note->chord());
}
}
}
//
// make sure that the timeline for dtrack
// has no gaps
//
int ctick = 0;
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
for (Segment* s = m->first(Segment::SegChordRest); s; s = s->next1(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
ChordRest* cr = static_cast<ChordRest*>(s->element(dtrack));
if (cr == 0)
continue;
int rest = s->tick() - ctick;
if (rest) {
// insert Rest
Segment* s = tick2segment(ctick);
if (s == 0) {
2013-07-25 17:22:49 +02:00
qDebug("no segment at %d", ctick);
2012-05-26 14:26:10 +02:00
continue;
}
setRest(ctick, dtrack, Fraction::fromTicks(rest), false, 0);
}
ctick = s->tick() + cr->actualTicks();
}
int rest = m->tick() + m->ticks() - ctick;
if (rest) {
setRest(ctick, dtrack, Fraction::fromTicks(rest), false, 0);
ctick += rest;
}
}
//
// same for strack
//
ctick = 0;
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
for (Segment* s = m->first(Segment::SegChordRest); s; s = s->next1(Segment::SegChordRest)) {
2012-05-26 14:26:10 +02:00
ChordRest* cr = static_cast<ChordRest*>(s->element(strack));
if (cr == 0)
continue;
int rest = s->tick() - ctick;
if (rest) {
// insert Rest
Segment* s = tick2segment(ctick);
if (s == 0) {
2013-07-25 17:22:49 +02:00
qDebug("no segment at %d", ctick);
2012-05-26 14:26:10 +02:00
continue;
}
setRest(ctick, strack, Fraction::fromTicks(rest), false, 0);
}
ctick = s->tick() + cr->actualTicks();
}
int rest = m->tick() + m->ticks() - ctick;
if (rest) {
setRest(ctick, strack, Fraction::fromTicks(rest), false, 0);
ctick += rest;
}
}
}
//---------------------------------------------------------
// cmdInsertPart
// insert before staffIdx
//---------------------------------------------------------
void Score::cmdInsertPart(Part* part, int staffIdx)
{
undoInsertPart(part, staffIdx);
int sidx = this->staffIdx(part);
int eidx = sidx + part->nstaves();
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
2012-05-26 14:26:10 +02:00
m->cmdAddStaves(sidx, eidx, true);
if (m->hasMMRest())
m->mmRest()->cmdAddStaves(sidx, eidx, true);
}
2012-05-26 14:26:10 +02:00
adjustBracketsIns(sidx, eidx);
}
//---------------------------------------------------------
// cmdRemovePart
//---------------------------------------------------------
void Score::cmdRemovePart(Part* part)
{
int sidx = staffIdx(part);
int n = part->nstaves();
int eidx = sidx + n;
//
// adjust measures
//
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
2012-05-26 14:26:10 +02:00
m->cmdRemoveStaves(sidx, eidx);
if (m->hasMMRest())
m->mmRest()->cmdRemoveStaves(sidx, eidx);
}
2012-05-26 14:26:10 +02:00
for (int i = 0; i < n; ++i)
cmdRemoveStaff(sidx);
2012-05-26 14:26:10 +02:00
undoRemovePart(part, sidx);
}
//---------------------------------------------------------
// insertPart
//---------------------------------------------------------
void Score::insertPart(Part* part, int idx)
{
int staff = 0;
for (QList<Part*>::iterator i = _parts.begin(); i != _parts.end(); ++i) {
if (staff >= idx) {
_parts.insert(i, part);
return;
}
staff += (*i)->nstaves();
}
_parts.push_back(part);
}
//---------------------------------------------------------
// removePart
//---------------------------------------------------------
void Score::removePart(Part* part)
{
_parts.removeAt(_parts.indexOf(part));
}
//---------------------------------------------------------
// insertStaff
//---------------------------------------------------------
void Score::insertStaff(Staff* staff, int idx)
{
_staves.insert(idx, staff);
staff->part()->insertStaff(staff);
for (auto i = staff->score()->spanner().cbegin(); i != staff->score()->spanner().cend(); ++i) {
Spanner* s = i->second;
if (s->staffIdx() >= idx) {
int t = s->track() + VOICES;
s->setTrack(t < ntracks() ? t : ntracks() - 1);
if (s->track2() != -1) {
t = s->track2() + VOICES;
s->setTrack2(t < ntracks() ? t : s->track());
}
}
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// adjustBracketsDel
//---------------------------------------------------------
void Score::adjustBracketsDel(int sidx, int eidx)
{
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
Staff* staff = _staves[staffIdx];
for (int i = 0; i < staff->bracketLevels(); ++i) {
int span = staff->bracketSpan(i);
if ((span == 0) || ((staffIdx + span) < sidx) || (staffIdx > eidx))
continue;
if ((sidx >= staffIdx) && (eidx <= (staffIdx + span)))
undoChangeBracketSpan(staff, i, span - (eidx-sidx));
}
int span = staff->barLineSpan();
2012-10-14 00:35:11 +02:00
if ((sidx >= staffIdx) && (eidx <= (staffIdx + span))) {
int newSpan = span - (eidx-sidx) + 1;
2012-10-14 00:35:11 +02:00
int lastSpannedStaffIdx = staffIdx + newSpan - 1;
undoChangeBarLineSpan(staff, newSpan, 0, (_staves[lastSpannedStaffIdx]->lines()-1)*2);
2012-10-14 00:35:11 +02:00
}
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// adjustBracketsIns
//---------------------------------------------------------
void Score::adjustBracketsIns(int sidx, int eidx)
{
for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
Staff* staff = _staves[staffIdx];
int bl = staff->bracketLevels();
for (int i = 0; i < bl; ++i) {
int span = staff->bracketSpan(i);
if ((span == 0) || ((staffIdx + span) < sidx) || (staffIdx > eidx))
continue;
if ((sidx >= staffIdx) && (eidx < (staffIdx + span)))
undoChangeBracketSpan(staff, i, span + (eidx-sidx));
}
int span = staff->barLineSpan();
if ((sidx >= staffIdx) && (eidx < (staffIdx + span)))
2013-09-11 00:23:57 +02:00
undoChangeBarLineSpan(staff, span, 0, (_staves[staffIdx + span -1]->lines()-1)*2);
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// adjustKeySigs
//---------------------------------------------------------
void Score::adjustKeySigs(int sidx, int eidx, KeyList km)
{
for (int staffIdx = sidx; staffIdx < eidx; ++staffIdx) {
Staff* staff = _staves[staffIdx];
if(!staff->isDrumStaff()) {
for (auto i = km.begin(); i != km.end(); ++i) {
int tick = i->first;
Measure* measure = tick2measure(tick);
KeySigEvent oKey = i->second;
KeySigEvent nKey = oKey;
int diff = -staff->part()->instr()->transpose().chromatic;
if (diff != 0 && !styleB(ST_concertPitch))
nKey.setAccidentalType(transposeKey(nKey.accidentalType(), diff));
(*(staff->keymap()))[tick] = nKey;
KeySig* keysig = new KeySig(this);
keysig->setTrack(staffIdx * VOICES);
keysig->setKeySigEvent(nKey);
Segment* s = measure->getSegment(keysig, tick);
s->add(keysig);
}
}
}
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// cmdRemoveStaff
//---------------------------------------------------------
void Score::cmdRemoveStaff(int staffIdx)
{
Staff* s = staff(staffIdx);
adjustBracketsDel(staffIdx, staffIdx+1);
2013-09-19 18:24:58 +02:00
QList<Spanner*> sl;
for (auto i = _spanner.cbegin(); i != _spanner.cend(); ++i) {
Spanner* s = i->second;
if (s->staffIdx() == staffIdx)
sl.append(s);
}
for (auto i : sl)
undoRemoveElement(i);
2012-05-26 14:26:10 +02:00
undoRemoveStaff(s, staffIdx);
// remove linked staff and measures in linked staves in excerps
// should be done earlier for the main staff
2013-09-19 18:24:58 +02:00
if (s->linkedStaves()) {
for(Staff* staff : s->linkedStaves()->staves()) {
Score* lscore = staff->score();
if(lscore != this) {
int lstaffIdx = lscore->staffIdx(staff);
int pIndex = lscore->staffIdx(staff->part());
//adjustBracketsDel(lstaffIdx, lstaffIdx+1);
for (Measure* m = lscore->firstMeasure(); m; m = m->nextMeasure()) {
m->cmdRemoveStaves(lstaffIdx, lstaffIdx + 1);
if (m->hasMMRest())
m->mmRest()->cmdRemoveStaves(lstaffIdx, lstaffIdx + 1);
}
undoRemoveStaff(staff, lstaffIdx);
if (staff->part()->nstaves() == 0)
undoRemovePart(staff->part(), pIndex);
}
}
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// removeStaff
//---------------------------------------------------------
void Score::removeStaff(Staff* staff)
{
int idx = staffIdx(staff);
for (auto i = staff->score()->spanner().cbegin(); i != staff->score()->spanner().cend(); ++i) {
Spanner* s = i->second;
if (s->staffIdx() > idx) {
int t = s->track() - VOICES;
s->setTrack(t >=0 ? t : 0);
if (s->track2() != -1) {
t = s->track2() - VOICES;
s->setTrack2(t >=0 ? t : s->track());
}
}
}
2012-05-26 14:26:10 +02:00
_staves.removeAll(staff);
staff->part()->removeStaff(staff);
}
//---------------------------------------------------------
// sortStaves
//---------------------------------------------------------
void Score::sortStaves(QList<int>& dst)
{
systems()->clear(); //??
_parts.clear();
Part* curPart = 0;
QList<Staff*> dl;
foreach (int idx, dst) {
2012-05-26 14:26:10 +02:00
Staff* staff = _staves[idx];
if (staff->part() != curPart) {
curPart = staff->part();
curPart->staves()->clear();
_parts.push_back(curPart);
}
curPart->staves()->push_back(staff);
dl.push_back(staff);
}
_staves = dl;
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
2012-05-26 14:26:10 +02:00
m->sortStaves(dst);
if (m->hasMMRest())
m->mmRest()->sortStaves(dst);
2012-05-26 14:26:10 +02:00
}
for (auto i : _spanner.map()) {
Spanner* sp = i.second;
int voice = sp->voice();
int staffIdx = sp->staffIdx();
int idx = dst.indexOf(staffIdx);
if (idx >=0) {
sp->setTrack(idx * VOICES + voice);
if (sp->track2() != -1)
sp->setTrack2(idx * VOICES +(sp->track2() % VOICES)); // at least keep the voice...
}
}
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// cmdConcertPitchChanged
//---------------------------------------------------------
2014-04-09 14:13:22 +02:00
void Score::cmdConcertPitchChanged(bool flag, bool /*useDoubleSharpsFlats*/)
2012-05-26 14:26:10 +02:00
{
2014-04-02 18:11:56 +02:00
undo(new ChangeConcertPitch(this, flag)); // change style flag
2012-05-26 14:26:10 +02:00
2014-04-02 18:11:56 +02:00
for (Staff* staff : _staves) {
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 (staff->staffType()->group() == PERCUSSION_STAFF_GROUP)
2012-05-26 14:26:10 +02:00
continue;
2014-04-02 18:11:56 +02:00
Interval interval = staff->part()->instr()->transpose();
2012-05-26 14:26:10 +02:00
if (interval.isZero())
continue;
if (!flag)
interval.flip();
2014-04-02 18:11:56 +02:00
int staffIdx = staff->idx();
2014-04-02 18:11:56 +02:00
int startTrack = staffIdx * VOICES;
int endTrack = startTrack + VOICES;
transposeKeys(staffIdx, staffIdx+1, 0, lastSegment()->tick(), interval);
for (Segment* segment = firstSegment(Segment::SegChordRest); segment; segment = segment->next1(Segment::SegChordRest)) {
for (Element* e : segment->annotations()) {
if ((e->type() != Element::HARMONY) || (e->track() < startTrack) || (e->track() >= endTrack))
continue;
Harmony* h = static_cast<Harmony*>(e);
int rootTpc = transposeTpc(h->rootTpc(), interval, false);
int baseTpc = transposeTpc(h->baseTpc(), interval, false);
undoTransposeHarmony(h, rootTpc, baseTpc);
}
2012-05-26 14:26:10 +02:00
}
}
2014-04-22 17:02:03 +02:00
cmdUpdateNotes();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// addAudioTrack
//---------------------------------------------------------
void Score::addAudioTrack()
{
// TODO
}
//---------------------------------------------------------
// padToggle
//---------------------------------------------------------
void Score::padToggle(int n)
{
switch (n) {
case PAD_NOTE00:
_is.setDuration(TDuration::V_LONG);
break;
case PAD_NOTE0:
_is.setDuration(TDuration::V_BREVE);
break;
case PAD_NOTE1:
_is.setDuration(TDuration::V_WHOLE);
break;
case PAD_NOTE2:
_is.setDuration(TDuration::V_HALF);
break;
case PAD_NOTE4:
_is.setDuration(TDuration::V_QUARTER);
break;
case PAD_NOTE8:
_is.setDuration(TDuration::V_EIGHT);
break;
case PAD_NOTE16:
_is.setDuration(TDuration::V_16TH);
break;
case PAD_NOTE32:
_is.setDuration(TDuration::V_32ND);
break;
case PAD_NOTE64:
_is.setDuration(TDuration::V_64TH);
break;
case PAD_NOTE128:
_is.setDuration(TDuration::V_128TH);
break;
case PAD_REST:
2013-10-24 12:09:00 +02:00
_is.setRest(!_is.rest());
2012-05-26 14:26:10 +02:00
break;
case PAD_DOT:
if (_is.duration().dots() == 1)
_is.setDots(0);
else
_is.setDots(1);
break;
case PAD_DOTDOT:
if (_is.duration().dots() == 2)
_is.setDots(0);
else
_is.setDots(2);
break;
}
if (n >= PAD_NOTE00 && n <= PAD_NOTE128) {
_is.setDots(0);
//
// if in "note enter" mode, reset
// rest flag
//
if (noteEntryMode())
2013-10-24 12:09:00 +02:00
_is.setRest(false);
2012-05-26 14:26:10 +02:00
}
if (noteEntryMode() || !selection().isSingle()) {
return;
}
//do not allow to add a dot on a full measure rest
Element* e = selection().element();
2012-09-13 18:01:34 +02:00
if (e && e->type() == Element::REST) {
2012-05-26 14:26:10 +02:00
Rest* r = static_cast<Rest*>(e);
TDuration d = r->durationType();
if (d.type() == TDuration::V_MEASURE) {
_is.setDots(0);
// return;
}
}
Element* el = selection().element();
2012-09-13 18:01:34 +02:00
if (el->type() == Element::NOTE)
2012-05-26 14:26:10 +02:00
el = el->parent();
if (!el->isChordRest())
return;
ChordRest* cr = static_cast<ChordRest*>(el);
2012-09-13 18:01:34 +02:00
if (cr->type() == Element::CHORD && (static_cast<Chord*>(cr)->noteType() != NOTE_NORMAL)) {
2012-05-26 14:26:10 +02:00
//
// handle appoggiatura and acciaccatura
//
2013-03-18 15:14:05 +01:00
undo(new ChangeDurationType(cr, _is.duration()));
undo(new ChangeDuration(cr, _is.duration().fraction()));
2012-05-26 14:26:10 +02:00
}
else
changeCRlen(cr, _is.duration());
}
//---------------------------------------------------------
// deselect
//---------------------------------------------------------
void Score::deselect(Element* el)
{
refresh |= el->abbox();
_selection.remove(el);
}
//---------------------------------------------------------
// select
// staffIdx is valid, if element is of type MEASURE
//---------------------------------------------------------
void Score::select(Element* e, SelectType type, int staffIdx)
{
2012-09-13 18:01:34 +02:00
if (e && (e->type() == Element::NOTE || e->type() == Element::REST)) {
2012-05-26 14:26:10 +02:00
Element* ee = e;
2012-09-13 18:01:34 +02:00
if (ee->type() == Element::NOTE)
2012-05-26 14:26:10 +02:00
ee = ee->parent();
setPlayPos(static_cast<ChordRest*>(ee)->segment()->tick());
2012-05-26 14:26:10 +02:00
}
if (MScore::debugMode)
2013-07-25 17:22:49 +02:00
qDebug("select element <%s> type %d(state %d) staff %d",
2012-05-26 14:26:10 +02:00
e ? e->name() : "", type, selection().state(), e ? e->staffIdx() : -1);
SelState selState = _selection.state();
if (type == SELECT_SINGLE) {
deselectAll();
if (e == 0) {
selState = SEL_NONE;
_updateAll = true;
}
else {
2012-09-13 18:01:34 +02:00
if (e->type() == Element::MEASURE) {
2012-05-26 14:26:10 +02:00
select(e, SELECT_RANGE, staffIdx);
return;
}
refresh |= e->abbox();
_selection.add(e);
_is.setTrack(e->track());
selState = SEL_LIST;
2012-09-13 18:01:34 +02:00
if (e->type() == Element::NOTE)
2012-08-06 12:15:42 +02:00
e = e->parent();
2013-10-24 12:09:00 +02:00
if (e->type() == Element::REST || e->type() == Element::CHORD) {
_is.setLastSegment(_is.segment());
2012-05-26 14:26:10 +02:00
_is.setSegment(static_cast<ChordRest*>(e)->segment());
2013-10-24 12:09:00 +02:00
}
2012-05-26 14:26:10 +02:00
}
_selection.setActiveSegment(0);
_selection.setActiveTrack(0);
}
else if (type == SELECT_ADD) {
2012-09-13 18:01:34 +02:00
if (e->type() == Element::MEASURE) {
2012-05-26 14:26:10 +02:00
Measure* m = static_cast<Measure*>(e);
int tick = m->tick();
2013-09-28 12:05:48 +02:00
// int etick = tick + m->ticks();
2012-05-26 14:26:10 +02:00
if (_selection.state() == SEL_NONE) {
2013-06-16 23:33:37 +02:00
_selection.setStartSegment(m->tick2segment(tick));
2013-09-27 18:43:25 +02:00
// _selection.setEndSegment(m == lastMeasure() ? 0 : tick2segment(etick));
_selection.setEndSegment(m == lastMeasure() ? 0 : m->last());
2012-05-26 14:26:10 +02:00
}
else {
select(0, SELECT_SINGLE, 0);
return;
}
_updateAll = true;
selState = SEL_RANGE;
_selection.setStaffStart(0);
_selection.setStaffEnd(nstaves());
_selection.updateSelectedElements();
}
else {
if (_selection.state() == SEL_RANGE) {
select(0, SELECT_SINGLE, 0);
return;
}
else {
refresh |= e->abbox();
if (_selection.elements().contains(e))
_selection.remove(e);
else {
_selection.add(e);
selState = SEL_LIST;
}
}
}
}
else if (type == SELECT_RANGE) {
bool activeIsFirst = false;
int activeTrack = e->track();
2012-09-13 18:01:34 +02:00
if (e->type() == Element::MEASURE) {
2012-05-26 14:26:10 +02:00
Measure* m = static_cast<Measure*>(e);
int tick = m->tick();
int etick = tick + m->ticks();
activeTrack = staffIdx * VOICES;
if (_selection.state() == SEL_NONE) {
_selection.setStaffStart(staffIdx);
_selection.setStaffEnd(staffIdx + 1);
2013-06-16 23:33:37 +02:00
_selection.setStartSegment(m->tick2segment(tick));
2013-09-27 18:43:25 +02:00
// _selection.setEndSegment(m == lastMeasure() ? 0 : tick2segment(etick));
_selection.setEndSegment(m == lastMeasure() ? 0 : m->last());
2012-05-26 14:26:10 +02:00
}
else if (_selection.state() == SEL_RANGE) {
if (staffIdx < _selection.staffStart())
_selection.setStaffStart(staffIdx);
else if (staffIdx >= _selection.staffEnd())
_selection.setStaffEnd(staffIdx + 1);
if (tick < _selection.tickStart()) {
2013-06-16 23:33:37 +02:00
_selection.setStartSegment(m->tick2segment(tick));
2012-05-26 14:26:10 +02:00
activeIsFirst = true;
}
else if (etick >= _selection.tickEnd())
2013-09-27 18:43:25 +02:00
//_selection.setEndSegment(m == lastMeasure() ? 0 : tick2segment(etick));
_selection.setEndSegment(m == lastMeasure() ? 0 : m->last());
2012-05-26 14:26:10 +02:00
else {
if (_selection.activeSegment() == _selection.startSegment()) {
2013-06-16 23:33:37 +02:00
_selection.setStartSegment(m->tick2segment(tick));
2012-05-26 14:26:10 +02:00
activeIsFirst = true;
}
else
2013-09-27 18:43:25 +02:00
//_selection.setEndSegment(m == lastMeasure() ? 0 : tick2segment(etick));
_selection.setEndSegment(m == lastMeasure() ? 0 : m->last());
2012-05-26 14:26:10 +02:00
}
}
else if (_selection.isSingle()) {
Segment* seg = 0;
Element* oe = _selection.element();
bool reverse = false;
int ticks = 0;
if (oe->isChordRest())
ticks = static_cast<ChordRest*>(oe)->actualTicks();
int oetick = 0;
2012-09-13 18:01:34 +02:00
if (oe->parent()->type() == Element::SEGMENT)
2012-05-26 14:26:10 +02:00
oetick = static_cast<Segment*>(oe->parent())->tick();
if (tick < oetick)
seg = m->first();
else if (etick >= oetick + ticks) {
seg = m->last();
reverse = true;
}
int track = staffIdx * VOICES;
Element* el = 0;
// find first or last chord/rest in measure
for (;;) {
el = seg->element(track);
if (el && el->isChordRest())
break;
if (reverse)
2013-09-27 18:43:25 +02:00
seg = seg->prev1MM();
2012-05-26 14:26:10 +02:00
else
2013-09-27 18:43:25 +02:00
seg = seg->next1MM();
2012-05-26 14:26:10 +02:00
if (!seg)
break;
}
if (el)
select(el, SELECT_RANGE, staffIdx);
return;
}
else {
2013-07-25 17:22:49 +02:00
qDebug("SELECT_RANGE: measure: sel state %d", _selection.state());
return;
2012-05-26 14:26:10 +02:00
}
}
2013-08-01 10:53:14 +02:00
else if (e->type() == Element::NOTE || e->isChordRest()) {
2012-09-13 18:01:34 +02:00
if (e->type() == Element::NOTE)
2012-08-06 12:15:42 +02:00
e = e->parent();
2012-05-26 14:26:10 +02:00
ChordRest* cr = static_cast<ChordRest*>(e);
if (_selection.state() == SEL_NONE) {
_selection.setStaffStart(e->staffIdx());
_selection.setStaffEnd(_selection.staffStart() + 1);
_selection.setStartSegment(cr->segment());
activeTrack = cr->track();
_selection.setEndSegment(cr->segment()->nextCR(cr->track()));
}
else if (_selection.isSingle()) {
Element* oe = _selection.element();
2012-09-13 18:01:34 +02:00
if (oe && (oe->type() == Element::NOTE || oe->type() == Element::REST)) {
if (oe->type() == Element::NOTE)
2012-05-26 14:26:10 +02:00
oe = oe->parent();
ChordRest* ocr = static_cast<ChordRest*>(oe);
_selection.setStaffStart(oe->staffIdx());
_selection.setStaffEnd(_selection.staffStart() + 1);
_selection.setStartSegment(ocr->segment());
2013-08-01 10:53:14 +02:00
_selection.setEndSegment(tick2segment(ocr->tick() + ocr->actualTicks()));
2012-05-26 14:26:10 +02:00
if (!_selection.endSegment())
_selection.setEndSegment(ocr->segment()->next());
staffIdx = cr->staffIdx();
int tick = cr->tick();
if (staffIdx < _selection.staffStart())
_selection.setStaffStart(staffIdx);
else if (staffIdx >= _selection.staffEnd())
_selection.setStaffEnd(staffIdx + 1);
if (tick < _selection.tickStart()) {
_selection.setStartSegment(cr->segment());
activeIsFirst = true;
}
else if (tick >= _selection.tickEnd())
2013-08-01 10:53:14 +02:00
_selection.setEndSegment(tick2segment(cr->tick() + cr->actualTicks()));
2012-05-26 14:26:10 +02:00
else {
if (_selection.activeSegment() == _selection.startSegment()) {
_selection.setStartSegment(cr->segment());
activeIsFirst = true;
}
else
2013-08-01 10:53:14 +02:00
_selection.setEndSegment(tick2segment(cr->tick() + cr->actualTicks()));
2012-05-26 14:26:10 +02:00
}
}
else {
select(e, SELECT_SINGLE, 0);
return;
}
}
else if (_selection.state() == SEL_RANGE) {
staffIdx = cr->staffIdx();
int tick = cr->tick();
if (staffIdx < _selection.staffStart())
_selection.setStaffStart(staffIdx);
else if (staffIdx >= _selection.staffEnd())
_selection.setStaffEnd(staffIdx + 1);
if (tick < _selection.tickStart()) {
if (_selection.activeSegment() == _selection.endSegment())
_selection.setEndSegment(_selection.startSegment());
_selection.setStartSegment(cr->segment());
activeIsFirst = true;
}
else if (_selection.endSegment() && tick >= _selection.tickEnd()) {
if (_selection.activeSegment() == _selection.startSegment())
_selection.setStartSegment(_selection.endSegment());
Segment* s = cr->segment()->nextCR(cr->track());
_selection.setEndSegment(s);
}
else {
if (_selection.activeSegment() == _selection.startSegment()) {
_selection.setStartSegment(cr->segment());
activeIsFirst = true;
}
else {
_selection.setEndSegment(cr->segment()->nextCR(cr->track()));
}
}
}
else {
2013-07-25 17:22:49 +02:00
qDebug("sel state %d", _selection.state());
2012-05-26 14:26:10 +02:00
}
selState = SEL_RANGE;
if (!_selection.endSegment())
_selection.setEndSegment(cr->segment()->nextCR());
if (!_selection.startSegment())
_selection.setStartSegment(cr->segment());
}
else {
select(e, SELECT_SINGLE, staffIdx);
return;
}
if (activeIsFirst)
_selection.setActiveSegment(_selection.startSegment());
else
_selection.setActiveSegment(_selection.endSegment());
_selection.setActiveTrack(activeTrack);
selState = SEL_RANGE;
_selection.updateSelectedElements();
}
_selection.setState(selState);
}
//---------------------------------------------------------
// lassoSelect
//---------------------------------------------------------
void Score::lassoSelect(const QRectF& bbox)
{
select(0, SELECT_SINGLE, 0);
QRectF fr(bbox.normalized());
foreach(Page* page, _pages) {
QRectF pr(page->bbox());
QRectF frr(fr.translated(-page->pos()));
if (pr.right() < frr.left())
continue;
if (pr.left() > frr.right())
break;
QList<Element*> el = page->items(frr);
2012-05-26 14:26:10 +02:00
for (int i = 0; i < el.size(); ++i) {
Element* e = el.at(i);
2012-05-26 14:26:10 +02:00
if (frr.contains(e->abbox())) {
2012-09-13 18:01:34 +02:00
if (e->type() != Element::MEASURE && e->selectable())
select(e, SELECT_ADD, 0);
2012-05-26 14:26:10 +02:00
}
}
}
}
//---------------------------------------------------------
// lassoSelectEnd
//---------------------------------------------------------
void Score::lassoSelectEnd()
{
int noteRestCount = 0;
Segment* startSegment = 0;
Segment* endSegment = 0;
int startStaff = 0x7fffffff;
int endStaff = 0;
if (_selection.elements().isEmpty()) {
_selection.setState(SEL_NONE);
_updateAll = true;
2012-05-26 14:26:10 +02:00
return;
}
_selection.setState(SEL_LIST);
foreach(const Element* e, _selection.elements()) {
2012-09-13 18:01:34 +02:00
if (e->type() != Element::NOTE && e->type() != Element::REST)
2012-05-26 14:26:10 +02:00
continue;
++noteRestCount;
2012-09-13 18:01:34 +02:00
if (e->type() == Element::NOTE)
2012-05-26 14:26:10 +02:00
e = e->parent();
Segment* seg = static_cast<const ChordRest*>(e)->segment();
2012-08-09 12:12:43 +02:00
if ((startSegment == 0) || (*seg < *startSegment))
2012-05-26 14:26:10 +02:00
startSegment = seg;
2012-08-09 12:12:43 +02:00
if ((endSegment == 0) || (*seg > *endSegment)) {
2012-05-26 14:26:10 +02:00
endSegment = seg;
}
int idx = e->staffIdx();
if (idx < startStaff)
startStaff = idx;
if (idx > endStaff)
endStaff = idx;
}
if (noteRestCount > 0) {
endSegment = endSegment->nextCR(endStaff * VOICES);
2012-05-26 14:26:10 +02:00
_selection.setRange(startSegment, endSegment, startStaff, endStaff+1);
if (_selection.state() != SEL_RANGE)
_selection.setState(SEL_RANGE);
}
_updateAll = true;
}
//---------------------------------------------------------
// addLyrics
//---------------------------------------------------------
void Score::addLyrics(int tick, int staffIdx, const QString& txt)
{
if (txt.trimmed().isEmpty())
return;
Measure* measure = tick2measure(tick);
Segment* seg = measure->findSegment(Segment::SegChordRest, tick);
2012-05-26 14:26:10 +02:00
if (seg == 0) {
2013-07-25 17:22:49 +02:00
qDebug("no segment found for lyrics<%s> at tick %d",
2012-05-26 14:26:10 +02:00
qPrintable(txt), tick);
return;
}
int track = staffIdx * VOICES;
ChordRest* cr = static_cast<ChordRest*>(seg->element(track));
if (cr) {
Lyrics* l = new Lyrics(this);
l->setText(txt);
l->setTrack(track);
2012-05-26 14:26:10 +02:00
cr->add(l);
}
else {
2013-07-25 17:22:49 +02:00
qDebug("no chord/rest for lyrics<%s> at tick %d, staff %d",
2012-05-26 14:26:10 +02:00
qPrintable(txt), tick, staffIdx);
}
}
//---------------------------------------------------------
// setTempo
// convenience function to access TempoMap
//---------------------------------------------------------
void Score::setTempo(Segment* segment, qreal tempo)
{
setTempo(segment->tick(), tempo);
}
void Score::setTempo(int tick, qreal tempo)
{
tempomap()->setTempo(tick, tempo);
_playlistDirty = true;
}
//---------------------------------------------------------
// removeTempo
//---------------------------------------------------------
void Score::removeTempo(int tick)
{
tempomap()->delTempo(tick);
_playlistDirty = true;
}
//---------------------------------------------------------
// setPause
//---------------------------------------------------------
void Score::setPause(int tick, qreal seconds)
{
tempomap()->setPause(tick, seconds);
_playlistDirty = true;
}
//---------------------------------------------------------
// tempo
//---------------------------------------------------------
qreal Score::tempo(int tick) const
{
return tempomap()->tempo(tick);
}
//---------------------------------------------------------
// loWidth
//---------------------------------------------------------
qreal Score::loWidth() const
{
return pageFormat()->size().width() * MScore::DPI;
}
//---------------------------------------------------------
// loHeight
//---------------------------------------------------------
qreal Score::loHeight() const
{
return pageFormat()->size().height() * MScore::DPI;
}
//---------------------------------------------------------
// cmdSelectAll
//---------------------------------------------------------
void Score::cmdSelectAll()
{
2013-10-06 16:43:43 +02:00
if (_measures.size() == 0)
return;
_selection.setState(SEL_RANGE);
Segment* s1 = firstMeasureMM()->first();
Segment* s2 = lastMeasureMM()->last();
_selection.setRange(s1, s2, 0, nstaves());
_selection.updateSelectedElements();
setUpdateAll(true);
end();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// cmdSelectSection
//---------------------------------------------------------
void Score::cmdSelectSection()
{
Segment* s = _selection.startSegment();
if (s == 0)
return;
MeasureBase* sm = s->measure();
MeasureBase* em = sm;
while (sm->prev()) {
if (sm->prev()->sectionBreak())
break;
sm = sm->prev();
}
while (em->next()) {
if (em->sectionBreak())
break;
em = em->next();
}
2012-09-13 18:01:34 +02:00
while (sm && sm->type() != Element::MEASURE)
2012-05-26 14:26:10 +02:00
sm = sm->next();
2012-09-13 18:01:34 +02:00
while (em && em->type() != Element::MEASURE)
2012-05-26 14:26:10 +02:00
em = em->next();
if (sm == 0 || em == 0)
return;
_selection.setRange(static_cast<Measure*>(sm)->first(),
static_cast<Measure*>(em)->last(), 0, nstaves());
}
//---------------------------------------------------------
// undo
//---------------------------------------------------------
void Score::undo(UndoCommand* cmd) const
{
undo()->push(cmd);
}
//---------------------------------------------------------
// setLayoutMode
//---------------------------------------------------------
void Score::setLayoutMode(LayoutMode lm)
{
_layoutMode = lm;
}
//---------------------------------------------------------
// linkId
//---------------------------------------------------------
int Score::linkId()
{
2012-09-22 19:40:45 +02:00
return (rootScore()->_linkId)++;
2012-05-26 14:26:10 +02:00
}
2012-09-22 19:40:45 +02:00
// val is a used link id
2012-05-26 14:26:10 +02:00
void Score::linkId(int val)
{
2012-09-10 16:10:25 +02:00
Score* s = rootScore();
2012-09-22 19:40:45 +02:00
if (val >= s->_linkId)
s->_linkId = val + 1; // update unused link id
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// scoreList
// return a list of scores containing the root score
// and all part scores (if there are any)
//---------------------------------------------------------
QList<Score*> Score::scoreList()
{
QList<Score*> scores;
Score* root = rootScore();
scores.append(root);
foreach(const Excerpt* ex, root->excerpts())
scores.append(ex->score());
return scores;
}
//---------------------------------------------------------
// switchLayer
//---------------------------------------------------------
bool Score::switchLayer(const QString& s)
{
int layerIdx = 0;
foreach(const Layer& l, layer()) {
if (s == l.name) {
setCurrentLayer(layerIdx);
return true;
}
++layerIdx;
}
return false;
}
2012-06-07 09:24:05 +02:00
//---------------------------------------------------------
// appendPart
//---------------------------------------------------------
void Score::appendPart(const QString& name)
{
static InstrumentTemplate defaultInstrument;
InstrumentTemplate* t;
t = searchTemplate(name);
2012-06-08 19:06:52 +02:00
if (t == 0) {
qDebug("appendPart: <%s> not found", qPrintable(name));
2012-06-07 09:24:05 +02:00
t = &defaultInstrument;
2012-06-08 19:06:52 +02:00
}
2012-06-07 09:24:05 +02:00
if (t->channel.isEmpty()) {
Channel a;
a.chorus = 0;
a.reverb = 0;
a.name = "normal";
a.bank = 0;
a.volume = 100;
a.pan = 60;
t->channel.append(a);
}
Part* part = new Part(this);
part->initFromInstrTemplate(t);
int n = nstaves();
for (int i = 0; i < t->nstaves(); ++i) {
2012-06-07 09:24:05 +02:00
Staff* staff = new Staff(this, part, i);
staff->setLines(t->staffLines[i]);
staff->setSmall(t->smallStaff[i]);
if (i == 0) {
staff->setBracket(0, t->bracket[0]);
staff->setBracketSpan(0, t->nstaves());
2012-06-07 09:24:05 +02:00
}
undoInsertStaff(staff, n + i);
}
part->staves()->front()->setBarLineSpan(part->nstaves());
cmdInsertPart(part, n);
fixTicks();
rebuildMidiMapping();
}
//---------------------------------------------------------
// appendMeasures
//---------------------------------------------------------
void Score::appendMeasures(int n)
{
for (int i = 0; i < n; ++i)
2012-09-13 18:01:34 +02:00
insertMeasure(Element::MEASURE, 0, false);
2012-06-07 09:24:05 +02:00
}
//---------------------------------------------------------
// addText
//---------------------------------------------------------
void Score::addText(const QString& type, const QString& txt)
{
MeasureBase* measure = first();
2012-09-13 18:01:34 +02:00
if (measure == 0 || measure->type() != Element::VBOX) {
insertMeasure(Element::VBOX, measure);
2012-06-07 09:24:05 +02:00
measure = first();
}
Text* text = new Text(this);
if (type == "title")
text->setTextStyleType(TEXT_STYLE_TITLE);
else if (type == "subtitle")
text->setTextStyleType(TEXT_STYLE_SUBTITLE);
text->setParent(measure);
text->setText(txt);
undoAddElement(text);
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// newCursor
//---------------------------------------------------------
Cursor* Score::newCursor()
{
return new Cursor(this);
}
2013-06-20 13:57:15 +02:00
//---------------------------------------------------------
// addSpanner
//---------------------------------------------------------
void Score::addSpanner(Spanner* s)
{
2013-07-05 11:23:52 +02:00
_spanner.addSpanner(s);
2013-06-20 13:57:15 +02:00
}
//---------------------------------------------------------
// removeSpanner
//---------------------------------------------------------
void Score::removeSpanner(Spanner* s)
{
2013-07-05 11:23:52 +02:00
_spanner.removeSpanner(s);
2013-06-20 13:57:15 +02:00
}
2013-06-10 11:03:34 +02:00
//---------------------------------------------------------
// findSpanner
//---------------------------------------------------------
Spanner* Score::findSpanner(int id) const
{
2013-07-05 11:23:52 +02:00
for (auto i = _spanner.crbegin(); i != _spanner.crend(); ++i) {
2013-06-20 13:57:15 +02:00
if (i->second->id() == id)
return i->second;
2013-06-10 11:03:34 +02:00
}
return 0;
}
//---------------------------------------------------------
// isSpannerStartEnd
// does is spanner start or end at tick position tick
// for track ?
//---------------------------------------------------------
bool Score::isSpannerStartEnd(int tick, int track) const
{
2013-07-05 11:23:52 +02:00
for (auto i : _spanner.map()) {
2013-06-20 13:57:15 +02:00
if (i.second->track() != track)
2013-06-10 11:03:34 +02:00
continue;
2013-06-20 13:57:15 +02:00
if (i.second->tick() == tick || i.second->tick2() == tick)
2013-06-10 11:03:34 +02:00
return true;
}
return false;
}
2013-06-19 16:25:29 +02:00
//---------------------------------------------------------
// undoInsertTime
// acts on the linked scores as well
2013-06-19 16:25:29 +02:00
//---------------------------------------------------------
void Score::undoInsertTime(int tick, int len)
2013-06-19 16:25:29 +02:00
{
qDebug() << "insertTime" << len << "at tick" << tick;
2013-06-19 16:25:29 +02:00
if (len == 0)
return;
2013-07-05 11:23:52 +02:00
for (auto i : _spanner.map()) {
2013-06-20 13:57:15 +02:00
Spanner* s = i.second;
2013-06-19 16:25:29 +02:00
if (s->tick2() < tick)
continue;
if (len > 0) {
if (tick > s->tick() && tick < s->tick2()) {
//
// case a:
// +----spanner--------+
// +---add---
//
undoChangeProperty(s, P_SPANNER_TICK2, s->tick2() + len);
2013-06-19 16:25:29 +02:00
}
else if (tick <= s->tick()) {
2013-06-19 16:25:29 +02:00
//
// case b:
// +----spanner--------
// +---add---
// and
// +----spanner--------
// +---add---+
2013-06-19 16:25:29 +02:00
undoChangeProperty(s, P_SPANNER_TICK, s->tick() + len);
2013-06-25 19:52:00 +02:00
undoChangeProperty(s, P_SPANNER_TICK2, s->tick2() + len);
2013-06-19 16:25:29 +02:00
}
}
else {
int tick2 = tick - len;
if (s->tick() >= tick2) {
2013-06-19 16:25:29 +02:00
//
// case A:
// +----remove---+ +---spanner---+
//
int t = s->tick() + len;
if (t < 0)
t = 0;
undoChangeProperty(s, P_SPANNER_TICK, t);
2013-06-25 19:52:00 +02:00
undoChangeProperty(s, P_SPANNER_TICK2, s->tick2() + len);
2013-06-19 16:25:29 +02:00
}
else if ((s->tick() < tick) && (s->tick2() > tick2)) {
//
// case B:
// +----spanner--------+
// +---remove---+
//
int t2 = s->tick2() + len;
if (t2 > s->tick())
undoChangeProperty(s, P_SPANNER_TICK2, t2);
2013-06-19 16:25:29 +02:00
}
else if (s->tick() >= tick && s->tick2() < tick2) {
//
// case C:
// +---spanner---+
// +----remove--------+
//
undoRemoveElement(s);
}
2013-06-19 17:37:21 +02:00
else if (s->tick() > tick && s->tick2() > tick2) {
2013-06-19 16:25:29 +02:00
//
// case D:
// +----spanner--------+
// +---remove---+
//
int d1 = s->tick() - tick;
int d2 = tick2 - s->tick();
int len = s->tickLen() - d2;
if (len == 0)
undoRemoveElement(s);
2013-07-05 11:40:53 +02:00
else {
2013-06-19 16:25:29 +02:00
undoChangeProperty(s, P_SPANNER_TICK, s->tick() - d1);
2013-07-05 11:40:53 +02:00
undoChangeProperty(s, P_SPANNER_TICK2, s->tick2() - (tick2-tick));
}
2013-06-19 16:25:29 +02:00
}
}
}
// insert time in (key, clef) maps
undo(new InsertTime(this, tick, len));
}
void Score::insertTime(int tick, int len)
{
for (Score* score : scoreList()) {
for(Staff* staff : score->staves()) {
KeyList* kl = staff->keymap();
KeyList kl2;
for (auto i = kl->upper_bound(tick); i != kl->end();) {
KeySigEvent kse = i->second;
int key = i->first;
kl->erase(i++);
kl2[key + len] = kse;
}
kl->insert(kl2.begin(), kl2.end());
ClefList* cl = staff->clefList();
ClefList cl2;
for (auto i = cl->upper_bound(tick); i != cl->end();) {
ClefTypeList ctl = i->second;
int key = i->first;
cl->erase(i++);
cl2[key + len] = ctl;
}
cl->insert(cl2.begin(), cl2.end());
}
}
2013-06-19 16:25:29 +02:00
}
//---------------------------------------------------------
2013-10-18 12:21:01 +02:00
// setPos
//---------------------------------------------------------
2013-10-18 12:21:01 +02:00
void Score::setPos(POS pos, int tick)
{
2013-10-18 12:21:01 +02:00
if (tick < 0)
tick = 0;
2013-10-18 12:21:01 +02:00
if (tick != _pos[int(pos)]) {
_pos[int(pos)] = tick;
emit posChanged(pos, unsigned(tick));
}
}
2013-05-13 18:49:17 +02:00
}