1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2013 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 /**
14 \file
15 Handling of several GUI commands.
16 */
17
18 #include <assert.h>
19
20 #include "types.h"
21 #include "musescoreCore.h"
22 #include "score.h"
23 #include "utils.h"
24 #include "key.h"
25 #include "clef.h"
26 #include "navigate.h"
27 #include "slur.h"
28 #include "tie.h"
29 #include "note.h"
30 #include "rest.h"
31 #include "chord.h"
32 #include "text.h"
33 #include "sig.h"
34 #include "staff.h"
35 #include "part.h"
36 #include "style.h"
37 #include "page.h"
38 #include "barline.h"
39 #include "tuplet.h"
40 #include "xml.h"
41 #include "ottava.h"
42 #include "trill.h"
43 #include "pedal.h"
44 #include "hairpin.h"
45 #include "textline.h"
46 #include "keysig.h"
47 #include "volta.h"
48 #include "dynamic.h"
49 #include "box.h"
50 #include "harmony.h"
51 #include "system.h"
52 #include "stafftext.h"
53 #include "articulation.h"
54 #include "layoutbreak.h"
55 #include "drumset.h"
56 #include "beam.h"
57 #include "lyrics.h"
58 #include "pitchspelling.h"
59 #include "measure.h"
60 #include "tempo.h"
61 #include "undo.h"
62 #include "timesig.h"
63 #include "repeat.h"
64 #include "tempotext.h"
65 #include "noteevent.h"
66 #include "breath.h"
67 #include "stringdata.h"
68 #include "stafftype.h"
69 #include "segment.h"
70 #include "chordlist.h"
71 #include "mscore.h"
72 #include "accidental.h"
73 #include "sequencer.h"
74 #include "tremolo.h"
75 #include "rehearsalmark.h"
76 #include "sym.h"
77
78 namespace Ms {
79
80 //---------------------------------------------------------
81 // reset
82 //---------------------------------------------------------
83
reset()84 void CmdState::reset()
85 {
86 layoutFlags = LayoutFlag::NO_FLAGS;
87 _updateMode = UpdateMode::DoNothing;
88 _startTick = Fraction(-1,1);
89 _endTick = Fraction(-1,1);
90
91 _startStaff = -1;
92 _endStaff = -1;
93 _el = nullptr;
94 _oneElement = true;
95 _mb = nullptr;
96 _oneMeasureBase = true;
97 _locked = false;
98 }
99
100 //---------------------------------------------------------
101 // setTick
102 //---------------------------------------------------------
103
setTick(const Fraction & t)104 void CmdState::setTick(const Fraction& t)
105 {
106 if (_locked)
107 return;
108
109 if (_startTick == Fraction(-1,1) || t < _startTick)
110 _startTick = t;
111 if (_endTick == Fraction(-1,1) || t > _endTick)
112 _endTick = t;
113 setUpdateMode(UpdateMode::Layout);
114 }
115
116 //---------------------------------------------------------
117 // setStaff
118 //---------------------------------------------------------
119
setStaff(int st)120 void CmdState::setStaff(int st)
121 {
122 Q_ASSERT(st > -2);
123 if (_locked || st == -1)
124 return;
125
126 if (_startStaff == -1 || st < _startStaff)
127 _startStaff = st;
128 if (_endStaff == -1 || st > _endStaff)
129 _endStaff = st;
130 }
131
132 //---------------------------------------------------------
133 // setMeasureBase
134 //---------------------------------------------------------
135
setMeasureBase(const MeasureBase * mb)136 void CmdState::setMeasureBase(const MeasureBase* mb)
137 {
138 if (!mb || _mb == mb || _locked)
139 return;
140
141 _oneMeasureBase = !_mb;
142 _mb = mb;
143 }
144
145 //---------------------------------------------------------
146 // setElement
147 //---------------------------------------------------------
148
setElement(const Element * e)149 void CmdState::setElement(const Element* e)
150 {
151 if (!e || _el == e || _locked)
152 return;
153
154 _oneElement = !_el;
155 _el = e;
156
157 if (_oneMeasureBase)
158 setMeasureBase(e->findMeasureBase());
159 }
160
161 //---------------------------------------------------------
162 // unsetElement
163 //---------------------------------------------------------
164
unsetElement(const Element * e)165 void CmdState::unsetElement(const Element* e)
166 {
167 if (_el == e)
168 _el = nullptr;
169 if (_mb == e)
170 _mb = nullptr;
171 }
172
173 //---------------------------------------------------------
174 // element
175 //---------------------------------------------------------
176
element() const177 const Element* CmdState::element() const
178 {
179 if (_oneElement)
180 return _el;
181 if (_oneMeasureBase)
182 return _mb;
183 return nullptr;
184 }
185
186 //---------------------------------------------------------
187 // setUpdateMode
188 //---------------------------------------------------------
189
_setUpdateMode(UpdateMode m)190 void CmdState::_setUpdateMode(UpdateMode m)
191 {
192 _updateMode = m;
193 }
194
setUpdateMode(UpdateMode m)195 void CmdState::setUpdateMode(UpdateMode m)
196 {
197 if (int(m) > int(_updateMode))
198 _setUpdateMode(m);
199 }
200
201 //---------------------------------------------------------
202 // startCmd
203 /// Start a GUI command by clearing the redraw area
204 /// and starting a user-visible undo.
205 //---------------------------------------------------------
206
startCmd()207 void Score::startCmd()
208 {
209 if (MScore::debugMode)
210 qDebug("===startCmd()");
211
212 cmdState().reset();
213
214 // Start collecting low-level undo operations for a
215 // user-visible undo action.
216 if (undoStack()->active()) {
217 qDebug("Score::startCmd(): cmd already active");
218 return;
219 }
220 undoStack()->beginMacro(this);
221 }
222
223 //---------------------------------------------------------
224 // undoRedo
225 //---------------------------------------------------------
226
undoRedo(bool undo,EditData * ed)227 void Score::undoRedo(bool undo, EditData* ed)
228 {
229 if (readOnly())
230 return;
231 cmdState().reset();
232 if (undo)
233 undoStack()->undo(ed);
234 else
235 undoStack()->redo(ed);
236 update(false);
237 masterScore()->setPlaylistDirty(); // TODO: flag all individual operations
238 updateSelection();
239 }
240
241 //---------------------------------------------------------
242 // endCmd
243 /// End a GUI command by (if \a undo) ending a user-visble undo
244 /// and (always) updating the redraw area.
245 //---------------------------------------------------------
246
endCmd(bool rollback)247 void Score::endCmd(bool rollback)
248 {
249 if (!undoStack()->active()) {
250 qDebug("Score::endCmd(): no cmd active");
251 update();
252 return;
253 }
254 if (readOnly() || MScore::_error != MS_NO_ERROR)
255 rollback = true;
256
257 if (rollback)
258 undoStack()->current()->unwind();
259
260 update(false);
261
262 if (MScore::debugMode)
263 qDebug("===endCmd() %d", undoStack()->current()->childCount());
264 const bool noUndo = undoStack()->current()->empty(); // nothing to undo?
265 undoStack()->endMacro(noUndo);
266
267 if (dirty()) {
268 masterScore()->setPlaylistDirty(); // TODO: flag individual operations
269 masterScore()->setAutosaveDirty(true);
270 }
271 MuseScoreCore::mscoreCore->endCmd();
272 cmdState().reset();
273 }
274
275 #ifndef NDEBUG
276 //---------------------------------------------------------
277 // CmdState::dump
278 //---------------------------------------------------------
279
dump()280 void CmdState::dump()
281 {
282 qDebug("CmdState: mode %d %d-%d", int(_updateMode), _startTick.ticks(), _endTick.ticks());
283 // bool _excerptsChanged { false };
284 // bool _instrumentsChanged { false };
285
286 }
287 #endif
288
289 //---------------------------------------------------------
290 // update
291 // layout & update
292 //---------------------------------------------------------
293
update(bool resetCmdState)294 void Score::update(bool resetCmdState)
295 {
296 bool updateAll = false;
297 for (MasterScore* ms : *movements()) {
298 CmdState& cs = ms->cmdState();
299 ms->deletePostponed();
300 if (cs.layoutRange()) {
301 for (Score* s : ms->scoreList())
302 s->doLayoutRange(cs.startTick(), cs.endTick());
303 updateAll = true;
304 }
305 }
306
307 for (MasterScore* ms : *movements()) {
308 CmdState& cs = ms->cmdState();
309 if (updateAll || cs.updateAll()) {
310 for (Score* s : scoreList()) {
311 for (MuseScoreView* v : qAsConst(s->viewer)) {
312 v->updateAll();
313 }
314 }
315 }
316 else if (cs.updateRange()) {
317 // updateRange updates only current score
318 qreal d = spatium() * .5;
319 _updateState.refresh.adjust(-d, -d, 2 * d, 2 * d);
320 for (MuseScoreView* v : qAsConst(viewer))
321 v->dataChanged(_updateState.refresh);
322 _updateState.refresh = QRectF();
323 }
324 const InputState& is = inputState();
325 if (is.noteEntryMode() && is.segment()) {
326 setPlayPos(is.segment()->tick());
327 }
328 if (playlistDirty()) {
329 for (Score* s : scoreList())
330 emit s->playlistChanged();
331 masterScore()->setPlaylistClean();
332 }
333 if (resetCmdState)
334 cs.reset();
335 }
336 if (_selection.isRange() && !_selection.isLocked())
337 _selection.updateSelectedElements();
338 }
339
340 //---------------------------------------------------------
341 // deletePostponed
342 //---------------------------------------------------------
343
deletePostponed()344 void Score::deletePostponed()
345 {
346 for (ScoreElement* e : qAsConst(_updateState._deleteList)) {
347 if (e->isSystem()) {
348 System* s = toSystem(e);
349 for (SpannerSegment* ss : s->spannerSegments()) {
350 if (ss->system() == s)
351 ss->setSystem(0);
352 }
353 }
354 }
355 qDeleteAll(_updateState._deleteList);
356 _updateState._deleteList.clear();
357 }
358
359 //---------------------------------------------------------
360 // cmdAddSpanner
361 // drop VOLTA, OTTAVA, TRILL, PEDAL, DYNAMIC
362 // HAIRPIN, LET_RING, VIBRATO and TEXTLINE
363 //---------------------------------------------------------
364
cmdAddSpanner(Spanner * spanner,const QPointF & pos,bool firstStaffOnly)365 void Score::cmdAddSpanner(Spanner* spanner, const QPointF& pos, bool firstStaffOnly)
366 {
367 int staffIdx;
368 Segment* segment;
369 MeasureBase* mb = pos2measure(pos, &staffIdx, 0, &segment, 0);
370 if (firstStaffOnly)
371 staffIdx = 0;
372 // ignore if we do not have a measure
373 if (mb == 0 || mb->type() != ElementType::MEASURE) {
374 qDebug("cmdAddSpanner: cannot put object here");
375 delete spanner;
376 return;
377 }
378
379 // all spanners live in voice 0 (except slurs/ties)
380 int track = staffIdx == -1 ? -1 : staffIdx * VOICES;
381
382 spanner->setTrack(track);
383 spanner->setTrack2(track);
384
385 if (spanner->anchor() == Spanner::Anchor::SEGMENT) {
386 spanner->setTick(segment->tick());
387 Fraction lastTick = lastMeasure()->tick() + lastMeasure()->ticks();
388 Fraction tick2 = qMin(segment->measure()->tick() + segment->measure()->ticks(), lastTick);
389 spanner->setTick2(tick2);
390 }
391 else { // Anchor::MEASURE, Anchor::CHORD, Anchor::NOTE
392 Measure* m = toMeasure(mb);
393 QRectF b(m->canvasBoundingRect());
394
395 if (pos.x() >= (b.x() + b.width() * .5) && m != lastMeasureMM() && m->nextMeasure()->system() == m->system())
396 m = m->nextMeasure();
397 spanner->setTick(m->tick());
398 spanner->setTick2(m->endTick());
399 }
400 spanner->eraseSpannerSegments();
401
402 undoAddElement(spanner);
403 select(spanner, SelectType::SINGLE, 0);
404 }
405
406 //---------------------------------------------------------
407 // cmdAddSpanner
408 // used when applying a spanner to a selection
409 //---------------------------------------------------------
410
cmdAddSpanner(Spanner * spanner,int staffIdx,Segment * startSegment,Segment * endSegment)411 void Score::cmdAddSpanner(Spanner* spanner, int staffIdx, Segment* startSegment, Segment* endSegment)
412 {
413 int track = staffIdx * VOICES;
414 spanner->setTrack(track);
415 spanner->setTrack2(track);
416 for (auto ss : spanner->spannerSegments())
417 ss->setTrack(track);
418 spanner->setTick(startSegment->tick());
419 Fraction tick2;
420 if (!endSegment)
421 tick2 = lastSegment()->tick();
422 else if (endSegment == startSegment)
423 tick2 = startSegment->measure()->last()->tick();
424 else
425 tick2 = endSegment->tick();
426 spanner->setTick2(tick2);
427 #if 0 // TODO
428 TextLine* tl = toTextLine(spanner);
429 if (tl) {
430 StyledPropertyListIdx st;
431 Text* t;
432 // begin
433 t = tl->beginTextElement();
434 if (t) {
435 st = t->textStyleType();
436 if (st >= StyledPropertyListIdx::DEFAULT)
437 t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
438 }
439 // continue
440 t = tl->continueTextElement();
441 if (t) {
442 st = t->textStyleType();
443 if (st >= StyledPropertyListIdx::DEFAULT)
444 t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
445 }
446 // end
447 t = tl->endTextElement();
448 if (t) {
449 st = t->textStyleType();
450 if (st >= StyledPropertyListIdx::DEFAULT)
451 t->textStyle().restyle(MScore::baseStyle().textStyle(st), textStyle(st));
452 }
453 }
454 #endif
455 undoAddElement(spanner);
456 }
457
458 //---------------------------------------------------------
459 // expandVoice
460 // fills gaps in voice with rests,
461 // from previous cr (or beginning of measure) to next cr (or end of measure)
462 //---------------------------------------------------------
463
expandVoice(Segment * s,int track)464 void Score::expandVoice(Segment* s, int track)
465 {
466 if (!s) {
467 qDebug("expand voice: no segment");
468 return;
469 }
470 if (s->element(track))
471 return;
472
473 // find previous segment with cr in this track
474 Segment* ps;
475 for (ps = s; ps; ps = ps->prev(SegmentType::ChordRest)) {
476 if (ps->element(track))
477 break;
478 }
479 if (ps) {
480 ChordRest* cr = toChordRest(ps->element(track));
481 Fraction tick = cr->tick() + cr->actualTicks();
482 if (tick > s->tick()) {
483 // previous cr extends past current segment
484 qDebug("expandVoice: cannot insert element here");
485 return;
486 }
487 if (cr->isChord()) {
488 // previous cr ends on or before current segment
489 // for chords, move ps to just after cr ends
490 // so we can fill any gap that might exist
491 // but don't move ps if previous cr is a rest
492 // this will be combined with any new rests needed to fill up to s->tick() below
493 ps = ps->measure()->undoGetSegment(SegmentType::ChordRest, tick);
494 }
495 }
496 //
497 // fill up to s->tick() with rests
498 //
499 Measure* m = s->measure();
500 Fraction stick = ps ? ps->tick() : m->tick();
501 Fraction ticks = s->tick() - stick;
502 if (ticks.isNotZero())
503 setRest(stick, track, ticks, false, 0);
504
505 //
506 // fill from s->tick() until next chord/rest in measure
507 //
508 Segment* ns;
509 for (ns = s->next(SegmentType::ChordRest); ns; ns = ns->next(SegmentType::ChordRest)) {
510 if (ns->element(track))
511 break;
512 }
513 ticks = ns ? (ns->tick() - s->tick()) : (m->ticks() - s->rtick());
514 if (ticks == m->ticks())
515 addRest(s, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
516 else
517 setRest(s->tick(), track, ticks, false, 0);
518 }
519
expandVoice()520 void Score::expandVoice()
521 {
522 Segment* s = _is.segment();
523 int track = _is.track();
524 expandVoice(s, track);
525 }
526
527 //---------------------------------------------------------
528 // cmdAddInterval
529 //---------------------------------------------------------
530
cmdAddInterval(int val,const std::vector<Note * > & nl)531 void Score::cmdAddInterval(int val, const std::vector<Note*>& nl)
532 {
533 startCmd();
534 for (Note* on : nl) {
535 Note* note = new Note(this);
536 Chord* chord = on->chord();
537 note->setParent(chord);
538 note->setTrack(chord->track());
539 int valTmp = val < 0 ? val+1 : val-1;
540
541 int npitch;
542 int ntpc1;
543 int ntpc2;
544 bool accidental = _is.noteEntryMode() && _is.accidentalType() != AccidentalType::NONE;
545 bool forceAccidental = false;
546 if (abs(valTmp) != 7 || accidental) {
547 int line = on->line() - valTmp;
548 Fraction tick = chord->tick();
549 Staff* estaff = staff(on->staffIdx() + chord->staffMove());
550 ClefType clef = estaff->clef(tick);
551 Key key = estaff->key(tick);
552 int ntpc;
553 if (accidental) {
554 AccidentalVal acci = Accidental::subtype2value(_is.accidentalType());
555 int step = absStep(line, clef);
556 int octave = step / 7;
557 npitch = step2pitch(step) + octave * 12 + int(acci);
558 forceAccidental = (npitch == line2pitch(line, clef, key));
559 ntpc = step2tpc(step % 7, acci);
560 }
561 else {
562 npitch = line2pitch(line, clef, key);
563 ntpc = pitch2tpc(npitch, key, Prefer::NEAREST);
564 }
565
566 Interval v = on->part()->instrument(tick)->transpose();
567 if (v.isZero())
568 ntpc1 = ntpc2 = ntpc;
569 else {
570 if (styleB(Sid::concertPitch)) {
571 v.flip();
572 ntpc1 = ntpc;
573 ntpc2 = Ms::transposeTpc(ntpc, v, true);
574 }
575 else {
576 npitch += v.chromatic;
577 ntpc2 = ntpc;
578 ntpc1 = Ms::transposeTpc(ntpc, v, true);
579 }
580 }
581 }
582 else { //special case for octave
583 Interval interval(7, 12);
584 if (val < 0)
585 interval.flip();
586 transposeInterval(on->pitch(), on->tpc(), &npitch, &ntpc1, interval, false);
587 ntpc1 = on->tpc1();
588 ntpc2 = on->tpc2();
589 }
590 if (npitch < 0 || npitch > 127) {
591 delete note;
592 endCmd();
593 return;
594 }
595 note->setPitch(npitch, ntpc1, ntpc2);
596
597 undoAddElement(note);
598 if (forceAccidental) {
599 Accidental* a = new Accidental(this);
600 a->setAccidentalType(_is.accidentalType());
601 a->setRole(AccidentalRole::USER);
602 a->setParent(note);
603 undoAddElement(a);
604 }
605 setPlayNote(true);
606
607 select(note, SelectType::SINGLE, 0);
608 }
609 if (_is.noteEntryMode())
610 _is.setAccidentalType(AccidentalType::NONE);
611 _is.moveToNextInputPos();
612 endCmd();
613 }
614
615 //---------------------------------------------------------
616 // setGraceNote
617 /// Create a grace note in front of a normal note.
618 /// \arg ch is the chord of the normal note
619 /// \arg pitch is the pitch of the grace note
620 /// \arg is the grace note type
621 /// \len is the visual duration of the grace note (1/16 or 1/32)
622 //---------------------------------------------------------
623
setGraceNote(Chord * ch,int pitch,NoteType type,int len)624 Note* Score::setGraceNote(Chord* ch, int pitch, NoteType type, int len)
625 {
626 Note* note = new Note(this);
627 Chord* chord = new Chord(this);
628
629 // allow grace notes to be added to other grace notes
630 // by really adding to parent chord
631 if (ch->noteType() != NoteType::NORMAL)
632 ch = toChord(ch->parent());
633
634 chord->setTrack(ch->track());
635 chord->setParent(ch);
636 chord->add(note);
637
638 note->setPitch(pitch);
639 // find corresponding note within chord and use its tpc information
640 for (Note* n : ch->notes()) {
641 if (n->pitch() == pitch) {
642 note->setTpc1(n->tpc1());
643 note->setTpc2(n->tpc2());
644 break;
645 }
646 }
647 // note with same pitch not found, derive tpc from pitch / key
648 if (!tpcIsValid(note->tpc1()) || !tpcIsValid(note->tpc2()))
649 note->setTpcFromPitch();
650
651 TDuration d;
652 d.setVal(len);
653 chord->setDurationType(d);
654 chord->setTicks(d.fraction());
655 chord->setNoteType(type);
656 chord->setMag(ch->staff()->mag(chord->tick()) * styleD(Sid::graceNoteMag));
657
658 undoAddElement(chord);
659 select(note, SelectType::SINGLE, 0);
660 return note;
661 }
662
663 //---------------------------------------------------------
664 // createCRSequence
665 // Create a rest or chord of len f.
666 // If f is not a basic len, create several rests or
667 // tied chords.
668 //
669 // f total len of ChordRest
670 // cr prototype CR
671 // tick start position in measure
672 //---------------------------------------------------------
673
createCRSequence(const Fraction & f,ChordRest * cr,const Fraction & t)674 void Score::createCRSequence(const Fraction& f, ChordRest* cr, const Fraction& t)
675 {
676 Fraction tick(t);
677 Measure* measure = cr->measure();
678 ChordRest* ocr = 0;
679 for (TDuration d : toDurationList(f, true)) {
680 ChordRest* ncr = toChordRest(cr->clone());
681 ncr->setDurationType(d);
682 ncr->setTicks(d.fraction());
683 undoAddCR(ncr, measure, measure->tick() + tick);
684 if (cr->isChord() && ocr) {
685 Chord* nc = toChord(ncr);
686 Chord* oc = toChord(ocr);
687 for (unsigned int i = 0; i < oc->notes().size(); ++i) {
688 Note* on = oc->notes()[i];
689 Note* nn = nc->notes()[i];
690 Tie* tie = new Tie(this);
691 tie->setStartNote(on);
692 tie->setEndNote(nn);
693 tie->setTick(tie->startNote()->tick());
694 tie->setTick2(tie->endNote()->tick());
695 tie->setTrack(cr->track());
696 on->setTieFor(tie);
697 nn->setTieBack(tie);
698 undoAddElement(tie);
699 }
700 }
701
702 tick += ncr->actualTicks();
703 ocr = ncr;
704 }
705 }
706
707 //---------------------------------------------------------
708 // setNoteRest
709 // pitch == -1 -> set rest
710 // return segment of last created note/rest
711 //---------------------------------------------------------
712
setNoteRest(Segment * segment,int track,NoteVal nval,Fraction sd,Direction stemDirection,bool forceAccidental,bool rhythmic,InputState * externalInputState)713 Segment* Score::setNoteRest(Segment* segment, int track, NoteVal nval, Fraction sd, Direction stemDirection, bool forceAccidental, bool rhythmic, InputState* externalInputState)
714 {
715 Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
716 InputState& is = externalInputState ? (*externalInputState) : _is;
717
718 bool isRest = nval.pitch == -1;
719 Fraction tick = segment->tick();
720 Element* nr = 0;
721 Tie* tie = 0;
722 ChordRest* cr = toChordRest(segment->element(track));
723
724 Measure* measure = 0;
725 for (;;) {
726 if (track % VOICES)
727 expandVoice(segment, track);
728
729 // the returned gap ends at the measure boundary or at tuplet end
730 Fraction dd = makeGap(segment, track, sd, cr ? cr->tuplet() : 0);
731
732 if (dd.isZero()) {
733 qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), sd.numerator(),
734 sd.denominator());
735 break;
736 }
737
738 measure = segment->measure();
739 std::vector<TDuration> dl;
740 if (rhythmic)
741 dl = toRhythmicDurationList(dd, isRest, segment->rtick(), sigmap()->timesig(tick).nominal(), measure, 1);
742 else
743 dl = toDurationList(dd, true);
744 size_t n = dl.size();
745 for (size_t i = 0; i < n; ++i) {
746 const TDuration& d = dl[i];
747 ChordRest* ncr;
748 Note* note = 0;
749 Tie* addTie = 0;
750 if (isRest) {
751 nr = ncr = new Rest(this);
752 nr->setTrack(track);
753 ncr->setDurationType(d);
754 ncr->setTicks(d == TDuration::DurationType::V_MEASURE ? measure->ticks() : d.fraction());
755 }
756 else {
757 nr = note = new Note(this);
758
759 if (tie) {
760 tie->setEndNote(note);
761 tie->setTick2(tie->endNote()->tick());
762 note->setTieBack(tie);
763 addTie = tie;
764 }
765 Chord* chord = new Chord(this);
766 chord->setTrack(track);
767 chord->setDurationType(d);
768 chord->setTicks(d.fraction());
769 chord->setStemDirection(stemDirection);
770 chord->add(note);
771 note->setNval(nval, tick);
772 if (forceAccidental) {
773 int tpc = styleB(Sid::concertPitch) ? nval.tpc1 : nval.tpc2;
774 AccidentalVal alter = tpc2alter(tpc);
775 AccidentalType at = Accidental::value2subtype(alter);
776 Accidental* a = new Accidental(this);
777 a->setAccidentalType(at);
778 a->setRole(AccidentalRole::USER);
779 note->add(a);
780 }
781 ncr = chord;
782 if (i+1 < n) {
783 tie = new Tie(this);
784 tie->setStartNote(note);
785 tie->setTick(tie->startNote()->tick());
786 tie->setTrack(track);
787 note->setTieFor(tie);
788 }
789 }
790 ncr->setTuplet(cr ? cr->tuplet() : 0);
791 undoAddCR(ncr, measure, tick);
792 if (addTie)
793 undoAddElement(addTie);
794 setPlayNote(true);
795 segment = ncr->segment();
796 tick += ncr->actualTicks();
797 }
798
799 sd -= dd;
800 if (sd.isZero())
801 break;
802
803 Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
804 if (nseg == 0) {
805 qDebug("reached end of score");
806 break;
807 }
808 segment = nseg;
809
810 cr = toChordRest(segment->element(track));
811
812 if (!cr) {
813 if (track % VOICES)
814 cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
815 else {
816 qDebug("no rest in voice 0");
817 break;
818 }
819 }
820 //
821 // Note does not fit on current measure, create Tie to
822 // next part of note
823 if (!isRest) {
824 tie = new Tie(this);
825 tie->setStartNote((Note*)nr);
826 tie->setTick(tie->startNote()->tick());
827 tie->setTrack(nr->track());
828 ((Note*)nr)->setTieFor(tie);
829 }
830 }
831 if (tie)
832 connectTies();
833 if (nr) {
834 if (is.slur() && nr->type() == ElementType::NOTE) {
835 // If the start element was the same as the end element when the slur was created,
836 // the end grip of the front slur segment was given an x-offset of 3.0 * spatium().
837 // Now that the slur is about to be given a new end element, this should be reset.
838 if (is.slur()->endElement() == is.slur()->startElement())
839 is.slur()->frontSegment()->reset();
840 //
841 // extend slur
842 //
843 Chord* chord = toNote(nr)->chord();
844 is.slur()->undoChangeProperty(Pid::SPANNER_TICKS, chord->tick() - is.slur()->tick());
845 for (ScoreElement* se : is.slur()->linkList()) {
846 Slur* slur = toSlur(se);
847 for (ScoreElement* ee : chord->linkList()) {
848 Element* e = static_cast<Element*>(ee);
849 if (e->score() == slur->score() && e->track() == slur->track2()) {
850 slur->score()->undo(new ChangeSpannerElements(slur, slur->startElement(), e));
851 break;
852 }
853 }
854 }
855 }
856 if (externalInputState) {
857 is.setTrack(nr->track());
858 cr = nr->isRest() ? toChordRest(nr) : toNote(nr)->chord();
859 is.setLastSegment(is.segment());
860 is.setSegment(cr->segment());
861 }
862 else {
863 select(nr, SelectType::SINGLE, 0);
864 }
865 }
866 return segment;
867 }
868
869 //---------------------------------------------------------
870 // makeGap
871 // make time gap at tick by removing/shortening
872 // chord/rest
873 //
874 // if keepChord, the chord at tick is not removed
875 //
876 // gap does not exceed measure or scope of tuplet
877 //
878 // return size of actual gap
879 //---------------------------------------------------------
880
makeGap(Segment * segment,int track,const Fraction & _sd,Tuplet * tuplet,bool keepChord)881 Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet* tuplet, bool keepChord)
882 {
883 Q_ASSERT(_sd.numerator());
884
885 Measure* measure = segment->measure();
886 Fraction accumulated;
887 Fraction sd = _sd;
888
889 //
890 // remember first segment which should
891 // not be deleted (it may contain other elements we want to preserve)
892 //
893 Segment* firstSegment = segment;
894 const Fraction firstSegmentEnd = firstSegment->tick() + firstSegment->ticks();
895 Fraction nextTick = segment->tick();
896
897 for (Segment* seg = firstSegment; seg; seg = seg->next(SegmentType::ChordRest)) {
898 //
899 // voices != 0 may have gaps:
900 //
901 ChordRest* cr = toChordRest(seg->element(track));
902 if (!cr) {
903 if (seg->tick() < nextTick)
904 continue;
905 Segment* seg1 = seg->next(SegmentType::ChordRest);
906 Fraction tick2 = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
907 segment = seg;
908 Fraction td(tick2 - seg->tick());
909 if (td > sd)
910 td = sd;
911 accumulated += td;
912 sd -= td;
913 if (sd.isZero())
914 break;
915 nextTick = tick2;
916 continue;
917 }
918 if (seg->tick() > nextTick) {
919 // there was a gap
920 Fraction td(seg->tick() - nextTick);
921 if (td > sd)
922 td = sd;
923 accumulated += td;
924 sd -= td;
925 if (sd.isZero())
926 break;
927 }
928 //
929 // limit to tuplet level
930 //
931 if (tuplet) {
932 bool tupletEnd = true;
933 Tuplet* t = cr->tuplet();
934 while (t) {
935 if (cr->tuplet() == tuplet) {
936 tupletEnd = false;
937 break;
938 }
939 t = t->tuplet();
940 }
941 if (tupletEnd)
942 break;
943 }
944 Fraction td(cr->ticks());
945
946 // remove tremolo between 2 notes, if present
947 if (cr->isChord()) {
948 Chord* c = toChord(cr);
949 if (c->tremolo()) {
950 Tremolo* tremolo = c->tremolo();
951 if (tremolo->twoNotes())
952 undoRemoveElement(tremolo);
953 }
954 }
955 Tuplet* ltuplet = cr->tuplet();
956 if (ltuplet != tuplet) {
957 //
958 // Current location points to the start of a (nested)tuplet.
959 // We have to remove the complete tuplet.
960
961 // get top level tuplet
962 while (ltuplet->tuplet())
963 ltuplet = ltuplet->tuplet();
964
965 // get last segment of tuplet, drilling down to leaf nodes as necessary
966 Tuplet* t = ltuplet;
967 while (t->elements().back()->isTuplet())
968 t = toTuplet(t->elements().back());
969 seg = toChordRest(t->elements().back())->segment();
970
971 // now delete the full tuplet
972 td = ltuplet->ticks();
973 cmdDeleteTuplet(ltuplet, false);
974 tuplet = 0;
975 }
976 else {
977 if (seg != firstSegment || !keepChord)
978 undoRemoveElement(cr);
979 // even if there was a tuplet, we didn't remove it
980 ltuplet = 0;
981 }
982 Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
983 nextTick += actualTicks(td, tuplet, timeStretch);
984 if (sd < td) {
985 //
986 // we removed too much
987 //
988 accumulated = _sd;
989 Fraction rd = td - sd;
990 Fraction tick = cr->tick() + actualTicks(sd, tuplet, timeStretch);
991
992 std::vector<TDuration> dList;
993 if (tuplet || staff(track / VOICES)->isLocalTimeSignature(tick)) {
994 dList = toDurationList(rd, false);
995 std::reverse(dList.begin(), dList.end());
996 }
997 else {
998 dList = toRhythmicDurationList(rd, true, tick - measure->tick(), sigmap()->timesig(tick).nominal(), measure, 0);
999 }
1000 if (dList.empty())
1001 break;
1002
1003 for (TDuration d : dList) {
1004 if (ltuplet) {
1005 // take care not to recreate tuplet we just deleted
1006 Rest* r = setRest(tick, track, d.fraction(), false, 0, false);
1007 tick += r->actualTicks();
1008 }
1009 else {
1010 tick += addClone(cr, tick, d)->actualTicks();
1011 }
1012 }
1013 break;
1014 }
1015 accumulated += td;
1016 sd -= td;
1017 if (sd.isZero())
1018 break;
1019 }
1020 // Fraction ticks = measure->tick() + measure->ticks() - segment->tick();
1021 // Fraction td = Fraction::fromTicks(ticks);
1022 // NEEDS REVIEW !!
1023 // once the statement below is removed, these two lines do nothing
1024 // if (td > sd)
1025 // td = sd;
1026 // ??? accumulated should already contain the total value of the created gap: line 749, 811 or 838
1027 // this line creates a qreal-sized gap if the needed gap crosses a measure boundary
1028 // by adding again the duration already added in line 838
1029 // accumulated += td;
1030
1031 const Fraction t1 = firstSegmentEnd;
1032 const Fraction t2 = firstSegment->tick() + accumulated;
1033 if (t1 < t2) {
1034 Segment* s1 = tick2rightSegment(t1);
1035 Segment* s2 = tick2rightSegment(t2);
1036 typedef SelectionFilterType Sel;
1037 // chord symbols can exist without chord/rest so they should not be removed
1038 constexpr Sel filter = static_cast<Sel>(int(Sel::ALL) & ~int(Sel::CHORD_SYMBOL));
1039 deleteAnnotationsFromRange(s1, s2, track, track + 1, filter);
1040 deleteSpannersFromRange(t1, t2, track, track + 1, filter);
1041 }
1042
1043 return accumulated;
1044 }
1045
1046 //---------------------------------------------------------
1047 // makeGap1
1048 // make time gap for each voice
1049 // starting at tick+voiceOffset[voice] by removing/shortening
1050 // chord/rest
1051 // - cr is top level (not part of a tuplet)
1052 // - do not stop at measure end
1053 //---------------------------------------------------------
1054
makeGap1(const Fraction & baseTick,int staffIdx,const Fraction & len,int voiceOffset[VOICES])1055 bool Score::makeGap1(const Fraction& baseTick, int staffIdx, const Fraction& len, int voiceOffset[VOICES])
1056 {
1057 Segment* seg = tick2segment(baseTick, true, SegmentType::ChordRest);
1058 if (!seg) {
1059 qDebug("no segment to paste at tick %d", baseTick.ticks());
1060 return false;
1061 }
1062 int strack = staffIdx * VOICES;
1063 for (int track = strack; track < strack + VOICES; track++) {
1064 if (voiceOffset[track-strack] == -1)
1065 continue;
1066 Fraction tick = baseTick + Fraction::fromTicks(voiceOffset[track-strack]);
1067 Measure* m = tick2measure(tick);
1068 if ((track % VOICES) && !m->hasVoices(staffIdx))
1069 continue;
1070
1071 Fraction newLen = len - Fraction::fromTicks(voiceOffset[track-strack]);
1072 Q_ASSERT(newLen.numerator() != 0);
1073
1074 if (newLen > Fraction(0,1)) {
1075 const Fraction endTick = tick + newLen;
1076 typedef SelectionFilterType Sel;
1077 // chord symbols can exist without chord/rest so they should not be removed
1078 constexpr Sel filter = static_cast<Sel>(int(Sel::ALL) & ~int(Sel::CHORD_SYMBOL));
1079 deleteAnnotationsFromRange(tick2rightSegment(tick), tick2rightSegment(endTick), track, track + 1, filter);
1080 deleteSpannersFromRange(tick, endTick, track, track + 1, filter);
1081 }
1082
1083 seg = m->undoGetSegment(SegmentType::ChordRest, tick);
1084 bool result = makeGapVoice(seg, track, newLen, tick);
1085 if (track == strack && !result) // makeGap failed for first voice
1086 return false;
1087 }
1088 return true;
1089 }
1090
makeGapVoice(Segment * seg,int track,Fraction len,const Fraction & tick)1091 bool Score::makeGapVoice(Segment* seg, int track, Fraction len, const Fraction& tick)
1092 {
1093 ChordRest* cr = 0;
1094 cr = toChordRest(seg->element(track));
1095 if (!cr) {
1096 // check if we are in the middle of a chord/rest
1097 Segment* seg1 = seg->prev(SegmentType::ChordRest);
1098 for (;;) {
1099 if (seg1 == 0) {
1100 if (!(track % VOICES))
1101 qDebug("no segment before tick %d", tick.ticks());
1102 // this happens only for voices other than voice 1
1103 expandVoice(seg, track);
1104 return makeGapVoice(seg,track,len,tick);
1105 }
1106 if (seg1->element(track))
1107 break;
1108 seg1 = seg1->prev(SegmentType::ChordRest);
1109 }
1110 ChordRest* cr1 = toChordRest(seg1->element(track));
1111 Fraction srcF = cr1->ticks();
1112 Fraction dstF = tick - cr1->tick();
1113 std::vector<TDuration> dList = toDurationList(dstF, true);
1114 size_t n = dList.size();
1115 undoChangeChordRestLen(cr1, TDuration(dList[0]));
1116 if (n > 1) {
1117 Fraction crtick = cr1->tick() + cr1->actualTicks();
1118 Measure* measure = tick2measure(crtick);
1119 if (cr1->type() == ElementType::CHORD) {
1120 // split Chord
1121 Chord* c = toChord(cr1);
1122 for (size_t i = 1; i < n; ++i) {
1123 TDuration d = dList[i];
1124 Chord* c2 = addChord(crtick, d, c, true, c->tuplet());
1125 c = c2;
1126 seg1 = c->segment();
1127 crtick += c->actualTicks();
1128 }
1129 }
1130 else {
1131 // split Rest
1132 Rest* r = toRest(cr1);
1133 for (size_t i = 1; i < n; ++i) {
1134 TDuration d = dList[i];
1135 Rest* r2 = toRest(r->clone());
1136 r2->setTicks(d.fraction());
1137 r2->setDurationType(d);
1138 undoAddCR(r2, measure, crtick);
1139 seg1 = r2->segment();
1140 crtick += r2->actualTicks();
1141 }
1142 }
1143 }
1144 setRest(tick, track, srcF - dstF, true, 0);
1145 for (;;) {
1146 seg1 = seg1->next1(SegmentType::ChordRest);
1147 if (seg1 == 0) {
1148 qDebug("no segment");
1149 return false;
1150 }
1151 if (seg1->element(track)) {
1152 cr = toChordRest(seg1->element(track));
1153 break;
1154 }
1155 }
1156 }
1157
1158 for (;;) {
1159 if (!cr) {
1160 qDebug("cannot make gap");
1161 return false;
1162 }
1163 Fraction l = makeGap(cr->segment(), cr->track(), len, 0);
1164 if (l.isZero()) {
1165 qDebug("returns zero gap");
1166 return false;
1167 }
1168 len -= l;
1169 if (len.isZero())
1170 break;
1171 // go to next cr
1172 Measure* m = cr->measure()->nextMeasure();
1173 if (m == 0) {
1174 qDebug("EOS reached");
1175 insertMeasure(ElementType::MEASURE, 0, false);
1176 m = cr->measure()->nextMeasure();
1177 if (m == 0) {
1178 qDebug("===EOS reached");
1179 return true;
1180 }
1181 }
1182 // first segment in measure was removed, have to recreate it
1183 Segment* s = m->undoGetSegment(SegmentType::ChordRest, m->tick());
1184 int t = cr->track();
1185 cr = toChordRest(s->element(t));
1186 if (!cr) {
1187 addRest(s, t, TDuration(TDuration::DurationType::V_MEASURE), 0);
1188 cr = toChordRest(s->element(t));
1189 }
1190 }
1191 return true;
1192 }
1193
1194 //---------------------------------------------------------
1195 // splitGapToMeasureBoundaries
1196 // cr - start of gap
1197 // gap - gap len
1198 //---------------------------------------------------------
1199
splitGapToMeasureBoundaries(ChordRest * cr,Fraction gap)1200 QList<Fraction> Score::splitGapToMeasureBoundaries(ChordRest* cr, Fraction gap)
1201 {
1202 QList<Fraction> flist;
1203
1204 Tuplet* tuplet = cr->tuplet();
1205 if (tuplet) {
1206 Fraction rest = tuplet->elementsDuration();
1207 for (DurationElement* de : tuplet->elements()) {
1208 if (de == cr)
1209 break;
1210 rest -= de->ticks();
1211 }
1212 if (rest < gap)
1213 qDebug("does not fit in tuplet");
1214 else
1215 flist.append(gap);
1216 return flist;
1217 }
1218
1219 Segment* s = cr->segment();
1220 while (gap > Fraction(0,1)) {
1221 Measure* m = s->measure();
1222 Fraction timeStretch = cr->staff()->timeStretch(s->tick());
1223 Fraction rest = (m->ticks() - s->rtick()) * timeStretch;
1224 if (rest >= gap) {
1225 flist.append(gap);
1226 return flist;
1227 }
1228 flist.append(rest);
1229 gap -= rest;
1230 m = m->nextMeasure();
1231 if (m == 0)
1232 return flist;
1233 s = m->first(SegmentType::ChordRest);
1234 }
1235 return flist;
1236 }
1237
1238 //---------------------------------------------------------
1239 // changeCRlen
1240 //---------------------------------------------------------
1241
changeCRlen(ChordRest * cr,const TDuration & d)1242 void Score::changeCRlen(ChordRest* cr, const TDuration& d)
1243 {
1244 Fraction dstF;
1245 if (d.type() == TDuration::DurationType::V_MEASURE)
1246 dstF = cr->measure()->stretchedLen(cr->staff());
1247 else
1248 dstF = d.fraction();
1249 changeCRlen(cr, dstF);
1250 }
1251
changeCRlen(ChordRest * cr,const Fraction & dstF,bool fillWithRest)1252 void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
1253 {
1254 if (cr->isRepeatMeasure()) {
1255 // it is not clear what should this
1256 // operation mean for measure repeats.
1257 return;
1258 }
1259 Fraction srcF(cr->ticks());
1260 if (srcF == dstF) {
1261 if (cr->isFullMeasureRest())
1262 undoChangeChordRestLen(cr, dstF);
1263 return;
1264 }
1265
1266 //keep selected element if any
1267 Element* selElement = selection().isSingle() ? getSelectedElement() : 0;
1268
1269 int track = cr->track();
1270 Tuplet* tuplet = cr->tuplet();
1271
1272 if (srcF > dstF) {
1273 //
1274 // make shorter and fill with rest
1275 //
1276 deselectAll();
1277 if (cr->isChord()) {
1278 //
1279 // remove ties and tremolo between 2 notes
1280 //
1281 Chord* c = toChord(cr);
1282 if (c->tremolo()) {
1283 Tremolo* tremolo = c->tremolo();
1284 if (tremolo->twoNotes())
1285 undoRemoveElement(tremolo);
1286 }
1287 foreach (Note* n, c->notes()) {
1288 if (n->tieFor())
1289 undoRemoveElement(n->tieFor());
1290 }
1291 }
1292 Fraction timeStretch = cr->staff()->timeStretch(cr->tick());
1293 std::vector<TDuration> dList = toDurationList(dstF, true);
1294 undoChangeChordRestLen(cr, dList[0]);
1295 Fraction tick2 = cr->tick();
1296 for (unsigned i = 1; i < dList.size(); ++i) {
1297 tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
1298 TDuration d = dList[i];
1299 setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
1300 }
1301 if (fillWithRest)
1302 setRest(cr->tick() + cr->actualTicks(), track, srcF - dstF, false, tuplet);
1303
1304 if (selElement)
1305 select(selElement, SelectType::SINGLE, 0);
1306 return;
1307 }
1308
1309 //
1310 // make longer
1311 //
1312 // split required len into Measures
1313 QList<Fraction> flist = splitGapToMeasureBoundaries(cr, dstF);
1314 if (flist.empty())
1315 return;
1316
1317 deselectAll();
1318
1319 Fraction tick = cr->tick();
1320 Fraction f = dstF;
1321 ChordRest* cr1 = cr;
1322 Chord* oc = 0;
1323
1324 bool first = true;
1325 for (Fraction f2 : qAsConst(flist)) {
1326 f -= f2;
1327 makeGap(cr1->segment(), cr1->track(), f2, tuplet, first);
1328
1329 if (cr->isRest()) {
1330 Fraction timeStretch = cr1->staff()->timeStretch(cr1->tick());
1331 Rest* r = toRest(cr);
1332 if (first) {
1333 std::vector<TDuration> dList = toDurationList(f2, true);
1334 undoChangeChordRestLen(cr, dList[0]);
1335 Fraction tick2 = cr->tick();
1336 for (unsigned i = 1; i < dList.size(); ++i) {
1337 tick2 += actualTicks(dList[i-1].ticks(), tuplet, timeStretch);
1338 TDuration d = dList[i];
1339 setRest(tick2, track, d.fraction(), (d.dots() > 0), tuplet);
1340 }
1341 }
1342 else {
1343 r = setRest(tick, track, f2, false, tuplet);
1344 }
1345 if (first) {
1346 select(r, SelectType::SINGLE, 0);
1347 first = false;
1348 }
1349 tick += actualTicks(f2, tuplet, timeStretch);
1350 }
1351 else {
1352 std::vector<TDuration> dList = toDurationList(f2, true);
1353 Measure* measure = tick2measure(tick);
1354 Fraction etick = measure->tick();
1355
1356 if (((tick - etick).ticks() % dList[0].ticks().ticks()) == 0) {
1357 for (TDuration du : dList) {
1358 Chord* cc;
1359 if (oc) {
1360 cc = oc;
1361 oc = addChord(tick, du, cc, true, tuplet);
1362 }
1363 else {
1364 cc = toChord(cr);
1365 undoChangeChordRestLen(cr, du);
1366 oc = cc;
1367 }
1368 if (oc && first) {
1369 if (!selElement)
1370 select(oc, SelectType::SINGLE, 0);
1371 else
1372 select(selElement, SelectType::SINGLE, 0);
1373 first = false;
1374 }
1375 if (oc)
1376 tick += oc->actualTicks();
1377 }
1378 }
1379 else {
1380 for (size_t i = dList.size(); i > 0; --i) { // loop probably needs to be in this reverse order
1381 Chord* cc;
1382 if (oc) {
1383 cc = oc;
1384 oc = addChord(tick, dList[i-1], cc, true, tuplet);
1385 }
1386 else {
1387 cc = toChord(cr);
1388 undoChangeChordRestLen(cr, dList[i-1]);
1389 oc = cc;
1390 }
1391 if (first) {
1392 // select(oc, SelectType::SINGLE, 0);
1393 if (selElement)
1394 select(selElement, SelectType::SINGLE, 0);
1395 first = false;
1396 }
1397 tick += oc->actualTicks();
1398 }
1399 }
1400 }
1401 Measure* m = cr1->measure();
1402 Measure* m1 = m->nextMeasure();
1403 if (m1 == 0)
1404 break;
1405 Segment* s = m1->first(SegmentType::ChordRest);
1406 expandVoice(s, track);
1407 cr1 = toChordRest(s->element(track));
1408 }
1409 connectTies();
1410 }
1411
1412 //---------------------------------------------------------
1413 // upDownChromatic
1414 //---------------------------------------------------------
1415
upDownChromatic(bool up,int pitch,Note * n,Key key,int tpc1,int tpc2,int & newPitch,int & newTpc1,int & newTpc2)1416 static void upDownChromatic(bool up, int pitch, Note* n, Key key, int tpc1, int tpc2, int& newPitch, int& newTpc1, int& newTpc2)
1417 {
1418 if (up && pitch < 127) {
1419 newPitch = pitch + 1;
1420 if (n->concertPitch()) {
1421 if (tpc1 > Tpc::TPC_A + int(key))
1422 newTpc1 = tpc1 - 5; // up semitone diatonic
1423 else
1424 newTpc1 = tpc1 + 7; // up semitone chromatic
1425 newTpc2 = n->transposeTpc(newTpc1);
1426 }
1427 else {
1428 if (tpc2 > Tpc::TPC_A + int(key))
1429 newTpc2 = tpc2 - 5; // up semitone diatonic
1430 else
1431 newTpc2 = tpc2 + 7; // up semitone chromatic
1432 newTpc1 = n->transposeTpc(newTpc2);
1433 }
1434 }
1435 else if (!up && pitch > 0) {
1436 newPitch = pitch - 1;
1437 if (n->concertPitch()) {
1438 if (tpc1 > Tpc::TPC_C + int(key))
1439 newTpc1 = tpc1 - 7; // down semitone chromatic
1440 else
1441 newTpc1 = tpc1 + 5; // down semitone diatonic
1442 newTpc2 = n->transposeTpc(newTpc1);
1443 }
1444 else {
1445 if (tpc2 > Tpc::TPC_C + int(key))
1446 newTpc2 = tpc2 - 7; // down semitone chromatic
1447 else
1448 newTpc2 = tpc2 + 5; // down semitone diatonic
1449 newTpc1 = n->transposeTpc(newTpc2);
1450 }
1451 }
1452 }
1453
1454 //---------------------------------------------------------
1455 // setTpc
1456 //---------------------------------------------------------
1457
setTpc(Note * oNote,int tpc,int & newTpc1,int & newTpc2)1458 static void setTpc(Note* oNote, int tpc, int& newTpc1, int& newTpc2)
1459 {
1460 if (oNote->concertPitch()) {
1461 newTpc1 = tpc;
1462 newTpc2 = oNote->transposeTpc(tpc);
1463 }
1464 else {
1465 newTpc2 = tpc;
1466 newTpc1 = oNote->transposeTpc(tpc);
1467 }
1468 }
1469
1470 //---------------------------------------------------------
1471 // upDown
1472 /// Increment/decrement pitch of note by one or by an octave.
1473 //---------------------------------------------------------
1474
upDown(bool up,UpDownMode mode)1475 void Score::upDown(bool up, UpDownMode mode)
1476 {
1477 QList<Note*> el = selection().uniqueNotes();
1478
1479 for (Note* oNote : qAsConst(el)) {
1480 Fraction tick = oNote->chord()->tick();
1481 Staff* staff = oNote->staff();
1482 Part* part = staff->part();
1483 Key key = staff->key(tick);
1484 int tpc1 = oNote->tpc1();
1485 int tpc2 = oNote->tpc2();
1486 int pitch = oNote->pitch();
1487 int newTpc1 = tpc1; // default to unchanged
1488 int newTpc2 = tpc2; // default to unchanged
1489 int newPitch = pitch; // default to unchanged
1490 int string = oNote->string();
1491 int fret = oNote->fret();
1492
1493 StaffGroup staffGroup = staff->staffType(oNote->chord()->tick())->group();
1494 // if not tab, check for instrument instead of staffType (for pitched to unpitched instrument changes)
1495 if ( staffGroup != StaffGroup::TAB)
1496 staffGroup = staff->part()->instrument(oNote->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
1497
1498 switch (staffGroup) {
1499 case StaffGroup::PERCUSSION:
1500 {
1501 const Drumset* ds = part->instrument(tick)->drumset();
1502 if (ds) {
1503 newPitch = up ? ds->nextPitch(pitch) : ds->prevPitch(pitch);
1504 newTpc1 = pitch2tpc(newPitch, Key::C, Prefer::NEAREST);
1505 newTpc2 = newTpc1;
1506 }
1507 }
1508 break;
1509 case StaffGroup::TAB:
1510 {
1511 const StringData* stringData = part->instrument(tick)->stringData();
1512 switch (mode) {
1513 case UpDownMode::OCTAVE: // move same note to next string, if possible
1514 {
1515 const StaffType* stt = staff->staffType(tick);
1516 string = stt->physStringToVisual(string);
1517 string += (up ? -1 : 1);
1518 if (string < 0 || string >= stringData->strings())
1519 return; // no next string to move to
1520 string = stt->visualStringToPhys(string);
1521 fret = stringData->fret(pitch, string, staff, tick);
1522 if (fret == -1) // can't have that note on that string
1523 return;
1524 // newPitch and newTpc remain unchanged
1525 }
1526 break;
1527
1528 case UpDownMode::DIATONIC: // increase / decrease the pitch,
1529 // letting the algorithm to choose fret & string
1530 upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1531 break;
1532
1533 case UpDownMode::CHROMATIC: // increase / decrease the fret
1534 { // without changing the string
1535 // compute new fret
1536 if (!stringData->frets()) {
1537 qDebug("upDown tab chromatic: no frets?");
1538 return;
1539 }
1540 fret += (up ? 1 : -1);
1541 if (fret < 0 || fret > stringData->frets()) {
1542 qDebug("upDown tab in-string: out of fret range");
1543 return;
1544 }
1545 // update pitch and tpc's and check it matches stringData
1546 upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1547 if (newPitch != stringData->getPitch(string, fret, staff, tick) ) {
1548 // oh-oh: something went very wrong!
1549 qDebug("upDown tab in-string: pitch mismatch");
1550 return;
1551 }
1552 // store the fretting change before undoChangePitch() chooses
1553 // a fretting of its own liking!
1554 oNote->undoChangeProperty(Pid::FRET, fret);
1555 }
1556 break;
1557 }
1558 }
1559 break;
1560 case StaffGroup::STANDARD:
1561 switch (mode) {
1562 case UpDownMode::OCTAVE:
1563 if (up) {
1564 if (pitch < 116)
1565 newPitch = pitch + 12;
1566 }
1567 else {
1568 if (pitch > 11)
1569 newPitch = pitch - 12;
1570 }
1571 // newTpc remains unchanged
1572 break;
1573
1574 case UpDownMode::CHROMATIC:
1575 upDownChromatic(up, pitch, oNote, key, tpc1, tpc2, newPitch, newTpc1, newTpc2);
1576 break;
1577
1578 case UpDownMode::DIATONIC:
1579 {
1580 int tpc = oNote->tpc();
1581 if (up) {
1582 if (tpc > Tpc::TPC_A + int(key)) {
1583 if (pitch < 127) {
1584 newPitch = pitch + 1;
1585 setTpc(oNote, tpc - 5, newTpc1, newTpc2);
1586 }
1587 }
1588 else {
1589 if (pitch < 126) {
1590 newPitch = pitch + 2;
1591 setTpc(oNote, tpc + 2, newTpc1, newTpc2);
1592 }
1593 }
1594 }
1595 else {
1596 if (tpc > Tpc::TPC_C + int(key)) {
1597 if (pitch > 1) {
1598 newPitch = pitch - 2;
1599 setTpc(oNote, tpc - 2, newTpc1, newTpc2);
1600 }
1601 }
1602 else {
1603 if (pitch > 0) {
1604 newPitch = pitch - 1;
1605 setTpc(oNote, tpc + 5, newTpc1, newTpc2);
1606 }
1607 }
1608 }
1609 }
1610 break;
1611 }
1612 break;
1613 }
1614
1615 if ((oNote->pitch() != newPitch) || (oNote->tpc1() != newTpc1) || oNote->tpc2() != newTpc2) {
1616 // remove accidental if present to make sure
1617 // user added accidentals are removed here
1618 // unless it's an octave change
1619 // in this case courtesy accidentals are preserved
1620 // because they're now harder to be re-entered due to the revised note-input workflow
1621 if (mode != UpDownMode::OCTAVE) {
1622 auto l = oNote->linkList();
1623 for (ScoreElement* e : qAsConst(l)) {
1624 Note* ln = toNote(e);
1625 if (ln->accidental())
1626 undo(new RemoveElement(ln->accidental()));
1627 }
1628 }
1629 undoChangePitch(oNote, newPitch, newTpc1, newTpc2);
1630 }
1631
1632 // store fret change only if undoChangePitch has not been called,
1633 // as undoChangePitch() already manages fret changes, if necessary
1634 else if (staff->staffType(tick)->group() == StaffGroup::TAB) {
1635 bool refret = false;
1636 if (oNote->string() != string) {
1637 oNote->undoChangeProperty(Pid::STRING, string);
1638 refret = true;
1639 }
1640 if (oNote->fret() != fret) {
1641 oNote->undoChangeProperty(Pid::FRET, fret);
1642 refret = true;
1643 }
1644 if (refret) {
1645 const StringData* stringData = part->instrument(tick)->stringData();
1646 stringData->fretChords(oNote->chord());
1647 }
1648 }
1649
1650 // play new note with velocity 80 for 0.3 sec:
1651 setPlayNote(true);
1652 }
1653 setSelectionChanged(true);
1654 }
1655
1656 //---------------------------------------------------------
1657 // upDownDelta
1658 /// Add the delta to the pitch of note.
1659 //---------------------------------------------------------
1660
upDownDelta(int pitchDelta)1661 void Score::upDownDelta(int pitchDelta)
1662 {
1663 while (pitchDelta > 0) {
1664 upDown(true, UpDownMode::CHROMATIC);
1665 pitchDelta--;
1666 }
1667
1668 while (pitchDelta < 0) {
1669 upDown(false, UpDownMode::CHROMATIC);
1670 pitchDelta++;
1671 }
1672 }
1673
1674 //---------------------------------------------------------
1675 // addArticulation
1676 /// Add attribute \a attr to all selected notes/rests.
1677 ///
1678 /// Called from padToggle() to add note prefix/accent.
1679 //---------------------------------------------------------
1680
addArticulation(SymId attr)1681 void Score::addArticulation(SymId attr)
1682 {
1683 QSet<Chord*> set;
1684 int numAdded = 0;
1685 int numRemoved = 0;
1686 for (Element* el : selection().elements()) {
1687 if (el->isNote() || el->isChord()) {
1688 Chord* cr = 0;
1689 // apply articulation on a given chord only once
1690 if (el->isNote()) {
1691 cr = toNote(el)->chord();
1692 if (set.contains(cr))
1693 continue;
1694 }
1695 Articulation* na = new Articulation(this);
1696 na->setSymId(attr);
1697 if (addArticulation(el, na)) {
1698 ++numAdded;
1699 }
1700 else {
1701 delete na;
1702 ++numRemoved;
1703 }
1704 if (cr)
1705 set.insert(cr);
1706 }
1707 }
1708 QString msg = Sym::id2userName(attr);
1709 if (numAdded == 1 && numRemoved == 0)
1710 msg = QObject::tr("%1 added").arg(msg);
1711 else if (numAdded == 0 && numRemoved == 1)
1712 msg = QObject::tr("%1 removed").arg(msg);
1713 else
1714 msg = QObject::tr("%1, added %2, removed %3")
1715 .arg(msg).arg(numAdded).arg(numRemoved);
1716 setAccessibleMessage(msg);
1717 }
1718
1719 //---------------------------------------------------------
1720 // toggleAccidental
1721 //---------------------------------------------------------
1722
toggleAccidental(AccidentalType at,const EditData & ed)1723 void Score::toggleAccidental(AccidentalType at, const EditData& ed)
1724 {
1725 if (_is.accidentalType() == at)
1726 at = AccidentalType::NONE;
1727 if (noteEntryMode()) {
1728 _is.setAccidentalType(at);
1729 _is.setRest(false);
1730 }
1731 else {
1732 if (selection().isNone()) {
1733 ed.view->startNoteEntryMode();
1734 _is.setAccidentalType(at);
1735 _is.setDuration(TDuration::DurationType::V_QUARTER);
1736 _is.setRest(false);
1737 }
1738 else
1739 changeAccidental(at);
1740 }
1741 }
1742 //---------------------------------------------------------
1743 // changeAccidental
1744 /// Change accidental to subtype \a idx for all selected
1745 /// notes.
1746 //---------------------------------------------------------
1747
changeAccidental(AccidentalType idx)1748 void Score::changeAccidental(AccidentalType idx)
1749 {
1750 foreach(Note* note, selection().noteList())
1751 changeAccidental(note, idx);
1752 }
1753
1754 //---------------------------------------------------------
1755 // changeAccidental2
1756 //---------------------------------------------------------
1757
changeAccidental2(Note * n,int pitch,int tpc)1758 static void changeAccidental2(Note* n, int pitch, int tpc)
1759 {
1760 Score* score = n->score();
1761 Chord* chord = n->chord();
1762 Staff* st = chord->staff();
1763 int fret = n->fret();
1764 int string = n->string();
1765
1766 if (st->isTabStaff(chord->tick())) {
1767 if (pitch != n->pitch()) {
1768 //
1769 // as pitch has changed, calculate new
1770 // string & fret
1771 //
1772 const StringData* stringData = n->part()->instrument(n->tick())->stringData();
1773 if (stringData)
1774 stringData->convertPitch(pitch, st, chord->tick(), &string, &fret);
1775 }
1776 }
1777 int tpc1;
1778 int tpc2 = n->transposeTpc(tpc);
1779 if (score->styleB(Sid::concertPitch))
1780 tpc1 = tpc;
1781 else {
1782 tpc1 = tpc2;
1783 tpc2 = tpc;
1784 }
1785
1786 if (!st->isTabStaff(chord->tick())) {
1787 //
1788 // handle ties
1789 //
1790 if (n->tieBack()) {
1791 if (pitch != n->pitch()) {
1792 score->undoRemoveElement(n->tieBack());
1793 if (n->tieFor())
1794 score->undoRemoveElement(n->tieFor());
1795 }
1796 }
1797 else {
1798 Note* nn = n;
1799 while (nn->tieFor()) {
1800 nn = nn->tieFor()->endNote();
1801 score->undo(new ChangePitch(nn, pitch, tpc1, tpc2));
1802 }
1803 }
1804 }
1805 score->undoChangePitch(n, pitch, tpc1, tpc2);
1806 }
1807
1808 //---------------------------------------------------------
1809 // changeAccidental
1810 /// Change accidental to subtype \accidental for
1811 /// note \a note.
1812 //---------------------------------------------------------
1813
changeAccidental(Note * note,AccidentalType accidental)1814 void Score::changeAccidental(Note* note, AccidentalType accidental)
1815 {
1816 Chord* chord = note->chord();
1817 if (!chord)
1818 return;
1819 Segment* segment = chord->segment();
1820 if (!segment)
1821 return;
1822 Measure* measure = segment->measure();
1823 if (!measure)
1824 return;
1825 Fraction tick = segment->tick();
1826 Staff* estaff = staff(chord->staffIdx() + chord->staffMove());
1827 if (!estaff)
1828 return;
1829 ClefType clef = estaff->clef(tick);
1830 int step = ClefInfo::pitchOffset(clef) - note->line();
1831 while (step < 0)
1832 step += 7;
1833 step %= 7;
1834 //
1835 // accidental change may result in pitch change
1836 //
1837 AccidentalVal acc2 = measure->findAccidental(note);
1838 AccidentalVal acc = (accidental == AccidentalType::NONE) ? acc2 : Accidental::subtype2value(accidental);
1839
1840 int pitch = line2pitch(note->line(), clef, Key::C) + int(acc);
1841 if (!note->concertPitch())
1842 pitch += note->transposition();
1843
1844 int tpc = step2tpc(step, acc);
1845
1846 bool forceRemove = false;
1847 bool forceAdd = false;
1848
1849 // delete accidental
1850 // both for this note and for any linked notes
1851 if (accidental == AccidentalType::NONE)
1852 forceRemove = true;
1853
1854 // precautionary or microtonal accidental
1855 // either way, we display it unconditionally
1856 // both for this note and for any linked notes
1857 else if (acc == acc2 || (pitch == note->pitch() && !Accidental::isMicrotonal(note->accidentalType())) || Accidental::isMicrotonal(accidental))
1858 forceAdd = true;
1859
1860 for (ScoreElement* se : note->linkList()) {
1861 Note* ln = toNote(se);
1862 if (ln->concertPitch() != note->concertPitch())
1863 continue;
1864 Score* lns = ln->score();
1865 Accidental* a = ln->accidental();
1866 if (forceRemove) {
1867 if (a)
1868 lns->undoRemoveElement(a);
1869 if (ln->tieBack())
1870 continue;
1871 }
1872 else if (forceAdd) {
1873 if (a)
1874 undoRemoveElement(a);
1875 Accidental* a1 = new Accidental(lns);
1876 a1->setParent(ln);
1877 a1->setAccidentalType(accidental);
1878 a1->setRole(AccidentalRole::USER);
1879 lns->undoAddElement(a1);
1880 }
1881 else if (a && Accidental::isMicrotonal(a->accidentalType())) {
1882 lns->undoRemoveElement(a);
1883 }
1884 changeAccidental2(ln, pitch, tpc);
1885 }
1886 setPlayNote(true);
1887 setSelectionChanged(true);
1888 }
1889
1890 //---------------------------------------------------------
1891 // addArticulation
1892 //---------------------------------------------------------
1893
addArticulation(Element * el,Articulation * a)1894 bool Score::addArticulation(Element* el, Articulation* a)
1895 {
1896 Chord* c;
1897 if (el->isNote())
1898 c = toNote(el)->chord();
1899 else if (el->isChord())
1900 c = toChord(el);
1901 else
1902 return false;
1903 Articulation* oa = c->hasArticulation(a);
1904 if (oa) {
1905 undoRemoveElement(oa);
1906 return false;
1907 }
1908 a->setParent(c);
1909 a->setTrack(c->track()); // make sure it propagates between score and parts
1910 undoAddElement(a);
1911 return true;
1912 }
1913
1914 //---------------------------------------------------------
1915 // resetUserStretch
1916 //---------------------------------------------------------
1917
resetUserStretch()1918 void Score::resetUserStretch()
1919 {
1920 Measure* m1;
1921 Measure* m2;
1922 // retrieve span of selection
1923 Segment* s1 = _selection.startSegment();
1924 Segment* s2 = _selection.endSegment();
1925 // if either segment is not returned by the selection
1926 // (for instance, no selection) fall back to first/last measure
1927 if (!s1)
1928 m1 = firstMeasureMM();
1929 else
1930 m1 = s1->measure();
1931 if (!s2)
1932 m2 = lastMeasureMM();
1933 else
1934 m2 = s2->measure();
1935 if (!m1 || !m2) // should not happen!
1936 return;
1937
1938 for (Measure* m = m1; m; m = m->nextMeasureMM()) {
1939 m->undoChangeProperty(Pid::USER_STRETCH, 1.0);
1940 if (m == m2)
1941 break;
1942 }
1943 }
1944
1945 //---------------------------------------------------------
1946 // moveUp
1947 //---------------------------------------------------------
1948
moveUp(ChordRest * cr)1949 void Score::moveUp(ChordRest* cr)
1950 {
1951 Staff* staff = cr->staff();
1952 Part* part = staff->part();
1953 int rstaff = staff->rstaff();
1954 int staffMove = cr->staffMove();
1955
1956 if ((staffMove == -1) || (rstaff + staffMove <= 0))
1957 return;
1958
1959 QList<Staff*>* staves = part->staves();
1960 // we know that staffMove+rstaff-1 index exists due to the previous condition.
1961 if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
1962 staves->at(rstaff+staffMove-1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
1963 qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
1964 }
1965 else {
1966 // move the chord up a staff
1967 undo(new ChangeChordStaffMove(cr, staffMove - 1));
1968 }
1969 }
1970
1971 //---------------------------------------------------------
1972 // moveDown
1973 //---------------------------------------------------------
1974
moveDown(ChordRest * cr)1975 void Score::moveDown(ChordRest* cr)
1976 {
1977 Staff* staff = cr->staff();
1978 Part* part = staff->part();
1979 int rstaff = staff->rstaff();
1980 int staffMove = cr->staffMove();
1981 // calculate the number of staves available so that we know whether there is another staff to move down to
1982 int rstaves = part->nstaves();
1983
1984 if ((staffMove == 1) || (rstaff + staffMove >= rstaves - 1)) {
1985 qDebug("moveDown staffMove==%d rstaff %d rstaves %d", staffMove, rstaff, rstaves);
1986 return;
1987 }
1988
1989 QList<Staff*>* staves = part->staves();
1990 // we know that staffMove+rstaff+1 index exists due to the previous condition.
1991 if (staff->staffType(cr->tick())->group() != StaffGroup::STANDARD ||
1992 staves->at(staffMove+rstaff+1)->staffType(cr->tick())->group() != StaffGroup::STANDARD) {
1993 qDebug("User attempted to move a note from/to a staff which does not use standard notation - ignoring.");
1994 }
1995 else {
1996 // move the chord down a staff
1997 undo(new ChangeChordStaffMove(cr, staffMove + 1));
1998 }
1999 }
2000
2001 //---------------------------------------------------------
2002 // cmdAddStretch
2003 //---------------------------------------------------------
2004
cmdAddStretch(qreal val)2005 void Score::cmdAddStretch(qreal val)
2006 {
2007 if (!selection().isRange())
2008 return;
2009 Fraction startTick = selection().tickStart();
2010 Fraction endTick = selection().tickEnd();
2011 for (Measure* m = firstMeasureMM(); m; m = m->nextMeasureMM()) {
2012 if (m->tick() < startTick)
2013 continue;
2014 if (m->tick() >= endTick)
2015 break;
2016 qreal stretch = m->userStretch();
2017 stretch += val;
2018 if (stretch < 0)
2019 stretch = 0;
2020 m->undoChangeProperty(Pid::USER_STRETCH, stretch);
2021 }
2022 }
2023
2024 //---------------------------------------------------------
2025 // cmdResetBeamMode
2026 //---------------------------------------------------------
2027
cmdResetBeamMode()2028 void Score::cmdResetBeamMode()
2029 {
2030 bool noSelection = selection().isNone();
2031 if (noSelection)
2032 cmdSelectAll();
2033 else if (!selection().isRange()) {
2034 qDebug("no system or staff selected");
2035 return;
2036 }
2037
2038 Fraction endTick = selection().tickEnd();
2039
2040 for (Segment* seg = selection().firstChordRestSegment(); seg && seg->tick() < endTick; seg = seg->next1(SegmentType::ChordRest)) {
2041 for (int track = selection().staffStart() * VOICES; track < selection().staffEnd() * VOICES; ++track) {
2042 ChordRest* cr = toChordRest(seg->element(track));
2043 if (!cr)
2044 continue;
2045 if (cr->type() == ElementType::CHORD) {
2046 if (cr->beamMode() != Beam::Mode::AUTO)
2047 cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::AUTO));
2048 }
2049 else if (cr->type() == ElementType::REST) {
2050 if (cr->beamMode() != Beam::Mode::NONE)
2051 cr->undoChangeProperty(Pid::BEAM_MODE, int(Beam::Mode::NONE));
2052 }
2053 }
2054 }
2055 if (noSelection)
2056 deselectAll();
2057 }
2058
2059 //---------------------------------------------------------
2060 // cmdResetStyle
2061 //---------------------------------------------------------
2062
cmdResetAllStyle()2063 void Score::cmdResetAllStyle()
2064 {
2065 style().resetAllStyles(this);
2066 }
2067
cmdResetTextStyleOverrides()2068 void Score::cmdResetTextStyleOverrides()
2069 {
2070 static const std::vector<Pid> propertiesToReset {
2071 Pid::FONT_FACE,
2072 Pid::FONT_SIZE,
2073 Pid::FONT_STYLE,
2074 Pid::SIZE_SPATIUM_DEPENDENT,
2075 Pid::FRAME_TYPE,
2076 Pid::TEXT_LINE_SPACING,
2077 Pid::FRAME_FG_COLOR,
2078 Pid::FRAME_BG_COLOR,
2079 Pid::FRAME_WIDTH,
2080 Pid::FRAME_PADDING,
2081 Pid::FRAME_ROUND,
2082 Pid::ALIGN
2083 };
2084
2085 for (Page* page : pages()) {
2086 auto elements = page->elements();
2087
2088 for (Element* element : elements) {
2089 if (!element || !element->isTextBase()) {
2090 continue;
2091 }
2092
2093 for (Pid propertyId : propertiesToReset) {
2094 element->resetProperty(propertyId);
2095 }
2096 }
2097 }
2098 }
2099
2100 //---------------------------------------------------------
2101 // cmdResetNoteAndRestGroupings
2102 //---------------------------------------------------------
2103
cmdResetNoteAndRestGroupings()2104 void Score::cmdResetNoteAndRestGroupings()
2105 {
2106 bool noSelection = selection().isNone();
2107 if (noSelection)
2108 cmdSelectAll();
2109 else if (!selection().isRange()) {
2110 qDebug("no system or staff selected");
2111 return;
2112 }
2113
2114 // save selection values because selection changes during grouping
2115 Fraction sTick = selection().tickStart();
2116 Fraction eTick = selection().tickEnd();
2117 int sStaff = selection().staffStart();
2118 int eStaff = selection().staffEnd();
2119
2120 startCmd();
2121 for (int staff = sStaff; staff < eStaff; staff++) {
2122 int sTrack = staff * VOICES;
2123 int eTrack = sTrack + VOICES;
2124 for (int track = sTrack; track < eTrack; track++) {
2125 if (selectionFilter().canSelectVoice(track))
2126 regroupNotesAndRests(sTick, eTick, track);
2127 }
2128 }
2129 endCmd();
2130 if (noSelection)
2131 deselectAll();
2132 }
2133
2134 //---------------------------------------------------------
2135 // resetElementShapePosition
2136 // For use with Score::scanElements.
2137 // Reset positions and autoplacement for the given
2138 // element.
2139 //---------------------------------------------------------
2140
resetElementPosition(void *,Element * e)2141 static void resetElementPosition(void*, Element* e)
2142 {
2143 if (e->generated())
2144 return;
2145 e->undoResetProperty(Pid::AUTOPLACE);
2146 e->undoResetProperty(Pid::OFFSET);
2147 e->setOffsetChanged(false);
2148 if (e->isSpanner())
2149 e->undoResetProperty(Pid::OFFSET2);
2150 }
2151
2152 //---------------------------------------------------------
2153 // cmdResetAllPositions
2154 //---------------------------------------------------------
2155
cmdResetAllPositions(bool undoable)2156 void Score::cmdResetAllPositions(bool undoable)
2157 {
2158 if (undoable)
2159 startCmd();
2160 resetAllPositions();
2161 if (undoable)
2162 endCmd();
2163 }
2164
resetAllPositions()2165 void Score::resetAllPositions()
2166 {
2167 scanElements(nullptr, resetElementPosition);
2168 }
2169
2170 //---------------------------------------------------------
2171 // processMidiInput
2172 //---------------------------------------------------------
2173
processMidiInput()2174 bool Score::processMidiInput()
2175 {
2176 if (midiInputQueue()->empty())
2177 return false;
2178
2179 if (MScore::debugMode)
2180 qDebug("processMidiInput");
2181
2182 NoteEntryMethod entryMethod = _is.noteEntryMethod();
2183 bool cmdActive = false;
2184 while (!midiInputQueue()->empty()) {
2185 MidiInputEvent ev = midiInputQueue()->dequeue();
2186 for (auto itr = activeMidiPitches()->begin(); itr != activeMidiPitches()->end();) {
2187 if ((*itr).pitch == ev.pitch)
2188 itr = activeMidiPitches()->erase(itr);
2189 else
2190 ++itr;
2191 }
2192 if (MScore::debugMode)
2193 qDebug("<-- !noteentry dequeue %i", ev.pitch);
2194 if (!noteEntryMode()
2195 || entryMethod == NoteEntryMethod::REALTIME_AUTO
2196 || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
2197 int staffIdx = selection().staffStart();
2198 Part* p;
2199 if (staffIdx < 0 || staffIdx >= nstaves())
2200 p = staff(0)->part();
2201 else
2202 p = staff(staffIdx)->part();
2203 if (p) {
2204 if (!styleB(Sid::concertPitch)) {
2205 ev.pitch += p->instrument(selection().tickStart())->transpose().chromatic;
2206 }
2207 MScore::seq->startNote(
2208 p->instrument(selection().tickStart())->channel(0)->channel(), // tick that way?
2209 ev.pitch,
2210 ev.velocity,
2211 0.0);
2212 }
2213 }
2214 if (noteEntryMode()) {
2215 if (ev.velocity == 0) {
2216 // delete note in realtime mode
2217 //Chord* chord = toChord(_is.cr());
2218 //std::vector<Note*> notes = chord->notes();
2219 if (entryMethod == NoteEntryMethod::REALTIME_AUTO || entryMethod == NoteEntryMethod::REALTIME_MANUAL) {
2220 if (_is.cr()->isChord()) {
2221 Note* n = toChord(_is.cr())->findNote(ev.pitch);
2222 if (n) {
2223 qDebug("Pitches match! Note %i, Pitch %i", n->pitch(), ev.pitch);
2224 if (!cmdActive) {
2225 startCmd();
2226 cmdActive = true;
2227 }
2228 deleteItem(n->tieBack());
2229 deleteItem(n);
2230 }
2231 }
2232 }
2233 continue;
2234 }
2235 if (!cmdActive) {
2236 startCmd();
2237 cmdActive = true;
2238 }
2239 if (activeMidiPitches()->empty())
2240 ev.chord = false;
2241 else
2242 ev.chord = true;
2243
2244 // holding shift while inputting midi will add the new pitch to the prior existing chord
2245 if (qApp->keyboardModifiers() & Qt::ShiftModifier) {
2246 Element* cr = _is.lastSegment()->element(_is.track());
2247 if (cr && cr->isChord())
2248 ev.chord = true;
2249 }
2250
2251 // TODO: add shadow note instead of real note in realtime modes
2252 // (note becomes real when realtime-advance triggered).
2253 addMidiPitch(ev.pitch, ev.chord);
2254 activeMidiPitches()->push_back(ev);
2255 }
2256 }
2257 if (cmdActive) {
2258 endCmd();
2259 //after relayout
2260 Element* e = inputState().cr();
2261 if (e) {
2262 for(MuseScoreView* v : qAsConst(viewer))
2263 v->adjustCanvasPosition(e, false);
2264 }
2265 return true;
2266 }
2267 return false;
2268 }
2269
2270 //---------------------------------------------------------
2271 // move
2272 // move current selection
2273 //---------------------------------------------------------
2274
move(const QString & cmd)2275 Element* Score::move(const QString& cmd)
2276 {
2277 ChordRest* cr { nullptr };
2278 Box* box { nullptr };
2279 if (noteEntryMode()) {
2280 // if selection exists and is grace note, use it
2281 // otherwise use chord/rest at input position
2282 // also use it if we are moving to next chord
2283 // to catch up with the cursor and not move the selection by 2 positions
2284 cr = selection().cr();
2285 if (cr && (cr->isGrace() || cmd == "next-chord" || cmd == "prev-chord"))
2286 ;
2287 else
2288 cr = inputState().cr();
2289 }
2290 else if (selection().activeCR())
2291 cr = selection().activeCR();
2292 else
2293 cr = selection().lastChordRest();
2294
2295 // no chord/rest found? look for another type of element,
2296 // but commands [empty-trailing-measure] and [top-staff] don't
2297 // necessarily need an active selection for appropriate functioning
2298 if (!cr && cmd != "empty-trailing-measure" && cmd != "top-staff") {
2299 if (selection().elements().empty())
2300 return 0;
2301 // retrieve last element of section list
2302 Element* el = selection().elements().last();
2303 Element* trg = 0;
2304
2305 // get parent of element and process accordingly:
2306 // trg is the element to select on "next-chord" cmd
2307 // cr is the ChordRest to move from on other cmd's
2308 int track = el->track(); // keep note of element track
2309 if (!el->isBox())
2310 el = el->parent();
2311 // element with no parent (eg, a newly-added line) - no way to find context
2312 if (!el)
2313 return 0;
2314 switch (el->type()) {
2315 case ElementType::NOTE: // a note is a valid target
2316 trg = el;
2317 cr = toNote(el)->chord();
2318 break;
2319 case ElementType::CHORD: // a chord or a rest are valid targets
2320 case ElementType::REST:
2321 trg = el;
2322 cr = toChordRest(trg);
2323 break;
2324 case ElementType::SEGMENT: { // from segment go to top chordrest in segment
2325 Segment* seg = toSegment(el);
2326 // if segment is not chord/rest or grace, move to next chord/rest or grace segment
2327 if (!seg->isChordRest()) {
2328 seg = seg->next1(SegmentType::ChordRest);
2329 if (seg == 0) // if none found, return failure
2330 return 0;
2331 }
2332 // segment for sure contains chords/rests,
2333 int size = int(seg->elist().size());
2334 // if segment has a chord/rest in original element track, use it
2335 if (track > -1 && track < size && seg->element(track)) {
2336 trg = seg->element(track);
2337 cr = toChordRest(trg);
2338 break;
2339 }
2340 // if not, get topmost chord/rest
2341 for (int i = 0; i < size; i++)
2342 if (seg->element(i)) {
2343 trg = seg->element(i);
2344 cr = toChordRest(trg);
2345 break;
2346 }
2347 break;
2348 }
2349 case ElementType::HBOX: // fallthrough
2350 case ElementType::VBOX: // fallthrough
2351 case ElementType::TBOX:
2352 box = toBox(el);
2353 break;
2354 default: // on anything else, return failure
2355 return 0;
2356 }
2357
2358 // if something found and command is forward, the element found is the destination
2359 if (trg && cmd == "next-chord") {
2360 // if chord, go to topmost note
2361 if (trg->type() == ElementType::CHORD)
2362 trg = toChord(trg)->upNote();
2363 setPlayNote(true);
2364 select(trg, SelectType::SINGLE, 0);
2365 return trg;
2366 }
2367 // if no chordrest and no box (frame) found, do nothing
2368 if (!cr && !box)
2369 return 0;
2370 // if some chordrest found, continue with default processing
2371 }
2372
2373 Element* el = 0;
2374 Segment* ois = noteEntryMode() ? _is.segment() : nullptr;
2375 Measure* oim = ois ? ois->measure() : nullptr;
2376
2377 if (cmd == "next-chord" && cr) {
2378 // note input cursor
2379 if (noteEntryMode())
2380 _is.moveToNextInputPos();
2381
2382 // selection "cursor"
2383 // find next chordrest, which might be a grace note
2384 // this may override note input cursor
2385 el = nextChordRest(cr);
2386 while (el && el->isRest() && toRest(el)->isGap())
2387 el = nextChordRest(toChordRest(el));
2388 if (el && noteEntryMode()) {
2389 // do not use if not in original or new measure (don't skip measures)
2390 Measure* m = toChordRest(el)->measure();
2391 Segment* nis = _is.segment();
2392 Measure* nim = nis ? nis->measure() : nullptr;
2393 if (m != oim && m != nim)
2394 el = cr;
2395 // do not use if new input segment is current cr
2396 // this means input cursor just caught up to current selection
2397 else if (cr && nis == cr->segment())
2398 el = cr;
2399 }
2400 else if (!el)
2401 el = cr;
2402 }
2403 else if (cmd == "prev-chord" && cr) {
2404 // note input cursor
2405 if (noteEntryMode() && _is.segment()) {
2406 Measure* m = _is.segment()->measure();
2407 Segment* s = _is.segment()->prev1(SegmentType::ChordRest);
2408 int track = _is.track();
2409 for (; s; s = s->prev1(SegmentType::ChordRest)) {
2410 if (s->element(track) || (s->measure() != m && s->rtick().isZero())) {
2411 if (s->element(track)) {
2412 if (s->element(track)->isRest() && toRest(s->element(track))->isGap())
2413 continue;
2414 }
2415 break;
2416 }
2417 }
2418 _is.moveInputPos(s);
2419 }
2420
2421 // selection "cursor"
2422 // find previous chordrest, which might be a grace note
2423 // this may override note input cursor
2424 el = prevChordRest(cr);
2425 while (el && el->isRest() && toRest(el)->isGap())
2426 el = prevChordRest(toChordRest(el));
2427 if (el && noteEntryMode()) {
2428 // do not use if not in original or new measure (don't skip measures)
2429 Measure* m = toChordRest(el)->measure();
2430 Segment* nis = _is.segment();
2431 Measure* nim = nis ? nis->measure() : nullptr;
2432 if (m != oim && m != nim)
2433 el = cr;
2434 // do not use if new input segment is current cr
2435 // this means input cursor just caught up to current selection
2436 else if (cr && nis == cr->segment())
2437 el = cr;
2438 }
2439 else if (!el)
2440 el = cr;
2441
2442 }
2443 else if (cmd == "next-measure") {
2444 if (box && box->nextMeasure() && box->nextMeasure()->first())
2445 el = box->nextMeasure()->first()->nextChordRest(0, false);
2446 if (cr)
2447 el = nextMeasure(cr);
2448 if (el && noteEntryMode())
2449 _is.moveInputPos(el);
2450 }
2451 else if (cmd == "prev-measure") {
2452 if (box && box->prevMeasure() && box->prevMeasure()->first())
2453 el = box->prevMeasure()->first()->nextChordRest(0, false);
2454 if (cr)
2455 el = prevMeasure(cr);
2456 if (el && noteEntryMode())
2457 _is.moveInputPos(el);
2458 }
2459 else if (cmd == "next-system" && cr) {
2460 el = cmdNextPrevSystem(cr, true);
2461 if (noteEntryMode())
2462 _is.moveInputPos(el);
2463 }
2464 else if (cmd == "prev-system" && cr) {
2465 el = cmdNextPrevSystem(cr, false);
2466 if (noteEntryMode())
2467 _is.moveInputPos(el);
2468 }
2469 else if (cmd == "next-frame") {
2470 auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
2471 el = measureBase ? cmdNextPrevFrame(measureBase, true) : nullptr;
2472 }
2473 else if (cmd == "prev-frame") {
2474 auto measureBase = cr ? cr->measure()->findMeasureBase() : box->findMeasureBase();
2475 el = measureBase ? cmdNextPrevFrame(measureBase, false) : nullptr;
2476 }
2477 else if (cmd == "next-section") {
2478 if (!(el = box))
2479 el = cr;
2480 el = cmdNextPrevSection(el, true);
2481 }
2482 else if (cmd == "prev-section") {
2483 if (!(el = box))
2484 el = cr;
2485 el = cmdNextPrevSection(el, false);
2486 }
2487 else if (cmd == "next-track" && cr) {
2488 el = nextTrack(cr);
2489 if (noteEntryMode())
2490 _is.moveInputPos(el);
2491 }
2492 else if (cmd == "prev-track" && cr) {
2493 el = prevTrack(cr);
2494 if (noteEntryMode())
2495 _is.moveInputPos(el);
2496 }
2497 else if (cmd == "top-staff") {
2498 el = cr ? cmdTopStaff(cr) : cmdTopStaff();
2499 if (noteEntryMode())
2500 _is.moveInputPos(el);
2501 }
2502 else if (cmd == "empty-trailing-measure") {
2503 const Measure* ftm = nullptr;
2504 if (!cr)
2505 ftm = firstTrailingMeasure() ? firstTrailingMeasure() : lastMeasure();
2506 else
2507 ftm = firstTrailingMeasure(&cr) ? firstTrailingMeasure(&cr) : lastMeasure();
2508 if (ftm) {
2509 if (score()->styleB(Sid::createMultiMeasureRests) && ftm->hasMMRest())
2510 ftm = ftm->mmRest1();
2511 el = !cr ? ftm->first()->nextChordRest(0, false) : ftm->first()->nextChordRest(trackZeroVoice(cr->track()), false);
2512 }
2513 // Note: Due to the nature of this command as being preparatory for input,
2514 // Note-Entry is activated from within ScoreView::cmd()
2515 _is.moveInputPos(el);
2516 }
2517
2518 if (el) {
2519 if (el->type() == ElementType::CHORD)
2520 el = toChord(el)->upNote(); // originally downNote
2521 setPlayNote(true);
2522 if (noteEntryMode()) {
2523 // if cursor moved into a gap, selection cannot follow
2524 // only select & play el if it was not already selected (does not normally happen)
2525 if (_is.cr() || !el->selected())
2526 select(el, SelectType::SINGLE, 0);
2527 else
2528 setPlayNote(false);
2529 for (MuseScoreView* view : qAsConst(viewer))
2530 view->moveCursor();
2531 }
2532 else {
2533 select(el, SelectType::SINGLE, 0);
2534 }
2535 }
2536 return el;
2537 }
2538
2539 //---------------------------------------------------------
2540 // selectMove
2541 //---------------------------------------------------------
2542
selectMove(const QString & cmd)2543 Element* Score::selectMove(const QString& cmd)
2544 {
2545 ChordRest* cr;
2546 if (selection().activeCR())
2547 cr = selection().activeCR();
2548 else
2549 cr = selection().lastChordRest();
2550 if (!cr && noteEntryMode())
2551 cr = inputState().cr();
2552 if (!cr)
2553 return 0;
2554
2555 ChordRest* el = 0;
2556 if (cmd == "select-next-chord")
2557 el = nextChordRest(cr, true);
2558 else if (cmd == "select-prev-chord")
2559 el = prevChordRest(cr, true);
2560 else if (cmd == "select-next-measure")
2561 el = nextMeasure(cr, true, true);
2562 else if (cmd == "select-prev-measure")
2563 el = prevMeasure(cr, true);
2564 else if (cmd == "select-begin-line") {
2565 Measure* measure = cr->segment()->measure()->system()->firstMeasure();
2566 if (!measure)
2567 return 0;
2568 el = measure->first()->nextChordRest(cr->track());
2569 }
2570 else if (cmd == "select-end-line") {
2571 Measure* measure = cr->segment()->measure()->system()->lastMeasure();
2572 if (!measure)
2573 return 0;
2574 el = measure->last()->nextChordRest(cr->track(), true);
2575 }
2576 else if (cmd == "select-begin-score") {
2577 Measure* measure = firstMeasureMM();
2578 if (!measure)
2579 return 0;
2580 el = measure->first()->nextChordRest(cr->track());
2581 }
2582 else if (cmd == "select-end-score") {
2583 Measure* measure = lastMeasureMM();
2584 if (!measure)
2585 return 0;
2586 el = measure->last()->nextChordRest(cr->track(), true);
2587 }
2588 else if (cmd == "select-staff-above")
2589 el = upStaff(cr);
2590 else if (cmd == "select-staff-below")
2591 el = downStaff(cr);
2592 if (el)
2593 select(el, SelectType::RANGE, el->staffIdx());
2594 return el;
2595 }
2596
2597 //---------------------------------------------------------
2598 // cmdMirrorNoteHead
2599 //---------------------------------------------------------
2600
cmdMirrorNoteHead()2601 void Score::cmdMirrorNoteHead()
2602 {
2603 const QList<Element*>& el = selection().elements();
2604 for (Element* e : el) {
2605 if (e->isNote()) {
2606 Note* note = toNote(e);
2607 if (note->staff() && note->staff()->isTabStaff(note->chord()->tick()))
2608 e->undoChangeProperty(Pid::GHOST, !note->ghost());
2609 else {
2610 MScore::DirectionH d = note->userMirror();
2611 if (d == MScore::DirectionH::AUTO)
2612 d = note->chord()->up() ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
2613 else
2614 d = d == MScore::DirectionH::LEFT ? MScore::DirectionH::RIGHT : MScore::DirectionH::LEFT;
2615 undoChangeUserMirror(note, d);
2616 }
2617 }
2618 else if (e->isHairpinSegment()) {
2619 Hairpin* h = toHairpinSegment(e)->hairpin();
2620 HairpinType st = h->hairpinType();
2621 switch (st) {
2622 case HairpinType::CRESC_HAIRPIN:
2623 st = HairpinType::DECRESC_HAIRPIN;
2624 break;
2625 case HairpinType::DECRESC_HAIRPIN:
2626 st = HairpinType::CRESC_HAIRPIN;
2627 break;
2628 case HairpinType::CRESC_LINE:
2629 st = HairpinType::DECRESC_LINE;
2630 break;
2631 case HairpinType::DECRESC_LINE:
2632 st = HairpinType::CRESC_LINE;
2633 break;
2634 case HairpinType::INVALID:
2635 break;
2636 }
2637 h->undoChangeProperty(Pid::HAIRPIN_TYPE, int(st));
2638 }
2639 }
2640 }
2641
2642 //---------------------------------------------------------
2643 // cmdIncDecDuration
2644 // When stepDotted is false and nSteps is 1 or -1, will halve or double the duration
2645 // When stepDotted is true, will step by nearest dotted or undotted note
2646 //---------------------------------------------------------
2647
cmdIncDecDuration(int nSteps,bool stepDotted)2648 void Score::cmdIncDecDuration(int nSteps, bool stepDotted)
2649 {
2650 Element* el = selection().element();
2651 if (el == 0)
2652 return;
2653 if (el->isNote())
2654 el = el->parent();
2655 if (!el->isChordRest())
2656 return;
2657
2658 ChordRest* cr = toChordRest(el);
2659
2660 // if measure rest is selected as input, then the correct initialDuration will be the
2661 // duration of the measure's time signature, else is just the input state's duration
2662 TDuration initialDuration = (cr->durationType() == TDuration::DurationType::V_MEASURE) ? TDuration(cr->measure()->timesig()) : _is.duration();
2663 TDuration d = initialDuration.shiftRetainDots(nSteps, stepDotted);
2664 if (!d.isValid())
2665 return;
2666 if (cr->isChord() && (toChord(cr)->noteType() != NoteType::NORMAL)) {
2667 //
2668 // handle appoggiatura and acciaccatura
2669 //
2670 undoChangeChordRestLen(cr, d);
2671 }
2672 else
2673 changeCRlen(cr, d);
2674 _is.setDuration(d);
2675 nextInputPos(cr, false);
2676 }
2677
2678 //---------------------------------------------------------
2679 // cmdAddBracket
2680 //---------------------------------------------------------
2681
cmdAddBracket()2682 void Score::cmdAddBracket()
2683 {
2684 for (Element* el : selection().elements()) {
2685 if (el->type() == ElementType::ACCIDENTAL) {
2686 Accidental* acc = toAccidental(el);
2687 acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::BRACKET));
2688 }
2689 }
2690 }
2691
2692 //---------------------------------------------------------
2693 // cmdAddParentheses
2694 //---------------------------------------------------------
2695
cmdAddParentheses()2696 void Score::cmdAddParentheses()
2697 {
2698 for (Element* el : selection().elements()) {
2699 if (el->type() == ElementType::NOTE) {
2700 Note* n = toNote(el);
2701 n->addParentheses();
2702 }
2703 else if (el->type() == ElementType::ACCIDENTAL) {
2704 Accidental* acc = toAccidental(el);
2705 acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::PARENTHESIS));
2706 }
2707 else if (el->type() == ElementType::HARMONY) {
2708 Harmony* h = toHarmony(el);
2709 h->setLeftParen(true);
2710 h->setRightParen(true);
2711 h->render();
2712 }
2713 else if (el->type() == ElementType::TIMESIG) {
2714 TimeSig* ts = toTimeSig(el);
2715 ts->setLargeParentheses(true);
2716 }
2717 }
2718 }
2719
2720 //---------------------------------------------------------
2721 // cmdAddBraces
2722 //---------------------------------------------------------
2723
cmdAddBraces()2724 void Score::cmdAddBraces()
2725 {
2726 for (Element* el : selection().elements()) {
2727 if (el->type() == ElementType::ACCIDENTAL) {
2728 Accidental* acc = toAccidental(el);
2729 acc->undoChangeProperty(Pid::ACCIDENTAL_BRACKET, int(AccidentalBracket::BRACE));
2730 }
2731 }
2732 }
2733
2734 //---------------------------------------------------------
2735 // cmdMoveRest
2736 //---------------------------------------------------------
2737
cmdMoveRest(Rest * rest,Direction dir)2738 void Score::cmdMoveRest(Rest* rest, Direction dir)
2739 {
2740 QPointF pos(rest->offset());
2741 if (dir == Direction::UP)
2742 pos.ry() -= spatium();
2743 else if (dir == Direction::DOWN)
2744 pos.ry() += spatium();
2745 rest->undoChangeProperty(Pid::OFFSET, pos);
2746 }
2747
2748 //---------------------------------------------------------
2749 // cmdMoveLyrics
2750 //---------------------------------------------------------
2751
cmdMoveLyrics(Lyrics * lyrics,Direction dir)2752 void Score::cmdMoveLyrics(Lyrics* lyrics, Direction dir)
2753 {
2754 int verse = lyrics->no() + (dir == Direction::UP ? -1 : 1);
2755 if (verse < 0)
2756 return;
2757 lyrics->undoChangeProperty(Pid::VERSE, verse);
2758 }
2759
2760 //---------------------------------------------------------
2761 // cmdInsertClef
2762 //---------------------------------------------------------
2763
cmdInsertClef(ClefType type)2764 void Score::cmdInsertClef(ClefType type)
2765 {
2766 undoChangeClef(staff(inputTrack()/VOICES), inputState().cr(), type);
2767 }
2768
2769 //---------------------------------------------------------
2770 // cmdInsertClef
2771 // insert clef before cr
2772 //---------------------------------------------------------
2773
cmdInsertClef(Clef * clef,ChordRest * cr)2774 void Score::cmdInsertClef(Clef* clef, ChordRest* cr)
2775 {
2776 undoChangeClef(cr->staff(), cr, clef->clefType());
2777 delete clef;
2778 }
2779
2780 //---------------------------------------------------------
2781 // cmdAddGrace
2782 /// adds grace note of specified type to selected notes
2783 //---------------------------------------------------------
2784
cmdAddGrace(NoteType graceType,int duration)2785 void Score::cmdAddGrace (NoteType graceType, int duration)
2786 {
2787 const QList<Element*> copyOfElements = selection().elements();
2788 for (Element* e : copyOfElements) {
2789 if (e->type() == ElementType::NOTE) {
2790 Note* n = toNote(e);
2791 setGraceNote(n->chord(), n->pitch(), graceType, duration);
2792 }
2793 }
2794 }
2795
2796 //---------------------------------------------------------
2797 // cmdExplode
2798 /// explodes contents of top selected staff into subsequent staves
2799 //---------------------------------------------------------
2800
cmdExplode()2801 void Score::cmdExplode()
2802 {
2803 if (!selection().isRange())
2804 return;
2805
2806 int srcStaff = selection().staffStart();
2807 int lastStaff = selection().staffEnd();
2808 int srcTrack = srcStaff * VOICES;
2809
2810 // reset selection to top staff only
2811 // force complete measures
2812 Segment* startSegment = selection().startSegment();
2813 Segment* endSegment = selection().endSegment();
2814 Measure* startMeasure = startSegment->measure();
2815 Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
2816
2817 Fraction lTick = endMeasure->endTick();
2818 bool voice = false;
2819
2820 for (Measure* m = startMeasure; m && m->tick() != lTick; m = m->nextMeasure()) {
2821 if (m->hasVoices(srcStaff)) {
2822 voice = true;
2823 break;
2824 }
2825 }
2826 if (! voice) {
2827 // force complete measures
2828 deselectAll();
2829 select(startMeasure, SelectType::RANGE, srcStaff);
2830 select(endMeasure, SelectType::RANGE, srcStaff);
2831 startSegment = selection().startSegment();
2832 endSegment = selection().endSegment();
2833 if (srcStaff == lastStaff - 1) {
2834 // only one staff was selected up front - determine number of staves
2835 // loop through all chords looking for maximum number of notes
2836 int n = 0;
2837 for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2838 Element* e = s->element(srcTrack);
2839 if (e && e->type() == ElementType::CHORD) {
2840 Chord* c = toChord(e);
2841 n = qMax(n, int(c->notes().size()));
2842 }
2843 }
2844 lastStaff = qMin(nstaves(), srcStaff + n);
2845 }
2846
2847 const QByteArray mimeData(selection().mimeData());
2848 // copy to all destination staves
2849 Segment* firstCRSegment = startMeasure->tick2segment(startMeasure->tick());
2850 for (int i = 1; srcStaff + i < lastStaff; ++i) {
2851 int track = (srcStaff + i) * VOICES;
2852 ChordRest* cr = toChordRest(firstCRSegment->element(track));
2853 if (cr) {
2854 XmlReader e(mimeData);
2855 e.setPasteMode(true);
2856 pasteStaff(e, cr->segment(), cr->staffIdx());
2857 }
2858 }
2859
2860 // loop through each staff removing all but one note from each chord
2861 for (int i = 0; srcStaff + i < lastStaff; ++i) {
2862 int track = (srcStaff + i) * VOICES;
2863 for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2864 Element* e = s->element(track);
2865 if (e && e->type() == ElementType::CHORD) {
2866 Chord* c = toChord(e);
2867 std::vector<Note*> notes = c->notes();
2868 int nnotes = int(notes.size());
2869 // keep note "i" from top, which is backwards from nnotes - 1
2870 // reuse notes if there are more instruments than notes
2871 int stavesPerNote = qMax((lastStaff - srcStaff) / nnotes, 1);
2872 int keepIndex = qMax(nnotes - 1 - (i / stavesPerNote), 0);
2873 Note* keepNote = c->notes()[keepIndex];
2874 foreach (Note* n, notes) {
2875 if (n != keepNote)
2876 undoRemoveElement(n);
2877 }
2878 }
2879 }
2880 }
2881 }
2882 else {
2883 int sTracks[VOICES];
2884 int dTracks[VOICES];
2885 if (srcStaff == lastStaff - 1)
2886 lastStaff = qMin(nstaves(), srcStaff + VOICES);
2887
2888 for (int i = 0; i < VOICES; i++) {
2889 sTracks[i] = -1;
2890 dTracks[i] = -1;
2891 }
2892 int full = 0;
2893
2894 for (Segment* seg = startSegment; seg && seg->tick() < lTick; seg = seg->next1()) {
2895 for (int i = srcTrack; i < srcTrack + VOICES && full != VOICES; i++) {
2896 bool t = true;
2897 for (int j = 0; j < VOICES; j++) {
2898 if (i == sTracks[j]) {
2899 t = false;
2900 break;
2901 }
2902 }
2903
2904 if (!seg->measure()->hasVoice(i) || seg->measure()->isOnlyRests(i) || !t)
2905 continue;
2906 sTracks[full] = i;
2907
2908 for(int j = srcTrack + full * VOICES; j < lastStaff * VOICES; j++) {
2909 if (i == j) {
2910 dTracks[full] = j;
2911 break;
2912 }
2913 for(Measure* m = seg->measure(); m && m->tick() < lTick; m = m->nextMeasure()) {
2914 if (!m->hasVoice(j) || (m->hasVoice(j) && m->isOnlyRests(j)))
2915 dTracks[full] = j;
2916 else {
2917 dTracks[full] = -1;
2918 break;
2919 }
2920 }
2921 if (dTracks[full] != -1)
2922 break;
2923 }
2924 full++;
2925 }
2926 }
2927
2928 for (int i = srcTrack, j = 0; i < lastStaff * VOICES && j < VOICES ; i += VOICES, j++) {
2929 int strack = sTracks[j % VOICES];
2930 int dtrack = dTracks[j % VOICES];
2931 if (strack != -1 && strack != dtrack && dtrack != -1)
2932 undo(new CloneVoice(startSegment, lTick, startSegment, strack, dtrack, -1, false));
2933 }
2934 }
2935
2936 // select exploded region
2937 deselectAll();
2938 select(startMeasure, SelectType::RANGE, srcStaff);
2939 select(endMeasure, SelectType::RANGE, lastStaff - 1);
2940 }
2941
2942 //---------------------------------------------------------
2943 // cmdImplode
2944 /// implodes contents of selected staves into top staff
2945 /// for single staff, merge voices
2946 //---------------------------------------------------------
2947
cmdImplode()2948 void Score::cmdImplode()
2949 {
2950 if (!selection().isRange())
2951 return;
2952
2953 int dstStaff = selection().staffStart();
2954 int endStaff = selection().staffEnd();
2955 int dstTrack = dstStaff * VOICES;
2956 int startTrack = dstStaff * VOICES;
2957 int endTrack = endStaff * VOICES;
2958 Segment* startSegment = selection().startSegment();
2959 Segment* endSegment = selection().endSegment();
2960 Measure* startMeasure = startSegment->measure();
2961 Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasure();
2962 Fraction startTick = startSegment->tick();
2963 Fraction endTick = endSegment ? endSegment->tick() : lastMeasure()->endTick();
2964 Q_ASSERT(startMeasure && endMeasure);
2965
2966 // if single staff selected, combine voices
2967 // otherwise combine staves
2968 if (dstStaff == endStaff - 1) {
2969
2970 // loop through segments adding notes to chord on top staff
2971 for (Segment* s = startSegment; s && s != endSegment; s = s->next1()) {
2972 if (!s->isChordRestType())
2973 continue;
2974 Element* dst = s->element(dstTrack);
2975 if (dst && dst->isChord()) {
2976 Chord* dstChord = toChord(dst);
2977 // see if we are tying in to this chord
2978 Chord* tied = 0;
2979 for (Note* n : dstChord->notes()) {
2980 if (n->tieBack()) {
2981 tied = n->tieBack()->startNote()->chord();
2982 break;
2983 }
2984 }
2985 // loop through each subsequent staff (or track within staff)
2986 // looking for notes to add
2987 for (int srcTrack = startTrack + 1; srcTrack < endTrack; srcTrack++) {
2988 Element* src = s->element(srcTrack);
2989 if (src && src->isChord()) {
2990 Chord* srcChord = toChord(src);
2991 // when combining voices, skip if not same duration
2992 if (srcChord->ticks() != dstChord->ticks())
2993 continue;
2994 // add notes
2995 for (Note* n : srcChord->notes()) {
2996 NoteVal nv(n->pitch());
2997 nv.tpc1 = n->tpc1();
2998 // skip duplicates
2999 if (dstChord->findNote(nv.pitch))
3000 continue;
3001 Note* nn = addNote(dstChord, nv);
3002 // add tie to this note if original chord was tied
3003 if (tied) {
3004 // find note to tie to
3005 for (Note *tn : tied->notes()) {
3006 if (nn->pitch() == tn->pitch() && nn->tpc() == tn->tpc() && !tn->tieFor()) {
3007 // found note to tie
3008 Tie* tie = new Tie(this);
3009 tie->setStartNote(tn);
3010 tie->setEndNote(nn);
3011 tie->setTick(tie->startNote()->tick());
3012 tie->setTick2(tie->endNote()->tick());
3013 tie->setTrack(tn->track());
3014 undoAddElement(tie);
3015 }
3016 }
3017 }
3018 }
3019 }
3020 // delete chordrest from source track if possible
3021 if (src && src->voice())
3022 undoRemoveElement(src);
3023 }
3024 }
3025 // TODO - use first voice that actually has a note and implode remaining voices on it?
3026 // see https://musescore.org/en/node/174111
3027 else if (dst) {
3028 // destination track has something, but it isn't a chord
3029 // remove rests from other voices if in "voice mode"
3030 for (int i = 1; i < VOICES; ++i) {
3031 Element* e = s->element(dstTrack + i);
3032 if (e && e->isRest())
3033 undoRemoveElement(e);
3034 }
3035 }
3036 }
3037 // delete orphaned spanners (TODO: figure out solution to reconnect orphaned spanners to their cloned notes)
3038 checkSpanner(startTick, endTick);
3039 }
3040 else {
3041 int tracks[VOICES];
3042 for (int i = 0; i < VOICES; i++)
3043 tracks[i] = -1;
3044 int full = 0;
3045
3046 // identify tracks to combine, storing the source track numbers in tracks[]
3047 // first four non-empty tracks to win
3048 for (int track = startTrack; track < endTrack && full < VOICES; ++track) {
3049 Measure* m = startMeasure;
3050 do {
3051 if (m->hasVoice(track) && !m->isOnlyRests(track)) {
3052 tracks[full++] = track;
3053 break;
3054 }
3055 } while ((m != endMeasure) && (m = m->nextMeasure()));
3056 }
3057
3058 // clone source tracks into destination
3059 for (int i = dstTrack; i < dstTrack + VOICES; i++) {
3060 int strack = tracks[i % VOICES];
3061 if (strack != -1 && strack != i) {
3062 undo( new CloneVoice(startSegment, endTick, startSegment, strack, i, i, false));
3063 }
3064 }
3065 }
3066
3067 // select destination staff only
3068 deselectAll();
3069 select(startMeasure, SelectType::RANGE, dstStaff);
3070 select(endMeasure, SelectType::RANGE, dstStaff);
3071 }
3072
3073 //---------------------------------------------------------
3074 // cmdSlashFill
3075 /// fills selected region with slashes
3076 //---------------------------------------------------------
3077
cmdSlashFill()3078 void Score::cmdSlashFill()
3079 {
3080 int startStaff = selection().staffStart();
3081 int endStaff = selection().staffEnd();
3082 Segment* startSegment = selection().startSegment();
3083 if (!startSegment) // empty score?
3084 return;
3085
3086 Segment* endSegment = selection().endSegment();
3087
3088 // operate on measures underlying mmrests
3089 if (startSegment && startSegment->measure() && startSegment->measure()->isMMRest())
3090 startSegment = startSegment->measure()->mmRestFirst()->first();
3091 if (endSegment && endSegment->measure() && endSegment->measure()->isMMRest())
3092 endSegment = endSegment->measure()->mmRestLast()->last();
3093
3094 Fraction endTick = endSegment ? endSegment->tick() : lastSegment()->tick() + Fraction::fromTicks(1);
3095 Chord* firstSlash = 0;
3096 Chord* lastSlash = 0;
3097
3098 // loop through staves in selection
3099 for (int staffIdx = startStaff; staffIdx < endStaff; ++staffIdx) {
3100 int track = staffIdx * VOICES;
3101 int voice = -1;
3102 // loop through segments adding slashes on each beat
3103 for (Segment* s = startSegment; s && s->tick() < endTick; s = s->next1()) {
3104 if (s->segmentType() != SegmentType::ChordRest)
3105 continue;
3106 // determine beat type based on time signature
3107 int d = s->measure()->timesig().denominator();
3108 int n = (d > 4 && s->measure()->timesig().numerator() % 3 == 0) ? 3 : 1;
3109 Fraction f(n, d);
3110 // skip over any leading segments before next (first) beat
3111 if (s->rtick().ticks() % f.ticks())
3112 continue;
3113 // determine voice to use - first available voice for this measure / staff
3114 if (voice == -1 || s->rtick().isZero()) {
3115 bool needGap[VOICES];
3116 for (voice = 0; voice < VOICES; ++voice) {
3117 needGap[voice] = false;
3118 ChordRest* cr = toChordRest(s->element(track + voice));
3119 // no chordrest == treat as ordinary rest for purpose of determining availbility of voice
3120 // but also, we will need to make a gap for this voice if we do end up choosing it
3121 if (!cr)
3122 needGap[voice] = true;
3123 // chord == keep looking for an available voice
3124 else if (cr->type() == ElementType::CHORD)
3125 continue;
3126 // full measure rest == OK to use voice
3127 else if (cr->durationType() == TDuration::DurationType::V_MEASURE)
3128 break;
3129 // no chordrest or ordinary rest == OK to use voice
3130 // if there are nothing but rests for duration of measure / selection
3131 bool ok = true;
3132 for (Segment* ns = s->next(SegmentType::ChordRest); ns && ns != endSegment; ns = ns->next(SegmentType::ChordRest)) {
3133 ChordRest* ncr = toChordRest(ns->element(track + voice));
3134 if (ncr && ncr->type() == ElementType::CHORD) {
3135 ok = false;
3136 break;
3137 }
3138 }
3139 if (ok)
3140 break;
3141 }
3142 // no available voices, just use voice 0
3143 if (voice == VOICES)
3144 voice = 0;
3145 // no cr was found in segment for this voice, so make gap
3146 if (needGap[voice])
3147 makeGapVoice(s, track + voice, f, s->tick());
3148 }
3149 // construct note
3150 int line = 0;
3151 bool error = false;
3152 NoteVal nv;
3153 if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::TAB)
3154 line = staff(staffIdx)->lines(s->tick()) / 2;
3155 else
3156 line = staff(staffIdx)->middleLine(s->tick()); // staff(staffIdx)->lines() - 1;
3157 if (staff(staffIdx)->staffType(s->tick())->group() == StaffGroup::PERCUSSION) {
3158 nv.pitch = 0;
3159 nv.headGroup = NoteHead::Group::HEAD_SLASH;
3160 }
3161 else {
3162 Position p;
3163 p.segment = s;
3164 p.staffIdx = staffIdx;
3165 p.line = line;
3166 p.fret = FRET_NONE;
3167 _is.setRest(false); // needed for tab
3168 nv = noteValForPosition(p, AccidentalType::NONE, error);
3169 }
3170 if (error)
3171 continue;
3172 // insert & turn into slash
3173 s = setNoteRest(s, track + voice, nv, f);
3174 Chord* c = toChord(s->element(track + voice));
3175 if (c->links()) {
3176 for (ScoreElement* e : *c->links()) {
3177 Chord* lc = toChord(e);
3178 lc->setSlash(true, true);
3179 }
3180 }
3181 else
3182 c->setSlash(true, true);
3183 lastSlash = c;
3184 if (!firstSlash)
3185 firstSlash = c;
3186 }
3187 }
3188
3189 // re-select the slashes
3190 deselectAll();
3191 if (firstSlash && lastSlash) {
3192 select(firstSlash, SelectType::RANGE);
3193 select(lastSlash, SelectType::RANGE);
3194 }
3195 }
3196
3197 //---------------------------------------------------------
3198 // cmdSlashRhythm
3199 /// converts rhythms in selected region to slashes
3200 //---------------------------------------------------------
3201
cmdSlashRhythm()3202 void Score::cmdSlashRhythm()
3203 {
3204 QList<Chord*> chords;
3205 // loop through all notes in selection
3206 foreach (Element* e, selection().elements()) {
3207 if (e->voice() >= 2 && e->isRest()) {
3208 Rest* r = toRest(e);
3209 if (r->links()) {
3210 for (ScoreElement* se : *r->links()) {
3211 Rest* lr = toRest(se);
3212 lr->setAccent(!lr->accent());
3213 }
3214 }
3215 else
3216 r->setAccent(!r->accent());
3217 continue;
3218 }
3219 else if (e->isNote()) {
3220 Note* n = toNote(e);
3221 if (n->noteType() != NoteType::NORMAL)
3222 continue;
3223 Chord* c = n->chord();
3224 // check for duplicates (chords with multiple notes)
3225 if (chords.contains(c))
3226 continue;
3227 chords.append(c);
3228 // toggle slash setting
3229 if (c->links()) {
3230 for (ScoreElement* se : *c->links()) {
3231 Chord* lc = toChord(se);
3232 lc->setSlash(!lc->slash(), false);
3233 }
3234 }
3235 else
3236 c->setSlash(!c->slash(), false);
3237 }
3238 }
3239 }
3240
3241 //---------------------------------------------------------
3242 // cmdRealizeChordSymbols
3243 /// Realize selected chord symbols into notes on the staff.
3244 ///
3245 /// If a voicing and duration type are specified, the
3246 /// harmony voicing settings will be overridden by the
3247 /// passed parameters. Otherwise, the settings set on the
3248 /// harmony object will be used.
3249 //---------------------------------------------------------
3250
cmdRealizeChordSymbols(bool literal,Voicing voicing,HDuration durationType)3251 void Score::cmdRealizeChordSymbols(bool literal, Voicing voicing, HDuration durationType)
3252 {
3253 const QList<Element*> elist = selection().elements();
3254 for (Element* e : elist) {
3255 if (!e->isHarmony())
3256 continue;
3257 Harmony* h = toHarmony(e);
3258 if (!h->isRealizable())
3259 continue;
3260 RealizedHarmony r = h->getRealizedHarmony();
3261 Segment* seg = h->parent()->isSegment() ? toSegment(h->parent()) : toSegment(h->parent()->parent());
3262 Fraction tick = seg->tick();
3263 Fraction duration = r.getActualDuration(tick.ticks(), durationType);
3264 bool concertPitch = styleB(Sid::concertPitch);
3265
3266 Chord* chord = new Chord(this); //chord template
3267 chord->setTrack(h->track()); //set track so notes have a track to sit on
3268
3269 //create chord from notes
3270 RealizedHarmony::PitchMap notes;
3271 if (voicing == Voicing::INVALID || durationType == HDuration::INVALID)
3272 notes = r.notes(); //no override, just use notes from realize harmony
3273 else {
3274 //generate notes list based on overridden settings
3275 int offset = 0;
3276 Interval interval = h->staff()->part()->instrument(h->tick())->transpose();
3277 if (!concertPitch)
3278 offset = interval.chromatic;
3279 notes = r.generateNotes(h->rootTpc(), h->baseTpc(),
3280 literal, voicing, offset);
3281 }
3282 RealizedHarmony::PitchMapIterator i(notes); //add notes to chord
3283 while (i.hasNext()) {
3284 i.next();
3285 Note* note = new Note(this);
3286 NoteVal nval;
3287 nval.pitch = i.key();
3288 if (concertPitch)
3289 nval.tpc1 = i.value();
3290 else
3291 nval.tpc2 = i.value();
3292 chord->add(note); //add note first to set track and such
3293 note->setNval(nval, tick);
3294 }
3295
3296 setChord(seg, h->track(), chord, duration); //add chord using template
3297 delete chord;
3298 }
3299 }
3300
3301 //---------------------------------------------------------
3302 // setChord
3303 // return segment of last created chord
3304 //---------------------------------------------------------
setChord(Segment * segment,int track,Chord * chordTemplate,Fraction dur,Direction stemDirection)3305 Segment* Score::setChord(Segment* segment, int track, Chord* chordTemplate, Fraction dur, Direction stemDirection)
3306 {
3307 Q_ASSERT(segment->segmentType() == SegmentType::ChordRest);
3308
3309 Fraction tick = segment->tick();
3310 Chord* nr = 0; //current added chord used so we can select the last added chord and so we can apply ties
3311 std::vector<Tie*> tie(chordTemplate->notes().size()); //keep pointer to a tie for each note in the chord in case we need to tie notes
3312 ChordRest* cr = toChordRest(segment->element(track)); //chord rest under the segment for the specified track
3313
3314 bool addTie = false;
3315
3316 Measure* measure = 0;
3317 //keep creating chords and tieing them until we created the full duration asked for (dur)
3318 for (;;) {
3319 if (track % VOICES)
3320 expandVoice(segment, track);
3321
3322 Tuplet* t = cr ? cr->tuplet() : 0;
3323 Fraction tDur = segment->ticks();
3324 Segment* seg = segment->next();
3325
3326 //we need to get a correct subduration so that makeGap can function properly
3327 //since makeGap() takes "normal" duration rather than actual length
3328 while (seg) {
3329 if (seg->segmentType() == SegmentType::ChordRest) {
3330 //design choice made to keep multiple notes across a tuplet as tied single notes rather than combining them
3331 //since it's arguably more readable, but the other code is still here (commented)
3332 ChordRest* testCr = toChordRest(seg->element(track));
3333
3334 //code here allows us to combine tuplet realization together which I have opted not to do for readability (of the music)
3335 //if (!!t ^ (testCr && testCr->tuplet())) //stop if we started with a tuplet and reach something that's not a tuplet,
3336 // break; //or start with not a tuplet and reach a tuplet
3337
3338 if (testCr && testCr->tuplet()) //stop on tuplet
3339 break;
3340 tDur += seg->ticks();
3341 }
3342 if (tDur >= dur) { //do not go further than the duration asked for
3343 tDur = dur;
3344 break;
3345 }
3346 seg = seg->next(); //iterate only across measure (hence usage of next() rather than next1())
3347 }
3348 if (t)
3349 tDur *= t->ratio(); //scale by tuplet ratio to get "normal" length rather than actual length when dealing with tuplets
3350
3351 // the returned gap ends at the measure boundary or at tuplet end
3352 Fraction dd = makeGap(segment, track, tDur, t);
3353
3354 if (dd.isZero()) {
3355 qDebug("cannot get gap at %d type: %d/%d", tick.ticks(), dur.numerator(),
3356 dur.denominator());
3357 break;
3358 }
3359
3360 measure = segment->measure();
3361 std::vector<TDuration> dl = toDurationList(dd, true);
3362 size_t n = dl.size();
3363 //add chord, tieing when necessary within measure
3364 for (size_t i = 0; i < n; ++i) {
3365 const TDuration& d = dl[i];
3366
3367 //create new chord from template and add it
3368 Chord* chord = new Chord(*chordTemplate);
3369 nr = chord;
3370
3371 chord->setTrack(track);
3372 chord->setDurationType(d);
3373 chord->setTicks(d.fraction());
3374 chord->setStemDirection(stemDirection);
3375 chord->setTuplet(t);
3376 undoAddCR(chord, measure, tick);
3377 //if there is something to tie, complete tie backwards
3378 //and add the tie to score
3379 const std::vector<Note*> notes = chord->notes();
3380 if (addTie) {
3381 for (size_t j = 0; j < notes.size(); ++j) {
3382 tie[j]->setEndNote(notes[j]);
3383 notes[j]->setTieBack(tie[j]);
3384 undoAddElement(tie[j]);
3385 }
3386 addTie = false;
3387 }
3388 //if we're not the last element in the duration list,
3389 //set tie forward
3390 if (i+1 < n) {
3391 for (size_t j = 0; j < notes.size(); ++j) {
3392 tie[j] = new Tie(this);
3393 tie[j]->setStartNote(notes[j]);
3394 tie[j]->setTick(tie[j]->startNote()->tick());
3395 tie[j]->setTrack(track);
3396 notes[j]->setTieFor(tie[j]);
3397 addTie = true;
3398 }
3399 }
3400 setPlayChord(true);
3401 segment = chord->segment();
3402 tick += chord->actualTicks();
3403 }
3404
3405 //subtract the duration already realized and move on
3406 if (t)
3407 dur -= dd / t->ratio();
3408 else
3409 dur -= dd;
3410 //we are done when there is no duration left to realize
3411 if (dur.isZero())
3412 break;
3413
3414 //go to next segment unless we are at the score (which means we will just be done there)
3415 Segment* nseg = tick2segment(tick, false, SegmentType::ChordRest);
3416 if (nseg == 0) {
3417 qDebug("reached end of score");
3418 break;
3419 }
3420 segment = nseg;
3421
3422 cr = toChordRest(segment->element(track));
3423
3424 if (!cr) {
3425 if (track % VOICES)
3426 cr = addRest(segment, track, TDuration(TDuration::DurationType::V_MEASURE), 0);
3427 else {
3428 qDebug("no rest in voice 0");
3429 break;
3430 }
3431 }
3432 //
3433 // Note does not fit on current measure, create Tie to
3434 // next part of note
3435 std::vector<Note*> notes = nr->notes();
3436 for (size_t i = 0; i < notes.size(); ++i) {
3437 tie[i] = new Tie(this);
3438 tie[i]->setStartNote(notes[i]);
3439 tie[i]->setTick(tie[i]->startNote()->tick());
3440 tie[i]->setTrack(notes[i]->track());
3441 notes[i]->setTieFor(tie[i]);
3442 }
3443 }
3444 if (!tie.empty())
3445 connectTies();
3446 if (nr)
3447 select(nr, SelectType::SINGLE, 0);
3448 return segment;
3449 }
3450
3451 //---------------------------------------------------------
3452 // cmdResequenceRehearsalMarks
3453 /// resequences rehearsal marks within a range selection
3454 /// or, if nothing is selected, the entire score
3455 //---------------------------------------------------------
3456
cmdResequenceRehearsalMarks()3457 void Score::cmdResequenceRehearsalMarks()
3458 {
3459 bool noSelection = !selection().isRange();
3460
3461 if (noSelection)
3462 cmdSelectAll();
3463 else if (!selection().isRange())
3464 return;
3465
3466 RehearsalMark* last = 0;
3467 for (Segment* s = selection().startSegment(); s && s != selection().endSegment(); s = s->next1()) {
3468 for (Element* e : s->annotations()) {
3469 if (e->type() == ElementType::REHEARSAL_MARK) {
3470 RehearsalMark* rm = toRehearsalMark(e);
3471 if (last) {
3472 QString rmText = nextRehearsalMarkText(last, rm);
3473 for (ScoreElement* le : rm->linkList())
3474 le->undoChangeProperty(Pid::TEXT, rmText);
3475 }
3476 last = rm;
3477 }
3478 }
3479 }
3480
3481 if (noSelection)
3482 deselectAll();
3483 }
3484
3485 //---------------------------------------------------------
3486 // addRemoveBreaks
3487 // interval lock
3488 // 0 false remove all linebreaks
3489 // > 0 false add linebreak every interval measure
3490 // d.c. true add linebreak at every system end
3491 //---------------------------------------------------------
3492
addRemoveBreaks(int interval,bool lock)3493 void Score::addRemoveBreaks(int interval, bool lock)
3494 {
3495 Segment* startSegment = selection().startSegment();
3496 if (!startSegment) // empty score?
3497 return;
3498 Segment* endSegment = selection().endSegment();
3499 Measure* startMeasure = startSegment->measure();
3500 Measure* endMeasure = endSegment ? endSegment->measure() : lastMeasureMM();
3501 Measure* lastMeasure = lastMeasureMM();
3502
3503 // loop through measures in selection
3504 // count mmrests as a single measure
3505 int count = 0;
3506 for (Measure* mm = startMeasure; mm; mm = mm->nextMeasureMM()) {
3507
3508 // even though we are counting mmrests as a single measure,
3509 // we need to find last real measure within mmrest for the actual break
3510 Measure* m = mm->isMMRest() ? mm->mmRestLast() : mm;
3511
3512 if (lock) {
3513 // skip last measure of score
3514 if (mm == lastMeasure)
3515 break;
3516 // skip if it already has a break
3517 if (m->lineBreak() || m->pageBreak())
3518 continue;
3519 // add break if last measure of system
3520 if (mm->system() && mm->system()->lastMeasure() == mm)
3521 m->undoSetLineBreak(true);
3522 }
3523 else {
3524 if (interval == 0) {
3525 // remove line break if present
3526 if (m->lineBreak())
3527 m->undoSetLineBreak(false);
3528 }
3529 else {
3530 if (++count == interval) {
3531 // skip last measure of score
3532 if (mm == lastMeasure)
3533 break;
3534 // found place for break; add if not already one present
3535 if (!(m->lineBreak() || m->pageBreak()))
3536 m->undoSetLineBreak(true);
3537 // reset count
3538 count = 0;
3539 }
3540 else if (m->lineBreak()) {
3541 // remove line break if present in wrong place
3542 m->undoSetLineBreak(false);
3543 }
3544 }
3545 }
3546
3547 if (mm == endMeasure)
3548 break;
3549 }
3550
3551 }
3552
3553 //---------------------------------------------------------
3554 // cmdRemoveEmptyTrailingMeasures
3555 //---------------------------------------------------------
3556
cmdRemoveEmptyTrailingMeasures()3557 void Score::cmdRemoveEmptyTrailingMeasures()
3558 {
3559 auto beginMeasure = firstTrailingMeasure();
3560 if (beginMeasure)
3561 deleteMeasures(beginMeasure, lastMeasure());
3562 }
3563
3564 //---------------------------------------------------------
3565 // cmdPitchUp
3566 //---------------------------------------------------------
3567
cmdPitchUp()3568 void Score::cmdPitchUp()
3569 {
3570 Element* el = selection().element();
3571 if (el && el->isLyrics())
3572 cmdMoveLyrics(toLyrics(el), Direction::UP);
3573 else if (el && (el->isArticulation() || el->isTextBase()))
3574 el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
3575 else if (el && el->isRest())
3576 cmdMoveRest(toRest(el), Direction::UP);
3577 else
3578 upDown(true, UpDownMode::CHROMATIC);
3579 }
3580
3581 //---------------------------------------------------------
3582 // cmdPitchDown
3583 //---------------------------------------------------------
3584
cmdPitchDown()3585 void Score::cmdPitchDown()
3586 {
3587 Element* el = selection().element();
3588 if (el && el->isLyrics())
3589 cmdMoveLyrics(toLyrics(el), Direction::DOWN);
3590 else if (el && (el->isArticulation() || el->isTextBase()))
3591 el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep * el->spatium()), PropertyFlags::UNSTYLED);
3592 else if (el && el->isRest())
3593 cmdMoveRest(toRest(el), Direction::DOWN);
3594 else
3595 upDown(false, UpDownMode::CHROMATIC);
3596 }
3597
3598 //---------------------------------------------------------
3599 // cmdTimeDelete
3600 //---------------------------------------------------------
3601
cmdTimeDelete()3602 void Score::cmdTimeDelete()
3603 {
3604 Element* e = selection().element();
3605 if (e && e->isBarLine() && toBarLine(e)->segment()->isEndBarLineType()) {
3606 Measure* m = toBarLine(e)->segment()->measure();
3607 cmdJoinMeasure(m, m->nextMeasure());
3608 }
3609 else {
3610 if (_is.insertMode())
3611 globalTimeDelete();
3612 else
3613 localTimeDelete();
3614 }
3615 }
3616
3617 //---------------------------------------------------------
3618 // cmdPitchUpOctave
3619 //---------------------------------------------------------
3620
cmdPitchUpOctave()3621 void Score::cmdPitchUpOctave()
3622 {
3623 Element* el = selection().element();
3624 if (el && (el->isArticulation() || el->isTextBase()))
3625 el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, -MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
3626 else
3627 upDown(true, UpDownMode::OCTAVE);
3628 }
3629
3630 //---------------------------------------------------------
3631 // cmdPitchDownOctave
3632 //---------------------------------------------------------
3633
cmdPitchDownOctave()3634 void Score::cmdPitchDownOctave()
3635 {
3636 Element* el = selection().element();
3637 if (el && (el->isArticulation() || el->isTextBase()))
3638 el->undoChangeProperty(Pid::OFFSET, el->offset() + QPointF(0.0, MScore::nudgeStep10 * el->spatium()), PropertyFlags::UNSTYLED);
3639 else
3640 upDown(false, UpDownMode::OCTAVE);
3641 }
3642
3643 //---------------------------------------------------------
3644 // cmdPadNoteInclreaseTAB
3645 //---------------------------------------------------------
3646
cmdPadNoteIncreaseTAB(const EditData & ed)3647 void Score::cmdPadNoteIncreaseTAB(const EditData& ed)
3648 {
3649 switch (_is.duration().type() ) {
3650 // cycle back from longest to shortest?
3651 // case TDuration::V_LONG:
3652 // padToggle(Pad::NOTE128, ed);
3653 // break;
3654 case TDuration::DurationType::V_BREVE:
3655 padToggle(Pad::NOTE00, ed);
3656 break;
3657 case TDuration::DurationType::V_WHOLE:
3658 padToggle(Pad::NOTE0, ed);
3659 break;
3660 case TDuration::DurationType::V_HALF:
3661 padToggle(Pad::NOTE1, ed);
3662 break;
3663 case TDuration::DurationType::V_QUARTER:
3664 padToggle(Pad::NOTE2, ed);
3665 break;
3666 case TDuration::DurationType::V_EIGHTH:
3667 padToggle(Pad::NOTE4, ed);
3668 break;
3669 case TDuration::DurationType::V_16TH:
3670 padToggle(Pad::NOTE8, ed);
3671 break;
3672 case TDuration::DurationType::V_32ND:
3673 padToggle(Pad::NOTE16, ed);
3674 break;
3675 case TDuration::DurationType::V_64TH:
3676 padToggle(Pad::NOTE32, ed);
3677 break;
3678 case TDuration::DurationType::V_128TH:
3679 padToggle(Pad::NOTE64, ed);
3680 break;
3681 default:
3682 break;
3683 }
3684 }
3685
3686 //---------------------------------------------------------
3687 // cmdPadNoteDecreaseTAB
3688 //---------------------------------------------------------
3689
cmdPadNoteDecreaseTAB(const EditData & ed)3690 void Score::cmdPadNoteDecreaseTAB(const EditData& ed)
3691 {
3692 switch (_is.duration().type() ) {
3693 case TDuration::DurationType::V_LONG:
3694 padToggle(Pad::NOTE0, ed);
3695 break;
3696 case TDuration::DurationType::V_BREVE:
3697 padToggle(Pad::NOTE1, ed);
3698 break;
3699 case TDuration::DurationType::V_WHOLE:
3700 padToggle(Pad::NOTE2, ed);
3701 break;
3702 case TDuration::DurationType::V_HALF:
3703 padToggle(Pad::NOTE4, ed);
3704 break;
3705 case TDuration::DurationType::V_QUARTER:
3706 padToggle(Pad::NOTE8, ed);
3707 break;
3708 case TDuration::DurationType::V_EIGHTH:
3709 padToggle(Pad::NOTE16, ed);
3710 break;
3711 case TDuration::DurationType::V_16TH:
3712 padToggle(Pad::NOTE32, ed);
3713 break;
3714 case TDuration::DurationType::V_32ND:
3715 padToggle(Pad::NOTE64, ed);
3716 break;
3717 case TDuration::DurationType::V_64TH:
3718 padToggle(Pad::NOTE128, ed);
3719 break;
3720 case TDuration::DurationType::V_128TH:
3721 padToggle(Pad::NOTE256, ed);
3722 break;
3723 case TDuration::DurationType::V_256TH:
3724 padToggle(Pad::NOTE512, ed);
3725 break;
3726 case TDuration::DurationType::V_512TH:
3727 padToggle(Pad::NOTE1024, ed);
3728 break;
3729 // cycle back from shortest to longest?
3730 // case TDuration::DurationType::V_1024TH:
3731 // padToggle(Pad::NOTE00, ed);
3732 // break;
3733 default:
3734 break;
3735 }
3736 }
3737
3738 //---------------------------------------------------------
3739 // cmdToggleLayoutBreak
3740 //---------------------------------------------------------
3741
cmdToggleLayoutBreak(LayoutBreak::Type type)3742 void Score::cmdToggleLayoutBreak(LayoutBreak::Type type)
3743 {
3744 // find measure(s)
3745 QList<MeasureBase*> mbl;
3746 if (selection().isRange()) {
3747 Measure* startMeasure = nullptr;
3748 Measure* endMeasure = nullptr;
3749 if (!selection().measureRange(&startMeasure, &endMeasure))
3750 return;
3751 if (!startMeasure || !endMeasure)
3752 return;
3753 #if 1
3754 // toggle break on the last measure of the range
3755 mbl.append(endMeasure);
3756 // if more than one measure selected,
3757 // also toggle break *before* the range (to try to fit selection on a single line)
3758 if (startMeasure != endMeasure && startMeasure->prev())
3759 mbl.append(startMeasure->prev());
3760 #else
3761 // toggle breaks throughout the selection
3762 for (Measure* m = startMeasure; m; m = m->nextMeasure()) {
3763 mbl.append(m);
3764 if (m == endMeasure)
3765 break;
3766 }
3767 #endif
3768 }
3769 else {
3770 MeasureBase* mb = nullptr;
3771 for (Element* el : selection().elements()) {
3772 switch (el->type()) {
3773 case ElementType::HBOX:
3774 case ElementType::VBOX:
3775 case ElementType::TBOX:
3776 mb = toMeasureBase(el);
3777 break;
3778 default: {
3779 // find measure
3780 Measure* measure = toMeasure(el->findMeasure());
3781 // for start repeat, attach break to previous measure
3782 if (measure && el->isBarLine()) {
3783 BarLine* bl = toBarLine(el);
3784 if (bl->barLineType() == BarLineType::START_REPEAT)
3785 measure = measure->prevMeasure();
3786 }
3787 // if measure is mmrest, then propagate to last original measure
3788 if (measure)
3789 mb = measure->isMMRest() ? measure->mmRestLast() : measure;
3790 }
3791 }
3792 }
3793 if (mb)
3794 mbl.append(mb);
3795 }
3796 // toggle the breaks
3797 for (MeasureBase* mb: mbl) {
3798 if (mb) {
3799 bool val = false;
3800 switch (type) {
3801 case LayoutBreak::Type::LINE:
3802 val = !mb->lineBreak();
3803 mb->undoSetBreak(val, type);
3804 // remove page break if appropriate
3805 if (val && mb->pageBreak())
3806 mb->undoSetBreak(false, LayoutBreak::Type::PAGE);
3807 break;
3808 case LayoutBreak::Type::PAGE:
3809 val = !mb->pageBreak();
3810 mb->undoSetBreak(val, type);
3811 // remove line break if appropriate
3812 if (val && mb->lineBreak())
3813 mb->undoSetBreak(false, LayoutBreak::Type::LINE);
3814 break;
3815 case LayoutBreak::Type::SECTION:
3816 val = !mb->sectionBreak();
3817 mb->undoSetBreak(val, type);
3818 break;
3819 default:
3820 break;
3821 }
3822 }
3823 }
3824 }
3825
3826 //---------------------------------------------------------
3827 // cmdToggleMmrest
3828 //---------------------------------------------------------
3829
cmdToggleMmrest()3830 void Score::cmdToggleMmrest()
3831 {
3832 bool val = !styleB(Sid::createMultiMeasureRests);
3833 deselectAll();
3834 undo(new ChangeStyleVal(this, Sid::createMultiMeasureRests, val));
3835 }
3836
3837 //---------------------------------------------------------
3838 // cmdToggleHideEmpty
3839 //---------------------------------------------------------
3840
cmdToggleHideEmpty()3841 void Score::cmdToggleHideEmpty()
3842 {
3843 bool val = !styleB(Sid::hideEmptyStaves);
3844 deselectAll();
3845 undo(new ChangeStyleVal(this, Sid::hideEmptyStaves, val));
3846 }
3847
3848 //---------------------------------------------------------
3849 // cmdSetVisible
3850 //---------------------------------------------------------
3851
cmdSetVisible()3852 void Score::cmdSetVisible()
3853 {
3854 for (Element* e : selection().elements())
3855 undo(new ChangeProperty(e, Pid::VISIBLE, true));
3856 }
3857
3858 //---------------------------------------------------------
3859 // cmdUnsetVisible
3860 //---------------------------------------------------------
3861
cmdUnsetVisible()3862 void Score::cmdUnsetVisible()
3863 {
3864 for (Element* e : selection().elements())
3865 undo(new ChangeProperty(e, Pid::VISIBLE, false));
3866 }
3867
3868 //---------------------------------------------------------
3869 // cmdAddPitch
3870 /// insert note or add note to chord
3871 // c d e f g a b entered:
3872 //---------------------------------------------------------
3873
cmdAddPitch(const EditData & ed,int note,bool addFlag,bool insert)3874 void Score::cmdAddPitch(const EditData& ed, int note, bool addFlag, bool insert)
3875 {
3876 InputState& is = inputState();
3877 if (is.track() == -1) // invalid state
3878 return;
3879 if (is.segment() == 0) {
3880 qDebug("cannot enter notes here (no chord rest at current position)");
3881 return;
3882 }
3883 is.setRest(false);
3884 const Drumset* ds = is.drumset();
3885 int octave = 4;
3886 if (ds) {
3887 char note1 = "CDEFGAB"[note];
3888 int pitch = -1;
3889 int voice = 0;
3890 for (int i = 0; i < 127; ++i) {
3891 if (!ds->isValid(i))
3892 continue;
3893 if (ds->shortcut(i) && (ds->shortcut(i) == note1)) {
3894 pitch = i;
3895 voice = ds->voice(i);
3896 break;
3897 }
3898 }
3899 if (pitch == -1) {
3900 qDebug(" shortcut %c not defined in drumset", note1);
3901 return;
3902 }
3903 is.setDrumNote(pitch);
3904 is.setTrack((is.track() / VOICES) * VOICES + voice);
3905 octave = pitch / 12;
3906 if (is.segment()) {
3907 Segment* seg = is.segment();
3908 while (seg) {
3909 if (seg->element(is.track()))
3910 break;
3911 seg = seg->prev(SegmentType::ChordRest);
3912 }
3913 if (seg)
3914 is.setSegment(seg);
3915 else
3916 is.setSegment(is.segment()->measure()->first(SegmentType::ChordRest));
3917 }
3918 }
3919 else {
3920 static const int tab[] = { 0, 2, 4, 5, 7, 9, 11 };
3921
3922 // if adding notes, add above the upNote of the current chord
3923 Element* el = selection().element();
3924 if (addFlag && el && el->isNote()) {
3925 Chord* chord = toNote(el)->chord();
3926 Note* n = chord->upNote();
3927 int tpc = n->tpc();
3928 octave = (n->epitch() - int(tpc2alter(tpc))) / PITCH_DELTA_OCTAVE;
3929 if (note <= tpc2step(tpc))
3930 octave++;
3931 }
3932 else {
3933 int curPitch = 60;
3934 if (is.segment()) {
3935 Staff* staff = Score::staff(is.track() / VOICES);
3936 Segment* seg = is.segment()->prev1(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
3937 while (seg) {
3938 if (seg->isChordRestType()) {
3939 Element* p = seg->element(is.track());
3940 if (p && p->isChord()) {
3941 Note* n = toChord(p)->downNote();
3942 // forget any accidental and/or adjustment due to key signature
3943 curPitch = n->epitch() - static_cast<int>(tpc2alter(n->tpc()));
3944 break;
3945 }
3946 }
3947 else if (seg->isClefType() || seg->isHeaderClefType()) {
3948 Element* p = seg->element( (is.track() / VOICES) * VOICES); // clef on voice 1
3949 if (p && p->isClef()) {
3950 Clef* clef = toClef(p);
3951 // check if it's an actual change or just a courtesy
3952 ClefType ctb = staff->clef(clef->tick() - Fraction::fromTicks(1));
3953 if (ctb != clef->clefType() || clef->tick().isZero()) {
3954 curPitch = line2pitch(4, clef->clefType(), Key::C); // C 72 for treble clef
3955 break;
3956 }
3957 }
3958 }
3959 seg = seg->prev1MM(SegmentType::ChordRest | SegmentType::Clef | SegmentType::HeaderClef);
3960 }
3961 octave = curPitch / 12;
3962 }
3963
3964 int delta = octave * 12 + tab[note] - curPitch;
3965 if (delta > 6)
3966 --octave;
3967 else if (delta < -6)
3968 ++octave;
3969 }
3970 }
3971 ed.view->startNoteEntryMode();
3972
3973 int step = octave * 7 + note;
3974 cmdAddPitch(step, addFlag, insert);
3975 ed.view->adjustCanvasPosition(is.cr(), false);
3976 }
3977
cmdAddPitch(int step,bool addFlag,bool insert)3978 void Score::cmdAddPitch(int step, bool addFlag, bool insert)
3979 {
3980 insert = insert || inputState().usingNoteEntryMethod(NoteEntryMethod::TIMEWISE);
3981 Position pos;
3982 if (addFlag) {
3983 Element* el = selection().element();
3984 if (el && el->isNote()) {
3985 Note* selectedNote = toNote(el);
3986 Chord* chord = selectedNote->chord();
3987 Segment* seg = chord->segment();
3988 pos.segment = seg;
3989 pos.staffIdx = selectedNote->track() / VOICES;
3990 ClefType clef = staff(pos.staffIdx)->clef(seg->tick());
3991 pos.line = relStep(step, clef);
3992 bool error;
3993 NoteVal nval = noteValForPosition(pos, _is.accidentalType(), error);
3994 if (error)
3995 return;
3996 bool forceAccidental = false;
3997 if (_is.accidentalType() != AccidentalType::NONE) {
3998 NoteVal nval2 = noteValForPosition(pos, AccidentalType::NONE, error);
3999 forceAccidental = (nval.pitch == nval2.pitch);
4000 }
4001 addNote(chord, nval, forceAccidental);
4002 _is.setAccidentalType(AccidentalType::NONE);
4003 return;
4004 }
4005 }
4006
4007 pos.segment = inputState().segment();
4008 pos.staffIdx = inputState().track() / VOICES;
4009 ClefType clef = staff(pos.staffIdx)->clef(pos.segment->tick());
4010 pos.line = relStep(step, clef);
4011
4012 if (inputState().usingNoteEntryMethod(NoteEntryMethod::REPITCH))
4013 repitchNote(pos, !addFlag);
4014 else {
4015 if (insert)
4016 insertChord(pos);
4017 else
4018 putNote(pos, !addFlag);
4019 }
4020 _is.setAccidentalType(AccidentalType::NONE);
4021 }
4022
4023 //---------------------------------------------------------
4024 // cmdToggleVisible
4025 //---------------------------------------------------------
4026
cmdToggleVisible()4027 void Score::cmdToggleVisible()
4028 {
4029 QSet<Element*> spanners;
4030 for (Element* e : selection().elements()) {
4031 if (e->isBracket()) // ignore
4032 continue;
4033 if (e->isNoteDot() && selection().elements().contains(e->parent()))
4034 // already handled in ScoreElement::undoChangeProperty(); don't toggle twice
4035 continue;
4036 bool spannerSegment = e->isSpannerSegment();
4037 if (!spannerSegment || !spanners.contains(toSpannerSegment(e)->spanner()))
4038 e->undoChangeProperty(Pid::VISIBLE, !e->getProperty(Pid::VISIBLE).toBool());
4039 if (spannerSegment)
4040 spanners.insert(toSpannerSegment(e)->spanner());
4041 }
4042 }
4043
4044 //---------------------------------------------------------
4045 // cmdAddFret
4046 /// insert note with given fret on current string
4047 //---------------------------------------------------------
4048
cmdAddFret(int fret)4049 void Score::cmdAddFret(int fret)
4050 {
4051 InputState& is = inputState();
4052 if (is.track() == -1) // invalid state
4053 return;
4054 if (!is.segment()) {
4055 qDebug("cannot enter notes here (no chord rest at current position)");
4056 return;
4057 }
4058 Position pos;
4059 pos.segment = is.segment();
4060 pos.staffIdx = is.track() / VOICES;
4061 pos.line = staff(pos.staffIdx)->staffType(is.tick())->physStringToVisual(is.string());
4062 pos.fret = fret;
4063 putNote(pos, false);
4064 }
4065
4066 //---------------------------------------------------------
4067 // cmdRelayout
4068 //---------------------------------------------------------
4069
cmdRelayout()4070 void Score::cmdRelayout()
4071 {
4072 setLayoutAll();
4073 }
4074
4075 //---------------------------------------------------------
4076 // cmdToggleAutoplace
4077 //---------------------------------------------------------
4078
cmdToggleAutoplace(bool all)4079 void Score::cmdToggleAutoplace(bool all)
4080 {
4081 if (all) {
4082 bool val = !styleB(Sid::autoplaceEnabled);
4083 undoChangeStyleVal(Sid::autoplaceEnabled, val);
4084 setLayoutAll();
4085 }
4086 else {
4087 QSet<Element*> spanners;
4088 for (Element* e : selection().elements()) {
4089 if (e->isSpannerSegment()) {
4090 if (Element* ee = e->propertyDelegate(Pid::AUTOPLACE))
4091 e = ee;
4092 // spanner segments may each have their own autoplace setting
4093 // but if they delegate to spanner, only toggle once
4094 if (e->isSpanner()) {
4095 if (spanners.contains(e))
4096 continue;
4097 spanners.insert(e);
4098 }
4099 }
4100 PropertyFlags pf = e->propertyFlags(Pid::AUTOPLACE);
4101 if (pf == PropertyFlags::STYLED)
4102 pf = PropertyFlags::UNSTYLED;
4103 e->undoChangeProperty(Pid::AUTOPLACE, !e->getProperty(Pid::AUTOPLACE).toBool(), pf);
4104 }
4105 }
4106 }
4107
4108 //---------------------------------------------------------
4109 // cmd
4110 //---------------------------------------------------------
4111
cmd(const QAction * a,EditData & ed)4112 void Score::cmd(const QAction* a, EditData& ed)
4113 {
4114 QString cmd(a ? a->data().toString() : "");
4115 if (MScore::debugMode)
4116 qDebug("<%s>", qPrintable(cmd));
4117
4118 struct ScoreCmd {
4119 const char* name;
4120 std::function<void(Score* cs, EditData& ed)> cmd;
4121 };
4122
4123 static const std::vector<ScoreCmd> cmdList {
4124 { "note-c", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, false); }},
4125 { "note-d", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, false); }},
4126 { "note-e", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, false); }},
4127 { "note-f", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, false); }},
4128 { "note-g", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, false); }},
4129 { "note-a", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, false); }},
4130 { "note-b", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, false); }},
4131 { "chord-c", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, true, false); }},
4132 { "chord-d", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, true, false); }},
4133 { "chord-e", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, true, false); }},
4134 { "chord-f", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, true, false); }},
4135 { "chord-g", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, true, false); }},
4136 { "chord-a", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, true, false); }},
4137 { "chord-b", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, true, false); }},
4138 { "insert-c", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 0, false, true); }},
4139 { "insert-d", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 1, false, true); }},
4140 { "insert-e", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 2, false, true); }},
4141 { "insert-f", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 3, false, true); }},
4142 { "insert-g", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 4, false, true); }},
4143 { "insert-a", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 5, false, true); }},
4144 { "insert-b", [](Score* cs, EditData& ed){ cs->cmdAddPitch(ed, 6, false, true); }},
4145 { "fret-0", [](Score* cs, EditData&){ cs->cmdAddFret(0); }},
4146 { "fret-1", [](Score* cs, EditData&){ cs->cmdAddFret(1); }},
4147 { "fret-2", [](Score* cs, EditData&){ cs->cmdAddFret(2); }},
4148 { "fret-3", [](Score* cs, EditData&){ cs->cmdAddFret(3); }},
4149 { "fret-4", [](Score* cs, EditData&){ cs->cmdAddFret(4); }},
4150 { "fret-5", [](Score* cs, EditData&){ cs->cmdAddFret(5); }},
4151 { "fret-6", [](Score* cs, EditData&){ cs->cmdAddFret(6); }},
4152 { "fret-7", [](Score* cs, EditData&){ cs->cmdAddFret(7); }},
4153 { "fret-8", [](Score* cs, EditData&){ cs->cmdAddFret(8); }},
4154 { "fret-9", [](Score* cs, EditData&){ cs->cmdAddFret(9); }},
4155 { "fret-10", [](Score* cs, EditData&){ cs->cmdAddFret(10); }},
4156 { "fret-11", [](Score* cs, EditData&){ cs->cmdAddFret(11); }},
4157 { "fret-12", [](Score* cs, EditData&){ cs->cmdAddFret(12); }},
4158 { "fret-13", [](Score* cs, EditData&){ cs->cmdAddFret(13); }},
4159 { "fret-14", [](Score* cs, EditData&){ cs->cmdAddFret(14); }},
4160 { "toggle-visible", [](Score* cs, EditData&){ cs->cmdToggleVisible(); }},
4161 { "reset-stretch", [](Score* cs, EditData&){ cs->resetUserStretch(); }},
4162 { "mirror-note", [](Score* cs, EditData&){ cs->cmdMirrorNoteHead(); }},
4163 { "double-duration", [](Score* cs, EditData&){ cs->cmdDoubleDuration(); }},
4164 { "half-duration", [](Score* cs, EditData&){ cs->cmdHalfDuration(); }},
4165 { "inc-duration-dotted", [](Score* cs, EditData&){ cs->cmdIncDurationDotted(); }},
4166 { "dec-duration-dotted", [](Score* cs, EditData&){ cs->cmdDecDurationDotted(); }},
4167 { "add-staccato", [](Score* cs, EditData&){ cs->addArticulation(SymId::articStaccatoAbove); }},
4168 { "add-tenuto", [](Score* cs, EditData&){ cs->addArticulation(SymId::articTenutoAbove); }},
4169 { "add-marcato", [](Score* cs, EditData&){ cs->addArticulation(SymId::articMarcatoAbove); }},
4170 { "add-sforzato", [](Score* cs, EditData&){ cs->addArticulation(SymId::articAccentAbove); }},
4171 { "add-trill", [](Score* cs, EditData&){ cs->addArticulation(SymId::ornamentTrill); }},
4172 { "add-up-bow", [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsUpBow); }},
4173 { "add-down-bow", [](Score* cs, EditData&){ cs->addArticulation(SymId::stringsDownBow); }},
4174 { "add-8va", [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VA); }},
4175 { "add-8vb", [](Score* cs, EditData&){ cs->cmdAddOttava(OttavaType::OTTAVA_8VB); }},
4176 { "note-longa", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed); }},
4177 { "note-longa-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE00, ed); }},
4178 { "note-breve", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed); }},
4179 { "note-breve-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE0, ed); }},
4180 { "pad-note-1", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed); }},
4181 { "pad-note-1-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1, ed); }},
4182 { "pad-note-2", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed); }},
4183 { "pad-note-2-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE2, ed); }},
4184 { "pad-note-4", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed); }},
4185 { "pad-note-4-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE4, ed); }},
4186 { "pad-note-8", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed); }},
4187 { "pad-note-8-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE8, ed); }},
4188 { "pad-note-16", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed); }},
4189 { "pad-note-16-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE16, ed); }},
4190 { "pad-note-32", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed); }},
4191 { "pad-note-32-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE32, ed); }},
4192 { "pad-note-64", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed); }},
4193 { "pad-note-64-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE64, ed); }},
4194 { "pad-note-128", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed); }},
4195 { "pad-note-128-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE128, ed); }},
4196 { "pad-note-256", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE256, ed); }},
4197 { "pad-note-256-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE256, ed); }},
4198 { "pad-note-512", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE512, ed); }},
4199 { "pad-note-512-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE512, ed); }},
4200 { "pad-note-1024", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1024, ed); }},
4201 { "pad-note-1024-TAB", [](Score* cs, EditData& ed){ cs->padToggle(Pad::NOTE1024, ed); }},
4202 { "reset-style", [](Score* cs, EditData&){ cs->cmdResetAllStyle(); }},
4203 { "reset-text-style-overrides", [](Score* cs, EditData&){ cs->cmdResetTextStyleOverrides(); }},
4204 { "reset-beammode", [](Score* cs, EditData&){ cs->cmdResetBeamMode(); }},
4205 { "reset-groupings", [](Score* cs, EditData&){ cs->cmdResetNoteAndRestGroupings(); }},
4206 { "clef-violin", [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::G); }},
4207 { "clef-bass", [](Score* cs, EditData&){ cs->cmdInsertClef(ClefType::F); }},
4208 { "voice-x12", [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 1); }},
4209 { "voice-x13", [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 2); }},
4210 { "voice-x14", [](Score* cs, EditData&){ cs->cmdExchangeVoice(0, 3); }},
4211 { "voice-x23", [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 2); }},
4212 { "voice-x24", [](Score* cs, EditData&){ cs->cmdExchangeVoice(1, 3); }},
4213 { "voice-x34", [](Score* cs, EditData&){ cs->cmdExchangeVoice(2, 3); }},
4214 { "pad-rest", [](Score* cs, EditData& ed){ cs->padToggle(Pad::REST, ed); }},
4215 { "pad-dot", [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT, ed); }},
4216 { "pad-dotdot", [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOTDOT, ed); }},
4217 { "pad-dot3", [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT3, ed); }},
4218 { "pad-dot4", [](Score* cs, EditData& ed){ cs->padToggle(Pad::DOT4, ed); }},
4219 { "beam-start", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN); }},
4220 { "beam-mid", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::MID); }},
4221 { "no-beam", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::NONE); }},
4222 { "beam32", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN32); }},
4223 { "beam64", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::BEGIN64); }},
4224 { "auto-beam", [](Score* cs, EditData&){ cs->cmdSetBeamMode(Beam::Mode::AUTO); }},
4225 { "sharp2", [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP2, ed); }},
4226 { "sharp", [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::SHARP, ed); }},
4227 { "nat", [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::NATURAL, ed); }},
4228 { "flat", [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT, ed); }},
4229 { "flat2", [](Score* cs, EditData& ed){ cs->toggleAccidental(AccidentalType::FLAT2, ed); }},
4230 { "sharp2-post", [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::SHARP2); }},
4231 { "sharp-post", [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::SHARP); }},
4232 { "nat-post", [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::NATURAL); }},
4233 { "flat-post", [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::FLAT); }},
4234 { "flat2-post", [](Score* cs, EditData&){ cs->changeAccidental(AccidentalType::FLAT2); }},
4235 { "flip", [](Score* cs, EditData&){ cs->cmdFlip(); }},
4236 { "stretch+", [](Score* cs, EditData&){ cs->cmdAddStretch(0.1); }},
4237 { "stretch-", [](Score* cs, EditData&){ cs->cmdAddStretch(-0.1); }},
4238 { "pitch-spell", [](Score* cs, EditData&){ cs->spell(); }},
4239 { "select-all", [](Score* cs, EditData&){ cs->cmdSelectAll(); }},
4240 { "select-section", [](Score* cs, EditData&){ cs->cmdSelectSection(); }},
4241 { "add-brackets", [](Score* cs, EditData&){ cs->cmdAddBracket(); }},
4242 { "add-parentheses", [](Score* cs, EditData&){ cs->cmdAddParentheses(); }},
4243 { "add-braces", [](Score* cs, EditData&){ cs->cmdAddBraces(); }},
4244 { "acciaccatura", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::ACCIACCATURA, MScore::division / 2); }},
4245 { "appoggiatura", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::APPOGGIATURA, MScore::division / 2); }},
4246 { "grace4", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE4, MScore::division); }},
4247 { "grace16", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16, MScore::division / 4); }},
4248 { "grace32", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32, MScore::division / 8); }},
4249 { "grace8after", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE8_AFTER, MScore::division / 2); }},
4250 { "grace16after", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE16_AFTER, MScore::division / 4); }},
4251 { "grace32after", [](Score* cs, EditData&){ cs->cmdAddGrace(NoteType::GRACE32_AFTER, MScore::division / 8); }},
4252 { "explode", [](Score* cs, EditData&){ cs->cmdExplode(); }},
4253 { "implode", [](Score* cs, EditData&){ cs->cmdImplode(); }},
4254 { "realize-chord-symbols", [](Score* cs, EditData&){ cs->cmdRealizeChordSymbols(); }},
4255 { "slash-fill", [](Score* cs, EditData&){ cs->cmdSlashFill(); }},
4256 { "slash-rhythm", [](Score* cs, EditData&){ cs->cmdSlashRhythm(); }},
4257 { "resequence-rehearsal-marks", [](Score* cs, EditData&){ cs->cmdResequenceRehearsalMarks(); }},
4258 { "del-empty-measures", [](Score* cs, EditData&){ cs->cmdRemoveEmptyTrailingMeasures(); }},
4259 { "add-audio", [](Score* cs, EditData&){ cs->addAudioTrack(); }},
4260 { "transpose-up", [](Score* cs, EditData&){ cs->transposeSemitone(1); }},
4261 { "transpose-down", [](Score* cs, EditData&){ cs->transposeSemitone(-1); }},
4262 { "pitch-up-diatonic-alterations", [](Score* cs, EditData&){ cs->transposeDiatonicAlterations(TransposeDirection::UP); }},
4263 { "pitch-down-diatonic-alterations", [](Score* cs, EditData&){ cs->transposeDiatonicAlterations(TransposeDirection::DOWN);}},
4264 { "delete", [](Score* cs, EditData&){ cs->cmdDeleteSelection(); }},
4265 { "full-measure-rest", [](Score* cs, EditData&){ cs->cmdFullMeasureRest(); }},
4266 { "toggle-insert-mode", [](Score* cs, EditData&){ cs->_is.setInsertMode(!cs->_is.insertMode()); }},
4267 { "pitch-up", [](Score* cs, EditData&){ cs->cmdPitchUp(); }},
4268 { "pitch-down", [](Score* cs, EditData&){ cs->cmdPitchDown(); }},
4269 { "time-delete", [](Score* cs, EditData&){ cs->cmdTimeDelete(); }},
4270 { "pitch-up-octave", [](Score* cs, EditData&){ cs->cmdPitchUpOctave(); }},
4271 { "pitch-down-octave", [](Score* cs, EditData&){ cs->cmdPitchDownOctave(); }},
4272 { "pad-note-increase", [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed); }},
4273 { "pad-note-decrease", [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed); }},
4274 { "pad-note-increase-TAB", [](Score* cs, EditData& ed){ cs->cmdPadNoteIncreaseTAB(ed); }},
4275 { "pad-note-decrease-TAB", [](Score* cs, EditData& ed){ cs->cmdPadNoteDecreaseTAB(ed); }},
4276 { "toggle-mmrest", [](Score* cs, EditData&){ cs->cmdToggleMmrest(); }},
4277 { "toggle-hide-empty", [](Score* cs, EditData&){ cs->cmdToggleHideEmpty(); }},
4278 { "set-visible", [](Score* cs, EditData&){ cs->cmdSetVisible(); }},
4279 { "unset-visible", [](Score* cs, EditData&){ cs->cmdUnsetVisible(); }},
4280 { "system-break", [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::LINE); }},
4281 { "page-break", [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::PAGE); }},
4282 { "section-break", [](Score* cs, EditData&){ cs->cmdToggleLayoutBreak(LayoutBreak::Type::SECTION); }},
4283 { "relayout", [](Score* cs, EditData&){ cs->cmdRelayout(); }},
4284 { "toggle-autoplace", [](Score* cs, EditData&){ cs->cmdToggleAutoplace(false); }},
4285 { "autoplace-enabled", [](Score* cs, EditData&){ cs->cmdToggleAutoplace(true); }},
4286 };
4287
4288 for (const auto& c : cmdList) {
4289 if (cmd == c.name) {
4290 startCmd();
4291 c.cmd(this, ed);
4292 endCmd();
4293 return;
4294 }
4295 }
4296 qDebug("unknown cmd <%s>", qPrintable(cmd));
4297 }
4298
4299
4300 }
4301
4302