2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
2013-09-05 20:05:49 +02:00
|
|
|
// Copyright (C) 2002-2013 Werner Schweer
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
Handling of several GUI commands.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "score.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "clef.h"
|
|
|
|
#include "navigate.h"
|
|
|
|
#include "slur.h"
|
2013-08-22 12:18:14 +02:00
|
|
|
#include "tie.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "note.h"
|
|
|
|
#include "rest.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "sig.h"
|
|
|
|
#include "staff.h"
|
|
|
|
#include "part.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "page.h"
|
|
|
|
#include "barline.h"
|
|
|
|
#include "tuplet.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "ottava.h"
|
|
|
|
#include "trill.h"
|
|
|
|
#include "pedal.h"
|
|
|
|
#include "hairpin.h"
|
|
|
|
#include "textline.h"
|
|
|
|
#include "keysig.h"
|
|
|
|
#include "volta.h"
|
|
|
|
#include "dynamic.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "harmony.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "stafftext.h"
|
|
|
|
#include "articulation.h"
|
|
|
|
#include "layoutbreak.h"
|
|
|
|
#include "drumset.h"
|
|
|
|
#include "beam.h"
|
|
|
|
#include "lyrics.h"
|
|
|
|
#include "pitchspelling.h"
|
|
|
|
#include "measure.h"
|
|
|
|
#include "tempo.h"
|
|
|
|
#include "sig.h"
|
|
|
|
#include "undo.h"
|
|
|
|
#include "timesig.h"
|
|
|
|
#include "repeat.h"
|
|
|
|
#include "tempotext.h"
|
|
|
|
#include "clef.h"
|
|
|
|
#include "noteevent.h"
|
|
|
|
#include "breath.h"
|
2013-12-05 21:37:28 +01:00
|
|
|
#include "stringdata.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "stafftype.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "chordlist.h"
|
|
|
|
#include "mscore.h"
|
|
|
|
#include "accidental.h"
|
|
|
|
#include "sequencer.h"
|
2013-09-05 20:05:49 +02:00
|
|
|
#include "tremolo.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
|
|
|
//---------------------------------------------------------
|
|
|
|
// startCmd
|
|
|
|
/// Start a GUI command by clearing the redraw area
|
|
|
|
/// and starting a user-visble undo.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::startCmd()
|
|
|
|
{
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("===startCmd()");
|
|
|
|
_layoutAll = true; ///< do a complete relayout
|
|
|
|
_playNote = false;
|
|
|
|
|
|
|
|
// Start collecting low-level undo operations for a
|
|
|
|
// user-visible undo action.
|
|
|
|
|
|
|
|
if (undo()->active()) {
|
|
|
|
// if (MScore::debugMode)
|
|
|
|
qDebug("Score::startCmd(): cmd already active");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
undo()->beginMacro();
|
|
|
|
undo(new SaveState(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// endCmd
|
|
|
|
/// End a GUI command by (if \a undo) ending a user-visble undo
|
|
|
|
/// and (always) updating the redraw area.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::endCmd()
|
|
|
|
{
|
|
|
|
if (!undo()->active()) {
|
|
|
|
// if (MScore::debugMode)
|
|
|
|
qDebug("Score::endCmd(): no cmd active");
|
|
|
|
end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-29 16:59:04 +01:00
|
|
|
foreach (Score* s, scoreList()) {
|
2013-06-05 15:47:34 +02:00
|
|
|
if (s->layoutAll()) {
|
|
|
|
s->_updateAll = true;
|
|
|
|
s->doLayout();
|
|
|
|
}
|
2013-10-29 16:59:04 +01:00
|
|
|
const InputState& is = s->inputState();
|
|
|
|
if (is.noteEntryMode() && is.segment())
|
2014-02-10 17:30:30 +01:00
|
|
|
s->setPlayPos(is.segment()->tick());
|
2013-06-05 15:47:34 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
bool noUndo = undo()->current()->childCount() <= 1;
|
|
|
|
if (!noUndo)
|
2012-09-05 11:49:48 +02:00
|
|
|
setDirty(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
undo()->endMacro(noUndo);
|
|
|
|
end(); // DEBUG
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// end
|
|
|
|
/// Update the redraw area.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::end()
|
|
|
|
{
|
|
|
|
foreach(Score* s, scoreList())
|
|
|
|
s->end1();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// update
|
|
|
|
// layout & update
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::update()
|
|
|
|
{
|
|
|
|
foreach(Score* s, scoreList()) {
|
2013-06-27 11:02:42 +02:00
|
|
|
if (s->layoutAll()) {
|
|
|
|
s->setUpdateAll(true);
|
|
|
|
s->doLayout();
|
|
|
|
}
|
|
|
|
s->end1();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// end1
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::end1()
|
|
|
|
{
|
|
|
|
if (_updateAll) {
|
|
|
|
foreach(MuseScoreView* v, viewer)
|
|
|
|
v->updateAll();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// update a little more:
|
|
|
|
qreal d = spatium() * .5;
|
|
|
|
refresh.adjust(-d, -d, 2 * d, 2 * d);
|
|
|
|
foreach(MuseScoreView* v, viewer)
|
|
|
|
v->dataChanged(refresh);
|
|
|
|
}
|
|
|
|
refresh = QRectF();
|
|
|
|
_updateAll = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// endUndoRedo
|
|
|
|
/// Common handling for ending undo or redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::endUndoRedo()
|
|
|
|
{
|
|
|
|
updateSelection();
|
2013-06-05 15:47:34 +02:00
|
|
|
foreach (Score* score, scoreList()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (score->layoutAll()) {
|
|
|
|
score->setUndoRedo(true);
|
2012-07-31 09:48:37 +02:00
|
|
|
score->doLayout();
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setUndoRedo(false);
|
|
|
|
score->setUpdateAll(true);
|
|
|
|
}
|
2013-10-29 16:59:04 +01:00
|
|
|
const InputState& is = score->inputState();
|
|
|
|
if (is.noteEntryMode() && is.segment())
|
2014-02-10 17:30:30 +01:00
|
|
|
score->setPlayPos(is.segment()->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setPlaylistDirty(true);
|
|
|
|
}
|
|
|
|
end();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdAddSpanner
|
|
|
|
// drop VOLTA, OTTAVA, TRILL, PEDAL, DYNAMIC
|
|
|
|
// HAIRPIN, and TEXTLINE
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-06-10 11:03:34 +02:00
|
|
|
void Score::cmdAddSpanner(Spanner* spanner, const QPointF& pos)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
int staffIdx;
|
|
|
|
Segment* segment;
|
|
|
|
MeasureBase* mb = pos2measure(pos, &staffIdx, 0, &segment, 0);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (mb == 0 || mb->type() != Element::MEASURE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qDebug("cmdAddSpanner: cannot put object here");
|
|
|
|
delete spanner;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int track = staffIdx == -1 ? -1 : staffIdx * VOICES;
|
|
|
|
spanner->setTrack(track);
|
|
|
|
|
2012-09-12 11:16:36 +02:00
|
|
|
if (spanner->anchor() == Spanner::ANCHOR_SEGMENT) {
|
2013-06-10 11:03:34 +02:00
|
|
|
spanner->setTick(segment->tick());
|
2013-07-16 09:03:47 +02:00
|
|
|
int lastTick = lastMeasure()->tick() + lastMeasure()->ticks();
|
|
|
|
int tick2 = qMin(segment->tick() + segment->measure()->ticks(), lastTick);
|
|
|
|
spanner->setTick2(tick2);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else { // ANCHOR_MEASURE
|
|
|
|
Measure* m = static_cast<Measure*>(mb);
|
|
|
|
QRectF b(m->canvasBoundingRect());
|
|
|
|
|
|
|
|
if (pos.x() >= (b.x() + b.width() * .5))
|
|
|
|
m = m->nextMeasure();
|
2013-06-10 11:03:34 +02:00
|
|
|
spanner->setTick(m->tick());
|
2013-06-25 14:29:18 +02:00
|
|
|
spanner->setTick2(m->endTick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
undoAddElement(spanner);
|
|
|
|
select(spanner, SELECT_SINGLE, 0);
|
|
|
|
|
2012-09-13 18:01:34 +02:00
|
|
|
if (spanner->type() == Element::TRILL) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = segment->element(staffIdx * VOICES);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e && e->type() == Element::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
|
|
|
Fraction l = chord->duration();
|
|
|
|
if (chord->notes().size() > 1) {
|
|
|
|
// trill do not work for chords
|
|
|
|
}
|
|
|
|
Note* note = chord->upNote();
|
|
|
|
while (note->tieFor()) {
|
|
|
|
note = note->tieFor()->endNote();
|
|
|
|
l += note->chord()->duration();
|
|
|
|
}
|
|
|
|
Segment* s = note->chord()->segment();
|
2012-08-03 15:54:02 +02:00
|
|
|
s = s->next1(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
while (s) {
|
|
|
|
Element* e = s->element(staffIdx * VOICES);
|
|
|
|
if (e)
|
|
|
|
break;
|
2012-08-03 15:54:02 +02:00
|
|
|
s = s->next1(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
if (s)
|
2013-06-25 14:29:18 +02:00
|
|
|
spanner->setTick2(s->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
Fraction d(1,32);
|
|
|
|
Fraction e = l / d;
|
|
|
|
int n = e.numerator() / e.denominator();
|
|
|
|
QList<NoteEvent*> events;
|
|
|
|
int pitch = chord->upNote()->ppitch();
|
|
|
|
int key = chord->staff()->key(segment->tick()).accidentalType();
|
|
|
|
int pitch2 = diatonicUpDown(key, pitch, 1);
|
|
|
|
int dpitch = pitch2 - pitch;
|
|
|
|
for (int i = 0; i < n; i += 2) {
|
|
|
|
events.append(new NoteEvent(0, i * 1000 / n, 1000/n));
|
|
|
|
events.append(new NoteEvent(dpitch, (i+1) *1000 / n, 1000/n));
|
|
|
|
}
|
|
|
|
undo(new ChangeNoteEvents(chord, events));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// expandVoice
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::expandVoice(Segment* s, int track)
|
|
|
|
{
|
|
|
|
if (s->element(track)) {
|
|
|
|
ChordRest* cr = (ChordRest*)(s->element(track));
|
|
|
|
qDebug("expand voice: found %s %s", cr->name(), qPrintable(cr->duration().print()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment* ps;
|
2012-08-03 15:54:02 +02:00
|
|
|
for (ps = s; ps; ps = ps->prev(Segment::SegChordRest)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (ps->element(track))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ps) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(ps->element(track));
|
|
|
|
int tick = cr->tick() + cr->actualTicks();
|
|
|
|
if (tick == s->tick())
|
|
|
|
return;
|
|
|
|
if (tick > s->tick()) {
|
|
|
|
qDebug("expandVoice: cannot insert element here");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// fill upto s->tick() with rests
|
|
|
|
//
|
|
|
|
Measure* m = s->measure();
|
|
|
|
int stick = ps ? ps->tick() : m->tick();
|
|
|
|
int ticks = s->tick() - stick;
|
|
|
|
if (ticks)
|
|
|
|
setRest(stick, track, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// fill from s->tick() until next chord/rest
|
|
|
|
//
|
|
|
|
Segment* ns;
|
2012-08-03 15:54:02 +02:00
|
|
|
for (ns = s->next(Segment::SegChordRest); ns; ns = ns->next(Segment::SegChordRest)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (ns->element(track))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ticks = ns ? (ns->tick() - s->tick()) : (m->ticks() - s->rtick());
|
|
|
|
if (ticks == m->ticks())
|
|
|
|
addRest(s, track, TDuration(TDuration::V_MEASURE), 0);
|
|
|
|
else
|
|
|
|
setRest(s->tick(), track, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Score::expandVoice()
|
|
|
|
{
|
|
|
|
Segment* s = _is.segment();
|
|
|
|
int track = _is.track();
|
|
|
|
expandVoice(s, track);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// addPitch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Note* Score::addPitch(int pitch, bool addFlag)
|
|
|
|
{
|
|
|
|
if (addFlag) {
|
2013-10-24 12:09:00 +02:00
|
|
|
qDebug("Score::addPitch at %d", _is.lastSegment()->tick());
|
|
|
|
Chord* c = static_cast<Chord*>(_is.lastSegment()->element(_is.track()));
|
|
|
|
|
|
|
|
if (c == 0 || c->type() != Element::CHORD) {
|
|
|
|
qDebug("Score::addPitch: cr %s", c ? c->name() : "zero");
|
2012-05-26 14:26:10 +02:00
|
|
|
return 0;
|
2013-10-24 12:09:00 +02:00
|
|
|
}
|
|
|
|
NoteVal val(pitch);
|
|
|
|
Note* note = addNote(c, val);
|
|
|
|
if (_is.lastSegment() == _is.segment())
|
|
|
|
_is.moveToNextInputPos();
|
|
|
|
return note;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
expandVoice();
|
|
|
|
|
|
|
|
// insert note
|
2012-08-04 15:46:43 +02:00
|
|
|
MScore::Direction stemDirection = MScore::AUTO;
|
2013-11-25 15:02:23 +01:00
|
|
|
NoteHeadGroup headGroup = NoteHeadGroup::HEAD_NORMAL;
|
2012-05-26 14:26:10 +02:00
|
|
|
int track = _is.track();
|
|
|
|
if (_is.drumNote() != -1) {
|
|
|
|
pitch = _is.drumNote();
|
|
|
|
Drumset* ds = _is.drumset();
|
|
|
|
headGroup = ds->noteHead(pitch);
|
|
|
|
stemDirection = ds->stemDirection(pitch);
|
|
|
|
track = ds->voice(pitch) + (_is.track() / VOICES) * VOICES;
|
|
|
|
_is.setTrack(track);
|
|
|
|
expandVoice();
|
|
|
|
}
|
|
|
|
if (!_is.cr())
|
|
|
|
return 0;
|
|
|
|
NoteVal nval;
|
|
|
|
nval.pitch = pitch;
|
|
|
|
nval.headGroup = headGroup;
|
|
|
|
Fraction duration;
|
2013-04-18 11:41:14 +02:00
|
|
|
if (_is.repitchMode()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
duration = _is.cr()->duration();
|
2013-04-18 11:41:14 +02:00
|
|
|
}
|
|
|
|
else {
|
2012-05-26 14:26:10 +02:00
|
|
|
duration = _is.duration().fraction();
|
2013-04-18 11:41:14 +02:00
|
|
|
}
|
|
|
|
Note* note = 0;
|
|
|
|
if (_is.repitchMode() && _is.cr()->type() == Element::CHORD) {
|
|
|
|
Chord* chord = static_cast<Chord*>(_is.cr());
|
|
|
|
note = new Note(this);
|
|
|
|
note->setNval(nval);
|
|
|
|
note->setParent(chord);
|
|
|
|
if (!addFlag) {
|
|
|
|
while (!chord->notes().isEmpty())
|
|
|
|
undoRemoveElement(chord->notes().first());
|
|
|
|
}
|
|
|
|
undoAddElement(note);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Segment* seg = setNoteRest(_is.segment(), track, nval, duration, stemDirection);
|
|
|
|
if (seg) {
|
|
|
|
note = static_cast<Chord*>(seg->element(track))->upNote();
|
2013-06-05 15:47:34 +02:00
|
|
|
setLayoutAll(true);
|
2013-04-18 11:41:14 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-10-24 12:09:00 +02:00
|
|
|
if (_is.slur()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// extend slur
|
|
|
|
//
|
|
|
|
ChordRest* e = searchNote(_is.tick(), _is.track());
|
|
|
|
if (e) {
|
|
|
|
int stick = 0;
|
2013-10-24 12:09:00 +02:00
|
|
|
Element* ee = _is.slur()->startElement();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (ee->isChordRest())
|
|
|
|
stick = static_cast<ChordRest*>(ee)->tick();
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (ee->type() == Element::NOTE)
|
2012-05-26 14:26:10 +02:00
|
|
|
stick = static_cast<Note*>(ee)->chord()->tick();
|
|
|
|
if (stick == e->tick()) {
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.slur()->setTick(stick);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.slur()->setTick2(e->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("addPitch: cannot find slur note");
|
|
|
|
setLayoutAll(true);
|
|
|
|
}
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.moveToNextInputPos();
|
2012-05-26 14:26:10 +02:00
|
|
|
return note;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdAddInterval
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdAddInterval(int val, const QList<Note*>& nl)
|
|
|
|
{
|
|
|
|
startCmd();
|
|
|
|
foreach(Note* on, nl) {
|
|
|
|
Note* note = new Note(*on);
|
|
|
|
Chord* chord = on->chord();
|
|
|
|
note->setParent(chord);
|
|
|
|
int valTmp = val < 0 ? val+1 : val-1;
|
|
|
|
|
|
|
|
int npitch;
|
|
|
|
int ntpc;
|
|
|
|
if( abs(valTmp) != 7 ) {
|
|
|
|
int line = on->line() - valTmp;
|
|
|
|
int tick = chord->tick();
|
|
|
|
Staff* estaff = staff(on->staffIdx() + chord->staffMove());
|
2013-09-05 16:37:49 +02:00
|
|
|
ClefType clef = estaff->clef(tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
int key = estaff->key(tick).accidentalType();
|
|
|
|
npitch = line2pitch(line, clef, key);
|
2013-02-07 23:52:13 +01:00
|
|
|
ntpc = pitch2tpc(npitch, key, PREFER_NEAREST);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else { //special case for octave
|
|
|
|
Interval interval(7, 12);
|
|
|
|
if(val < 0) {
|
|
|
|
interval.flip();
|
|
|
|
}
|
|
|
|
transposeInterval(on->pitch(), on->tpc(), &npitch, &ntpc, interval, false);
|
|
|
|
}
|
|
|
|
note->setPitch(npitch, ntpc);
|
|
|
|
|
|
|
|
undoAddElement(note);
|
|
|
|
_playNote = true;
|
2013-06-05 15:47:34 +02:00
|
|
|
setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
select(note, SELECT_SINGLE, 0);
|
|
|
|
}
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.moveToNextInputPos();
|
2012-05-26 14:26:10 +02:00
|
|
|
endCmd();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setGraceNote
|
|
|
|
/// Create a grace note in front of a normal note.
|
|
|
|
/// \arg chord is the normal note
|
|
|
|
/// \arg pitch is the pitch of the grace note
|
|
|
|
/// \arg is the grace note type
|
|
|
|
/// \len is the visual duration of the grace note (1/16 or 1/32)
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-08-30 15:05:17 +02:00
|
|
|
void Score::setGraceNote(Chord* ch, int pitch, NoteType type, bool /*behind*/, int len, int tpc)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Note* note = new Note(this);
|
2013-08-30 15:05:17 +02:00
|
|
|
if(tpc == INVALID_TPC)
|
|
|
|
note->setPitch(pitch);
|
|
|
|
else
|
|
|
|
note->setPitch(pitch, tpc);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
Chord* chord = new Chord(this);
|
|
|
|
chord->setTrack(ch->track());
|
|
|
|
chord->add(note);
|
2013-06-12 14:23:57 +02:00
|
|
|
chord->setParent(ch);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
TDuration d;
|
|
|
|
d.setVal(len);
|
|
|
|
chord->setDurationType(d);
|
|
|
|
chord->setDuration(d.fraction());
|
|
|
|
chord->setNoteType(type);
|
|
|
|
chord->setMag(ch->staff()->mag() * styleD(ST_graceNoteMag));
|
|
|
|
|
2013-06-12 14:23:57 +02:00
|
|
|
undoAddElement(chord);
|
2012-05-26 14:26:10 +02:00
|
|
|
select(note, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setNoteRest
|
|
|
|
// pitch == -1 -> set rest
|
|
|
|
// return segment of last created note/rest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Segment* Score::setNoteRest(Segment* segment, int track, NoteVal nval, Fraction sd,
|
2012-08-04 15:46:43 +02:00
|
|
|
MScore::Direction stemDirection)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-03-05 20:23:59 +01:00
|
|
|
assert(segment->segmentType() == Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
int tick = segment->tick();
|
|
|
|
Element* nr = 0;
|
|
|
|
Tie* tie = 0;
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(segment->element(track));
|
|
|
|
|
|
|
|
Measure* measure = 0;
|
|
|
|
for (;;) {
|
|
|
|
if (track % VOICES)
|
|
|
|
expandVoice(segment, track);
|
|
|
|
|
|
|
|
// the returned gap ends at the measure boundary or at tuplet end
|
|
|
|
Fraction dd = makeGap(segment, track, sd, cr ? cr->tuplet() : 0);
|
|
|
|
|
|
|
|
if (dd.isZero()) {
|
|
|
|
qDebug("cannot get gap at %d type: %d/%d", tick, sd.numerator(),
|
|
|
|
sd.denominator());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
QList<TDuration> dl = toDurationList(dd, true);
|
|
|
|
|
|
|
|
measure = segment->measure();
|
|
|
|
int n = dl.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
TDuration d = dl[i];
|
|
|
|
|
|
|
|
ChordRest* ncr;
|
|
|
|
Note* note = 0;
|
|
|
|
if (nval.pitch == -1) {
|
|
|
|
nr = ncr = new Rest(this);
|
|
|
|
nr->setTrack(track);
|
|
|
|
ncr->setDurationType(d);
|
|
|
|
ncr->setDuration(d.fraction());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nr = note = new Note(this);
|
|
|
|
|
|
|
|
if (tie) {
|
|
|
|
tie->setEndNote(note);
|
|
|
|
note->setTieBack(tie);
|
|
|
|
}
|
|
|
|
Chord* chord = new Chord(this);
|
|
|
|
chord->setTrack(track);
|
|
|
|
chord->setDurationType(d);
|
|
|
|
chord->setDuration(d.fraction());
|
|
|
|
chord->setStemDirection(stemDirection);
|
|
|
|
chord->add(note);
|
|
|
|
note->setNval(nval);
|
|
|
|
ncr = chord;
|
|
|
|
if (i+1 < n) {
|
|
|
|
tie = new Tie(this);
|
|
|
|
tie->setStartNote(note);
|
|
|
|
tie->setTrack(track);
|
|
|
|
note->setTieFor(tie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ncr->setTuplet(cr ? cr->tuplet() : 0);
|
|
|
|
undoAddCR(ncr, measure, tick);
|
|
|
|
_playNote = true;
|
|
|
|
segment = ncr->segment();
|
|
|
|
tick += ncr->actualTicks();
|
|
|
|
}
|
|
|
|
|
|
|
|
sd -= dd;
|
|
|
|
if (sd.isZero())
|
|
|
|
break;
|
|
|
|
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* nseg = tick2segment(tick, false, Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (nseg == 0) {
|
|
|
|
qDebug("reached end of score");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
segment = nseg;
|
|
|
|
|
|
|
|
cr = static_cast<ChordRest*>(segment->element(track));
|
|
|
|
|
|
|
|
if (cr == 0) {
|
|
|
|
if (track % VOICES)
|
|
|
|
cr = addRest(segment, track, TDuration(TDuration::V_MEASURE), 0);
|
|
|
|
else {
|
|
|
|
qDebug("no rest in voice 0");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Note does not fit on current measure, create Tie to
|
|
|
|
// next part of note
|
|
|
|
if (nval.pitch != -1) {
|
|
|
|
tie = new Tie(this);
|
|
|
|
tie->setStartNote((Note*)nr);
|
|
|
|
tie->setTrack(nr->track());
|
|
|
|
((Note*)nr)->setTieFor(tie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tie)
|
|
|
|
connectTies();
|
|
|
|
if (nr)
|
|
|
|
select(nr, SELECT_SINGLE, 0);
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// makeGap
|
|
|
|
// make time gap at tick by removing/shortening
|
|
|
|
// chord/rest
|
|
|
|
//
|
2013-05-10 10:51:27 +02:00
|
|
|
// if keepChord, the chord at tick is not removed
|
|
|
|
//
|
2012-05-26 14:26:10 +02:00
|
|
|
// gap does not exceed measure or scope of tuplet
|
|
|
|
//
|
|
|
|
// return size of actual gap
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-05-10 10:51:27 +02:00
|
|
|
Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet* tuplet, bool keepChord)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
assert(_sd.numerator());
|
|
|
|
|
|
|
|
Measure* measure = segment->measure();
|
2013-06-05 15:47:34 +02:00
|
|
|
setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
Fraction akkumulated;
|
|
|
|
Fraction sd = _sd;
|
|
|
|
|
|
|
|
//
|
|
|
|
// remember first segment which should
|
|
|
|
// not be deleted (it may contain other elements we want to preserve)
|
|
|
|
//
|
|
|
|
Segment* firstSegment = segment;
|
|
|
|
int nextTick = segment->tick();
|
|
|
|
|
2013-06-12 14:23:57 +02:00
|
|
|
for (Segment* seg = firstSegment; seg; seg = seg->next(Segment::SegChordRest)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// voices != 0 may have gaps:
|
|
|
|
//
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(seg->element(track));
|
|
|
|
if (!cr) {
|
|
|
|
if (seg->tick() < nextTick)
|
|
|
|
continue;
|
2012-08-03 15:54:02 +02:00
|
|
|
Segment* seg1 = seg->next(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
int tick2 = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
|
|
|
|
Fraction td(Fraction::fromTicks(tick2 - seg->tick()));
|
|
|
|
segment = seg;
|
|
|
|
if (td > sd)
|
|
|
|
td = sd;
|
|
|
|
akkumulated += td;
|
|
|
|
sd -= td;
|
|
|
|
if (sd.isZero())
|
|
|
|
return akkumulated;
|
2013-06-04 18:49:04 +02:00
|
|
|
nextTick = tick2;
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// limit to tuplet level
|
|
|
|
//
|
|
|
|
if (tuplet) {
|
|
|
|
bool tupletEnd = true;
|
|
|
|
Tuplet* t = cr->tuplet();
|
|
|
|
while (t) {
|
|
|
|
if (cr->tuplet() == tuplet) {
|
|
|
|
tupletEnd = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
t = t->tuplet();
|
|
|
|
}
|
2013-06-20 17:23:24 +02:00
|
|
|
if (tupletEnd)
|
2012-05-26 14:26:10 +02:00
|
|
|
return akkumulated;
|
|
|
|
}
|
|
|
|
Fraction td(cr->duration());
|
|
|
|
|
2013-09-05 20:05:49 +02:00
|
|
|
// remove tremolo between 2 notes, if present
|
|
|
|
if (cr->type() == Element::CHORD) {
|
|
|
|
Chord* c = static_cast<Chord*>(cr);
|
|
|
|
if (c->tremolo()) {
|
|
|
|
Tremolo* tremolo = c->tremolo();
|
|
|
|
if (tremolo->twoNotes())
|
|
|
|
undoRemoveElement(tremolo);
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
Tuplet* ltuplet = cr->tuplet();
|
|
|
|
if (cr->tuplet() != tuplet) {
|
|
|
|
//
|
|
|
|
// Current location points to the start of a (nested)tuplet.
|
|
|
|
// We have to remove the complete tuplet.
|
|
|
|
|
|
|
|
Tuplet* t = ltuplet;
|
2012-09-13 18:01:34 +02:00
|
|
|
while (t->elements().last()->type() == Element::TUPLET)
|
2012-05-26 14:26:10 +02:00
|
|
|
t = static_cast<Tuplet*>(t->elements().last());
|
|
|
|
seg = static_cast<ChordRest*>(t->elements().last())->segment();
|
|
|
|
|
|
|
|
td = ltuplet->duration();
|
|
|
|
cmdDeleteTuplet(ltuplet, false);
|
|
|
|
tuplet = 0;
|
|
|
|
}
|
|
|
|
else {
|
2013-05-10 10:51:27 +02:00
|
|
|
if(seg != firstSegment || !keepChord)
|
|
|
|
undoRemoveElement(cr);
|
2013-12-11 20:43:53 +01:00
|
|
|
if (seg != firstSegment && seg->isEmpty() && seg->annotations().size() == 0)
|
2012-05-26 14:26:10 +02:00
|
|
|
undoRemoveElement(seg);
|
|
|
|
}
|
|
|
|
nextTick += td.ticks();
|
|
|
|
if (sd < td) {
|
|
|
|
//
|
|
|
|
// we removed too much
|
|
|
|
//
|
|
|
|
akkumulated = _sd;
|
|
|
|
Fraction rd = td - sd;
|
|
|
|
|
|
|
|
QList<TDuration> dList = toDurationList(rd, false);
|
|
|
|
if (dList.isEmpty())
|
|
|
|
return akkumulated;
|
|
|
|
|
|
|
|
Fraction f(cr->staff()->timeStretch(cr->tick()) * sd);
|
|
|
|
for (Tuplet* t = tuplet; t; t = t->tuplet())
|
|
|
|
f /= t->ratio();
|
|
|
|
int tick = cr->tick() + f.ticks();
|
|
|
|
|
|
|
|
if ((tuplet == 0) && (((measure->tick() - tick) % dList[0].ticks()) == 0)) {
|
|
|
|
foreach(TDuration d, dList) {
|
|
|
|
qDebug(" addClone at %d, %d", tick, d.ticks());
|
|
|
|
tick += addClone(cr, tick, d)->actualTicks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (int i = dList.size() - 1; i >= 0; --i)
|
|
|
|
tick += addClone(cr, tick, dList[i])->actualTicks();
|
|
|
|
}
|
|
|
|
return akkumulated;
|
|
|
|
}
|
|
|
|
akkumulated += td;
|
|
|
|
sd -= td;
|
|
|
|
if (sd.isZero())
|
|
|
|
return akkumulated;
|
|
|
|
}
|
|
|
|
// int ticks = measure->tick() + measure->ticks() - segment->tick();
|
|
|
|
// Fraction td = Fraction::fromTicks(ticks);
|
|
|
|
// NEEDS REVIEW !!
|
|
|
|
// once the statement below is removed, these two lines do nothing
|
|
|
|
// if (td > sd)
|
|
|
|
// td = sd;
|
|
|
|
// ??? akkumulated should already contain the total value of the created gap: line 749, 811 or 838
|
|
|
|
// this line creates a qreal-sized gap if the needed gap crosses a measure boundary
|
|
|
|
// by adding again the duration already added in line 838
|
|
|
|
// akkumulated += td;
|
|
|
|
return akkumulated;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// makeGap1
|
|
|
|
// make time gap at tick by removing/shortening
|
|
|
|
// chord/rest
|
|
|
|
// - cr is top level (not part of a tuplet)
|
|
|
|
// - do not stop at measure end
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::makeGap1(int tick, int staffIdx, Fraction len)
|
|
|
|
{
|
|
|
|
ChordRest* cr = 0;
|
2013-06-12 14:23:57 +02:00
|
|
|
Segment* seg = tick2segment(tick, true, Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (!seg) {
|
|
|
|
qDebug("1:makeGap1: no segment at %d", tick);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
cr = static_cast<ChordRest*>(seg->element(track));
|
|
|
|
if (!cr) {
|
2013-06-12 14:23:57 +02:00
|
|
|
// check if we are in the middle of a chord/rest
|
|
|
|
Segment* seg1 = 0;
|
|
|
|
for (;;) {
|
|
|
|
seg1 = seg->prev(Segment::SegChordRest);
|
|
|
|
if (seg1 == 0) {
|
|
|
|
qDebug("1:makeGap1: no segment at %d", tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
return false;
|
|
|
|
}
|
2013-06-12 14:23:57 +02:00
|
|
|
if (seg1->element(track))
|
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-06-12 14:23:57 +02:00
|
|
|
ChordRest* cr1 = static_cast<ChordRest*>(seg1->element(track));
|
2013-06-20 15:25:11 +02:00
|
|
|
Fraction srcF = cr1->duration();
|
2013-06-12 14:23:57 +02:00
|
|
|
Fraction dstF = Fraction::fromTicks(tick - cr1->tick());
|
|
|
|
undoChangeChordRestLen(cr1, TDuration(dstF));
|
2013-06-20 15:25:11 +02:00
|
|
|
setRest(tick, track, srcF - dstF, true, 0);
|
2013-06-12 14:23:57 +02:00
|
|
|
for (;;) {
|
2013-06-20 15:25:11 +02:00
|
|
|
seg1 = seg1->next1(Segment::SegChordRest);
|
|
|
|
if (seg1 == 0) {
|
2013-06-12 14:23:57 +02:00
|
|
|
qDebug("2:makeGap1: no segment");
|
|
|
|
return false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-06-20 15:25:11 +02:00
|
|
|
if (seg1->element(track)) {
|
|
|
|
tick = seg1->tick();
|
|
|
|
cr = static_cast<ChordRest*>(seg1->element(track));
|
2013-06-12 14:23:57 +02:00
|
|
|
break;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (!cr) {
|
|
|
|
qDebug("makeGap1: cannot make gap");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Fraction l = makeGap(cr->segment(), cr->track(), len, 0);
|
|
|
|
if (l.isZero()) {
|
|
|
|
qDebug("makeGap1: makeGap returns zero gap");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
len -= l;
|
|
|
|
if (len.isZero())
|
|
|
|
break;
|
|
|
|
// go to next cr
|
|
|
|
Measure* m = cr->measure()->nextMeasure();
|
|
|
|
if (m == 0) {
|
|
|
|
qDebug("EOS reached");
|
2012-09-13 18:01:34 +02:00
|
|
|
insertMeasure(Element::MEASURE, 0, false);
|
2012-05-26 14:26:10 +02:00
|
|
|
m = cr->measure()->nextMeasure();
|
|
|
|
if (m == 0) {
|
|
|
|
qDebug("===EOS reached");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2013-06-28 17:46:24 +02:00
|
|
|
Segment* s = m->first(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
int track = cr->track();
|
|
|
|
cr = static_cast<ChordRest*>(s->element(track));
|
|
|
|
if (cr == 0) {
|
|
|
|
addRest(s, track, TDuration(TDuration::V_MEASURE), 0);
|
|
|
|
cr = static_cast<ChordRest*>(s->element(track));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// splitGapToMeasureBoundaries
|
|
|
|
// cr - start of gap
|
|
|
|
// gap - gap len
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
QList<Fraction> Score::splitGapToMeasureBoundaries(ChordRest* cr, Fraction gap)
|
|
|
|
{
|
|
|
|
QList<Fraction> flist;
|
|
|
|
|
|
|
|
Tuplet* tuplet = cr->tuplet();
|
|
|
|
if (tuplet) {
|
2013-05-10 10:51:27 +02:00
|
|
|
if(tuplet->tuplet())
|
|
|
|
return flist; // do no deal with nested tuplets
|
|
|
|
Fraction rest = Fraction::fromTicks(tuplet->tick() + tuplet->duration().ticks() - cr->segment()->tick()) * tuplet->ratio();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (rest < gap)
|
|
|
|
qDebug("does not fit in tuplet");
|
|
|
|
else
|
|
|
|
flist.append(gap);
|
|
|
|
return flist;
|
|
|
|
}
|
|
|
|
|
|
|
|
Segment* s = cr->segment();
|
|
|
|
while (gap > Fraction(0)) {
|
|
|
|
Measure* m = s->measure();
|
|
|
|
Fraction rest = Fraction::fromTicks(m->ticks() - s->rtick());
|
|
|
|
if (rest >= gap) {
|
|
|
|
flist.append(gap);
|
|
|
|
return flist;
|
|
|
|
}
|
|
|
|
flist.append(rest);
|
|
|
|
gap -= rest;
|
|
|
|
m = m->nextMeasure();
|
|
|
|
if (m == 0)
|
|
|
|
return flist;
|
2012-08-03 15:54:02 +02:00
|
|
|
s = m->first(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
return flist;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// changeCRlen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::changeCRlen(ChordRest* cr, const TDuration& d)
|
|
|
|
{
|
|
|
|
Fraction srcF(cr->duration());
|
|
|
|
Fraction dstF;
|
|
|
|
if (d.type() == TDuration::V_MEASURE)
|
|
|
|
dstF = cr->measure()->stretchedLen(cr->staff());
|
|
|
|
else
|
|
|
|
dstF = d.fraction();
|
|
|
|
|
|
|
|
qDebug("changeCRlen: %d/%d -> %d/%d", srcF.numerator(), srcF.denominator(),
|
|
|
|
dstF.numerator(), dstF.denominator());
|
|
|
|
|
|
|
|
if (srcF == dstF)
|
|
|
|
return;
|
|
|
|
int track = cr->track();
|
|
|
|
Tuplet* tuplet = cr->tuplet();
|
2013-06-05 16:48:09 +02:00
|
|
|
|
|
|
|
//keep selected note if any
|
|
|
|
Note* selNote = 0;
|
|
|
|
if(selection().isSingle()) {
|
|
|
|
Element* el = getSelectedElement();
|
|
|
|
if(el->type() == Element::NOTE)
|
|
|
|
selNote = static_cast<Note*>(el);
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
if (srcF > dstF) {
|
|
|
|
//
|
|
|
|
// make shorter and fill with rest
|
|
|
|
//
|
2013-05-10 10:51:27 +02:00
|
|
|
deselectAll();
|
2012-09-13 18:01:34 +02:00
|
|
|
if (cr->type() == Element::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
2013-09-05 20:05:49 +02:00
|
|
|
// remove ties and tremolo between 2 notes
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
Chord* c = static_cast<Chord*>(cr);
|
2013-09-05 20:05:49 +02:00
|
|
|
if (c->tremolo()) {
|
|
|
|
Tremolo* tremolo = c->tremolo();
|
|
|
|
if (tremolo->twoNotes())
|
|
|
|
undoRemoveElement(tremolo);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
foreach(Note* n, c->notes()) {
|
|
|
|
if (n->tieFor())
|
|
|
|
undoRemoveElement(n->tieFor());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
undoChangeChordRestLen(cr, TDuration(dstF));
|
2013-06-04 18:29:14 +02:00
|
|
|
qDebug(" setRest at %d+%d, %d/%d",
|
|
|
|
cr->tick(), cr->actualTicks(), (srcF-dstF).numerator(), (srcF-dstF).denominator());
|
2012-05-26 14:26:10 +02:00
|
|
|
setRest(cr->tick() + cr->actualTicks(), track, srcF - dstF, false, tuplet);
|
2013-06-05 16:48:09 +02:00
|
|
|
if(!selNote)
|
|
|
|
select(cr, SELECT_SINGLE, 0);
|
|
|
|
else
|
|
|
|
select(selNote, SELECT_SINGLE, 0);
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// make longer
|
|
|
|
//
|
|
|
|
// split required len into Measures
|
|
|
|
QList<Fraction> flist = splitGapToMeasureBoundaries(cr, dstF);
|
|
|
|
if (flist.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2013-05-10 10:51:27 +02:00
|
|
|
deselectAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
qDebug("ChangeCRLen::List:");
|
|
|
|
foreach (Fraction f, flist)
|
|
|
|
qDebug(" %d/%d", f.numerator(), f.denominator());
|
|
|
|
|
|
|
|
int tick = cr->tick();
|
|
|
|
Fraction f = dstF;
|
|
|
|
ChordRest* cr1 = cr;
|
|
|
|
Chord* oc = 0;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
foreach (Fraction f2, flist) {
|
|
|
|
f -= f2;
|
2013-05-10 10:51:27 +02:00
|
|
|
makeGap(cr1->segment(), cr1->track(), f2, tuplet, first);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2012-09-13 18:01:34 +02:00
|
|
|
if (cr->type() == Element::REST) {
|
2012-05-26 14:26:10 +02:00
|
|
|
qDebug(" +ChangeCRLen::setRest %d/%d", f2.numerator(), f2.denominator());
|
|
|
|
Fraction timeStretch = cr1->staff()->timeStretch(cr1->tick());
|
2013-05-18 17:07:20 +02:00
|
|
|
Rest* r = static_cast<Rest*>(cr);
|
|
|
|
if (first) {
|
|
|
|
QList<TDuration> dList = toDurationList(f2, true);
|
|
|
|
undoChangeChordRestLen(cr, dList[0]);
|
|
|
|
if(dList.size() > 1) {
|
|
|
|
TDuration remain = TDuration(f2) - dList[0];
|
|
|
|
setRest(tick +dList[0].ticks(), track, remain.fraction() * timeStretch, (remain.dots() > 0), tuplet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = setRest(tick, track, f2 * timeStretch, (d.dots() > 0), tuplet);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (first) {
|
|
|
|
select(r, SELECT_SINGLE, 0);
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
qDebug(" ChangeCRLen:: %d += %d(actual=%d)", tick, f2.ticks(), f2.ticks() * timeStretch.numerator() / timeStretch.denominator());
|
|
|
|
tick += f2.ticks() * timeStretch.numerator() / timeStretch.denominator();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QList<TDuration> dList = toDurationList(f2, true);
|
|
|
|
Measure* measure = tick2measure(tick);
|
|
|
|
int etick = measure->tick();
|
|
|
|
// if (measure->tick() != tick)
|
|
|
|
// etick += measure->ticks();
|
|
|
|
if (((tick - etick) % dList[0].ticks()) == 0) {
|
2013-05-10 10:51:27 +02:00
|
|
|
foreach(TDuration du, dList) {
|
2012-05-26 14:26:10 +02:00
|
|
|
bool genTie;
|
|
|
|
Chord* cc;
|
|
|
|
if (oc) {
|
|
|
|
genTie = true;
|
|
|
|
cc = oc;
|
2013-05-10 10:51:27 +02:00
|
|
|
oc = addChord(tick, du, cc, genTie, tuplet);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
genTie = false;
|
|
|
|
cc = static_cast<Chord*>(cr);
|
2013-05-10 10:51:27 +02:00
|
|
|
undoChangeChordRestLen(cr, du);
|
|
|
|
oc = cc;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
if (oc && first) {
|
2013-06-05 16:48:09 +02:00
|
|
|
if(!selNote)
|
|
|
|
select(oc, SELECT_SINGLE, 0);
|
|
|
|
else
|
|
|
|
select(selNote, SELECT_SINGLE, 0);
|
2012-05-26 14:26:10 +02:00
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
if (oc)
|
|
|
|
tick += oc->actualTicks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (int i = dList.size() - 1; i >= 0; --i) {
|
|
|
|
bool genTie;
|
|
|
|
Chord* cc;
|
|
|
|
if (oc) {
|
|
|
|
genTie = true;
|
|
|
|
cc = oc;
|
2013-05-10 10:51:27 +02:00
|
|
|
oc = addChord(tick, dList[i], cc, genTie, tuplet);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
genTie = false;
|
|
|
|
cc = static_cast<Chord*>(cr);
|
2013-05-10 10:51:27 +02:00
|
|
|
undoChangeChordRestLen(cr, dList[i]);
|
|
|
|
oc = cc;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
if (first) {
|
|
|
|
select(oc, SELECT_SINGLE, 0);
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
tick += oc->actualTicks();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Measure* m = cr1->measure();
|
|
|
|
Measure* m1 = m->nextMeasure();
|
|
|
|
if (m1 == 0)
|
|
|
|
break;
|
2013-06-28 17:46:24 +02:00
|
|
|
Segment* s = m1->first(Segment::SegChordRest);
|
2012-05-26 14:26:10 +02:00
|
|
|
expandVoice(s, track);
|
|
|
|
cr1 = static_cast<ChordRest*>(s->element(track));
|
|
|
|
}
|
|
|
|
connectTies();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// upDown
|
|
|
|
/// Increment/decrement pitch of note by one or by an octave.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::upDown(bool up, UpDownMode mode)
|
|
|
|
{
|
|
|
|
QList<Note*> el;
|
|
|
|
int tick = -1;
|
|
|
|
foreach (Note* note, selection().noteList()) {
|
|
|
|
while (note->tieBack())
|
|
|
|
note = note->tieBack()->startNote();
|
|
|
|
for (; note; note = note->tieFor() ? note->tieFor()->endNote() : 0) {
|
2013-10-29 14:34:02 +01:00
|
|
|
if (!el.contains(note)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
el.append(note);
|
|
|
|
if (tick == -1)
|
|
|
|
tick = note->chord()->tick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (el.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
foreach(Note* oNote, el) {
|
2013-06-12 14:23:57 +02:00
|
|
|
Part* part = oNote->staff()->part();
|
|
|
|
int key = oNote->staff()->key(tick).accidentalType();
|
|
|
|
int tpc = oNote->tpc();
|
|
|
|
int pitch = oNote->pitch();
|
|
|
|
int newTpc = tpc; // default to unchanged
|
|
|
|
int newPitch = pitch; // default to unchanged
|
|
|
|
int string = oNote->string();
|
|
|
|
int fret = oNote->fret();
|
2013-09-15 18:43:48 +02:00
|
|
|
StringData* stringData;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
switch(oNote->staff()->staffType()->group()) {
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
case PERCUSSION_STAFF_GROUP:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Drumset* ds = part->instr()->drumset();
|
2013-09-29 00:55:37 +02:00
|
|
|
if(ds) {
|
|
|
|
newPitch = up ? ds->prevPitch(pitch) : ds->nextPitch(pitch);
|
|
|
|
newTpc = oNote->tpc();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
case TAB_STAFF_GROUP:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-09-15 18:43:48 +02:00
|
|
|
stringData = part->instr()->stringData();
|
2012-05-26 14:26:10 +02:00
|
|
|
switch(mode) {
|
|
|
|
case UP_DOWN_OCTAVE: // move same note to next string, if possible
|
|
|
|
{
|
2012-09-19 14:15:49 +02:00
|
|
|
StaffTypeTablature * stt = static_cast<StaffTypeTablature*>(oNote->staff()->staffType());
|
|
|
|
string = stt->physStringToVisual(string);
|
2012-05-26 14:26:10 +02:00
|
|
|
string += (up ? -1 : 1);
|
2013-09-15 18:43:48 +02:00
|
|
|
if(string < 0 || string >= stringData->strings())
|
2012-05-26 14:26:10 +02:00
|
|
|
return; // no next string to move to
|
2012-09-19 14:15:49 +02:00
|
|
|
string = stt->VisualStringToPhys(string);
|
2013-09-15 18:43:48 +02:00
|
|
|
fret = stringData->fret(pitch, string);
|
2012-05-26 14:26:10 +02:00
|
|
|
if(fret == -1) // can't have that note on that string
|
|
|
|
return;
|
2013-02-07 23:52:13 +01:00
|
|
|
// newPitch and newTpc remain unchanged
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-04 00:12:37 +02:00
|
|
|
case UP_DOWN_DIATONIC: // increase / decrease the pitch,
|
2012-05-26 14:26:10 +02:00
|
|
|
// letting the algorithm to choose fret & string
|
2013-02-07 23:52:13 +01:00
|
|
|
if (up) {
|
|
|
|
if (pitch < 127) {
|
|
|
|
newPitch = pitch + 1;
|
|
|
|
if (tpc > TPC_A + key)
|
|
|
|
newTpc = tpc - 5; // up semitone diatonic
|
|
|
|
else
|
|
|
|
newTpc = tpc + 7; // up semitone chromatic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pitch > 0) {
|
|
|
|
newPitch = pitch - 1;
|
|
|
|
if (tpc > TPC_C + key)
|
|
|
|
newTpc = tpc - 7; // down semitone chromatic
|
|
|
|
else
|
|
|
|
newTpc = tpc + 5; // down semitone diatonic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
|
2013-04-04 00:12:37 +02:00
|
|
|
case UP_DOWN_CHROMATIC: // increase / decrease the fret
|
2012-05-26 14:26:10 +02:00
|
|
|
{ // without changing the string
|
|
|
|
fret += (up ? 1 : -1);
|
|
|
|
if (fret < 0)
|
|
|
|
fret = 0;
|
2013-09-15 18:43:48 +02:00
|
|
|
else if (fret >= stringData->frets())
|
|
|
|
fret = stringData->frets() - 1;
|
|
|
|
newPitch = stringData->getPitch(string, fret);
|
2013-02-07 23:52:13 +01:00
|
|
|
newTpc = pitch2tpc(newPitch, key, up ? PREFER_SHARPS : PREFER_FLATS);
|
2012-05-26 14:26:10 +02:00
|
|
|
// store the fretting change before undoChangePitch() chooses
|
|
|
|
// a fretting of its own liking!
|
2012-08-06 09:29:11 +02:00
|
|
|
undoChangeProperty(oNote, P_FRET, fret);
|
|
|
|
undoChangeProperty(oNote, P_STRING, string);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
Re-factor presets and staff types.
1) Built-in staff types have been removed.
2) Presets are internally used as source for the staff types of a new score, to match data in Instruments.xml and as reference to check for modifications.
3) Each new score is given by default one staff type for each preset with the same name.
4) The Instrument page of the New Score Wizard lists (under the name of "Staff types") the default staff types applicable to the instrument (actually it lists the preset, as the score does not have any staff type yet).
5) The "Add | Instruments" dlg box lists all the staff types applicable to the instrument: = to the list of 4) + any user-created staff type.
6) The Staff Properties dlg box lists all the staff types applicable to the instrument: = list in 5)
7) The Staff Type Editor lists all the staff types
This should ensure consistency among the several lists of staff types and avoid duplication of similar items
Terminology:
7) A new staff type created in the editor is named by default with the group name ("Standard-", "Perc-", "Tab-") + the index of the new type in its group + the suffix "[*]" marking a user customisation. The user is anyway able to rename it, if he want.
8) The pitched staff type has been renamed everywhere (hopefully!) to "Standard"
9) The term 'preset' have been removed from the UI, except from the Staff Type Editor where it keeps its meaning of ready-made collections of parameters
The commit affects many files, but a fair number of them have only changes in names of literals. The files with significant code changes are:
libmscore/score.cpp
libmscore/stafftype.cpp/.h
mscore/editstafftype.cpp (code for naming a new staff type)
mscore/instrdialog.cpp (building type list)
Note: as score files store staff type indications as integer indices and the number and order of new default staff types is different from the old built-in types, there is a compatibility issue with old 2.0 score which use percussion and tab staves. In Score::read() (libmscore/scorefile.cpp), there is a rudimentary attempt to cope with this.Old scores will need manual fix anyway. There should not be any (new) compatibility issue with 1.x scores, as they did not use staff types.
2013-08-18 11:55:31 +02:00
|
|
|
case STANDARD_STAFF_GROUP:
|
2012-05-26 14:26:10 +02:00
|
|
|
switch(mode) {
|
|
|
|
case UP_DOWN_OCTAVE:
|
2013-02-07 23:52:13 +01:00
|
|
|
if (up) {
|
|
|
|
if (pitch < 116)
|
|
|
|
newPitch = pitch + 12;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pitch > 11)
|
|
|
|
newPitch = pitch - 12;
|
|
|
|
}
|
|
|
|
// newTpc remains unchanged
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UP_DOWN_CHROMATIC:
|
2013-02-07 23:52:13 +01:00
|
|
|
if (up) {
|
|
|
|
if (pitch < 127) {
|
|
|
|
newPitch = pitch + 1;
|
|
|
|
if (tpc > TPC_A + key)
|
|
|
|
newTpc = tpc - 5; // up semitone diatonic
|
|
|
|
else
|
|
|
|
newTpc = tpc + 7; // up semitone chromatic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pitch > 0) {
|
|
|
|
newPitch = pitch - 1;
|
|
|
|
if (tpc > TPC_C + key)
|
|
|
|
newTpc = tpc - 7; // down semitone chromatic
|
|
|
|
else
|
|
|
|
newTpc = tpc + 5; // down semitone diatonic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UP_DOWN_DIATONIC:
|
2013-02-07 23:52:13 +01:00
|
|
|
if (up) {
|
|
|
|
if (tpc > TPC_A + key) {
|
|
|
|
if (pitch < 127) {
|
|
|
|
newPitch = pitch + 1;
|
|
|
|
newTpc = tpc - 5; // up semitone diatonic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pitch < 126) {
|
|
|
|
newPitch = pitch + 2;
|
|
|
|
newTpc = tpc + 2; // up tone
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (tpc > TPC_C + key) {
|
|
|
|
if (pitch > 1) {
|
|
|
|
newPitch = pitch - 2;
|
|
|
|
newTpc = tpc - 2; // down tone
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pitch > 0) {
|
|
|
|
newPitch = pitch - 1;
|
|
|
|
newTpc = tpc + 5; // down semitone diatonic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-03-10 14:13:25 +01:00
|
|
|
if ((oNote->pitch() != newPitch) || (oNote->tpc() != newTpc)) {
|
|
|
|
// remove accidental if present to make sure
|
|
|
|
// user added accidentals are removed here.
|
|
|
|
if (oNote->accidental())
|
|
|
|
undoRemoveElement(oNote->accidental());
|
2014-01-30 01:41:21 +01:00
|
|
|
|
|
|
|
Staff* s = oNote->score()->staff(oNote->staffIdx() + oNote->chord()->staffMove());
|
|
|
|
int tick = oNote->chord()->tick();
|
|
|
|
ClefType clef = s->clef(tick);
|
|
|
|
int newLine = relStep(absStep(newTpc, newPitch), clef);
|
|
|
|
|
|
|
|
undoChangePitch(oNote, newPitch, newTpc, newLine);
|
2013-03-10 14:13:25 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
// store fret change only if undoChangePitch has not been called,
|
|
|
|
// as undoChangePitch() already manages fret changes, if necessary
|
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
|
|
|
else if( oNote->staff()->staffType()->group() == TAB_STAFF_GROUP) {
|
2012-09-19 14:15:49 +02:00
|
|
|
bool refret = false;
|
|
|
|
if (oNote->string() != string) {
|
2012-08-06 09:29:11 +02:00
|
|
|
undoChangeProperty(oNote, P_STRING, string);
|
2012-09-19 14:15:49 +02:00
|
|
|
refret = true;
|
|
|
|
}
|
|
|
|
if (oNote->fret() != fret) {
|
2012-08-06 09:29:11 +02:00
|
|
|
undoChangeProperty(oNote, P_FRET, fret);
|
2012-09-19 14:15:49 +02:00
|
|
|
refret = true;
|
|
|
|
}
|
|
|
|
if (refret)
|
2013-09-15 18:43:48 +02:00
|
|
|
stringData->fretChords(oNote->chord());
|
2012-08-06 09:29:11 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
// play new note with velocity 80 for 0.3 sec:
|
|
|
|
_playNote = true;
|
|
|
|
}
|
2013-02-18 19:52:24 +01:00
|
|
|
_selection.clear();
|
|
|
|
foreach(Note* note, el)
|
|
|
|
_selection.add(note);
|
2012-05-26 14:26:10 +02:00
|
|
|
_selection.updateState(); // accidentals may have changed
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// addArticulation
|
|
|
|
/// Add attribute \a attr to all selected notes/rests.
|
|
|
|
///
|
|
|
|
/// Called from padToggle() to add note prefix/accent.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::addArticulation(ArticulationType attr)
|
|
|
|
{
|
|
|
|
foreach(Element* el, selection().elements()) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el->type() == Element::NOTE || el->type() == Element::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Articulation* na = new Articulation(this);
|
2013-03-05 20:23:59 +01:00
|
|
|
na->setArticulationType(attr);
|
2013-02-21 14:28:16 +01:00
|
|
|
if (!addArticulation(el, na))
|
|
|
|
delete na;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// changeAccidental
|
|
|
|
/// Change accidental to subtype \a idx for all selected
|
|
|
|
/// notes.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-10-01 20:03:31 +02:00
|
|
|
void Score::changeAccidental(Accidental::AccidentalType idx)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2013-11-27 11:51:16 +01:00
|
|
|
foreach(Note* note, selection().noteList())
|
2012-05-26 14:26:10 +02:00
|
|
|
changeAccidental(note, idx);
|
|
|
|
}
|
|
|
|
|
2013-09-02 12:13:46 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// changeAccidental2
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-11-27 11:51:16 +01:00
|
|
|
static void changeAccidental2(Note* n, int pitch, int tpc)
|
2013-09-02 12:13:46 +02:00
|
|
|
{
|
|
|
|
Score* score = n->score();
|
|
|
|
Chord* chord = n->chord();
|
|
|
|
int staffIdx = chord->staffIdx();
|
|
|
|
Staff* st = chord->staff();
|
|
|
|
int fret = n->fret();
|
|
|
|
int string = n->string();
|
|
|
|
|
|
|
|
if (st->isTabStaff()) {
|
|
|
|
if (pitch != n->pitch()) {
|
|
|
|
//
|
|
|
|
// as pitch has changed, calculate new
|
|
|
|
// string & fret
|
|
|
|
//
|
2013-09-15 18:43:48 +02:00
|
|
|
StringData* stringData = n->staff()->part()->instr()->stringData();
|
|
|
|
if (stringData)
|
|
|
|
stringData->convertPitch(pitch, &string, &fret);
|
2013-09-02 12:13:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
score->undo(new ChangePitch(n, pitch, tpc, n->line()));
|
|
|
|
if (!st->isTabStaff()) {
|
|
|
|
//
|
|
|
|
// handle ties
|
|
|
|
//
|
|
|
|
if (n->tieBack()) {
|
|
|
|
score->undoRemoveElement(n->tieBack());
|
|
|
|
if (n->tieFor())
|
|
|
|
score->undoRemoveElement(n->tieFor());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Note* nn = n;
|
|
|
|
while (nn->tieFor()) {
|
|
|
|
nn = nn->tieFor()->endNote();
|
|
|
|
score->undo(new ChangePitch(nn, pitch, tpc, nn->line()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// recalculate needed accidentals for
|
|
|
|
// whole measure
|
|
|
|
//
|
|
|
|
score->updateAccidentals(chord->measure(), staffIdx);
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// changeAccidental
|
|
|
|
/// Change accidental to subtype \accidental for
|
|
|
|
/// note \a note.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-10-01 20:03:31 +02:00
|
|
|
void Score::changeAccidental(Note* note, Accidental::AccidentalType accidental)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QList<Staff*> staffList;
|
|
|
|
Staff* ostaff = note->chord()->staff();
|
|
|
|
LinkedStaves* linkedStaves = ostaff->linkedStaves();
|
|
|
|
if (linkedStaves)
|
|
|
|
staffList = linkedStaves->staves();
|
|
|
|
else
|
|
|
|
staffList.append(ostaff);
|
|
|
|
|
|
|
|
Chord* chord = note->chord();
|
|
|
|
Segment* segment = chord->segment();
|
|
|
|
Measure* measure = segment->measure();
|
|
|
|
int tick = segment->tick();
|
|
|
|
Staff* estaff = staff(chord->staffIdx() + chord->staffMove());
|
2013-09-05 16:37:49 +02:00
|
|
|
ClefType clef = estaff->clef(tick);
|
|
|
|
int step = ClefInfo::pitchOffset(clef) - note->line();
|
2012-05-26 14:26:10 +02:00
|
|
|
while (step < 0)
|
|
|
|
step += 7;
|
|
|
|
step %= 7;
|
|
|
|
//
|
|
|
|
// accidental change may result in pitch change
|
|
|
|
//
|
2012-08-08 20:46:29 +02:00
|
|
|
AccidentalVal acc = Accidental::subtype2value(accidental);
|
|
|
|
AccidentalVal acc2 = measure->findAccidental(note);
|
2012-10-01 20:03:31 +02:00
|
|
|
Accidental::AccidentalType accType;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
int pitch, tpc;
|
2012-10-01 20:03:31 +02:00
|
|
|
if (accidental == Accidental::ACC_NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// delete accidentals
|
|
|
|
//
|
2012-10-01 20:03:31 +02:00
|
|
|
accType = Accidental::ACC_NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
pitch = line2pitch(note->line(), clef, 0) + acc2;
|
|
|
|
tpc = step2tpc(step, acc2);
|
|
|
|
// check if there's accidentals left, previously set as
|
|
|
|
// precautionary accidentals
|
2013-09-02 12:13:46 +02:00
|
|
|
Accidental* a = note->accidental();
|
|
|
|
if (a)
|
2012-05-26 14:26:10 +02:00
|
|
|
undoRemoveElement(note->accidental());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (acc2 == acc) {
|
|
|
|
//
|
|
|
|
// this is a precautionary accidental
|
|
|
|
//
|
|
|
|
accType = accidental;
|
|
|
|
pitch = line2pitch(note->line(), clef, 0) + Accidental::subtype2value(accType);
|
|
|
|
tpc = step2tpc(step, acc);
|
|
|
|
|
|
|
|
Accidental* a = new Accidental(this);
|
|
|
|
a->setParent(note);
|
2013-03-05 20:23:59 +01:00
|
|
|
a->setAccidentalType(accidental);
|
2012-10-01 20:03:31 +02:00
|
|
|
a->setRole(Accidental::ACC_USER);
|
2012-06-04 15:57:41 +02:00
|
|
|
undoAddElement(a);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
accType = accidental;
|
|
|
|
pitch = line2pitch(note->line(), clef, 0) + Accidental::subtype2value(accType);
|
|
|
|
tpc = step2tpc(step, acc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-02 12:13:46 +02:00
|
|
|
|
|
|
|
if (note->links()) {
|
|
|
|
for (Element* e : *note->links())
|
|
|
|
changeAccidental2(static_cast<Note*>(e), pitch, tpc);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-09-02 12:13:46 +02:00
|
|
|
else
|
|
|
|
changeAccidental2(note, pitch, tpc);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// addArticulation
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2013-02-21 14:28:16 +01:00
|
|
|
bool Score::addArticulation(Element* el, Articulation* a)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
ChordRest* cr;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el->type() == Element::NOTE)
|
2013-02-21 14:28:16 +01:00
|
|
|
cr = static_cast<ChordRest*>(static_cast<Note*>(el)->chord());
|
|
|
|
else if (el->type() == Element::REST
|
|
|
|
|| el->type() == Element::CHORD
|
|
|
|
|| el->type() == Element::REPEAT_MEASURE)
|
2012-05-26 14:26:10 +02:00
|
|
|
cr = static_cast<ChordRest*>(el);
|
2013-02-21 14:28:16 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
Articulation* oa = cr->hasArticulation(a);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (oa) {
|
|
|
|
undoRemoveElement(oa);
|
2013-02-21 14:28:16 +01:00
|
|
|
return false;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-02-21 14:28:16 +01:00
|
|
|
a->setParent(cr);
|
|
|
|
undoAddElement(a);
|
|
|
|
return true;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// resetUserStretch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::resetUserStretch()
|
|
|
|
{
|
|
|
|
Measure* m1;
|
|
|
|
Measure* m2;
|
|
|
|
// retrieve span of selection
|
|
|
|
Segment* s1 = _selection.startSegment();
|
|
|
|
Segment* s2 = _selection.endSegment();
|
|
|
|
// if either segment is not returned by the selection
|
|
|
|
// (for instance, no selection) fall back to first/last measure
|
|
|
|
if(!s1)
|
|
|
|
m1 = firstMeasure();
|
|
|
|
else
|
|
|
|
m1 = s1->measure();
|
|
|
|
if(!s2)
|
|
|
|
m2 = lastMeasure();
|
|
|
|
else
|
|
|
|
m2 = s2->measure();
|
|
|
|
if(!m1 || !m2) // should not happen!
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (Measure* m = m1; m; m = m->nextMeasure()) {
|
2013-03-18 15:14:05 +01:00
|
|
|
undo(new ChangeStretch(m, 1.0));
|
2012-05-26 14:26:10 +02:00
|
|
|
if (m == m2)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_layoutAll = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// moveUp
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::moveUp(Chord* chord)
|
|
|
|
{
|
|
|
|
int rstaff = chord->staff()->rstaff();
|
|
|
|
int staffMove = chord->staffMove();
|
|
|
|
|
|
|
|
if ((staffMove == -1) || (rstaff + staffMove <= 0))
|
|
|
|
return;
|
|
|
|
undo(new ChangeChordStaffMove(chord, staffMove - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// moveDown
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::moveDown(Chord* chord)
|
|
|
|
{
|
|
|
|
Staff* staff = chord->staff();
|
|
|
|
Part* part = staff->part();
|
|
|
|
int rstaff = staff->rstaff();
|
|
|
|
int rstaves = part->nstaves();
|
|
|
|
int staffMove = chord->staffMove();
|
|
|
|
|
|
|
|
if ((staffMove == 1) || (rstaff + staffMove >= rstaves - 1)) {
|
|
|
|
qDebug("moveDown staffMove==%d rstaff %d rstaves %d", staffMove, rstaff, rstaves);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
undo(new ChangeChordStaffMove(chord, staffMove + 1));
|
|
|
|
_layoutAll = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdAddStretch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdAddStretch(qreal val)
|
|
|
|
{
|
|
|
|
if (selection().state() != SEL_RANGE)
|
|
|
|
return;
|
|
|
|
int startTick = selection().tickStart();
|
|
|
|
int endTick = selection().tickEnd();
|
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
|
|
|
|
if (m->tick() < startTick)
|
|
|
|
continue;
|
|
|
|
if (m->tick() >= endTick)
|
|
|
|
break;
|
|
|
|
qreal stretch = m->userStretch();
|
|
|
|
stretch += val;
|
|
|
|
undo(new ChangeStretch(m, stretch));
|
|
|
|
}
|
|
|
|
_layoutAll = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdInsertClef
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdInsertClef(ClefType type)
|
|
|
|
{
|
|
|
|
if (!noteEntryMode())
|
|
|
|
return;
|
|
|
|
undoChangeClef(staff(inputTrack()/VOICES), inputState().segment(), type);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdResetBeamMode
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdResetBeamMode()
|
|
|
|
{
|
|
|
|
if (selection().state() != SEL_RANGE) {
|
|
|
|
qDebug("no system or staff selected");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int startTick = selection().tickStart();
|
|
|
|
int endTick = selection().tickEnd();
|
|
|
|
|
2013-06-12 14:23:57 +02:00
|
|
|
Segment::SegmentTypes st = Segment::SegChordRest;
|
2012-05-26 14:26:10 +02:00
|
|
|
for (Segment* seg = firstMeasure()->first(st); seg; seg = seg->next1(st)) {
|
|
|
|
if (seg->tick() < startTick)
|
|
|
|
continue;
|
|
|
|
if (seg->tick() >= endTick)
|
|
|
|
break;
|
|
|
|
for (int track = 0; track < nstaves() * VOICES; ++track) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(seg->element(track));
|
|
|
|
if (cr == 0)
|
|
|
|
continue;
|
2012-09-13 18:01:34 +02:00
|
|
|
if (cr->type() == Element::CHORD) {
|
2013-03-05 20:23:59 +01:00
|
|
|
if (cr->beamMode() != BeamMode::AUTO)
|
|
|
|
undoChangeProperty(cr, P_BEAM_MODE, int(BeamMode::AUTO));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (cr->type() == Element::REST) {
|
2013-03-26 23:11:24 +01:00
|
|
|
if (cr->beamMode() != BeamMode::NONE)
|
|
|
|
undoChangeProperty(cr, P_BEAM_MODE, int(BeamMode::NONE));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_layoutAll = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// processMidiInput
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
bool Score::processMidiInput()
|
|
|
|
{
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("processMidiInput");
|
|
|
|
if (midiInputQueue.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool cmdActive = false;
|
|
|
|
Note* n = 0;
|
|
|
|
while (!midiInputQueue.isEmpty()) {
|
|
|
|
MidiInputEvent ev = midiInputQueue.dequeue();
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("<-- !noteentry dequeue %i", ev.pitch);
|
|
|
|
if (!noteEntryMode()) {
|
|
|
|
int staffIdx = selection().staffStart();
|
|
|
|
Part* p;
|
|
|
|
if (staffIdx < 0 || staffIdx >= nstaves())
|
2012-11-04 09:49:08 +01:00
|
|
|
p = staff(0)->part();
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
p = staff(staffIdx)->part();
|
|
|
|
if (p)
|
2012-06-28 14:50:47 +02:00
|
|
|
MScore::seq->startNote(p->instr()->channel(0).channel, ev.pitch, 80,
|
2012-05-26 14:26:10 +02:00
|
|
|
MScore::defaultPlayDuration, 0.0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!cmdActive) {
|
|
|
|
startCmd();
|
|
|
|
cmdActive = true;
|
|
|
|
}
|
2013-01-10 00:34:35 +01:00
|
|
|
Note* n2 = addPitch(ev.pitch, ev.chord);
|
|
|
|
if (n2)
|
|
|
|
n = n2;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cmdActive) {
|
|
|
|
_layoutAll = true;
|
|
|
|
endCmd();
|
|
|
|
//after relayout
|
2013-01-17 20:42:44 +01:00
|
|
|
if (n) {
|
|
|
|
foreach(MuseScoreView* v, viewer)
|
|
|
|
v->adjustCanvasPosition(n, false);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// move
|
|
|
|
// move current selection
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Element* Score::move(const QString& cmd)
|
|
|
|
{
|
|
|
|
ChordRest* cr;
|
|
|
|
if (selection().activeCR())
|
|
|
|
cr = selection().activeCR();
|
|
|
|
else
|
|
|
|
cr = selection().lastChordRest();
|
2013-10-24 12:09:00 +02:00
|
|
|
if (cr == 0 && noteEntryMode())
|
2012-05-26 14:26:10 +02:00
|
|
|
cr = inputState().cr();
|
2012-12-27 22:07:16 +01:00
|
|
|
|
|
|
|
// no chord/rest found? look for another type of element
|
|
|
|
if (cr == 0) {
|
|
|
|
Element* el = 0;
|
|
|
|
Element* trg = 0;
|
|
|
|
// retrieve last element of section list
|
|
|
|
if (!selection().elements().isEmpty())
|
|
|
|
el = selection().elements().last();
|
2013-08-02 17:39:45 +02:00
|
|
|
if (!el) // no element, no party!
|
2012-12-27 22:07:16 +01:00
|
|
|
return 0;
|
|
|
|
// get parent of element and process accordingly:
|
|
|
|
// trg is the element to select on "next-chord" cmd
|
|
|
|
// cr is the ChordRest to move from on other cmd's
|
2012-12-28 15:18:52 +01:00
|
|
|
int track = el->track(); // keep note of element track
|
2012-12-27 22:07:16 +01:00
|
|
|
el = el->parent();
|
|
|
|
switch (el->type()) {
|
|
|
|
case Element::NOTE: // a note is a valid target
|
|
|
|
trg = el;
|
|
|
|
cr = static_cast<Note*>(el)->chord();
|
|
|
|
break;
|
|
|
|
case Element::CHORD: // a chord or a rest are valid targets
|
|
|
|
case Element::REST:
|
|
|
|
trg = el;
|
|
|
|
cr = static_cast<ChordRest*>(trg);
|
|
|
|
break;
|
|
|
|
case Element::SEGMENT: { // from segment go to top chordrest in segment
|
|
|
|
Segment* seg = static_cast<Segment*>(el);
|
|
|
|
// if segment is not chord/rest or grace, move to next chord/rest or grace segment
|
2013-06-12 14:23:57 +02:00
|
|
|
if (!seg->isChordRest()) {
|
|
|
|
seg = seg->next1(Segment::SegChordRest);
|
2012-12-27 22:07:16 +01:00
|
|
|
if (seg == 0) // if none found, reutrn failure
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-28 15:18:52 +01:00
|
|
|
// segment for sure contains chords/rests,
|
2012-12-27 22:07:16 +01:00
|
|
|
int size = seg->elist().size();
|
2012-12-28 15:18:52 +01:00
|
|
|
// if segment has a chord/rest in original element track, use it
|
|
|
|
if(track > -1 && track < size && seg->element(track)) {
|
|
|
|
trg = seg->element(track);
|
|
|
|
cr = static_cast<ChordRest*>(trg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// if not, get topmost chord/rest
|
2012-12-27 22:07:16 +01:00
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
if (seg->element(i)) {
|
|
|
|
trg = seg->element(i);
|
|
|
|
cr = static_cast<ChordRest*>(trg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: // on anything else, return failure
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if something found and command is forward, the element found is the destination
|
|
|
|
if (trg && cmd == "next-chord") {
|
|
|
|
// if chord, go to topmost note
|
|
|
|
if (trg->type() == Element::CHORD)
|
|
|
|
trg = static_cast<Chord*>(trg)->upNote();
|
|
|
|
_playNote = true;
|
|
|
|
select(trg, SELECT_SINGLE, 0);
|
|
|
|
return trg;
|
|
|
|
}
|
|
|
|
// if no chordrest found, do nothing
|
2013-08-02 17:39:45 +02:00
|
|
|
if (cr == 0)
|
2012-12-27 22:07:16 +01:00
|
|
|
return 0;
|
|
|
|
// if some chordrest found, continue with default processing
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
Element* el = 0;
|
|
|
|
if (cmd == "next-chord") {
|
|
|
|
if (noteEntryMode())
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.moveToNextInputPos();
|
2013-06-12 14:23:57 +02:00
|
|
|
el = nextChordRest(cr);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else if (cmd == "prev-chord") {
|
|
|
|
if (noteEntryMode()) {
|
|
|
|
Segment* s = _is.segment()->prev1();
|
|
|
|
//
|
|
|
|
// if _is._segment is first chord/rest segment in measure
|
|
|
|
// make sure "m" points to previous measure
|
|
|
|
//
|
2013-03-05 20:23:59 +01:00
|
|
|
while (s && s->segmentType() != Segment::SegChordRest)
|
2012-05-26 14:26:10 +02:00
|
|
|
s = s->prev1();
|
|
|
|
if (s == 0)
|
|
|
|
return 0;
|
|
|
|
Measure* m = s->measure();
|
|
|
|
|
|
|
|
int track = _is.track();
|
|
|
|
for (; s; s = s->prev1()) {
|
2013-03-05 20:23:59 +01:00
|
|
|
if (s->segmentType() != Segment::SegChordRest)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
if (s->element(track) || s->measure() != m)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (s && !s->element(track))
|
2013-06-28 17:46:24 +02:00
|
|
|
s = m->first(Segment::SegChordRest);
|
2013-10-24 12:09:00 +02:00
|
|
|
_is.moveInputPos(s);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-06-12 14:23:57 +02:00
|
|
|
el = prevChordRest(cr);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-11-23 15:22:16 +01:00
|
|
|
else if (cmd == "next-measure") {
|
2012-05-26 14:26:10 +02:00
|
|
|
el = nextMeasure(cr);
|
2013-10-24 12:09:00 +02:00
|
|
|
if (noteEntryMode())
|
|
|
|
_is.moveInputPos(el);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2012-11-23 15:22:16 +01:00
|
|
|
else if (cmd == "prev-measure") {
|
2012-05-26 14:26:10 +02:00
|
|
|
el = prevMeasure(cr);
|
2013-10-24 12:09:00 +02:00
|
|
|
if (noteEntryMode())
|
|
|
|
_is.moveInputPos(el);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-08-02 23:45:45 +02:00
|
|
|
else if (cmd == "next-track") {
|
|
|
|
el = nextTrack(cr);
|
2013-10-24 12:09:00 +02:00
|
|
|
if (noteEntryMode())
|
|
|
|
_is.moveInputPos(el);
|
2013-08-02 23:45:45 +02:00
|
|
|
}
|
|
|
|
else if (cmd == "prev-track") {
|
|
|
|
el = prevTrack(cr);
|
2013-10-24 12:09:00 +02:00
|
|
|
if (noteEntryMode())
|
|
|
|
_is.moveInputPos(el);
|
2013-08-02 23:45:45 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (el) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el->type() == Element::CHORD)
|
2013-08-02 23:45:45 +02:00
|
|
|
el = static_cast<Chord*>(el)->upNote(); // originally downNote
|
2012-05-26 14:26:10 +02:00
|
|
|
_playNote = true;
|
|
|
|
select(el, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// selectMove
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Element* Score::selectMove(const QString& cmd)
|
|
|
|
{
|
|
|
|
ChordRest* cr;
|
|
|
|
if (selection().activeCR())
|
|
|
|
cr = selection().activeCR();
|
|
|
|
else
|
|
|
|
cr = selection().lastChordRest();
|
2013-10-24 12:09:00 +02:00
|
|
|
if (cr == 0 && noteEntryMode())
|
2012-05-26 14:26:10 +02:00
|
|
|
cr = inputState().cr();
|
|
|
|
if (cr == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ChordRest* el = 0;
|
|
|
|
if (cmd == "select-next-chord")
|
|
|
|
el = nextChordRest(cr);
|
|
|
|
else if (cmd == "select-prev-chord")
|
|
|
|
el = prevChordRest(cr);
|
|
|
|
else if (cmd == "select-next-measure")
|
|
|
|
el = nextMeasure(cr, true);
|
|
|
|
else if (cmd == "select-prev-measure")
|
|
|
|
el = prevMeasure(cr);
|
|
|
|
else if (cmd == "select-begin-line") {
|
|
|
|
Measure* measure = cr->segment()->measure()->system()->firstMeasure();
|
|
|
|
if (!measure)
|
|
|
|
return 0;
|
|
|
|
el = measure->first()->nextChordRest(cr->track());
|
|
|
|
}
|
|
|
|
else if (cmd == "select-end-line") {
|
|
|
|
Measure* measure = cr->segment()->measure()->system()->lastMeasure();
|
|
|
|
if (!measure)
|
|
|
|
return 0;
|
|
|
|
el = measure->last()->nextChordRest(cr->track(), true);
|
|
|
|
}
|
|
|
|
else if (cmd == "select-begin-score") {
|
|
|
|
Measure* measure = first()->system()->firstMeasure();
|
|
|
|
if (!measure)
|
|
|
|
return 0;
|
|
|
|
el = measure->first()->nextChordRest(cr->track());
|
|
|
|
}
|
|
|
|
else if (cmd == "select-end-score") {
|
|
|
|
Measure* measure = last()->system()->lastMeasure();
|
|
|
|
if (!measure)
|
|
|
|
return 0;
|
|
|
|
el = measure->last()->nextChordRest(cr->track(), true);
|
|
|
|
}
|
|
|
|
else if (cmd == "select-staff-above")
|
|
|
|
el = upStaff(cr);
|
|
|
|
else if (cmd == "select-staff-below")
|
|
|
|
el = downStaff(cr);
|
|
|
|
if (el)
|
|
|
|
select(el, SELECT_RANGE, el->staffIdx());
|
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdMirrorNoteHead
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdMirrorNoteHead()
|
|
|
|
{
|
|
|
|
const QList<Element*>& el = selection().elements();
|
|
|
|
foreach(Element* e, el) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Note* note = static_cast<Note*>(e);
|
2012-08-16 11:09:36 +02:00
|
|
|
if (note->staff() && note->staff()->isTabStaff())
|
2012-05-26 14:26:10 +02:00
|
|
|
note->score()->undoChangeProperty(e, P_GHOST, true);
|
|
|
|
else {
|
2012-08-04 15:46:43 +02:00
|
|
|
MScore::DirectionH d = note->userMirror();
|
|
|
|
if (d == MScore::DH_AUTO)
|
|
|
|
d = note->chord()->up() ? MScore::DH_RIGHT : MScore::DH_LEFT;
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2012-08-04 15:46:43 +02:00
|
|
|
d = d == MScore::DH_LEFT ? MScore::DH_RIGHT : MScore::DH_LEFT;
|
2012-05-26 14:26:10 +02:00
|
|
|
undoChangeUserMirror(note, d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdHalfDuration
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdHalfDuration()
|
|
|
|
{
|
|
|
|
Element* el = selection().element();
|
|
|
|
if (el == 0)
|
|
|
|
return;
|
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);
|
|
|
|
TDuration d = _is.duration().shift(1);
|
|
|
|
if (!d.isValid() || (d.type() > TDuration::V_64TH))
|
|
|
|
return;
|
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
|
|
|
|
//
|
|
|
|
cr->setDurationType(d);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
changeCRlen(cr, d);
|
|
|
|
_is.setDuration(d);
|
|
|
|
nextInputPos(cr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdDoubleDuration
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmdDoubleDuration()
|
|
|
|
{
|
|
|
|
Element* el = selection().element();
|
|
|
|
if (el == 0)
|
|
|
|
return;
|
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);
|
|
|
|
TDuration d = _is.duration().shift(-1);
|
|
|
|
if (!d.isValid() || (d.type() < TDuration::V_WHOLE))
|
|
|
|
return;
|
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
|
|
|
|
//
|
|
|
|
cr->setDurationType(d);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
changeCRlen(cr, d);
|
|
|
|
_is.setDuration(d);
|
|
|
|
nextInputPos(cr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdMoveRest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-08-04 15:46:43 +02:00
|
|
|
void Score::cmdMoveRest(Rest* rest, MScore::Direction dir)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QPointF pos(rest->userOff());
|
2012-08-04 15:46:43 +02:00
|
|
|
if (dir == MScore::UP)
|
2012-05-26 14:26:10 +02:00
|
|
|
pos.ry() -= spatium();
|
2012-08-04 15:46:43 +02:00
|
|
|
else if (dir == MScore::DOWN)
|
2012-05-26 14:26:10 +02:00
|
|
|
pos.ry() += spatium();
|
2012-08-23 17:40:04 +02:00
|
|
|
undoChangeProperty(rest, P_USER_OFF, pos);
|
2012-05-26 14:26:10 +02:00
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmdMoveLyrics
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-08-04 15:46:43 +02:00
|
|
|
void Score::cmdMoveLyrics(Lyrics* lyrics, MScore::Direction dir)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
ChordRest* cr = lyrics->chordRest();
|
|
|
|
QList<Lyrics*>& ll = cr->lyricsList();
|
|
|
|
int no = lyrics->no();
|
2012-08-04 15:46:43 +02:00
|
|
|
if (dir == MScore::UP) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (no) {
|
|
|
|
if (ll[no-1] == 0) {
|
|
|
|
ll[no-1] = ll[no];
|
|
|
|
ll[no] = 0;
|
|
|
|
lyrics->setNo(no-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (no == ll.size()-1) {
|
|
|
|
ll.append(ll[no]);
|
|
|
|
ll[no] = 0;
|
|
|
|
lyrics->setNo(no+1);
|
|
|
|
}
|
|
|
|
else if (ll[no + 1] == 0) {
|
|
|
|
ll[no+1] = ll[no];
|
|
|
|
ll[no] = 0;
|
|
|
|
lyrics->setNo(no+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// cmd
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::cmd(const QAction* a)
|
|
|
|
{
|
|
|
|
QString cmd(a ? a->data().toString() : "");
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("Score::cmd <%s>", qPrintable(cmd));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Hack for moving articulations while selected
|
|
|
|
//
|
|
|
|
Element* el = selection().element();
|
2013-04-04 00:12:37 +02:00
|
|
|
if (cmd == "pitch-up") {
|
2013-08-26 14:45:01 +02:00
|
|
|
if (el && (el->type() == Element::ARTICULATION || el->isText()))
|
2012-05-26 14:26:10 +02:00
|
|
|
undoMove(el, el->userOff() + QPointF(0.0, -MScore::nudgeStep * el->spatium()));
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (el && el->type() == Element::REST)
|
2012-08-04 15:46:43 +02:00
|
|
|
cmdMoveRest(static_cast<Rest*>(el), MScore::UP);
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (el && el->type() == Element::LYRICS)
|
2012-08-04 15:46:43 +02:00
|
|
|
cmdMoveLyrics(static_cast<Lyrics*>(el), MScore::UP);
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
upDown(true, UP_DOWN_CHROMATIC);
|
|
|
|
}
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pitch-down") {
|
2013-08-26 14:45:01 +02:00
|
|
|
if (el && (el->type() == Element::ARTICULATION || el->isText()))
|
2012-05-26 14:26:10 +02:00
|
|
|
undoMove(el, el->userOff() + QPointF(0.0, MScore::nudgeStep * el->spatium()));
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (el && el->type() == Element::REST)
|
2012-08-04 15:46:43 +02:00
|
|
|
cmdMoveRest(static_cast<Rest*>(el), MScore::DOWN);
|
2012-09-13 18:01:34 +02:00
|
|
|
else if (el && el->type() == Element::LYRICS)
|
2012-08-04 15:46:43 +02:00
|
|
|
cmdMoveLyrics(static_cast<Lyrics*>(el), MScore::DOWN);
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
upDown(false, UP_DOWN_CHROMATIC);
|
|
|
|
}
|
|
|
|
else if (cmd == "add-staccato")
|
|
|
|
addArticulation(Articulation_Staccato);
|
|
|
|
else if (cmd == "add-tenuto")
|
|
|
|
addArticulation(Articulation_Tenuto);
|
2012-09-05 11:49:48 +02:00
|
|
|
else if (cmd == "add-marcato")
|
2012-06-04 15:57:41 +02:00
|
|
|
addArticulation(Articulation_Marcato);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "add-trill")
|
|
|
|
addArticulation(Articulation_Trill);
|
|
|
|
else if (cmd == "add-hairpin")
|
|
|
|
cmdAddHairpin(false);
|
|
|
|
else if (cmd == "add-hairpin-reverse")
|
|
|
|
cmdAddHairpin(true);
|
2013-08-12 10:37:30 +02:00
|
|
|
else if (cmd == "add-8va")
|
|
|
|
cmdAddOttava(OttavaType::OTTAVA_8VA);
|
|
|
|
else if (cmd == "add-8vb")
|
|
|
|
cmdAddOttava(OttavaType::OTTAVA_8VB);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "delete-measures")
|
|
|
|
cmdDeleteSelectedMeasures();
|
|
|
|
else if (cmd == "time-delete") {
|
|
|
|
// TODO:
|
|
|
|
// remove measures if stave-range is 0-nstaves()
|
|
|
|
cmdDeleteSelectedMeasures();
|
|
|
|
}
|
2013-08-26 14:45:01 +02:00
|
|
|
else if (cmd == "pitch-up-octave") {
|
|
|
|
if (el && (el->type() == Element::ARTICULATION || el->isText()))
|
|
|
|
undoMove(el, el->userOff() + QPointF(0.0, -MScore::nudgeStep10 * el->spatium()));
|
|
|
|
else
|
|
|
|
upDown(true, UP_DOWN_OCTAVE);
|
|
|
|
}
|
|
|
|
else if (cmd == "pitch-down-octave") {
|
|
|
|
if (el && (el->type() == Element::ARTICULATION || el->isText()))
|
|
|
|
undoMove(el, el->userOff() + QPointF(0.0, MScore::nudgeStep10 * el->spatium()));
|
|
|
|
else
|
|
|
|
upDown(false, UP_DOWN_OCTAVE);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "pitch-up-diatonic")
|
|
|
|
upDown(true, UP_DOWN_DIATONIC);
|
|
|
|
else if (cmd == "pitch-down-diatonic")
|
|
|
|
upDown(false, UP_DOWN_DIATONIC);
|
|
|
|
else if (cmd == "move-up") {
|
|
|
|
setLayoutAll(false);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && el->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Note* note = static_cast<Note*>(el);
|
|
|
|
moveUp(note->chord());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmd == "move-down") {
|
|
|
|
setLayoutAll(false);
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && el->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Note* note = static_cast<Note*>(el);
|
|
|
|
moveDown(note->chord());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmd == "up-chord") {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && (el->type() == Element::NOTE || el->type() == Element::REST)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = upAlt(el);
|
|
|
|
if (e) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_playNote = true;
|
|
|
|
}
|
|
|
|
select(e, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
|
|
|
else if (cmd == "down-chord") {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && (el->type() == Element::NOTE || el->type() == Element::REST)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = downAlt(el);
|
|
|
|
if (e) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_playNote = true;
|
|
|
|
}
|
|
|
|
select(e, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
|
|
|
else if (cmd == "top-chord" ) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && el->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = upAltCtrl(static_cast<Note*>(el));
|
|
|
|
if (e) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_playNote = true;
|
|
|
|
}
|
|
|
|
select(e, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
|
|
|
else if (cmd == "bottom-chord") {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (el && el->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Element* e = downAltCtrl(static_cast<Note*>(el));
|
|
|
|
if (e) {
|
2012-09-13 18:01:34 +02:00
|
|
|
if (e->type() == Element::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
_playNote = true;
|
|
|
|
}
|
|
|
|
select(e, SELECT_SINGLE, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
2013-04-14 21:27:56 +02:00
|
|
|
else if (cmd == "note-longa" || cmd == "note-longa-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE00);
|
2013-04-14 21:27:56 +02:00
|
|
|
else if (cmd == "note-breve" || cmd == "note-breve-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE0);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-1" || cmd == "pad-note-1-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE1);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-2" || cmd == "pad-note-2-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE2);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-4" || cmd == "pad-note-4-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE4);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-8" || cmd == "pad-note-8-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE8);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-16" || cmd == "pad-note-16-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE16);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-32" || cmd == "pad-note-32-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE32);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-64" || cmd == "pad-note-64-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE64);
|
2013-04-04 00:12:37 +02:00
|
|
|
else if (cmd == "pad-note-128" || cmd == "pad-note-128-TAB")
|
2012-05-26 14:26:10 +02:00
|
|
|
padToggle(PAD_NOTE128);
|
2013-04-14 21:27:56 +02:00
|
|
|
else if (cmd == "pad-note-increase-TAB") {
|
2013-03-28 11:54:39 +01:00
|
|
|
switch (_is.duration().type() ) {
|
|
|
|
// cycle back from longest to shortest?
|
|
|
|
// case TDuration::V_LONG:
|
|
|
|
// padToggle(PAD_NOTE128);
|
|
|
|
// break;
|
|
|
|
case TDuration::V_BREVE:
|
|
|
|
padToggle(PAD_NOTE00);
|
|
|
|
break;
|
|
|
|
case TDuration::V_WHOLE:
|
|
|
|
padToggle(PAD_NOTE0);
|
|
|
|
break;
|
|
|
|
case TDuration::V_HALF:
|
|
|
|
padToggle(PAD_NOTE1);
|
|
|
|
break;
|
|
|
|
case TDuration::V_QUARTER:
|
|
|
|
padToggle(PAD_NOTE2);
|
|
|
|
break;
|
|
|
|
case TDuration::V_EIGHT:
|
|
|
|
padToggle(PAD_NOTE4);
|
|
|
|
break;
|
|
|
|
case TDuration::V_16TH:
|
|
|
|
padToggle(PAD_NOTE8);
|
|
|
|
break;
|
|
|
|
case TDuration::V_32ND:
|
|
|
|
padToggle(PAD_NOTE16);
|
|
|
|
break;
|
|
|
|
case TDuration::V_64TH:
|
|
|
|
padToggle(PAD_NOTE32);
|
|
|
|
break;
|
|
|
|
case TDuration::V_128TH:
|
|
|
|
padToggle(PAD_NOTE64);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-04-14 21:27:56 +02:00
|
|
|
else if (cmd == "pad-note-decrease-TAB") {
|
2013-03-28 11:54:39 +01:00
|
|
|
switch (_is.duration().type() ) {
|
|
|
|
case TDuration::V_LONG:
|
|
|
|
padToggle(PAD_NOTE0);
|
|
|
|
break;
|
|
|
|
case TDuration::V_BREVE:
|
|
|
|
padToggle(PAD_NOTE1);
|
|
|
|
break;
|
|
|
|
case TDuration::V_WHOLE:
|
|
|
|
padToggle(PAD_NOTE2);
|
|
|
|
break;
|
|
|
|
case TDuration::V_HALF:
|
|
|
|
padToggle(PAD_NOTE4);
|
|
|
|
break;
|
|
|
|
case TDuration::V_QUARTER:
|
|
|
|
padToggle(PAD_NOTE8);
|
|
|
|
break;
|
|
|
|
case TDuration::V_EIGHT:
|
|
|
|
padToggle(PAD_NOTE16);
|
|
|
|
break;
|
|
|
|
case TDuration::V_16TH:
|
|
|
|
padToggle(PAD_NOTE32);
|
|
|
|
break;
|
|
|
|
case TDuration::V_32ND:
|
|
|
|
padToggle(PAD_NOTE64);
|
|
|
|
break;
|
|
|
|
case TDuration::V_64TH:
|
|
|
|
padToggle(PAD_NOTE128);
|
|
|
|
break;
|
|
|
|
// cycle back from shortest to longest?
|
|
|
|
// case TDuration::V_128TH:
|
|
|
|
// padToggle(PAD_NOTE00);
|
|
|
|
// break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "pad-rest")
|
|
|
|
padToggle(PAD_REST);
|
|
|
|
else if (cmd == "pad-dot")
|
|
|
|
padToggle(PAD_DOT);
|
|
|
|
else if (cmd == "pad-dotdot")
|
|
|
|
padToggle(PAD_DOTDOT);
|
|
|
|
else if (cmd == "beam-start")
|
2013-03-05 20:23:59 +01:00
|
|
|
cmdSetBeamMode(BeamMode::BEGIN);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "beam-mid")
|
2013-03-05 20:23:59 +01:00
|
|
|
cmdSetBeamMode(BeamMode::MID);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "no-beam")
|
2013-03-26 23:11:24 +01:00
|
|
|
cmdSetBeamMode(BeamMode::NONE);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "beam-32")
|
2013-03-05 20:23:59 +01:00
|
|
|
cmdSetBeamMode(BeamMode::BEGIN32);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "sharp2")
|
2012-10-01 20:03:31 +02:00
|
|
|
changeAccidental(Accidental::ACC_SHARP2);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "sharp")
|
2012-10-01 20:03:31 +02:00
|
|
|
changeAccidental(Accidental::ACC_SHARP);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "nat")
|
2012-10-01 20:03:31 +02:00
|
|
|
changeAccidental(Accidental::ACC_NATURAL);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "flat")
|
2012-10-01 20:03:31 +02:00
|
|
|
changeAccidental(Accidental::ACC_FLAT);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "flat2")
|
2012-10-01 20:03:31 +02:00
|
|
|
changeAccidental(Accidental::ACC_FLAT2);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "repitch")
|
|
|
|
_is.setRepitchMode(a->isChecked());
|
|
|
|
else if (cmd == "flip")
|
|
|
|
cmdFlip();
|
|
|
|
else if (cmd == "stretch+")
|
|
|
|
cmdAddStretch(0.1);
|
|
|
|
else if (cmd == "stretch-")
|
|
|
|
cmdAddStretch(-0.1);
|
|
|
|
else if (cmd == "pitch-spell")
|
|
|
|
spell();
|
|
|
|
else if (cmd == "select-all")
|
|
|
|
cmdSelectAll();
|
|
|
|
else if (cmd == "select-section")
|
|
|
|
cmdSelectSection();
|
|
|
|
else if (cmd == "concert-pitch") {
|
|
|
|
if (styleB(ST_concertPitch) != a->isChecked())
|
|
|
|
cmdConcertPitchChanged(a->isChecked(), true);
|
|
|
|
}
|
|
|
|
else if (cmd == "reset-beammode")
|
|
|
|
cmdResetBeamMode();
|
|
|
|
else if (cmd == "clef-violin")
|
2013-09-05 16:37:49 +02:00
|
|
|
cmdInsertClef(ClefType::G);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "clef-bass")
|
2013-09-05 16:37:49 +02:00
|
|
|
cmdInsertClef(ClefType::F);
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "voice-x12")
|
|
|
|
cmdExchangeVoice(0, 1);
|
|
|
|
else if (cmd == "voice-x13")
|
|
|
|
cmdExchangeVoice(0, 2);
|
|
|
|
else if (cmd == "voice-x14")
|
|
|
|
cmdExchangeVoice(0, 3);
|
|
|
|
else if (cmd == "voice-x23")
|
|
|
|
cmdExchangeVoice(1, 2);
|
|
|
|
else if (cmd == "voice-x24")
|
|
|
|
cmdExchangeVoice(1, 3);
|
|
|
|
else if (cmd == "voice-x34")
|
|
|
|
cmdExchangeVoice(2, 3);
|
|
|
|
else if (cmd == "system-break" || cmd == "page-break" || cmd == "section-break") {
|
2013-10-05 23:13:33 +02:00
|
|
|
LayoutBreak::LayoutBreakType type;
|
2012-05-26 14:26:10 +02:00
|
|
|
if (cmd == "system-break")
|
2013-10-05 23:13:33 +02:00
|
|
|
type = LayoutBreak::LINE;
|
2012-05-26 14:26:10 +02:00
|
|
|
else if (cmd == "page-break")
|
2013-10-05 23:13:33 +02:00
|
|
|
type = LayoutBreak::PAGE;
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
2013-10-05 23:13:33 +02:00
|
|
|
type = LayoutBreak::SECTION;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-10-29 14:34:02 +01:00
|
|
|
if (el && el->type() == Element::BAR_LINE && el->parent()->type() == Element::SEGMENT) {
|
|
|
|
Measure* measure = static_cast<Measure*>(el->parent()->parent());
|
2013-09-27 18:43:25 +02:00
|
|
|
if (measure->isMMRest()) {
|
|
|
|
// if measure is mm rest, then propagate to last original measure
|
|
|
|
measure = measure->nextMeasure();
|
|
|
|
if (measure)
|
|
|
|
measure = measure->prevMeasure();
|
|
|
|
}
|
|
|
|
if (measure)
|
|
|
|
measure->undoSetBreak(!measure->lineBreak(), type);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (cmd == "reset-stretch")
|
|
|
|
resetUserStretch();
|
|
|
|
else if (cmd == "mirror-note")
|
|
|
|
cmdMirrorNoteHead();
|
|
|
|
else if (cmd == "double-duration")
|
|
|
|
cmdDoubleDuration();
|
|
|
|
else if (cmd == "half-duration")
|
|
|
|
cmdHalfDuration();
|
|
|
|
else if (cmd == "") { //Midi note received only?
|
|
|
|
if (!noteEntryMode())
|
|
|
|
setLayoutAll(false);
|
|
|
|
}
|
|
|
|
else if (cmd == "add-audio")
|
|
|
|
addAudioTrack();
|
|
|
|
else if (cmd == "transpose-up")
|
|
|
|
transposeSemitone(1);
|
|
|
|
else if (cmd == "transpose-down")
|
|
|
|
transposeSemitone(-1);
|
2013-09-28 11:24:00 +02:00
|
|
|
else if (cmd == "toggle-mmrest") {
|
|
|
|
bool val = !styleB(ST_createMultiMeasureRests);
|
|
|
|
undo(new ChangeStyleVal(this, ST_createMultiMeasureRests, val));
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
else
|
|
|
|
qDebug("1unknown cmd <%s>", qPrintable(cmd));
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
|
|
|
|